1- // Package secretsharing provides methods to split secrets in shares.
1+ // Package secretsharing provides methods to split secrets into shares.
22//
33// Let n be the number of parties, and t the number of corrupted parties such
44// that 0 <= t < n. A (t,n) secret sharing allows to split a secret into n
88// which relies on Lagrange polynomial interpolation.
99//
1010// The NewFeldmanSecretSharing function creates a Feldman secret sharing [2],
11- // which extends Shamir's by allowing to verify that a share was honestly
12- // generated.
11+ // which extends Shamir's by allowing to verify that a share is part of a
12+ // committed secret.
13+ //
14+ // In this implementation, secret sharing is defined over the scalar field of
15+ // a prime order group.
1316//
1417// References
1518//
@@ -28,11 +31,11 @@ import (
2831
2932// Share represents a share of a secret.
3033type Share struct {
31- ID uint // ID uniquely identifies a share in a secret sharing instance.
34+ ID uint64 // ID uniquely identifies a share in a secret sharing instance.
3235 Value group.Scalar // Value stores the share generated from a secret sharing instance.
3336}
3437
35- type ss struct {
38+ type SecretSharing struct {
3639 g group.Group
3740 t , n uint
3841}
@@ -41,47 +44,47 @@ type ss struct {
4144// A (t,n) secret sharing allows to split a secret into n shares, such that the
4245// secret can be only recovered from any subset of t+1 shares. Returns an error
4346// if 0 <= t < n does not hold.
44- func NewShamirSecretSharing (g group.Group , t , n uint ) (ss , error ) {
47+ func NewShamirSecretSharing (g group.Group , t , n uint ) (SecretSharing , error ) {
4548 if t >= n {
46- return ss {}, errors .New ("secretsharing: bad parameters" )
49+ return SecretSharing {}, errors .New ("secretsharing: bad parameters" )
4750 }
48- return ss {g : g , t : t , n : n }, nil
51+ return SecretSharing {g : g , t : t , n : n }, nil
4952}
5053
5154// Params returns the t and n parameters of the secret sharing.
52- func (s ss ) Params () (t , n uint ) { return s .t , s .n }
55+ func (s SecretSharing ) Params () (t , n uint ) { return s .t , s .n }
5356
54- func (s ss ) polyFromSecret (rnd io.Reader , secret group.Scalar ) (p polynomial.Polynomial ) {
57+ func (s SecretSharing ) polyFromSecret (rnd io.Reader , secret group.Scalar ) (p polynomial.Polynomial ) {
5558 c := make ([]group.Scalar , s .t + 1 )
56- for i := range c {
59+ for i := 1 ; i < len ( c ); i ++ {
5760 c [i ] = s .g .RandomScalar (rnd )
5861 }
59- c [0 ]. Set ( secret )
62+ c [0 ] = secret . Copy ( )
6063 return polynomial .New (c )
6164}
6265
63- func (s ss ) generateShares (poly polynomial.Polynomial ) []Share {
66+ func (s SecretSharing ) generateShares (poly polynomial.Polynomial ) []Share {
6467 shares := make ([]Share , s .n )
6568 x := s .g .NewScalar ()
6669 for i := range shares {
6770 id := i + 1
6871 x .SetUint64 (uint64 (id ))
69- shares [i ].ID = uint (id )
72+ shares [i ].ID = uint64 (id )
7073 shares [i ].Value = poly .Evaluate (x )
7174 }
7275
7376 return shares
7477}
7578
7679// Shard splits the secret into n shares.
77- func (s ss ) Shard (rnd io.Reader , secret group.Scalar ) []Share {
80+ func (s SecretSharing ) Shard (rnd io.Reader , secret group.Scalar ) []Share {
7881 return s .generateShares (s .polyFromSecret (rnd , secret ))
7982}
8083
8184// Recover returns the secret provided more than t shares are given. Returns an
8285// error if the number of shares is not above the threshold or goes beyond the
8386// maximum number of shares.
84- func (s ss ) Recover (shares []Share ) (group.Scalar , error ) {
87+ func (s SecretSharing ) Recover (shares []Share ) (group.Scalar , error ) {
8588 if l := len (shares ); l <= int (s .t ) {
8689 return nil , fmt .Errorf ("secretsharing: does not reach the threshold %v with %v shares" , s .t , l )
8790 } else if l > int (s .n ) {
@@ -91,7 +94,7 @@ func (s ss) Recover(shares []Share) (group.Scalar, error) {
9194 x := make ([]group.Scalar , s .t + 1 )
9295 px := make ([]group.Scalar , s .t + 1 )
9396 for i := range shares [:s .t + 1 ] {
94- x [i ] = s .g .NewScalar ().SetUint64 (uint64 ( shares [i ].ID ) )
97+ x [i ] = s .g .NewScalar ().SetUint64 (shares [i ].ID )
9598 px [i ] = shares [i ].Value
9699 }
97100
@@ -103,31 +106,32 @@ func (s ss) Recover(shares []Share) (group.Scalar, error) {
103106
104107type SharesCommitment = []group.Element
105108
106- type vss struct { s ss }
109+ type VerifiableSecretSharing struct { s SecretSharing }
107110
108111// NewFeldmanSecretSharing implements a (t,n) Feldman's verifiable secret
109112// sharing. A (t,n) secret sharing allows to split a secret into n shares, such
110113// that the secret can be only recovered from any subset of t+1 shares. This
111114// method is verifiable because once the shares and the secret are committed
112115// during sharding, one can later verify whether the share was generated
113116// honestly. Returns an error if 0 < t <= n does not hold.
114- func NewFeldmanSecretSharing (g group.Group , t , n uint ) (vss , error ) {
117+ func NewFeldmanSecretSharing (g group.Group , t , n uint ) (VerifiableSecretSharing , error ) {
115118 s , err := NewShamirSecretSharing (g , t , n )
116- return vss {s }, err
119+ return VerifiableSecretSharing {s }, err
117120}
118121
119122// Params returns the t and n parameters of the secret sharing.
120- func (v vss ) Params () (t , n uint ) { return v .s .Params () }
123+ func (v VerifiableSecretSharing ) Params () (t , n uint ) { return v .s .Params () }
121124
122125// Shard splits the secret into n shares, and also returns a commitment to both
123- // the secret and the shares.
124- func (v vss ) Shard (rnd io.Reader , secret group.Scalar ) ([]Share , SharesCommitment ) {
126+ // the secret and the shares. The ShareCommitment must be sent to each party
127+ // so each party can verify its share is correct. Sharding a secret more
128+ // than once produces ShareCommitments with the same first entry.
129+ func (v VerifiableSecretSharing ) Shard (rnd io.Reader , secret group.Scalar ) ([]Share , SharesCommitment ) {
125130 poly := v .s .polyFromSecret (rnd , secret )
126131 shares := v .s .generateShares (poly )
127- coeffs := poly .Coefficients ()
128- shareComs := make (SharesCommitment , len (coeffs ))
129- for i := range coeffs {
130- shareComs [i ] = v .s .g .NewElement ().MulGen (coeffs [i ])
132+ shareComs := make (SharesCommitment , poly .Degree ()+ 1 )
133+ for i := range shareComs {
134+ shareComs [i ] = v .s .g .NewElement ().MulGen (poly .Coefficient (uint (i )))
131135 }
132136
133137 return shares , shareComs
@@ -136,7 +140,7 @@ func (v vss) Shard(rnd io.Reader, secret group.Scalar) ([]Share, SharesCommitmen
136140// Verify returns true if a share was produced by sharding a secret. It uses
137141// the share commitments generated by the Shard function to verify this
138142// property.
139- func (v vss ) Verify (s Share , c SharesCommitment ) bool {
143+ func (v VerifiableSecretSharing ) Verify (s Share , c SharesCommitment ) bool {
140144 if len (c ) != int (v .s .t + 1 ) {
141145 return false
142146 }
@@ -145,7 +149,7 @@ func (v vss) Verify(s Share, c SharesCommitment) bool {
145149 sum := v .s .g .NewElement ().Set (c [lc ])
146150 x := v .s .g .NewScalar ()
147151 for i := lc - 1 ; i >= 0 ; i -- {
148- x .SetUint64 (uint64 ( s .ID ) )
152+ x .SetUint64 (s .ID )
149153 sum .Mul (sum , x )
150154 sum .Add (sum , c [i ])
151155 }
@@ -156,4 +160,6 @@ func (v vss) Verify(s Share, c SharesCommitment) bool {
156160// Recover returns the secret provided more than t shares are given. Returns an
157161// error if the number of shares is not above the threshold (t) or is larger
158162// than the maximum number of shares (n).
159- func (v vss ) Recover (shares []Share ) (group.Scalar , error ) { return v .s .Recover (shares ) }
163+ func (v VerifiableSecretSharing ) Recover (shares []Share ) (group.Scalar , error ) {
164+ return v .s .Recover (shares )
165+ }
0 commit comments