Skip to content

Commit 9e2b5b0

Browse files
committed
Show use cases of splitter.
1 parent 42d3297 commit 9e2b5b0

File tree

2 files changed

+81
-55
lines changed

2 files changed

+81
-55
lines changed

secretsharing/ss.go

+30-35
Original file line numberDiff line numberDiff line change
@@ -52,26 +52,6 @@ func (s SecretSharing) Shard(rnd io.Reader, secret group.Scalar, n uint) ([]Shar
5252
return NewSplitter(rnd, s.t, secret).multipleShard(n)
5353
}
5454

55-
// Recover returns the secret provided more than t shares are given. Returns an
56-
// error if the number of shares is not above the threshold t.
57-
func (s SecretSharing) Recover(shares []Share) (group.Scalar, error) {
58-
if l := len(shares); l <= int(s.t) {
59-
return nil, errThreshold(s.t, uint(l))
60-
}
61-
62-
x := make([]group.Scalar, s.t+1)
63-
px := make([]group.Scalar, s.t+1)
64-
for i := range shares[:s.t+1] {
65-
x[i] = shares[i].ID
66-
px[i] = shares[i].Value
67-
}
68-
69-
l := polynomial.NewLagrangePolynomial(x, px)
70-
zero := shares[0].ID.Group().NewScalar()
71-
72-
return l.Evaluate(zero), nil
73-
}
74-
7555
type SharesCommitment = []group.Element
7656

7757
// VerifiableSecretSharing provides a (t,n) Feldman's verifiable secret sharing.
@@ -123,12 +103,6 @@ func (v VerifiableSecretSharing) Verify(s Share, c SharesCommitment) bool {
123103
return polI.IsEqual(sum)
124104
}
125105

