From 1b68fea98d32b016c3cab9d001950874e6b4abb3 Mon Sep 17 00:00:00 2001 From: armfazh Date: Mon, 10 Oct 2022 12:42:56 -0700 Subject: [PATCH] Updates after cjpatton's review. --- math/polynomial/polynomial.go | 13 ++++--- secretsharing/ss.go | 66 +++++++++++++++++++---------------- 2 files changed, 42 insertions(+), 37 deletions(-) diff --git a/math/polynomial/polynomial.go b/math/polynomial/polynomial.go index 5dfbe4a89..275eaed53 100644 --- a/math/polynomial/polynomial.go +++ b/math/polynomial/polynomial.go @@ -56,14 +56,13 @@ func (p Polynomial) Evaluate(x group.Scalar) group.Scalar { return px } -// Coefficients returns a deep-copy of the polynomial's coefficients in -// ascending order with respect to the degree. -func (p Polynomial) Coefficients() []group.Scalar { - c := make([]group.Scalar, len(p.c)) - for i := range p.c { - c[i] = p.c[i].Copy() +// Coefficient returns a deep-copy of the n-th polynomial's coefficient. +// Note coefficients are sorted in ascending order with respect to the degree. +func (p Polynomial) Coefficient(n uint) group.Scalar { + if int(n) >= len(p.c) { + panic("polynomial: invalid index for coefficient") } - return c + return p.c[n].Copy() } // LagrangePolynomial stores a Lagrange polynomial over the set of scalars of a group. diff --git a/secretsharing/ss.go b/secretsharing/ss.go index 64c5ac55d..d89877a2a 100644 --- a/secretsharing/ss.go +++ b/secretsharing/ss.go @@ -1,4 +1,4 @@ -// Package secretsharing provides methods to split secrets in shares. +// Package secretsharing provides methods to split secrets into shares. // // Let n be the number of parties, and t the number of corrupted parties such // that 0 <= t < n. A (t,n) secret sharing allows to split a secret into n @@ -8,8 +8,11 @@ // which relies on Lagrange polynomial interpolation. // // The NewFeldmanSecretSharing function creates a Feldman secret sharing [2], -// which extends Shamir's by allowing to verify that a share was honestly -// generated. +// which extends Shamir's by allowing to verify that a share is part of a +// committed secret. +// +// In this implementation, secret sharing is defined over the scalar field of +// a prime order group. // // References // @@ -28,11 +31,11 @@ import ( // Share represents a share of a secret. type Share struct { - ID uint // ID uniquely identifies a share in a secret sharing instance. + ID uint64 // ID uniquely identifies a share in a secret sharing instance. Value group.Scalar // Value stores the share generated from a secret sharing instance. } -type ss struct { +type SecretSharing struct { g group.Group t, n uint } @@ -41,32 +44,32 @@ type ss struct { // A (t,n) secret sharing allows to split a secret into n shares, such that the // secret can be only recovered from any subset of t+1 shares. Returns an error // if 0 <= t < n does not hold. -func NewShamirSecretSharing(g group.Group, t, n uint) (ss, error) { +func NewShamirSecretSharing(g group.Group, t, n uint) (SecretSharing, error) { if t >= n { - return ss{}, errors.New("secretsharing: bad parameters") + return SecretSharing{}, errors.New("secretsharing: bad parameters") } - return ss{g: g, t: t, n: n}, nil + return SecretSharing{g: g, t: t, n: n}, nil } // Params returns the t and n parameters of the secret sharing. -func (s ss) Params() (t, n uint) { return s.t, s.n } +func (s SecretSharing) Params() (t, n uint) { return s.t, s.n } -func (s ss) polyFromSecret(rnd io.Reader, secret group.Scalar) (p polynomial.Polynomial) { +func (s SecretSharing) polyFromSecret(rnd io.Reader, secret group.Scalar) (p polynomial.Polynomial) { c := make([]group.Scalar, s.t+1) - for i := range c { + for i := 1; i < len(c); i++ { c[i] = s.g.RandomScalar(rnd) } - c[0].Set(secret) + c[0] = secret.Copy() return polynomial.New(c) } -func (s ss) generateShares(poly polynomial.Polynomial) []Share { +func (s SecretSharing) generateShares(poly polynomial.Polynomial) []Share { shares := make([]Share, s.n) x := s.g.NewScalar() for i := range shares { id := i + 1 x.SetUint64(uint64(id)) - shares[i].ID = uint(id) + shares[i].ID = uint64(id) shares[i].Value = poly.Evaluate(x) } @@ -74,14 +77,14 @@ func (s ss) generateShares(poly polynomial.Polynomial) []Share { } // Shard splits the secret into n shares. -func (s ss) Shard(rnd io.Reader, secret group.Scalar) []Share { +func (s SecretSharing) Shard(rnd io.Reader, secret group.Scalar) []Share { return s.generateShares(s.polyFromSecret(rnd, secret)) } // Recover returns the secret provided more than t shares are given. Returns an // error if the number of shares is not above the threshold or goes beyond the // maximum number of shares. -func (s ss) Recover(shares []Share) (group.Scalar, error) { +func (s SecretSharing) Recover(shares []Share) (group.Scalar, error) { if l := len(shares); l <= int(s.t) { return nil, fmt.Errorf("secretsharing: does not reach the threshold %v with %v shares", s.t, l) } else if l > int(s.n) { @@ -91,7 +94,7 @@ func (s ss) Recover(shares []Share) (group.Scalar, error) { x := make([]group.Scalar, s.t+1) px := make([]group.Scalar, s.t+1) for i := range shares[:s.t+1] { - x[i] = s.g.NewScalar().SetUint64(uint64(shares[i].ID)) + x[i] = s.g.NewScalar().SetUint64(shares[i].ID) px[i] = shares[i].Value } @@ -103,7 +106,7 @@ func (s ss) Recover(shares []Share) (group.Scalar, error) { type SharesCommitment = []group.Element -type vss struct{ s ss } +type VerifiableSecretSharing struct{ s SecretSharing } // NewFeldmanSecretSharing implements a (t,n) Feldman's verifiable secret // sharing. A (t,n) secret sharing allows to split a secret into n shares, such @@ -111,23 +114,24 @@ type vss struct{ s ss } // method is verifiable because once the shares and the secret are committed // during sharding, one can later verify whether the share was generated // honestly. Returns an error if 0 < t <= n does not hold. -func NewFeldmanSecretSharing(g group.Group, t, n uint) (vss, error) { +func NewFeldmanSecretSharing(g group.Group, t, n uint) (VerifiableSecretSharing, error) { s, err := NewShamirSecretSharing(g, t, n) - return vss{s}, err + return VerifiableSecretSharing{s}, err } // Params returns the t and n parameters of the secret sharing. -func (v vss) Params() (t, n uint) { return v.s.Params() } +func (v VerifiableSecretSharing) Params() (t, n uint) { return v.s.Params() } // Shard splits the secret into n shares, and also returns a commitment to both -// the secret and the shares. -func (v vss) Shard(rnd io.Reader, secret group.Scalar) ([]Share, SharesCommitment) { +// the secret and the shares. The ShareCommitment must be sent to each party +// so each party can verify its share is correct. Sharding a secret more +// than once produces ShareCommitments with the same first entry. +func (v VerifiableSecretSharing) Shard(rnd io.Reader, secret group.Scalar) ([]Share, SharesCommitment) { poly := v.s.polyFromSecret(rnd, secret) shares := v.s.generateShares(poly) - coeffs := poly.Coefficients() - shareComs := make(SharesCommitment, len(coeffs)) - for i := range coeffs { - shareComs[i] = v.s.g.NewElement().MulGen(coeffs[i]) + shareComs := make(SharesCommitment, poly.Degree()+1) + for i := range shareComs { + shareComs[i] = v.s.g.NewElement().MulGen(poly.Coefficient(uint(i))) } return shares, shareComs @@ -136,7 +140,7 @@ func (v vss) Shard(rnd io.Reader, secret group.Scalar) ([]Share, SharesCommitmen // Verify returns true if a share was produced by sharding a secret. It uses // the share commitments generated by the Shard function to verify this // property. -func (v vss) Verify(s Share, c SharesCommitment) bool { +func (v VerifiableSecretSharing) Verify(s Share, c SharesCommitment) bool { if len(c) != int(v.s.t+1) { return false } @@ -145,7 +149,7 @@ func (v vss) Verify(s Share, c SharesCommitment) bool { sum := v.s.g.NewElement().Set(c[lc]) x := v.s.g.NewScalar() for i := lc - 1; i >= 0; i-- { - x.SetUint64(uint64(s.ID)) + x.SetUint64(s.ID) sum.Mul(sum, x) sum.Add(sum, c[i]) } @@ -156,4 +160,6 @@ func (v vss) Verify(s Share, c SharesCommitment) bool { // Recover returns the secret provided more than t shares are given. Returns an // error if the number of shares is not above the threshold (t) or is larger // than the maximum number of shares (n). -func (v vss) Recover(shares []Share) (group.Scalar, error) { return v.s.Recover(shares) } +func (v VerifiableSecretSharing) Recover(shares []Share) (group.Scalar, error) { + return v.s.Recover(shares) +}