Skip to content

Commit

Permalink
Applying ChrisW comments.
Browse files Browse the repository at this point in the history
  • Loading branch information
armfazh committed Oct 18, 2022
1 parent 1b68fea commit 98bfada
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 69 deletions.
108 changes: 51 additions & 57 deletions secretsharing/ss.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
package secretsharing

import (
"errors"
"fmt"
"io"

Expand All @@ -31,75 +30,65 @@ import (

// Share represents a share of a secret.
type Share struct {
ID uint64 // ID uniquely identifies a share in a secret sharing instance.
Value group.Scalar // Value stores the share generated from a secret sharing instance.
// ID uniquely identifies a share in a secret sharing instance.
ID group.Scalar
// Value stores the share generated from a secret sharing instance.
Value group.Scalar
}

type SecretSharing struct {
g group.Group
t, n uint
t uint // t is the threshold.
}

// NewShamirSecretSharing implements a (t,n) Shamir's secret sharing.
// A (t,n) secret sharing allows to split a secret into n shares, such that the
// secret can be only recovered from any subset of t+1 shares. Returns an error
// if 0 <= t < n does not hold.
func NewShamirSecretSharing(g group.Group, t, n uint) (SecretSharing, error) {
if t >= n {
return SecretSharing{}, errors.New("secretsharing: bad parameters")
}
return SecretSharing{g: g, t: t, n: n}, nil
}

// Params returns the t and n parameters of the secret sharing.
func (s SecretSharing) Params() (t, n uint) { return s.t, s.n }
// secret can be only recovered from any subset of t+1 shares.
func NewShamirSecretSharing(t uint) SecretSharing { return SecretSharing{t} }

func (s SecretSharing) polyFromSecret(rnd io.Reader, secret group.Scalar) (p polynomial.Polynomial) {
func (s SecretSharing) polyFromSecret(rnd io.Reader, secret group.Scalar) polynomial.Polynomial {
c := make([]group.Scalar, s.t+1)
g := secret.Group()
c[0] = secret.Copy()
for i := 1; i < len(c); i++ {
c[i] = s.g.RandomScalar(rnd)
c[i] = g.RandomScalar(rnd)
}
c[0] = secret.Copy()
return polynomial.New(c)
}

func (s SecretSharing) generateShares(poly polynomial.Polynomial) []Share {
shares := make([]Share, s.n)
x := s.g.NewScalar()
// Shard splits the secret into n shares.
func (s SecretSharing) Shard(rnd io.Reader, secret group.Scalar, n uint) ([]Share, error) {
if n <= s.t {
return nil, errThreshold(s.t, n)
}

g := secret.Group()
poly := s.polyFromSecret(rnd, secret)
shares := make([]Share, n)
for i := range shares {
id := i + 1
x.SetUint64(uint64(id))
shares[i].ID = uint64(id)
shares[i].Value = poly.Evaluate(x)
id := g.NewScalar().SetUint64(uint64(i + 1))
shares[i] = Share{ID: id, Value: poly.Evaluate(id)}
}

return shares
}

// Shard splits the secret into n shares.
func (s SecretSharing) Shard(rnd io.Reader, secret group.Scalar) []Share {
return s.generateShares(s.polyFromSecret(rnd, secret))
return shares, nil
}

// Recover returns the secret provided more than t shares are given. Returns an
// error if the number of shares is not above the threshold or goes beyond the
// maximum number of shares.
func (s SecretSharing) Recover(shares []Share) (group.Scalar, error) {
if l := len(shares); l <= int(s.t) {
return nil, fmt.Errorf("secretsharing: does not reach the threshold %v with %v shares", s.t, l)
} else if l > int(s.n) {
return nil, fmt.Errorf("secretsharing: %v shares above max number of shares %v", l, s.n)
return nil, errThreshold(s.t, uint(l))
}

x := make([]group.Scalar, s.t+1)
px := make([]group.Scalar, s.t+1)
for i := range shares[:s.t+1] {
x[i] = s.g.NewScalar().SetUint64(shares[i].ID)
x[i] = shares[i].ID
px[i] = shares[i].Value
}

l := polynomial.NewLagrangePolynomial(x, px)
zero := s.g.NewScalar()
zero := shares[0].ID.Group().NewScalar()

return l.Evaluate(zero), nil
}
Expand All @@ -110,31 +99,33 @@ type VerifiableSecretSharing struct{ s SecretSharing }

// NewFeldmanSecretSharing implements a (t,n) Feldman's verifiable secret
// sharing. A (t,n) secret sharing allows to split a secret into n shares, such
// that the secret can be only recovered from any subset of t+1 shares. This
// method is verifiable because once the shares and the secret are committed
// during sharding, one can later verify whether the share was generated
// honestly. Returns an error if 0 < t <= n does not hold.
func NewFeldmanSecretSharing(g group.Group, t, n uint) (VerifiableSecretSharing, error) {
s, err := NewShamirSecretSharing(g, t, n)
return VerifiableSecretSharing{s}, err
}

// Params returns the t and n parameters of the secret sharing.
func (v VerifiableSecretSharing) Params() (t, n uint) { return v.s.Params() }
// that the secret can be only recovered from any subset of t+1 shares. It's
// verifiable as it allows checking whether a share is part of a secret committed
// during sharding.
func NewFeldmanSecretSharing(t uint) (v VerifiableSecretSharing) { v.s.t = t; return }

// Shard splits the secret into n shares, and also returns a commitment to both
// the secret and the shares. The ShareCommitment must be sent to each party
// so each party can verify its share is correct. Sharding a secret more
// than once produces ShareCommitments with the same first entry.
func (v VerifiableSecretSharing) Shard(rnd io.Reader, secret group.Scalar) ([]Share, SharesCommitment) {
func (v VerifiableSecretSharing) Shard(rnd io.Reader, secret group.Scalar, n uint) ([]Share, SharesCommitment, error) {
if n <= v.s.t {
return nil, nil, errThreshold(v.s.t, n)
}

g := secret.Group()
poly := v.s.polyFromSecret(rnd, secret)
shares := v.s.generateShares(poly)
shares := make([]Share, n)
for i := range shares {
id := g.NewScalar().SetUint64(uint64(i + 1))
shares[i] = Share{ID: id, Value: poly.Evaluate(id)}
}
shareComs := make(SharesCommitment, poly.Degree()+1)
for i := range shareComs {
shareComs[i] = v.s.g.NewElement().MulGen(poly.Coefficient(uint(i)))
shareComs[i] = g.NewElement().MulGen(poly.Coefficient(uint(i)))
}

return shares, shareComs
return shares, shareComs, nil
}

// Verify returns true if a share was produced by sharding a secret. It uses
Expand All @@ -145,15 +136,14 @@ func (v VerifiableSecretSharing) Verify(s Share, c SharesCommitment) bool {
return false
}

g := s.ID.Group()
lc := len(c) - 1
sum := v.s.g.NewElement().Set(c[lc])
x := v.s.g.NewScalar()
sum := g.NewElement().Set(c[lc])
for i := lc - 1; i >= 0; i-- {
x.SetUint64(s.ID)
sum.Mul(sum, x)
sum.Mul(sum, s.ID)
sum.Add(sum, c[i])
}
polI := v.s.g.NewElement().MulGen(s.Value)
polI := g.NewElement().MulGen(s.Value)
return polI.IsEqual(sum)
}

Expand All @@ -163,3 +153,7 @@ func (v VerifiableSecretSharing) Verify(s Share, c SharesCommitment) bool {
func (v VerifiableSecretSharing) Recover(shares []Share) (group.Scalar, error) {
return v.s.Recover(shares)
}

var errThreshold = func(t, n uint) error {
return fmt.Errorf("secretsharing: number of shares (n=%v) must be above the threshold (t=%v)", n, t)
}
25 changes: 13 additions & 12 deletions secretsharing/ss_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ func TestSecretSharing(tt *testing.T) {
t := uint(2)
n := uint(5)

s, err := secretsharing.NewShamirSecretSharing(g, t, n)
test.CheckNoErr(tt, err, "failed to create Shamir secret sharing")
s := secretsharing.NewShamirSecretSharing(t)

want := g.RandomScalar(rand.Reader)
shares := s.Shard(rand.Reader, want)
shares, err := s.Shard(rand.Reader, want, n)
test.CheckNoErr(tt, err, "failed to shard a secret")
test.CheckOk(len(shares) == int(n), "bad num shares", tt)

tt.Run("subsetSize", func(ttt *testing.T) {
Expand All @@ -43,11 +43,11 @@ func TestVerifiableSecretSharing(tt *testing.T) {
t := uint(3)
n := uint(5)

vs, err := secretsharing.NewFeldmanSecretSharing(g, t, n)
test.CheckNoErr(tt, err, "failed to create Feldman secret sharing")
vs := secretsharing.NewFeldmanSecretSharing(t)

want := g.RandomScalar(rand.Reader)
shares, com := vs.Shard(rand.Reader, want)
shares, com, err := vs.Shard(rand.Reader, want, n)
test.CheckNoErr(tt, err, "failed to shard a secret")
test.CheckOk(len(shares) == int(n), "bad num shares", tt)
test.CheckOk(len(com) == int(t+1), "bad num commitments", tt)

Expand Down Expand Up @@ -76,6 +76,7 @@ func TestVerifiableSecretSharing(tt *testing.T) {
tt.Run("badShares", func(ttt *testing.T) {
badShares := make([]secretsharing.Share, len(shares))
for i := range shares {
badShares[i].ID = shares[i].ID.Copy()
badShares[i].Value = shares[i].Value.Copy()
badShares[i].Value.SetUint64(9)
}
Expand Down Expand Up @@ -103,13 +104,13 @@ func BenchmarkSecretSharing(b *testing.B) {
t := uint(3)
n := uint(5)

s, _ := secretsharing.NewShamirSecretSharing(g, t, n)
s := secretsharing.NewShamirSecretSharing(t)
want := g.RandomScalar(rand.Reader)
shares := s.Shard(rand.Reader, want)
shares, _ := s.Shard(rand.Reader, want, n)

b.Run("Shard", func(b *testing.B) {
for i := 0; i < b.N; i++ {
s.Shard(rand.Reader, want)
_, _ = s.Shard(rand.Reader, want, n)
}
})

Expand All @@ -125,13 +126,13 @@ func BenchmarkVerifiableSecretSharing(b *testing.B) {
t := uint(3)
n := uint(5)

vs, _ := secretsharing.NewFeldmanSecretSharing(g, t, n)
vs := secretsharing.NewFeldmanSecretSharing(t)
want := g.RandomScalar(rand.Reader)
shares, com := vs.Shard(rand.Reader, want)
shares, com, _ := vs.Shard(rand.Reader, want, n)

b.Run("Shard", func(b *testing.B) {
for i := 0; i < b.N; i++ {
vs.Shard(rand.Reader, want)
_, _, _ = vs.Shard(rand.Reader, want, n)
}
})

Expand Down

0 comments on commit 98bfada

Please sign in to comment.