Skip to content

Commit

Permalink
Add commitment tu public key share (#39)
Browse files Browse the repository at this point in the history
* Add commitment to public key share

Signed-off-by: bytemare <3641580+bytemare@users.noreply.github.com>
  • Loading branch information
bytemare committed Jul 11, 2024
1 parent af3c077 commit a974901
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 33 deletions.
9 changes: 3 additions & 6 deletions examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,22 +65,19 @@ func ExampleVerify() {
secret := g.NewScalar().Random()

// Shard the secret into shares
shares, polynomial, err := secretsharing.ShardReturnPolynomial(g, secret, threshold, shareholders)
shares, err := secretsharing.ShardAndCommit(g, secret, threshold, shareholders)
if err != nil {
panic(err)
}

// Commit to polynomial.
commitment := secretsharing.Commit(g, polynomial)

// You can verify any public key using the commitment. This can be run by a single participant or any other
// participant access to the participant's public key.
for _, keyshare := range shares {
// Let's derive the public key. Other parties won't have access to the private key, naturally.
publicKey := g.Base().Multiply(keyshare.SecretKey())
publicShare := keyshare.Public()

// Verify that the key share's public key is consistent with the commitment.
if !secretsharing.Verify(g, keyshare.Identifier(), publicKey, commitment) {
if !secretsharing.Verify(g, publicShare.ID, publicShare.PublicKey, publicShare.Commitment) {
panic("invalid public key for shareholder")
}
}
Expand Down
51 changes: 40 additions & 11 deletions sharing.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ type PublicKeyShare struct {
// The PublicKey of Secret belonging to the participant.
PublicKey *group.Element

// The Commitment to the polynomial the key was created with.
Commitment []*group.Element

// ID of the participant.
ID uint64
}
Expand Down Expand Up @@ -66,8 +69,22 @@ func (s KeyShare) Public() *PublicKeyShare {
return s.PublicKeyShare
}

func makeKeyShare(g group.Group, id uint64, p Polynomial) *KeyShare {
ids := g.NewScalar().SetUInt64(id)
yi := p.Evaluate(ids)

return &KeyShare{
Secret: yi,
PublicKeyShare: &PublicKeyShare{
PublicKey: g.Base().Multiply(yi),
Commitment: nil,
ID: id,
},
}
}

// Shard splits the secret into total shares, recoverable by a subset of threshold shares.
// To use Verifiable Secret Sharing, use ShardReturnPolynomial and commit to the polynomial with Commit.
// To use Verifiable Secret Sharing, use ShardAndCommit.
func Shard(
g group.Group,
secret *group.Scalar,
Expand All @@ -83,21 +100,33 @@ func Shard(
return shares, err
}

func makeKeyShare(g group.Group, id uint64, p Polynomial) *KeyShare {
ids := g.NewScalar().SetUInt64(id)
yi := p.Evaluate(ids)
// ShardAndCommit does the same as Shard but populates the returned key shares with the Commitment to the polynomial.
func ShardAndCommit(g group.Group,
secret *group.Scalar,
threshold, total uint,
polynomial ...*group.Scalar,
) ([]*KeyShare, error) {
shares, p, err := ShardReturnPolynomial(g, secret, threshold, total, polynomial...)
if err != nil {
return nil, err
}

return &KeyShare{
Secret: yi,
PublicKeyShare: &PublicKeyShare{
PublicKey: g.Base().Multiply(yi),
ID: id,
},
commitment := Commit(g, p)

for _, share := range shares {
share.Commitment = commitment
}

for _, pi := range p {
pi.Zero() // zero-out the polynomial, just to be sure.
}

return shares, nil
}

// ShardReturnPolynomial splits the secret into total shares, recoverable by a subset of threshold shares, and returns
// the constructed secret polynomial. To use Verifiable Secret Sharing, call Commit with the returned polynomial.
// the constructed secret polynomial without committing to it. Use the Commit function if you want to commit to the
// returned polynomial.
func ShardReturnPolynomial(
g group.Group,
secret *group.Scalar,
Expand Down
36 changes: 20 additions & 16 deletions tests/ss_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,11 @@ func TestCommitment(t *testing.T) {
t.Run(g.String(), func(tt *testing.T) {
secret := g.NewScalar().Random()

shares, polynomial, err := secretsharing.ShardReturnPolynomial(g, secret, threshold, total)
shares, err := secretsharing.ShardAndCommit(g, secret, threshold, total)
if err != nil {
t.Fatal(err)
}

commitment := secretsharing.Commit(g, polynomial)

for i, keyshare := range shares {
pk := g.Base().Multiply(keyshare.Secret)

Expand All @@ -166,7 +164,7 @@ func TestCommitment(t *testing.T) {
t.Fatal("expected equality")
}

if !secretsharing.Verify(g, keyshare.ID, pk, commitment) {
if !secretsharing.Verify(g, pubkey.ID, pk, pubkey.Commitment) {
t.Fatalf("invalid public key for shareholder %d", i)
}
}
Expand Down Expand Up @@ -206,13 +204,11 @@ func TestVerify_BadShares(t *testing.T) {
t.Run(g.String(), func(tt *testing.T) {
secret := g.NewScalar().Random()

shares, polynomial, err := secretsharing.ShardReturnPolynomial(g, secret, threshold, total)
shares, err := secretsharing.ShardAndCommit(g, secret, threshold, total)
if err != nil {
t.Fatal(err)
}

commitments := secretsharing.Commit(g, polynomial)

// Alter the shares
for _, share := range shares {
share.Secret.Random()
Expand All @@ -221,7 +217,7 @@ func TestVerify_BadShares(t *testing.T) {
// Verify
for _, share := range shares {
pk := g.Base().Multiply(share.Secret)
if secretsharing.Verify(g, share.ID, pk, commitments) {
if secretsharing.Verify(g, share.ID, pk, share.Commitment) {
t.Fatalf("verification succeeded but shouldn't")
}
}
Expand Down Expand Up @@ -288,6 +284,14 @@ func TestShard_LowShares(t *testing.T) {
if _, err := secretsharing.Shard(g, secret, threshold, total); err == nil || err.Error() != expected {
t.Fatalf("expected error %q, got %q", expected, err)
}

if _, err := secretsharing.ShardAndCommit(g, secret, threshold, total); err == nil || err.Error() != expected {
t.Fatalf("expected error %q, got %q", expected, err)
}

if _, _, err := secretsharing.ShardReturnPolynomial(g, secret, threshold, total); err == nil || err.Error() != expected {
t.Fatalf("expected error %q, got %q", expected, err)
}
})
}
}
Expand Down Expand Up @@ -501,32 +505,32 @@ func TestCombine_BadIdentifiers_Duplicates(t *testing.T) {
}

func TestPubKeyForCommitment(t *testing.T) {
threshold := uint(3) // threshold is the minimum amount of necessary shares to recombine the secret
shareholders := uint(7) // the total amount of key share-holders
threshold := uint(3) // threshold is the minimum amount of necessary shares to recombine the secret
total := uint(7) // the total amount of key share-holders

for _, g := range groups {
// This is the global secret to be shared
secret := g.NewScalar().Random()

// Shard the secret into shares
shares, polynomial, err := secretsharing.ShardReturnPolynomial(g, secret, threshold, shareholders)
shares, err := secretsharing.ShardAndCommit(g, secret, threshold, total)
if err != nil {
panic(err)
t.Fatal(err)
}

commitment := secretsharing.Commit(g, polynomial)
publicShare := shares[0].Public()

// No expected error
pk, err := secretsharing.PubKeyForCommitment(g, shares[0].ID, commitment)
pk, err := secretsharing.PubKeyForCommitment(g, publicShare.ID, publicShare.Commitment)
if err != nil {
t.Fatal(err)
}

if pk.Equal(shares[0].PublicKey) != 1 {
if pk.Equal(publicShare.PublicKey) != 1 {
t.Fatalf("unexpected public key:\n\twant: %v\n\tgot : %v\n", shares[0].PublicKey.Hex(), pk.Hex())
}

if !secretsharing.Verify(g, shares[0].ID, shares[0].PublicKey, commitment) {
if !secretsharing.Verify(g, publicShare.ID, publicShare.PublicKey, publicShare.Commitment) {
t.Fatal("unexpected public key")
}
}
Expand Down

0 comments on commit a974901

Please sign in to comment.