Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove BLS signatures aggregate #540

Merged
merged 3 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions benchmark/benchmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,16 +146,16 @@ func benchmarkSign(sigType string) map[string]interface{} {
// Signing
for _, i := range keys {
results["sign"][fmt.Sprintf("%d", i)] = testing.Benchmark(func(b *testing.B) {
_, scheme, _, privates, _, _ := test.PrepareBLS(i)
scheme, _, privates, _, _ := test.PrepareBLS(i)
test.BenchSign(b, scheme, benchMessage, privates)
})
}

// Verification
for _, i := range keys {
results["verify"][fmt.Sprintf("%d", i)] = testing.Benchmark(func(b *testing.B) {
suite, scheme, publics, _, msgs, sigs := test.PrepareBLS(i)
test.BLSBenchVerify(b, sigs, scheme, suite, publics, msgs)
scheme, publics, _, msgs, sigs := test.PrepareBLS(i)
test.BLSBenchVerify(b, sigs, scheme, publics, msgs)
})
}
}
Expand Down
43 changes: 33 additions & 10 deletions pairing/bls12381/bls12381_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"go.dedis.ch/kyber/v4/pairing"
circl "go.dedis.ch/kyber/v4/pairing/bls12381/circl"
kilic "go.dedis.ch/kyber/v4/pairing/bls12381/kilic"
"go.dedis.ch/kyber/v4/sign/bdn"
"go.dedis.ch/kyber/v4/sign/bls"
"go.dedis.ch/kyber/v4/sign/tbls"
"go.dedis.ch/kyber/v4/util/random"
Expand Down Expand Up @@ -665,14 +666,15 @@ var (
var result interface{}

func BenchmarkKilic(b *testing.B) {
BLSBenchmark(b, "kilic")
BDNBenchmark(b, "kilic")
}

func BenchmarkCircl(b *testing.B) {
BLSBenchmark(b, "circl")
BDNBenchmark(b, "circl")
}

func BLSBenchmark(b *testing.B, curveOption string) {
//nolint: gocyclo,cyclop // breaking this down doesn't make sense
func BDNBenchmark(b *testing.B, curveOption string) {
b.Logf("----------------------")
b.Logf("Payload to sign: %d bytes\n", dataSize)
b.Logf("Numbers of signatures: %v\n", numSigs)
Expand Down Expand Up @@ -700,8 +702,8 @@ func BLSBenchmark(b *testing.B, curveOption string) {
panic(fmt.Errorf("invalid curve option: %s", curveOption))
}

schemeOnG1 := bls.NewSchemeOnG1(suite)
schemeOnG2 := bls.NewSchemeOnG2(suite)
schemeOnG1 := bdn.NewSchemeOnG1(suite)
schemeOnG2 := bdn.NewSchemeOnG2(suite)

maxN := 1
for _, s := range numSigs {
Expand Down Expand Up @@ -730,31 +732,52 @@ func BLSBenchmark(b *testing.B, curveOption string) {
}
}

// Prepare masks for aggregation
maskG1, err := bdn.NewMask(suite.G1(), pubKeysOnG1, nil)
if err != nil {
panic(err)
}
maskG2, err := bdn.NewMask(suite.G2(), pubKeysOnG2, nil)
if err != nil {
panic(err)
}

for _, n := range numSigs {
for i := 0; i < n; i++ {
maskG1.SetBit(i, true)
maskG2.SetBit(i, true)
}

// Benchmark aggregation of public keys
b.Run(fmt.Sprintf("AggregatePublicKeys-G1 on %d signs", n), func(bb *testing.B) {
for j := 0; j < bb.N; j++ {
result = schemeOnG1.AggregatePublicKeys(pubKeysOnG1[:n]...)
result, err = schemeOnG1.AggregatePublicKeys(maskG1)
if err != nil {
require.NoError(b, err)
}
}
})
b.Run(fmt.Sprintf("AggregatePublicKeys-G2 on %d signs", n), func(bb *testing.B) {
for j := 0; j < bb.N; j++ {
result = schemeOnG2.AggregatePublicKeys(pubKeysOnG2[:n]...)
result, err = schemeOnG2.AggregatePublicKeys(maskG2)
if err != nil {
panic(err)
}
}
})

// Benchmark aggregation of signatures
b.Run(fmt.Sprintf("AggregateSign-G1 on %d signs", n), func(bb *testing.B) {
for j := 0; j < bb.N; j++ {
result, err = schemeOnG1.AggregateSignatures(sigsOnG1[:n]...)
result, err = schemeOnG1.AggregateSignatures(sigsOnG1[:n], maskG1)
if err != nil {
panic(err)
}
}
})
b.Run(fmt.Sprintf("AggregateSign-G1 on %d signs", n), func(bb *testing.B) {
b.Run(fmt.Sprintf("AggregateSign-G2 on %d signs", n), func(bb *testing.B) {
for j := 0; j < bb.N; j++ {
result, err = schemeOnG2.AggregateSignatures(sigsOnG2[:n]...)
result, err = schemeOnG2.AggregateSignatures(sigsOnG2[:n], maskG2)
if err != nil {
panic(err)
}
Expand Down
28 changes: 0 additions & 28 deletions pairing/bn256/bls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,12 @@ package bn256
import (
"testing"

"github.com/stretchr/testify/require"
"go.dedis.ch/kyber/v4/internal/test"
"go.dedis.ch/kyber/v4/sign/bls"
"go.dedis.ch/kyber/v4/util/random"
)

func TestBLSSchemeBN256G1(t *testing.T) {
suite := NewSuite()
s := bls.NewSchemeOnG1(suite)
test.SchemeTesting(t, s)
}

func TestBinaryMarshalAfterAggregation_issue400(t *testing.T) {
suite := NewSuite()
s := bls.NewSchemeOnG1(suite)
_, public1 := s.NewKeyPair(random.New())
_, public2 := s.NewKeyPair(random.New())

workingKey := s.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 := s.AggregatePublicKeys(public1, public1, public2)

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

point := suite.G2().Point()
err = point.UnmarshalBinary(bits)
require.Nil(t, err)
}
2 changes: 1 addition & 1 deletion sign/bdn/bdn.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func hashPointToR(group kyber.Group, 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
6 changes: 1 addition & 5 deletions sign/bdn/bdn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,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
mask, _ := NewMask(suite, 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
83 changes: 6 additions & 77 deletions sign/bls/bls.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@
// 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
// new version of the protocol should be used to make sure a signature
// When using aggregated signatures, this version is vulnerable to rogue
// public-key attack.
// The `sign/bdn` package 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
// attack and a later version will merge bls and asmbls.
// attack and for that reason, the code performing aggregation was removed.
//
// See the paper: https://crypto.stanford.edu/~dabo/pubs/papers/BLSmultisig.html
package bls

import (
"crypto/cipher"
"crypto/sha256"
"errors"
"fmt"

Expand All @@ -30,7 +30,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 +45,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 @@ -94,74 +94,3 @@ 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 {
h := sha256.Sum256(msg)
if m[h] {
return false
}
m[h] = true
}
return true
}
Loading
Loading