Documentation
¶
Overview ¶
Package primitives provides the curve abstraction Lens uses for all elliptic-curve-based threshold operations.
The package is deliberately small. Three concrete curves are shipped:
- Ed25519 — RFC 8032 / FIPS 186-5 EdDSA curve (filippo.io/edwards25519)
- secp256k1 — SEC 2 / Bitcoin curve (decred/dcrd/dcrec/secp256k1)
- Ristretto255 — RFC 9496 prime-order group over Curve25519 (gtank/ristretto255)
All three implement the Curve interface below. Two curves never share Scalar / Point types — each curve owns its concrete types and casts internally; the interfaces exist so generic threshold code can treat them uniformly.
Why a separate curve package ¶
Lens deliberately does NOT depend on github.com/luxfi/threshold for curve operations: the Lens kernel must be importable by the LSS-Lens adapter inside the threshold module without creating a circular dependency. The curve interface is small enough that re-implementing it costs less than the dependency tangle.
No bias, no leakage ¶
Scalar sampling rejects until the drawn bytes interpret to a value in [0, order). Point operations never panic on invalid inputs — they return errors that propagate to the protocol layer.
Index ¶
- Variables
- func HashPoint(tag string, p Point) [32]byte
- func HashPoints(tag string, ps ...Point) [32]byte
- func Lagrange(curve Curve, ids []int) (map[int]Scalar, error)
- func LagrangeAt(curve Curve, ids []int, x Scalar) (map[int]Scalar, error)
- func SortedInts(ids []int) []int
- func VerifyPedersenShare(curve Curve, share, blind Scalar, commits []Point, x Scalar) error
- type Curve
- type Ed25519
- func (Ed25519) BasePoint() Point
- func (Ed25519) HashToScalar(data []byte) Scalar
- func (Ed25519) Name() string
- func (Ed25519) NewPoint() Point
- func (Ed25519) NewScalar() Scalar
- func (Ed25519) PointBytes() int
- func (Ed25519) SampleScalar(rand io.Reader) (Scalar, error)
- func (Ed25519) ScalarBytes() int
- func (c Ed25519) SecondaryGenerator() Point
- type Point
- type Polynomial
- type Ristretto255
- func (Ristretto255) BasePoint() Point
- func (Ristretto255) HashToScalar(data []byte) Scalar
- func (Ristretto255) Name() string
- func (Ristretto255) NewPoint() Point
- func (Ristretto255) NewScalar() Scalar
- func (Ristretto255) PointBytes() int
- func (Ristretto255) SampleScalar(rand io.Reader) (Scalar, error)
- func (Ristretto255) ScalarBytes() int
- func (Ristretto255) SecondaryGenerator() Point
- type Scalar
- type Secp256k1
- func (Secp256k1) BasePoint() Point
- func (Secp256k1) HashToScalar(data []byte) Scalar
- func (Secp256k1) Name() string
- func (Secp256k1) NewPoint() Point
- func (Secp256k1) NewScalar() Scalar
- func (Secp256k1) PointBytes() int
- func (Secp256k1) SampleScalar(rand io.Reader) (Scalar, error)
- func (Secp256k1) ScalarBytes() int
- func (Secp256k1) SecondaryGenerator() Point
Constants ¶
This section is empty.
Variables ¶
var ErrCommitMismatch = errors.New("lens/primitives: Pedersen commitment verification failed")
ErrCommitMismatch is returned when a (share, blind) pair fails the Pedersen verification equation.
var ErrShamirInsufficient = errors.New("lens/primitives: insufficient shares for Shamir recovery")
ErrShamirInsufficient is returned when fewer than `threshold` shares are supplied to a reconstruction routine.
Functions ¶
func HashPoint ¶
HashPoint returns BLAKE3-32 over a domain-separated tag and the canonical encoding of `p`. Used as a stable identifier for a curve-point in transcript hashing.
func HashPoints ¶
HashPoints returns BLAKE3-32 over a domain-separated tag and the canonical encoding of every point in `ps`, length-prefixed for unambiguous parsing.
func Lagrange ¶
Lagrange returns the Lagrange basis coefficients λ_i^T evaluated at X = 0 for the set of one-indexed party IDs T:
λ_i = Π_{j ∈ T, j ≠ i} (-x_j) / (x_i - x_j)
where x_k is the scalar representation of party ID k. Used to reconstruct s = Σ_i λ_i · s_i over the curve.
IDs MUST be distinct, non-zero, and < group order.
func LagrangeAt ¶
LagrangeAt returns Lagrange coefficients evaluated at an arbitrary scalar `x` (rather than at 0). Used during VSR to evaluate the composite polynomial G(x_j) = Σ_i λ_i · g_i(x_j).
func SortedInts ¶
SortedInts returns a copy of `ids` sorted ascending.
func VerifyPedersenShare ¶
VerifyPedersenShare checks the commitment-equation
share·G + blind·H ?= Σ_{k=0..t-1} x^k · C_k
where (share, blind) is what the recipient at evaluation point x received from the dealer, and the C_k are the dealer's broadcast Pedersen commits to its (secretCoeffs, blindCoeffs). Returns nil if the share is consistent; ErrCommitMismatch otherwise.
Types ¶
type Curve ¶
type Curve interface {
// Name returns the curve identifier (e.g. "ed25519",
// "secp256k1", "ristretto255"). Used in transcript binding and
// activation cert serialization. MUST be unique across curves.
Name() string
// ScalarBytes returns the canonical byte length of an encoded
// Scalar.
ScalarBytes() int
// PointBytes returns the canonical byte length of an encoded Point.
PointBytes() int
// NewScalar returns the additive identity (zero) Scalar.
NewScalar() Scalar
// NewPoint returns the identity Point.
NewPoint() Point
// BasePoint returns the canonical generator G of the prime-order
// subgroup of the curve.
BasePoint() Point
// SecondaryGenerator returns the canonical Pedersen-binding
// generator H. H is independent of G — neither is a known scalar
// multiple of the other. Derived deterministically per curve via
// hash-to-curve from a domain-separated nothing-up-my-sleeve tag
// (see lens.<curve>.h-base.v1 in the per-curve implementation).
SecondaryGenerator() Point
// SampleScalar draws a uniform Scalar in [0, order) from rand.
// Uses rejection sampling so the distribution is unbiased.
SampleScalar(rand io.Reader) (Scalar, error)
// HashToScalar maps the byte string `data` to a Scalar via a
// curve-specific domain-separated wide-reduction hash. Output
// distribution is statistically indistinguishable from uniform on
// [0, order).
HashToScalar(data []byte) Scalar
}
Curve is the abstract elliptic-curve group Lens operates on. Each concrete implementation pins one curve identity (Ed25519, secp256k1, Ristretto255) and carries the corresponding Scalar / Point types.
func NewRistretto255 ¶
func NewRistretto255() Curve
NewRistretto255 returns the singleton Ristretto255 curve.
type Ed25519 ¶
type Ed25519 struct{}
Ed25519 is the RFC 8032 / FIPS 186-5 Edwards-form curve. The prime-order subgroup has order ℓ = 2^252 + 27742317777372353535851937790883648493.
G is the conventional Ed25519 base point. H is derived deterministically via hash-to-curve from a Lens-specific nothing-up-my-sleeve tag, then cleared to the prime-order subgroup via multiplication by the cofactor.
func (Ed25519) HashToScalar ¶
HashToScalar maps a byte string to a uniform scalar via SHA-512 + SetUniformBytes (the standard reduction for ℓ).
func (Ed25519) PointBytes ¶
func (Ed25519) SampleScalar ¶
SampleScalar draws a uniform scalar from a 64-byte read which is reduced mod ℓ via SetUniformBytes (statistically unbiased).
func (Ed25519) ScalarBytes ¶
func (Ed25519) SecondaryGenerator ¶
type Point ¶
type Point interface {
encoding.BinaryMarshaler
encoding.BinaryUnmarshaler
// Curve returns the curve this point belongs to.
Curve() Curve
// Add returns receiver + other (group operation).
Add(other Point) Point
// Sub returns receiver - other.
Sub(other Point) Point
// Negate returns -receiver.
Negate() Point
// IsIdentity returns true iff this is the identity element.
IsIdentity() bool
// Equal returns true iff receiver == other.
Equal(other Point) bool
}
Point is an element of the curve group. Point operations are non-mutating — every method returns a fresh point.
func PedersenCommit ¶
PedersenCommit returns C = secret·G + blind·H over the supplied curve. G is the curve's base point; H is the curve's secondary generator (returned by SecondaryGenerator).
The commitment is hiding (when blind is uniform random) and binding (under the discrete log assumption between G and H).
func PedersenVectorCommit ¶
PedersenVectorCommit commits to the t coefficients of a polynomial f(X) = c_0 + c_1·X + ... + c_{t-1}·X^{t-1} together with matching blinding coefficients r_0, ..., r_{t-1}. Returns the t commitments C_k = c_k·G + r_k·H.
type Polynomial ¶
type Polynomial struct {
// contains filtered or unexported fields
}
Polynomial represents f(X) = a_0 + a_1·X + ... + a_t·X^t with coefficients in the curve's scalar field.
func NewPolynomial ¶
NewPolynomial constructs a polynomial of the given degree with the supplied constant term and (degree) random higher-order coefficients drawn from rand.
If constant == nil, the constant term is set to zero (used by HJKY97 zero-poly Refresh).
func PolynomialFromCoefficients ¶
func PolynomialFromCoefficients(curve Curve, coeffs []Scalar) *Polynomial
PolynomialFromCoefficients wraps an explicit coefficient slice as a polynomial. The slice is shared, not copied — the caller is responsible for not mutating it externally.
func Shamir ¶
func Shamir( curve Curve, secret Scalar, threshold, n int, rand io.Reader, ) (*Polynomial, map[int]Scalar, error)
Shamir produces a (t, n)-Shamir secret sharing of `secret` over the curve's scalar field. Returns:
- The polynomial f with f(0) = secret and (t-1) random higher- order coefficients drawn from `rand`.
- A map partyID → f(partyID) for partyID in [1, n].
The threshold t is the minimum number of shares needed to recover the secret (so the polynomial degree is t-1).
Note that party IDs are 1-indexed; ID 0 is reserved (evaluating at 0 reveals the secret).
func (*Polynomial) Coefficients ¶
func (p *Polynomial) Coefficients() []Scalar
Coefficients returns the underlying coefficient slice (not a copy). Used by the commitment layer to compute Pedersen commits per term.
func (*Polynomial) Constant ¶
func (p *Polynomial) Constant() Scalar
Constant returns a copy of the constant term.
func (*Polynomial) Degree ¶
func (p *Polynomial) Degree() int
Degree returns the polynomial's degree.
func (*Polynomial) Evaluate ¶
func (p *Polynomial) Evaluate(x Scalar) Scalar
Evaluate computes f(x) via Horner's method. Panics if x is zero, to avoid leaking the secret constant term.
func (*Polynomial) EvaluateUnchecked ¶
func (p *Polynomial) EvaluateUnchecked(x Scalar) Scalar
EvaluateUnchecked is like Evaluate but allows x = 0. Used in test/KAT paths to recover f(0) (the secret) for verification.
type Ristretto255 ¶
type Ristretto255 struct{}
Ristretto255 is the prime-order group from RFC 9496, built on Curve25519 via the Ristretto encoding. Group order is identical to Ed25519's ℓ.
func (Ristretto255) BasePoint ¶
func (Ristretto255) BasePoint() Point
func (Ristretto255) HashToScalar ¶
func (Ristretto255) HashToScalar(data []byte) Scalar
HashToScalar produces a uniform scalar via SHA-512 + reduction.
func (Ristretto255) NewPoint ¶
func (Ristretto255) NewPoint() Point
func (Ristretto255) NewScalar ¶
func (Ristretto255) NewScalar() Scalar
func (Ristretto255) PointBytes ¶
func (Ristretto255) PointBytes() int
func (Ristretto255) SampleScalar ¶
func (Ristretto255) SampleScalar(rand io.Reader) (Scalar, error)
SampleScalar draws a uniform scalar via 64-byte read + reduction.
func (Ristretto255) ScalarBytes ¶
func (Ristretto255) ScalarBytes() int
func (Ristretto255) SecondaryGenerator ¶
func (Ristretto255) SecondaryGenerator() Point
SecondaryGenerator derives H from a fixed nothing-up-my-sleeve tag expanded to 64 uniform bytes via SHA-512, then mapped to the group via the FromUniformBytes Elligator construction (the standard hash-to-curve for Ristretto255).
type Scalar ¶
type Scalar interface {
encoding.BinaryMarshaler
encoding.BinaryUnmarshaler
// Curve returns the curve this scalar belongs to.
Curve() Curve
// Set copies other into the receiver and returns the receiver.
Set(other Scalar) Scalar
// SetBytes interprets `bytes` (big-endian, padded to ScalarBytes())
// as a value mod the group order and assigns it. Returns an error
// if `bytes` has the wrong length.
SetBytes(bytes []byte) error
// SetUint64 assigns the receiver to the value `v`.
SetUint64(v uint64) Scalar
// Add computes receiver = receiver + other (mod order) and returns
// the receiver.
Add(other Scalar) Scalar
// Sub computes receiver = receiver - other (mod order) and returns
// the receiver.
Sub(other Scalar) Scalar
// Mul computes receiver = receiver * other (mod order) and returns
// the receiver.
Mul(other Scalar) Scalar
// Negate computes receiver = -receiver (mod order) and returns the
// receiver.
Negate() Scalar
// Invert computes receiver = receiver^-1 (mod order) and returns
// the receiver. If receiver is zero, the result is undefined and
// the implementation may panic — callers MUST check IsZero first
// or guarantee non-zero by construction.
Invert() Scalar
// IsZero returns true iff the receiver is the additive identity.
IsZero() bool
// Equal returns true iff receiver == other in constant time.
Equal(other Scalar) bool
// ActOnBase returns receiver * G (the base point), without
// mutating the receiver.
ActOnBase() Point
// Act returns receiver * P, without mutating either input.
Act(p Point) Point
}
Scalar is a value modulo the curve's group order. Operations are constant-time where the underlying implementation supports it.
The operations mutate the receiver and return it for chaining, mirroring filippo.io/edwards25519 and threshold's curve.Scalar conventions. To preserve a value across an operation, copy it first via Set on a fresh NewScalar.
func LagrangeRecover ¶
LagrangeRecover reconstructs the secret f(0) from the supplied (partyID → share) map, using the smallest-ID t-element subset. Intended for tests and KAT verification — calling this in production gives the caller the master secret.
type Secp256k1 ¶
type Secp256k1 struct{}
Secp256k1 is the SEC2 / Bitcoin curve.
func (Secp256k1) HashToScalar ¶
HashToScalar maps a byte string to a scalar via SHA-512 + reduction.
func (Secp256k1) PointBytes ¶
func (Secp256k1) SampleScalar ¶
SampleScalar draws a uniform scalar in [0, n) via rejection sampling.
func (Secp256k1) ScalarBytes ¶
func (Secp256k1) SecondaryGenerator ¶
SecondaryGenerator returns H, an independent generator for Pedersen commits. Derived deterministically via try-and-increment hash-to-curve over a Lens-specific nothing-up-my-sleeve tag.