126-
// Recover returns the secret provided more than t shares are given. Returns an
127-
// error if the number of shares is not above the threshold t.
128-
func (v VerifiableSecretSharing) Recover(shares []Share) (group.Scalar, error) {
129-
return v.s.Recover(shares)
130-
}
131-
132106
type Splitter struct {
133107
g group.Group
134108
t uint
@@ -150,6 +124,20 @@ func NewSplitter(rnd io.Reader, t uint, secret group.Scalar) (sp Splitter) {
150124
return
151125
}
152126

127+
func (sp Splitter) Shard(rnd io.Reader) (s Share) {
128+
return sp.ShardWithID(sp.g.RandomNonZeroScalar(rnd))
129+
}
130+
131+
func (sp Splitter) ShardWithID(id group.Scalar) (s Share) {
132+
if id.IsZero() {
133+
panic("secretsharing: id cannot be zero")
134+
}
135+
136+
s.ID = id.Copy()
137+
s.Value = sp.poly.Evaluate(s.ID)
138+
return
139+
}
140+
153141
func (sp Splitter) multipleShard(n uint) ([]Share, error) {
154142
if n <= sp.t {
155143
return nil, errThreshold(sp.t, n)
@@ -164,18 +152,25 @@ func (sp Splitter) multipleShard(n uint) ([]Share, error) {
164152
return shares, nil
165153
}
166154

167-
func (sp Splitter) Shard(rnd io.Reader) (s Share) {
168-
return sp.ShardWithID(sp.g.RandomNonZeroScalar(rnd))
169-
}
155+
// Recover returns a secret provided more than t different shares are given.
156+
// Returns an error if the number of shares is not above the threshold t.
157+
// Panics if some shares are duplicated.
158+
func Recover(t uint, shares []Share) (secret group.Scalar, err error) {
159+
if l := len(shares); l <= int(t) {
160+
return nil, errThreshold(t, uint(l))
161+
}
170162

171-
func (sp Splitter) ShardWithID(id group.Scalar) (s Share) {
172-
if id.IsZero() {
173-
panic("secretsharing: id cannot be zero")
163+
x := make([]group.Scalar, t+1)
164+
px := make([]group.Scalar, t+1)
165+
for i := range shares[:t+1] {
166+
x[i] = shares[i].ID
167+
px[i] = shares[i].Value
174168
}
175169

176-
s.ID = id.Copy()
177-
s.Value = sp.poly.Evaluate(s.ID)
178-
return
170+
l := polynomial.NewLagrangePolynomial(x, px)
171+
zero := shares[0].ID.Group().NewScalar()
172+
173+
return l.Evaluate(zero), nil
179174
}
180175

181176
func errThreshold(t, n uint) error {

secretsharing/ss_test.go

+51-20
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,23 @@ func TestSecretSharing(tt *testing.T) {
1414
t := uint(2)
1515
n := uint(5)
1616

17-
s := secretsharing.NewShamirSecretSharing(t)
17+
ss := secretsharing.NewShamirSecretSharing(t)
1818

19-
want := g.RandomScalar(rand.Reader)
20-
shares, err := s.Shard(rand.Reader, want, n)
19+
secret := g.RandomScalar(rand.Reader)
20+
shares, err := ss.Shard(rand.Reader, secret, n)
2121
test.CheckNoErr(tt, err, "failed to shard a secret")
2222
test.CheckOk(len(shares) == int(n), "bad num shares", tt)
2323

2424
tt.Run("subsetSize", func(ttt *testing.T) {
2525
// Test any possible subset size.
2626
for k := 0; k <= int(n); k++ {
27-
got, err := s.Recover(shares[:k])
27+
got, err := secretsharing.Recover(t, shares[:k])
2828
if !(int(t) < k && k <= int(n)) {
2929
test.CheckIsErr(ttt, err, "should not recover secret")
3030
test.CheckOk(got == nil, "not nil secret", ttt)
3131
} else {
3232
test.CheckNoErr(ttt, err, "should recover secret")
33+
want := secret
3334
if !got.IsEqual(want) {
3435
test.ReportError(ttt, got, want, t, k, n)
3536
}
@@ -45,8 +46,8 @@ func TestVerifiableSecretSharing(tt *testing.T) {
4546

4647
vs := secretsharing.NewFeldmanSecretSharing(t)
4748

48-
want := g.RandomScalar(rand.Reader)
49-
shares, com, err := vs.Shard(rand.Reader, want, n)
49+
secret := g.RandomScalar(rand.Reader)
50+
shares, com, err := vs.Shard(rand.Reader, secret, n)
5051
test.CheckNoErr(tt, err, "failed to shard a secret")
5152
test.CheckOk(len(shares) == int(n), "bad num shares", tt)
5253
test.CheckOk(len(com) == int(t+1), "bad num commitments", tt)
@@ -60,12 +61,13 @@ func TestVerifiableSecretSharing(tt *testing.T) {
6061
tt.Run("subsetSize", func(ttt *testing.T) {
6162
// Test any possible subset size.
6263
for k := 0; k <= int(n); k++ {
63-
got, err := vs.Recover(shares[:k])
64+
got, err := secretsharing.Recover(t, shares[:k])
6465
if k <= int(t) {
6566
test.CheckIsErr(ttt, err, "should not recover secret")
6667
test.CheckOk(got == nil, "not nil secret", ttt)
6768
} else {
6869
test.CheckNoErr(ttt, err, "should recover secret")
70+
want := secret
6971
if !got.IsEqual(want) {
7072
test.ReportError(ttt, got, want, t, k, n)
7173
}
@@ -99,24 +101,59 @@ func TestVerifiableSecretSharing(tt *testing.T) {
99101
})
100102
}
101103

104+
func TestSplitter(tt *testing.T) {
105+
g := group.P256
106+
t := uint(2)
107+
n := uint(5)
108+
secret := g.RandomScalar(rand.Reader)
109+
sp := secretsharing.NewSplitter(rand.Reader, t, secret)
110+
111+
tt.Run("recoverOk", func(ttt *testing.T) {
112+
// Splitter can create shares at will, not exactly n many.
113+
shares := []secretsharing.Share{
114+
sp.Shard(rand.Reader),
115+
sp.Shard(rand.Reader),
116+
sp.Shard(rand.Reader),
117+
}
118+
got, err := secretsharing.Recover(t, shares)
119+
test.CheckNoErr(tt, err, "failed to recover the secret")
120+
want := secret
121+
if !got.IsEqual(want) {
122+
test.ReportError(tt, got, want, t, n)
123+
}
124+
})
125+
126+
tt.Run("duplicatedFail", func(ttt *testing.T) {
127+
// Panics if trying to recover duplicated shares.
128+
share := sp.Shard(rand.Reader)
129+
sameShares := []secretsharing.Share{share, share, share}
130+
err := test.CheckPanic(func() {
131+
got, err := secretsharing.Recover(t, sameShares)
132+
test.CheckIsErr(tt, err, "must fail to recover the secret")
133+
test.CheckOk(got == nil, "must not recover", tt)
134+
})
135+
test.CheckOk(err == nil, "must panic", tt)
136+
})
137+
}
138+
102139
func BenchmarkSecretSharing(b *testing.B) {
103140
g := group.P256
104141
t := uint(3)
105142
n := uint(5)
106143

107144
s := secretsharing.NewShamirSecretSharing(t)
108-
want := g.RandomScalar(rand.Reader)
109-
shares, _ := s.Shard(rand.Reader, want, n)
145+
secret := g.RandomScalar(rand.Reader)
146+
shares, _ := s.Shard(rand.Reader, secret, n)
110147

111148
b.Run("Shard", func(b *testing.B) {
112149
for i := 0; i < b.N; i++ {
113-
_, _ = s.Shard(rand.Reader, want, n)
150+
_, _ = s.Shard(rand.Reader, secret, n)
114151
}
115152
})
116153

117154
b.Run("Recover", func(b *testing.B) {
118155
for i := 0; i < b.N; i++ {
119-
_, _ = s.Recover(shares)
156+
_, _ = secretsharing.Recover(t, shares)
120157
}
121158
})
122159
}
@@ -127,18 +164,12 @@ func BenchmarkVerifiableSecretSharing(b *testing.B) {
127164
n := uint(5)
128165

129166
vs := secretsharing.NewFeldmanSecretSharing(t)
130-
want := g.RandomScalar(rand.Reader)
131-
shares, com, _ := vs.Shard(rand.Reader, want, n)
167+
secret := g.RandomScalar(rand.Reader)
168+
shares, com, _ := vs.Shard(rand.Reader, secret, n)
132169

133170
b.Run("Shard", func(b *testing.B) {
134171
for i := 0; i < b.N; i++ {
135-
_, _, _ = vs.Shard(rand.Reader, want, n)
136-
}
137-
})
138-
139-
b.Run("Recover", func(b *testing.B) {
140-
for i := 0; i < b.N; i++ {
141-
_, _ = vs.Recover(shares)
172+
_, _, _ = vs.Shard(rand.Reader, secret, n)
142173
}
143174
})
144175

0 commit comments

Comments
 (0)