@@ -32,49 +32,28 @@ import (
3232type Share struct {
3333 // ID uniquely identifies a share in a secret sharing instance.
3434 ID group.Scalar
35- // Value stores the share generated from a secret sharing instance.
35+ // Value stores the share generated by a secret sharing instance.
3636 Value group.Scalar
3737}
3838
39+ // SecretSharing provides a (t,n) Shamir's secret sharing. It allows splitting
40+ // a secret into n shares, such that the secret can be only recovered from
41+ // any subset of t+1 shares.
3942type SecretSharing struct {
4043 t uint // t is the threshold.
4144}
4245
43- // NewShamirSecretSharing implements a (t,n) Shamir's secret sharing.
44- // A (t,n) secret sharing allows to split a secret into n shares, such that the
45- // secret can be only recovered from any subset of t+1 shares.
46+ // NewShamirSecretSharing implements a (t,n) Shamir's secret sharing with
47+ // threshold t.
4648func NewShamirSecretSharing (t uint ) SecretSharing { return SecretSharing {t } }
4749
48- func (s SecretSharing ) polyFromSecret (rnd io.Reader , secret group.Scalar ) polynomial.Polynomial {
49- c := make ([]group.Scalar , s .t + 1 )
50- g := secret .Group ()
51- c [0 ] = secret .Copy ()
52- for i := 1 ; i < len (c ); i ++ {
53- c [i ] = g .RandomScalar (rnd )
54- }
55- return polynomial .New (c )
56- }
57-
58- // Shard splits the secret into n shares.
50+ // Shard splits a secret into n shares.
5951func (s SecretSharing ) Shard (rnd io.Reader , secret group.Scalar , n uint ) ([]Share , error ) {
60- if n <= s .t {
61- return nil , errThreshold (s .t , n )
62- }
63-
64- g := secret .Group ()
65- poly := s .polyFromSecret (rnd , secret )
66- shares := make ([]Share , n )
67- for i := range shares {
68- id := g .NewScalar ().SetUint64 (uint64 (i + 1 ))
69- shares [i ] = Share {ID : id , Value : poly .Evaluate (id )}
70- }
71-
72- return shares , nil
52+ return NewSplitter (rnd , s .t , secret ).multipleShard (n )
7353}
7454
7555// Recover returns the secret provided more than t shares are given. Returns an
76- // error if the number of shares is not above the threshold or goes beyond the
77- // maximum number of shares.
56+ // error if the number of shares is not above the threshold t.
7857func (s SecretSharing ) Recover (shares []Share ) (group.Scalar , error ) {
7958 if l := len (shares ); l <= int (s .t ) {
8059 return nil , errThreshold (s .t , uint (l ))
@@ -95,42 +74,39 @@ func (s SecretSharing) Recover(shares []Share) (group.Scalar, error) {
9574
9675type SharesCommitment = []group.Element
9776
77+ // VerifiableSecretSharing provides a (t,n) Feldman's verifiable secret sharing.
78+ // It allows splitting a secret into n shares, such that the secret can be only
79+ // recovered from any subset of t+1 shares.
80+ // It's verifiable as it allows checking whether a share is part of a secret
81+ // committed during sharding.
9882type VerifiableSecretSharing struct { s SecretSharing }
9983
10084// NewFeldmanSecretSharing implements a (t,n) Feldman's verifiable secret
101- // sharing. A (t,n) secret sharing allows to split a secret into n shares, such
102- // that the secret can be only recovered from any subset of t+1 shares. It's
103- // verifiable as it allows checking whether a share is part of a secret committed
104- // during sharding.
85+ // sharing with threshold t.
10586func NewFeldmanSecretSharing (t uint ) (v VerifiableSecretSharing ) { v .s .t = t ; return }
10687
10788// Shard splits the secret into n shares, and also returns a commitment to both
10889// the secret and the shares. The ShareCommitment must be sent to each party
10990// so each party can verify its share is correct. Sharding a secret more
11091// than once produces ShareCommitments with the same first entry.
11192func (v VerifiableSecretSharing ) Shard (rnd io.Reader , secret group.Scalar , n uint ) ([]Share , SharesCommitment , error ) {
112- if n <= v .s .t {
113- return nil , nil , errThreshold (v .s .t , n )
93+ splitter := NewSplitter (rnd , v .s .t , secret )
94+ shares , err := splitter .multipleShard (n )
95+ if err != nil {
96+ return nil , nil , err
11497 }
11598
11699 g := secret .Group ()
117- poly := v .s .polyFromSecret (rnd , secret )
118- shares := make ([]Share , n )
119- for i := range shares {
120- id := g .NewScalar ().SetUint64 (uint64 (i + 1 ))
121- shares [i ] = Share {ID : id , Value : poly .Evaluate (id )}
122- }
123- shareComs := make (SharesCommitment , poly .Degree ()+ 1 )
100+ shareComs := make (SharesCommitment , splitter .poly .Degree ()+ 1 )
124101 for i := range shareComs {
125- shareComs [i ] = g .NewElement ().MulGen (poly .Coefficient (uint (i )))
102+ shareComs [i ] = g .NewElement ().MulGen (splitter . poly .Coefficient (uint (i )))
126103 }
127104
128105 return shares , shareComs , nil
129106}
130107
131- // Verify returns true if a share was produced by sharding a secret. It uses
132- // the share commitments generated by the Shard function to verify this
133- // property.
108+ // Verify returns true if a share was produced by sharding a secret. It uses the
109+ // share commitments generated by the Shard function.
134110func (v VerifiableSecretSharing ) Verify (s Share , c SharesCommitment ) bool {
135111 if len (c ) != int (v .s .t + 1 ) {
136112 return false
@@ -148,12 +124,60 @@ func (v VerifiableSecretSharing) Verify(s Share, c SharesCommitment) bool {
148124}
149125
150126// Recover returns the secret provided more than t shares are given. Returns an
151- // error if the number of shares is not above the threshold (t) or is larger
152- // than the maximum number of shares (n).
127+ // error if the number of shares is not above the threshold t.
153128func (v VerifiableSecretSharing ) Recover (shares []Share ) (group.Scalar , error ) {
154129 return v .s .Recover (shares )
155130}
156131
157- var errThreshold = func (t , n uint ) error {
132+ type Splitter struct {
133+ g group.Group
134+ t uint
135+ poly polynomial.Polynomial
136+ }
137+
138+ // NewSplitter returns a Splitter that can shard a secret with threshold t.
139+ func NewSplitter (rnd io.Reader , t uint , secret group.Scalar ) (sp Splitter ) {
140+ sp .g = secret .Group ()
141+ sp .t = t
142+
143+ c := make ([]group.Scalar , sp .t + 1 )
144+ c [0 ] = secret .Copy ()
145+ for i := 1 ; i < len (c ); i ++ {
146+ c [i ] = sp .g .RandomScalar (rnd )
147+ }
148+ sp .poly = polynomial .New (c )
149+
150+ return
151+ }
152+
153+ func (sp Splitter ) multipleShard (n uint ) ([]Share , error ) {
154+ if n <= sp .t {
155+ return nil , errThreshold (sp .t , n )
156+ }
157+
158+ shares := make ([]Share , n )
159+ id := sp .g .NewScalar ()
160+ for i := range shares {
161+ shares [i ] = sp .ShardWithID (id .SetUint64 (uint64 (i + 1 )))
162+ }
163+
164+ return shares , nil
165+ }
166+
167+ func (sp Splitter ) Shard (rnd io.Reader ) (s Share ) {
168+ return sp .ShardWithID (sp .g .RandomNonZeroScalar (rnd ))
169+ }
170+
171+ func (sp Splitter ) ShardWithID (id group.Scalar ) (s Share ) {
172+ if id .IsZero () {
173+ panic ("secretsharing: id cannot be zero" )
174+ }
175+
176+ s .ID = id .Copy ()
177+ s .Value = sp .poly .Evaluate (s .ID )
178+ return
179+ }
180+
181+ func errThreshold (t , n uint ) error {
158182 return fmt .Errorf ("secretsharing: number of shares (n=%v) must be above the threshold (t=%v)" , n , t )
159183}
0 commit comments