Skip to content

Commit

Permalink
Remove aggregation from BLS + update BDN
Browse files Browse the repository at this point in the history
  • Loading branch information
K1li4nL committed Aug 16, 2024
1 parent b172e02 commit d804bae
Show file tree
Hide file tree
Showing 4 changed files with 6 additions and 276 deletions.
2 changes: 1 addition & 1 deletion sign/bdn/bdn.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func hashPointToR(pubs []kyber.Point) ([]kyber.Scalar, error) {
}

type Scheme struct {
blsScheme sign.AggregatableScheme
blsScheme sign.Scheme
sigGroup kyber.Group
keyGroup kyber.Group
pairing func(signature, public, hashedPoint kyber.Point) bool
Expand Down
8 changes: 2 additions & 6 deletions sign/bdn/bdn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,11 @@ func TestBDN_RogueAttack(t *testing.T) {
sig, err := Sign(suite, private2, msg)
require.NoError(t, err)

// Old scheme not resistant to the attack
agg := scheme.AggregatePublicKeys(pubs...)
require.NoError(t, scheme.Verify(agg, msg, sig))

// New scheme that should detect
// New scheme that should detect rogue pk attack
mask, _ := sign.NewMask(pubs, nil)
mask.SetBit(0, true)
mask.SetBit(1, true)
agg, err = AggregatePublicKeys(suite, mask)
agg, err := AggregatePublicKeys(suite, mask)
require.NoError(t, err)
require.Error(t, Verify(suite, agg, msg, sig))
}
Expand Down
66 changes: 3 additions & 63 deletions sign/bls/bls.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// was introduced in the paper "Short Signatures from the Weil Pairing". BLS
// requires pairing-based cryptography.
//
// Deprecated: This version is vulnerable to rogue public-key attack and the
// This version is vulnerable to rogue public-key attack and the
// new version of the protocol should be used to make sure a signature
// aggregate cannot be verified by a forged key. You can find the protocol
// in kyber/sign/bdn. Note that only the aggregation is broken against the
Expand All @@ -15,7 +15,6 @@ import (
"crypto/cipher"
"crypto/sha256"
"errors"
"fmt"

"go.dedis.ch/kyber/v4"
"go.dedis.ch/kyber/v4/pairing"
Expand All @@ -30,7 +29,7 @@ type scheme struct {

// NewSchemeOnG1 returns a sign.Scheme that uses G1 for its signature space and G2
// for its public keys
func NewSchemeOnG1(suite pairing.Suite) sign.AggregatableScheme {
func NewSchemeOnG1(suite pairing.Suite) sign.Scheme {
sigGroup := suite.G1()
keyGroup := suite.G2()
pairing := func(public, hashedMsg, sigPoint kyber.Point) bool {
Expand All @@ -45,7 +44,7 @@ func NewSchemeOnG1(suite pairing.Suite) sign.AggregatableScheme {

// NewSchemeOnG2 returns a sign.Scheme that uses G2 for its signature space and
// G1 for its public key
func NewSchemeOnG2(suite pairing.Suite) sign.AggregatableScheme {
func NewSchemeOnG2(suite pairing.Suite) sign.Scheme {
sigGroup := suite.G2()
keyGroup := suite.G1()
pairing := func(public, hashedMsg, sigPoint kyber.Point) bool {
Expand Down Expand Up @@ -95,65 +94,6 @@ func (s *scheme) Verify(X kyber.Point, msg, sig []byte) error {
return nil
}

func (s *scheme) AggregateSignatures(sigs ...[]byte) ([]byte, error) {
sig := s.sigGroup.Point()
for _, sigBytes := range sigs {
sigToAdd := s.sigGroup.Point()
if err := sigToAdd.UnmarshalBinary(sigBytes); err != nil {
return nil, err
}
sig.Add(sig, sigToAdd)
}
return sig.MarshalBinary()
}

func (s *scheme) AggregatePublicKeys(Xs ...kyber.Point) kyber.Point {
aggregated := s.keyGroup.Point()
for _, X := range Xs {
aggregated.Add(aggregated, X)
}
return aggregated
}

// BatchVerify verifies a large number of publicKey/msg pairings with a single aggregated signature.
// Since aggregation is generally much faster than verification, this can be a speed enhancement.
// Benchmarks show a roughly 50% performance increase over individual signature verification
// Every msg must be unique or there is the possibility to accept an invalid signature
// see: https://crypto.stackexchange.com/questions/56288/is-bls-signature-scheme-strongly-unforgeable/56290
// for a description of why each message must be unique.
func BatchVerify(suite pairing.Suite, publics []kyber.Point, msgs [][]byte, sig []byte) error {
if !distinct(msgs) {
return fmt.Errorf("bls: error, messages must be distinct")
}

s := suite.G1().Point()
if err := s.UnmarshalBinary(sig); err != nil {
return err
}

var aggregatedLeft kyber.Point
for i := range msgs {
hashable, ok := suite.G1().Point().(kyber.HashablePoint)
if !ok {
return errors.New("bls: point needs to implement hashablePoint")
}
hm := hashable.Hash(msgs[i])
pair := suite.Pair(hm, publics[i])

if i == 0 {
aggregatedLeft = pair
} else {
aggregatedLeft.Add(aggregatedLeft, pair)
}
}

right := suite.Pair(s, suite.G2().Point().Base())
if !aggregatedLeft.Equal(right) {
return errors.New("bls: invalid signature")
}
return nil
}

func distinct(msgs [][]byte) bool {
m := make(map[[32]byte]bool)
for _, msg := range msgs {
Expand Down
206 changes: 0 additions & 206 deletions sign/bls/bls_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package bls

import (
"crypto/rand"
"testing"

"github.com/stretchr/testify/require"
"go.dedis.ch/kyber/v4"
"go.dedis.ch/kyber/v4/pairing/bn256"
"go.dedis.ch/kyber/v4/util/random"
"go.dedis.ch/kyber/v4/xof/blake2xb"
Expand Down Expand Up @@ -62,116 +60,6 @@ func TestBLSFailKey(t *testing.T) {
}
}

func TestBLSAggregateSignatures(t *testing.T) {
msg := []byte("Hello Boneh-Lynn-Shacham")
suite := bn256.NewSuite()
scheme := NewSchemeOnG1(suite)
private1, public1 := scheme.NewKeyPair(random.New())
private2, public2 := scheme.NewKeyPair(random.New())
sig1, err := scheme.Sign(private1, msg)
require.Nil(t, err)
sig2, err := scheme.Sign(private2, msg)
require.Nil(t, err)
aggregatedSig, err := scheme.AggregateSignatures(sig1, sig2)
require.Nil(t, err)

aggregatedKey := scheme.AggregatePublicKeys(public1, public2)

err = scheme.Verify(aggregatedKey, msg, aggregatedSig)
require.Nil(t, err)
}

func TestBLSFailAggregatedSig(t *testing.T) {
msg := []byte("Hello Boneh-Lynn-Shacham")
suite := bn256.NewSuite()
scheme := NewSchemeOnG1(suite)
private1, public1 := scheme.NewKeyPair(random.New())
private2, public2 := scheme.NewKeyPair(random.New())
sig1, err := scheme.Sign(private1, msg)
require.Nil(t, err)
sig2, err := scheme.Sign(private2, msg)
require.Nil(t, err)
aggregatedSig, err := scheme.AggregateSignatures(sig1, sig2)
require.Nil(t, err)
aggregatedKey := scheme.AggregatePublicKeys(public1, public2)

aggregatedSig[0] ^= 0x01
if scheme.Verify(aggregatedKey, msg, aggregatedSig) == nil {
t.Fatal("bls: verification succeeded unexpectedly")
}
}
func TestBLSFailAggregatedKey(t *testing.T) {
msg := []byte("Hello Boneh-Lynn-Shacham")
suite := bn256.NewSuite()
scheme := NewSchemeOnG1(suite)
private1, public1 := scheme.NewKeyPair(random.New())
private2, public2 := scheme.NewKeyPair(random.New())
_, public3 := scheme.NewKeyPair(random.New())
sig1, err := scheme.Sign(private1, msg)
require.Nil(t, err)
sig2, err := scheme.Sign(private2, msg)
require.Nil(t, err)
aggregatedSig, err := scheme.AggregateSignatures(sig1, sig2)
require.Nil(t, err)
badAggregatedKey := scheme.AggregatePublicKeys(public1, public2, public3)

if scheme.Verify(badAggregatedKey, msg, aggregatedSig) == nil {
t.Fatal("bls: verification succeeded unexpectedly")
}
}

func TestBLSBatchVerify(t *testing.T) {
msg1 := []byte("Hello Boneh-Lynn-Shacham")
msg2 := []byte("Hello Dedis & Boneh-Lynn-Shacham")
suite := bn256.NewSuite()
scheme := NewSchemeOnG1(suite)
private1, public1 := scheme.NewKeyPair(random.New())
private2, public2 := scheme.NewKeyPair(random.New())
sig1, err := scheme.Sign(private1, msg1)
require.Nil(t, err)
sig2, err := scheme.Sign(private2, msg2)
require.Nil(t, err)
aggregatedSig, err := scheme.AggregateSignatures(sig1, sig2)
require.Nil(t, err)

err = BatchVerify(suite, []kyber.Point{public1, public2}, [][]byte{msg1, msg2}, aggregatedSig)
require.Nil(t, err)
}

func TestBLSFailBatchVerify(t *testing.T) {
msg1 := []byte("Hello Boneh-Lynn-Shacham")
msg2 := []byte("Hello Dedis & Boneh-Lynn-Shacham")
suite := bn256.NewSuite()
scheme := NewSchemeOnG1(suite)
private1, public1 := scheme.NewKeyPair(random.New())
private2, public2 := scheme.NewKeyPair(random.New())
sig1, err := scheme.Sign(private1, msg1)
require.Nil(t, err)
sig2, err := scheme.Sign(private2, msg2)
require.Nil(t, err)

t.Run("fails with a bad signature", func(t *testing.T) {
aggregatedSig, err := scheme.AggregateSignatures(sig1, sig2)
require.Nil(t, err)
msg2[0] ^= 0x01
if BatchVerify(suite, []kyber.Point{public1, public2}, [][]byte{msg1, msg2}, aggregatedSig) == nil {
t.Fatal("bls: verification succeeded unexpectedly")
}
})

t.Run("fails with a duplicate msg", func(t *testing.T) {
private3, public3 := scheme.NewKeyPair(random.New())
sig3, err := scheme.Sign(private3, msg1)
require.Nil(t, err)
aggregatedSig, err := scheme.AggregateSignatures(sig1, sig2, sig3)
require.Nil(t, err)

if BatchVerify(suite, []kyber.Point{public1, public2, public3}, [][]byte{msg1, msg2, msg1}, aggregatedSig) == nil {
t.Fatal("bls: verification succeeded unexpectedly")
}
})
}

func BenchmarkBLSKeyCreation(b *testing.B) {
suite := bn256.NewSuite()
scheme := NewSchemeOnG1(suite)
Expand All @@ -192,97 +80,3 @@ func BenchmarkBLSSign(b *testing.B) {
require.Nil(b, err)
}
}

func BenchmarkBLSAggregateSigs(b *testing.B) {
suite := bn256.NewSuite()
scheme := NewSchemeOnG1(suite)
private1, _ := scheme.NewKeyPair(random.New())
private2, _ := scheme.NewKeyPair(random.New())
msg := []byte("Hello many times Boneh-Lynn-Shacham")
sig1, err := scheme.Sign(private1, msg)
require.Nil(b, err)
sig2, err := scheme.Sign(private2, msg)
require.Nil(b, err)

b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := scheme.AggregateSignatures(sig1, sig2)
require.Nil(b, err)
}
}

func BenchmarkBLSVerifyAggregate(b *testing.B) {
suite := bn256.NewSuite()
scheme := NewSchemeOnG1(suite)
private1, public1 := scheme.NewKeyPair(random.New())
private2, public2 := scheme.NewKeyPair(random.New())
msg := []byte("Hello many times Boneh-Lynn-Shacham")
sig1, err := scheme.Sign(private1, msg)
require.Nil(b, err)
sig2, err := scheme.Sign(private2, msg)
require.Nil(b, err)
sig, err := scheme.AggregateSignatures(sig1, sig2)
require.Nil(b, err)
key := scheme.AggregatePublicKeys(public1, public2)
b.ResetTimer()
for i := 0; i < b.N; i++ {
err := scheme.Verify(key, msg, sig)
require.Nil(b, err)
}
}

func BenchmarkBLSVerifyBatchVerify(b *testing.B) {
suite := bn256.NewSuite()
scheme := NewSchemeOnG1(suite)
numSigs := 100
privates := make([]kyber.Scalar, numSigs)
publics := make([]kyber.Point, numSigs)
msgs := make([][]byte, numSigs)
sigs := make([][]byte, numSigs)
for i := 0; i < numSigs; i++ {
private, public := scheme.NewKeyPair(random.New())
privates[i] = private
publics[i] = public
msg := make([]byte, 64)
_, err := rand.Read(msg)
require.Nil(b, err)
msgs[i] = msg
sig, err := scheme.Sign(private, msg)
require.Nil(b, err)
sigs[i] = sig
}

b.ResetTimer()
for i := 0; i < b.N; i++ {
aggregateSig, _ := scheme.AggregateSignatures(sigs...)
err := BatchVerify(suite, publics, msgs, aggregateSig)
require.Nil(b, err)
}
}

func TestBinaryMarshalAfterAggregation_issue400(t *testing.T) {
suite := bn256.NewSuite()
scheme := NewSchemeOnG1(suite)

_, public1 := scheme.NewKeyPair(random.New())
_, public2 := scheme.NewKeyPair(random.New())

workingKey := scheme.AggregatePublicKeys(public1, public2, public1)

workingBits, err := workingKey.MarshalBinary()
require.Nil(t, err)

workingPoint := suite.G2().Point()
err = workingPoint.UnmarshalBinary(workingBits)
require.Nil(t, err)

// this was failing before the fix
aggregatedKey := scheme.AggregatePublicKeys(public1, public1, public2)

bits, err := aggregatedKey.MarshalBinary()
require.Nil(t, err)

point := suite.G2().Point()
err = point.UnmarshalBinary(bits)
require.Nil(t, err)
}

0 comments on commit d804bae

Please sign in to comment.