Skip to content

Commit b0a42cb

Browse files
committedOct 19, 2022
Add splitter of secrets.
1 parent a480114 commit b0a42cb

File tree

1 file changed

+74
-50
lines changed

1 file changed

+74
-50
lines changed
 

‎secretsharing/ss.go

+74-50
Original file line numberDiff line numberDiff line change
@@ -32,49 +32,28 @@ import (
3232
type 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.
3942
type 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.
4648
func 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.
5951
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)
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.
7857
func (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

9675
type 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.
9882
type 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.
10586
func 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.
11192
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
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.
134110
func (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.
153128
func (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

Comments
 (0)