@@ -32,49 +32,28 @@ import (
32
32
type Share struct {
33
33
// ID uniquely identifies a share in a secret sharing instance.
34
34
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.
36
36
Value group.Scalar
37
37
}
38
38
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.
39
42
type SecretSharing struct {
40
43
t uint // t is the threshold.
41
44
}
42
45
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.
46
48
func NewShamirSecretSharing (t uint ) SecretSharing { return SecretSharing {t } }
47
49
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.
59
51
func (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 )
73
53
}
74
54
75
55
// 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.
78
57
func (s SecretSharing ) Recover (shares []Share ) (group.Scalar , error ) {
79
58
if l := len (shares ); l <= int (s .t ) {
80
59
return nil , errThreshold (s .t , uint (l ))
@@ -95,42 +74,39 @@ func (s SecretSharing) Recover(shares []Share) (group.Scalar, error) {
95
74
96
75
type SharesCommitment = []group.Element
97
76
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.
98
82
type VerifiableSecretSharing struct { s SecretSharing }
99
83
100
84
// 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.
105
86
func NewFeldmanSecretSharing (t uint ) (v VerifiableSecretSharing ) { v .s .t = t ; return }
106
87
107
88
// Shard splits the secret into n shares, and also returns a commitment to both
108
89
// the secret and the shares. The ShareCommitment must be sent to each party
109
90
// so each party can verify its share is correct. Sharding a secret more
110
91
// than once produces ShareCommitments with the same first entry.
111
92
func (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
114
97
}
115
98
116
99
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 )
124
101
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 )))
126
103
}
127
104
128
105
return shares , shareComs , nil
129
106
}
130
107
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.
134
110
func (v VerifiableSecretSharing ) Verify (s Share , c SharesCommitment ) bool {
135
111
if len (c ) != int (v .s .t + 1 ) {
136
112
return false
@@ -148,12 +124,60 @@ func (v VerifiableSecretSharing) Verify(s Share, c SharesCommitment) bool {
148
124
}
149
125
150
126
// 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.
153
128
func (v VerifiableSecretSharing ) Recover (shares []Share ) (group.Scalar , error ) {
154
129
return v .s .Recover (shares )
155
130
}
156
131
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 {
158
182
return fmt .Errorf ("secretsharing: number of shares (n=%v) must be above the threshold (t=%v)" , n , t )
159
183
}
0 commit comments