2
2
//
3
3
// Let n be the number of parties, and t the number of corrupted parties such
4
4
// that 0 <= t < n. A (t,n) secret sharing allows to split a secret into n
5
- // shares, such that the secret can be recovered from any subset of t+1 shares.
5
+ // shares, such that the secret can be recovered from any subset of at least t+1
6
+ // different shares.
6
7
//
7
- // The NewShamirSecretSharing function creates a Shamir secret sharing [1],
8
- // which relies on Lagrange polynomial interpolation.
8
+ // A Shamir secret sharing [1] relies on Lagrange polynomial interpolation.
9
+ // A Feldman secret sharing [2] extends Shamir's by commiting the secret, which
10
+ // allows to verify that a share is part of the committed secret.
9
11
//
10
- // The NewFeldmanSecretSharing function creates a Feldman secret sharing [2],
11
- // which extends Shamir's by allowing to verify that a share is part of a
12
- // committed secret .
12
+ // New returns a SecretSharing compatible with Shamir secret sharing.
13
+ // The SecretSharing can be verifiable (compatible with Feldman secret sharing)
14
+ // using the CommitSecret and Verify functions .
13
15
//
14
16
// In this implementation, secret sharing is defined over the scalar field of
15
17
// a prime order group.
16
18
//
17
19
// References
18
20
//
19
- // [1] https://dl.acm.org/doi/10.1145/359168.359176
20
- // [2] https://ieeexplore.ieee.org/document/4568297
21
+ // [1] Shamir, How to share a secret. https://dl.acm.org/doi/10.1145/359168.359176/
22
+ // [2] Feldman, A practical scheme for non-interactive verifiable secret sharing. https://ieeexplore.ieee.org/document/4568297/
21
23
package secretsharing
22
24
23
25
import (
@@ -30,131 +32,96 @@ import (
30
32
31
33
// Share represents a share of a secret.
32
34
type Share struct {
33
- // ID uniquely identifies a share in a secret sharing instance.
35
+ // ID uniquely identifies a share in a secret sharing instance. ID is never zero.
34
36
ID group.Scalar
35
37
// Value stores the share generated by a secret sharing instance.
36
38
Value group.Scalar
37
39
}
38
40
41
+ // SecretCommitment is the set of commitments generated by splitting a secret.
42
+ type SecretCommitment = []group.Element
43
+
39
44
// SecretSharing provides a (t,n) Shamir's secret sharing. It allows splitting
40
45
// a secret into n shares, such that the secret can be only recovered from
41
46
// any subset of t+1 shares.
42
47
type SecretSharing struct {
43
- t uint // t is the threshold.
44
- }
45
-
46
- // NewShamirSecretSharing implements a (t,n) Shamir's secret sharing with
47
- // threshold t.
48
- func NewShamirSecretSharing (t uint ) SecretSharing { return SecretSharing {t } }
49
-
50
- // Shard splits a secret into n shares.
51
- func (s SecretSharing ) Shard (rnd io.Reader , secret group.Scalar , n uint ) ([]Share , error ) {
52
- return NewSplitter (rnd , s .t , secret ).multipleShard (n )
53
- }
54
-
55
- type SharesCommitment = []group.Element
56
-
57
- // VerifiableSecretSharing provides a (t,n) Feldman's verifiable secret sharing.
58
- // It allows splitting a secret into n shares, such that the secret can be only
59
- // recovered from any subset of t+1 shares.
60
- // It's verifiable as it allows checking whether a share is part of a secret
61
- // committed during sharding.
62
- type VerifiableSecretSharing struct { s SecretSharing }
63
-
64
- // NewFeldmanSecretSharing implements a (t,n) Feldman's verifiable secret
65
- // sharing with threshold t.
66
- func NewFeldmanSecretSharing (t uint ) (v VerifiableSecretSharing ) { v .s .t = t ; return }
67
-
68
- // Shard splits the secret into n shares, and also returns a commitment to both
69
- // the secret and the shares. The ShareCommitment must be sent to each party
70
- // so each party can verify its share is correct. Sharding a secret more
71
- // than once produces ShareCommitments with the same first entry.
72
- func (v VerifiableSecretSharing ) Shard (rnd io.Reader , secret group.Scalar , n uint ) ([]Share , SharesCommitment , error ) {
73
- splitter := NewSplitter (rnd , v .s .t , secret )
74
- shares , err := splitter .multipleShard (n )
75
- if err != nil {
76
- return nil , nil , err
77
- }
78
-
79
- g := secret .Group ()
80
- shareComs := make (SharesCommitment , splitter .poly .Degree ()+ 1 )
81
- for i := range shareComs {
82
- shareComs [i ] = g .NewElement ().MulGen (splitter .poly .Coefficient (uint (i )))
83
- }
84
-
85
- return shares , shareComs , nil
86
- }
87
-
88
- // Verify returns true if a share was produced by sharding a secret. It uses the
89
- // share commitments generated by the Shard function.
90
- func (v VerifiableSecretSharing ) Verify (s Share , c SharesCommitment ) bool {
91
- if len (c ) != int (v .s .t + 1 ) {
92
- return false
93
- }
94
-
95
- g := s .ID .Group ()
96
- lc := len (c ) - 1
97
- sum := g .NewElement ().Set (c [lc ])
98
- for i := lc - 1 ; i >= 0 ; i -- {
99
- sum .Mul (sum , s .ID )
100
- sum .Add (sum , c [i ])
101
- }
102
- polI := g .NewElement ().MulGen (s .Value )
103
- return polI .IsEqual (sum )
104
- }
105
-
106
- type Splitter struct {
107
48
g group.Group
108
49
t uint
109
50
poly polynomial.Polynomial
110
51
}
111
52
112
- // NewSplitter returns a Splitter that can shard a secret with threshold t.
113
- func NewSplitter (rnd io.Reader , t uint , secret group.Scalar ) (sp Splitter ) {
114
- sp .g = secret .Group ()
115
- sp .t = t
116
-
117
- c := make ([]group.Scalar , sp .t + 1 )
53
+ // New returns a SecretSharing providing a (t,n) Shamir's secret sharing.
54
+ // It allows splitting a secret into n shares, such that the secret is
55
+ // only recovered from any subset of at least t+1 shares.
56
+ func New (rnd io.Reader , t uint , secret group.Scalar ) SecretSharing {
57
+ c := make ([]group.Scalar , t + 1 )
118
58
c [0 ] = secret .Copy ()
59
+ g := secret .Group ()
119
60
for i := 1 ; i < len (c ); i ++ {
120
- c [i ] = sp . g .RandomScalar (rnd )
61
+ c [i ] = g .RandomScalar (rnd )
121
62
}
122
- sp .poly = polynomial .New (c )
123
63
124
- return
64
+ return SecretSharing { g : g , t : t , poly : polynomial . New ( c )}
125
65
}
126
66
127
- func (sp Splitter ) Shard (rnd io.Reader ) (s Share ) {
128
- return sp .ShardWithID (sp .g .RandomNonZeroScalar (rnd ))
67
+ // Share creates n shares with an ID monotonically increasing from 1 to n.
68
+ func (ss SecretSharing ) Share (n uint ) []Share {
69
+ shares := make ([]Share , n )
70
+ id := ss .g .NewScalar ()
71
+ for i := range shares {
72
+ shares [i ] = ss .ShareWithID (id .SetUint64 (uint64 (i + 1 )))
73
+ }
74
+
75
+ return shares
129
76
}
130
77
131
- func (sp Splitter ) ShardWithID (id group.Scalar ) (s Share ) {
78
+ // ShareWithID creates one share of the secret using the ID as identifier.
79
+ // Notice that shares with the same ID are considered equal.
80
+ // Panics, if the ID is zero.
81
+ func (ss SecretSharing ) ShareWithID (id group.Scalar ) Share {
132
82
if id .IsZero () {
133
83
panic ("secretsharing: id cannot be zero" )
134
84
}
135
85
136
- s .ID = id .Copy ()
137
- s .Value = sp .poly .Evaluate (s .ID )
138
- return
86
+ return Share {
87
+ ID : id .Copy (),
88
+ Value : ss .poly .Evaluate (id ),
89
+ }
139
90
}
140
91
141
- func (sp Splitter ) multipleShard (n uint ) ([]Share , error ) {
142
- if n <= sp .t {
143
- return nil , errThreshold (sp .t , n )
92
+ // CommitSecret creates a commitment to the secret for further verifying shares.
93
+ func (ss SecretSharing ) CommitSecret () SecretCommitment {
94
+ c := make (SecretCommitment , ss .poly .Degree ()+ 1 )
95
+ for i := range c {
96
+ c [i ] = ss .g .NewElement ().MulGen (ss .poly .Coefficient (uint (i )))
144
97
}
98
+ return c
99
+ }
145
100
146
- shares := make ([]Share , n )
147
- id := sp .g .NewScalar ()
148
- for i := range shares {
149
- shares [i ] = sp .ShardWithID (id .SetUint64 (uint64 (i + 1 )))
101
+ // Verify returns true if the share s was produced by sharing a secret with
102
+ // threshold t and commitment of the secret c.
103
+ func Verify (t uint , s Share , c SecretCommitment ) bool {
104
+ if len (c ) != int (t + 1 ) {
105
+ return false
106
+ }
107
+ if s .ID .IsZero () {
108
+ return false
150
109
}
151
110
152
- return shares , nil
111
+ g := s .ID .Group ()
112
+ lc := len (c ) - 1
113
+ sum := g .NewElement ().Set (c [lc ])
114
+ for i := lc - 1 ; i >= 0 ; i -- {
115
+ sum .Mul (sum , s .ID )
116
+ sum .Add (sum , c [i ])
117
+ }
118
+ polI := g .NewElement ().MulGen (s .Value )
119
+ return polI .IsEqual (sum )
153
120
}
154
121
155
122
// Recover returns a secret provided more than t different shares are given.
156
123
// Returns an error if the number of shares is not above the threshold t.
157
- // Panics if some shares are duplicated.
124
+ // Panics if some shares are duplicated, i.e., shares must have different IDs .
158
125
func Recover (t uint , shares []Share ) (secret group.Scalar , err error ) {
159
126
if l := len (shares ); l <= int (t ) {
160
127
return nil , errThreshold (t , uint (l ))
0 commit comments