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
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.
67//
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.
911//
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 .
1315//
1416// In this implementation, secret sharing is defined over the scalar field of
1517// a prime order group.
1618//
1719// References
1820//
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/
2123package secretsharing
2224
2325import (
@@ -30,131 +32,96 @@ import (
3032
3133// Share represents a share of a secret.
3234type 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.
3436 ID group.Scalar
3537 // Value stores the share generated by a secret sharing instance.
3638 Value group.Scalar
3739}
3840
41+ // SecretCommitment is the set of commitments generated by splitting a secret.
42+ type SecretCommitment = []group.Element
43+
3944// SecretSharing provides a (t,n) Shamir's secret sharing. It allows splitting
4045// a secret into n shares, such that the secret can be only recovered from
4146// any subset of t+1 shares.
4247type 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 {
10748 g group.Group
10849 t uint
10950 poly polynomial.Polynomial
11051}
11152
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 )
11858 c [0 ] = secret .Copy ()
59+ g := secret .Group ()
11960 for i := 1 ; i < len (c ); i ++ {
120- c [i ] = sp . g .RandomScalar (rnd )
61+ c [i ] = g .RandomScalar (rnd )
12162 }
122- sp .poly = polynomial .New (c )
12363
124- return
64+ return SecretSharing { g : g , t : t , poly : polynomial . New ( c )}
12565}
12666
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
12976}
13077
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 {
13282 if id .IsZero () {
13383 panic ("secretsharing: id cannot be zero" )
13484 }
13585
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+ }
13990}
14091
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 )))
14497 }
98+ return c
99+ }
145100
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
150109 }
151110
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 )
153120}
154121
155122// Recover returns a secret provided more than t different shares are given.
156123// 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 .
158125func Recover (t uint , shares []Share ) (secret group.Scalar , err error ) {
159126 if l := len (shares ); l <= int (t ) {
160127 return nil , errThreshold (t , uint (l ))
0 commit comments