mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 21:08:10 -05:00
Make BLST The Permanent Default (#8710)
* remove herumi * gaz * deprecate flag * remove source builds of herumi * remove * Revert "remove source builds of herumi" This reverts commitac7dd133ed. * disable blst * remove herumi hard requirement from fuzz * restrict viz, ensure all deps removed from fuzz * remove source builds * add back opts * add back herumi initialization * Revert "add back opts" This reverts commitad9b409b8a. * Revert "remove source builds" This reverts commitb78ee30dba. * Revert "restrict viz, ensure all deps removed from fuzz" This reverts commit65d951da93. * Revert "remove herumi hard requirement from fuzz" This reverts commitad92191d81. * redundant * add lock for rand generation Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>
This commit is contained in:
@@ -16,7 +16,6 @@ go_library(
|
||||
"//shared/bls/blst:go_default_library",
|
||||
"//shared/bls/common:go_default_library",
|
||||
"//shared/bls/herumi:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -27,7 +26,6 @@ go_test(
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//shared/bls/common:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -10,15 +10,16 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/blst"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/common"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/herumi"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
)
|
||||
|
||||
// Initialize herumi temporarily while we transition to blst for ethdo.
|
||||
func init() {
|
||||
herumi.HerumiInit()
|
||||
}
|
||||
|
||||
// SecretKeyFromBytes creates a BLS private key from a BigEndian byte slice.
|
||||
func SecretKeyFromBytes(privKey []byte) (SecretKey, error) {
|
||||
if featureconfig.Get().EnableBlst {
|
||||
return blst.SecretKeyFromBytes(privKey)
|
||||
}
|
||||
return herumi.SecretKeyFromBytes(privKey)
|
||||
return blst.SecretKeyFromBytes(privKey)
|
||||
}
|
||||
|
||||
// SecretKeyFromBigNum takes in a big number string and creates a BLS private key.
|
||||
@@ -39,66 +40,35 @@ func SecretKeyFromBigNum(s string) (SecretKey, error) {
|
||||
|
||||
// PublicKeyFromBytes creates a BLS public key from a BigEndian byte slice.
|
||||
func PublicKeyFromBytes(pubKey []byte) (PublicKey, error) {
|
||||
if featureconfig.Get().EnableBlst {
|
||||
return blst.PublicKeyFromBytes(pubKey)
|
||||
}
|
||||
return herumi.PublicKeyFromBytes(pubKey)
|
||||
return blst.PublicKeyFromBytes(pubKey)
|
||||
}
|
||||
|
||||
// SignatureFromBytes creates a BLS signature from a LittleEndian byte slice.
|
||||
func SignatureFromBytes(sig []byte) (Signature, error) {
|
||||
if featureconfig.Get().EnableBlst {
|
||||
return blst.SignatureFromBytes(sig)
|
||||
}
|
||||
return herumi.SignatureFromBytes(sig)
|
||||
return blst.SignatureFromBytes(sig)
|
||||
}
|
||||
|
||||
// AggregatePublicKeys aggregates the provided raw public keys into a single key.
|
||||
func AggregatePublicKeys(pubs [][]byte) (PublicKey, error) {
|
||||
if featureconfig.Get().EnableBlst {
|
||||
return blst.AggregatePublicKeys(pubs)
|
||||
}
|
||||
return herumi.AggregatePublicKeys(pubs)
|
||||
return blst.AggregatePublicKeys(pubs)
|
||||
}
|
||||
|
||||
// AggregateSignatures converts a list of signatures into a single, aggregated sig.
|
||||
func AggregateSignatures(sigs []common.Signature) common.Signature {
|
||||
if featureconfig.Get().EnableBlst {
|
||||
return blst.AggregateSignatures(sigs)
|
||||
}
|
||||
return herumi.AggregateSignatures(sigs)
|
||||
return blst.AggregateSignatures(sigs)
|
||||
}
|
||||
|
||||
// VerifyMultipleSignatures verifies multiple signatures for distinct messages securely.
|
||||
func VerifyMultipleSignatures(sigs [][]byte, msgs [][32]byte, pubKeys []common.PublicKey) (bool, error) {
|
||||
if featureconfig.Get().EnableBlst {
|
||||
return blst.VerifyMultipleSignatures(sigs, msgs, pubKeys)
|
||||
}
|
||||
// Manually decompress each signature as herumi does not
|
||||
// have a batch decompress method.
|
||||
rawSigs := make([]Signature, len(sigs))
|
||||
var err error
|
||||
for i, s := range sigs {
|
||||
rawSigs[i], err = herumi.SignatureFromBytes(s)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return herumi.VerifyMultipleSignatures(rawSigs, msgs, pubKeys)
|
||||
return blst.VerifyMultipleSignatures(sigs, msgs, pubKeys)
|
||||
}
|
||||
|
||||
// NewAggregateSignature creates a blank aggregate signature.
|
||||
func NewAggregateSignature() common.Signature {
|
||||
if featureconfig.Get().EnableBlst {
|
||||
return blst.NewAggregateSignature()
|
||||
}
|
||||
return herumi.NewAggregateSignature()
|
||||
return blst.NewAggregateSignature()
|
||||
}
|
||||
|
||||
// RandKey creates a new private key using a random input.
|
||||
func RandKey() (common.SecretKey, error) {
|
||||
if featureconfig.Get().EnableBlst {
|
||||
return blst.RandKey()
|
||||
}
|
||||
return herumi.RandKey()
|
||||
return blst.RandKey()
|
||||
}
|
||||
|
||||
@@ -4,25 +4,11 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/common"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestDisallowZeroSecretKeys(t *testing.T) {
|
||||
flags := &featureconfig.Flags{}
|
||||
t.Run("herumi", func(t *testing.T) {
|
||||
flags := &featureconfig.Flags{}
|
||||
reset := featureconfig.InitWithReset(flags)
|
||||
defer reset()
|
||||
|
||||
_, err := SecretKeyFromBytes(common.ZeroSecretKey[:])
|
||||
require.Equal(t, common.ErrZeroKey, err)
|
||||
})
|
||||
|
||||
t.Run("blst", func(t *testing.T) {
|
||||
flags.EnableBlst = true
|
||||
reset := featureconfig.InitWithReset(flags)
|
||||
defer reset()
|
||||
// Blst does a zero check on the key during deserialization.
|
||||
_, err := SecretKeyFromBytes(common.ZeroSecretKey[:])
|
||||
require.Equal(t, common.ErrSecretUnmarshal, err)
|
||||
@@ -30,42 +16,14 @@ func TestDisallowZeroSecretKeys(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDisallowZeroPublicKeys(t *testing.T) {
|
||||
flags := &featureconfig.Flags{}
|
||||
|
||||
t.Run("herumi", func(t *testing.T) {
|
||||
reset := featureconfig.InitWithReset(flags)
|
||||
defer reset()
|
||||
|
||||
_, err := PublicKeyFromBytes(common.InfinitePublicKey[:])
|
||||
require.Equal(t, common.ErrInfinitePubKey, err)
|
||||
})
|
||||
|
||||
t.Run("blst", func(t *testing.T) {
|
||||
flags.EnableBlst = true
|
||||
reset := featureconfig.InitWithReset(flags)
|
||||
defer reset()
|
||||
|
||||
_, err := PublicKeyFromBytes(common.InfinitePublicKey[:])
|
||||
require.Equal(t, common.ErrInfinitePubKey, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDisallowZeroPublicKeys_AggregatePubkeys(t *testing.T) {
|
||||
flags := &featureconfig.Flags{}
|
||||
|
||||
t.Run("herumi", func(t *testing.T) {
|
||||
reset := featureconfig.InitWithReset(flags)
|
||||
defer reset()
|
||||
|
||||
_, err := AggregatePublicKeys([][]byte{common.InfinitePublicKey[:], common.InfinitePublicKey[:]})
|
||||
require.Equal(t, common.ErrInfinitePubKey, err)
|
||||
})
|
||||
|
||||
t.Run("blst", func(t *testing.T) {
|
||||
flags.EnableBlst = true
|
||||
reset := featureconfig.InitWithReset(flags)
|
||||
defer reset()
|
||||
|
||||
_, err := AggregatePublicKeys([][]byte{common.InfinitePublicKey[:], common.InfinitePublicKey[:]})
|
||||
require.Equal(t, common.ErrInfinitePubKey, err)
|
||||
})
|
||||
|
||||
@@ -5,6 +5,7 @@ package blst
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/common"
|
||||
@@ -195,10 +196,14 @@ func VerifyMultipleSignatures(sigs [][]byte, msgs [][32]byte, pubKeys []common.P
|
||||
}
|
||||
// Secure source of RNG
|
||||
randGen := rand.NewGenerator()
|
||||
randLock := new(sync.Mutex)
|
||||
|
||||
randFunc := func(scalar *blst.Scalar) {
|
||||
var rbytes [scalarBytes]byte
|
||||
randLock.Lock()
|
||||
// Ignore error as the error will always be nil in `read` in math/rand.
|
||||
randGen.Read(rbytes[:])
|
||||
randLock.Unlock()
|
||||
scalar.FromBEndian(rbytes[:])
|
||||
}
|
||||
dummySig := new(blstSignature)
|
||||
|
||||
@@ -1,71 +1,15 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
# gazelle:resolve go github.com/herumi/bls-eth-go-binary/bls @herumi_bls_eth_go_binary//:go_default_library
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"init.go",
|
||||
"public_key.go",
|
||||
"secret_key.go",
|
||||
"signature.go",
|
||||
],
|
||||
srcs = ["init.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/shared/bls/herumi",
|
||||
visibility = [
|
||||
"//shared/bls:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//shared/bls/common:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/rand:go_default_library",
|
||||
"@com_github_dgraph_io_ristretto//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@herumi_bls_eth_go_binary//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"public_key_test.go",
|
||||
"secret_key_test.go",
|
||||
"signature_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//shared/bls/common:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/testutil/assert:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
"@herumi_bls_eth_go_binary//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
# gazelle:exclude bls_benchmark_test.go
|
||||
go_test(
|
||||
name = "go_benchmark_test",
|
||||
size = "small",
|
||||
srcs = ["bls_benchmark_test.go"],
|
||||
args = [
|
||||
"-test.bench=.",
|
||||
"-test.benchmem",
|
||||
"-test.v",
|
||||
],
|
||||
local = True,
|
||||
tags = [
|
||||
"benchmark",
|
||||
"manual",
|
||||
"no-cache",
|
||||
],
|
||||
deps = [
|
||||
":go_default_library",
|
||||
"//shared/bls/common:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"@herumi_bls_eth_go_binary//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
package herumi_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/herumi/bls-eth-go-binary/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/common"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/herumi"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func BenchmarkPairing(b *testing.B) {
|
||||
require.NoError(b, bls.Init(bls.BLS12_381))
|
||||
if err := bls.SetETHmode(bls.EthModeDraft07); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
newGt := &bls.GT{}
|
||||
newG1 := &bls.G1{}
|
||||
newG2 := &bls.G2{}
|
||||
|
||||
newGt.SetInt64(10)
|
||||
hash := hashutil.Hash([]byte{})
|
||||
require.NoError(b, newG1.HashAndMapTo(hash[:]))
|
||||
require.NoError(b, newG2.HashAndMapTo(hash[:]))
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
bls.Pairing(newGt, newG1, newG2)
|
||||
}
|
||||
|
||||
}
|
||||
func BenchmarkSignature_Verify(b *testing.B) {
|
||||
sk, err := herumi.RandKey()
|
||||
require.NoError(b, err)
|
||||
|
||||
msg := []byte("Some msg")
|
||||
sig := sk.Sign(msg)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
require.Equal(b, true, sig.Verify(sk.PublicKey(), msg))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSignature_AggregateVerify(b *testing.B) {
|
||||
sigN := 128 // MAX_ATTESTATIONS per block.
|
||||
|
||||
var pks []common.PublicKey
|
||||
var sigs []common.Signature
|
||||
var msgs [][32]byte
|
||||
for i := 0; i < sigN; i++ {
|
||||
msg := [32]byte{'s', 'i', 'g', 'n', 'e', 'd', byte(i)}
|
||||
sk, err := herumi.RandKey()
|
||||
require.NoError(b, err)
|
||||
sig := sk.Sign(msg[:])
|
||||
pks = append(pks, sk.PublicKey())
|
||||
sigs = append(sigs, sig)
|
||||
msgs = append(msgs, msg)
|
||||
}
|
||||
aggregated := herumi.Aggregate(sigs)
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
require.Equal(b, true, aggregated.AggregateVerify(pks, msgs))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSecretKey_Marshal(b *testing.B) {
|
||||
key, err := herumi.RandKey()
|
||||
require.NoError(b, err)
|
||||
d := key.Marshal()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := herumi.SecretKeyFromBytes(d)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
// Package herumi implements a go-wrapper around a library implementing the
|
||||
// the BLS12-381 curve and signature scheme. This package exposes a public API for
|
||||
// verifying and aggregating BLS signatures used by Ethereum 2.0.
|
||||
//
|
||||
// This implementation uses the library written by Herumi.
|
||||
package herumi
|
||||
@@ -2,7 +2,8 @@ package herumi
|
||||
|
||||
import "github.com/herumi/bls-eth-go-binary/bls"
|
||||
|
||||
func init() {
|
||||
// HerumiInit allows the required curve orders and appropriate sub-groups to be initialized.
|
||||
func HerumiInit() {
|
||||
if err := bls.Init(bls.BLS12_381); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
package herumi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/dgraph-io/ristretto"
|
||||
bls12 "github.com/herumi/bls-eth-go-binary/bls"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/common"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
var maxKeys = int64(100000)
|
||||
var pubkeyCache, _ = ristretto.NewCache(&ristretto.Config{
|
||||
NumCounters: maxKeys,
|
||||
MaxCost: 1 << 22, // ~4mb is cache max size
|
||||
BufferItems: 64,
|
||||
})
|
||||
|
||||
// PublicKey used in the BLS signature scheme.
|
||||
type PublicKey struct {
|
||||
p *bls12.PublicKey
|
||||
}
|
||||
|
||||
// PublicKeyFromBytes creates a BLS public key from a BigEndian byte slice.
|
||||
func PublicKeyFromBytes(pubKey []byte) (common.PublicKey, error) {
|
||||
if featureconfig.Get().SkipBLSVerify {
|
||||
return &PublicKey{}, nil
|
||||
}
|
||||
if len(pubKey) != params.BeaconConfig().BLSPubkeyLength {
|
||||
return nil, fmt.Errorf("public key must be %d bytes", params.BeaconConfig().BLSPubkeyLength)
|
||||
}
|
||||
if cv, ok := pubkeyCache.Get(string(pubKey)); ok {
|
||||
return cv.(*PublicKey).Copy(), nil
|
||||
}
|
||||
p := &bls12.PublicKey{}
|
||||
err := p.Deserialize(pubKey)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not unmarshal bytes into public key")
|
||||
}
|
||||
pubKeyObj := &PublicKey{p: p}
|
||||
if pubKeyObj.IsInfinite() {
|
||||
return nil, common.ErrInfinitePubKey
|
||||
}
|
||||
pubkeyCache.Set(string(pubKey), pubKeyObj.Copy(), 48)
|
||||
return pubKeyObj, nil
|
||||
}
|
||||
|
||||
// AggregatePublicKeys aggregates the provided raw public keys into a single key.
|
||||
func AggregatePublicKeys(pubs [][]byte) (common.PublicKey, error) {
|
||||
if len(pubs) == 0 {
|
||||
return &PublicKey{}, nil
|
||||
}
|
||||
p, err := PublicKeyFromBytes(pubs[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, k := range pubs[1:] {
|
||||
pubkey, err := PublicKeyFromBytes(k)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.Aggregate(pubkey)
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Marshal a public key into a LittleEndian byte slice.
|
||||
func (p *PublicKey) Marshal() []byte {
|
||||
return p.p.Serialize()
|
||||
}
|
||||
|
||||
// Copy the public key to a new pointer reference.
|
||||
func (p *PublicKey) Copy() common.PublicKey {
|
||||
np := *p.p
|
||||
return &PublicKey{p: &np}
|
||||
}
|
||||
|
||||
// IsInfinite checks if the public key is infinite.
|
||||
func (p *PublicKey) IsInfinite() bool {
|
||||
return p.p.IsZero()
|
||||
}
|
||||
|
||||
// Aggregate two public keys.
|
||||
func (p *PublicKey) Aggregate(p2 common.PublicKey) common.PublicKey {
|
||||
if featureconfig.Get().SkipBLSVerify {
|
||||
return p
|
||||
}
|
||||
p.p.Add(p2.(*PublicKey).p)
|
||||
return p
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
package herumi_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/herumi"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestPublicKeyFromBytes(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []byte
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "Nil",
|
||||
err: errors.New("public key must be 48 bytes"),
|
||||
},
|
||||
{
|
||||
name: "Empty",
|
||||
input: []byte{},
|
||||
err: errors.New("public key must be 48 bytes"),
|
||||
},
|
||||
{
|
||||
name: "Short",
|
||||
input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
err: errors.New("public key must be 48 bytes"),
|
||||
},
|
||||
{
|
||||
name: "Long",
|
||||
input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
err: errors.New("public key must be 48 bytes"),
|
||||
},
|
||||
{
|
||||
name: "Bad",
|
||||
input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
err: errors.New("could not unmarshal bytes into public key: err blsPublicKeyDeserialize 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
|
||||
},
|
||||
{
|
||||
name: "Good",
|
||||
input: []byte{0xa9, 0x9a, 0x76, 0xed, 0x77, 0x96, 0xf7, 0xbe, 0x22, 0xd5, 0xb7, 0xe8, 0x5d, 0xee, 0xb7, 0xc5, 0x67, 0x7e, 0x88, 0xe5, 0x11, 0xe0, 0xb3, 0x37, 0x61, 0x8f, 0x8c, 0x4e, 0xb6, 0x13, 0x49, 0xb4, 0xbf, 0x2d, 0x15, 0x3f, 0x64, 0x9f, 0x7b, 0x53, 0x35, 0x9f, 0xe8, 0xb9, 0x4a, 0x38, 0xe4, 0x4c},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
res, err := herumi.PublicKeyFromBytes(test.input)
|
||||
if test.err != nil {
|
||||
assert.ErrorContains(t, test.err.Error(), err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.DeepEqual(t, test.input, res.Marshal())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublicKey_Copy(t *testing.T) {
|
||||
priv, err := herumi.RandKey()
|
||||
require.NoError(t, err)
|
||||
pubkeyA := priv.PublicKey()
|
||||
pubkeyBytes := pubkeyA.Marshal()
|
||||
|
||||
pubkeyB := pubkeyA.Copy()
|
||||
priv2, err := herumi.RandKey()
|
||||
require.NoError(t, err)
|
||||
pubkeyB.Aggregate(priv2.PublicKey())
|
||||
|
||||
if !bytes.Equal(pubkeyA.Marshal(), pubkeyBytes) {
|
||||
t.Fatal("Pubkey was mutated after copy")
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package herumi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
bls12 "github.com/herumi/bls-eth-go-binary/bls"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/common"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// bls12SecretKey used in the BLS signature scheme.
|
||||
type bls12SecretKey struct {
|
||||
p *bls12.SecretKey
|
||||
}
|
||||
|
||||
// RandKey creates a new private key using a random method provided as an io.Reader.
|
||||
func RandKey() (common.SecretKey, error) {
|
||||
secKey := &bls12.SecretKey{}
|
||||
secKey.SetByCSPRNG()
|
||||
if secKey.IsZero() {
|
||||
return nil, errors.New("generated a zero secret key")
|
||||
}
|
||||
return &bls12SecretKey{secKey}, nil
|
||||
}
|
||||
|
||||
// SecretKeyFromBytes creates a BLS private key from a BigEndian byte slice.
|
||||
func SecretKeyFromBytes(privKey []byte) (common.SecretKey, error) {
|
||||
if len(privKey) != params.BeaconConfig().BLSSecretKeyLength {
|
||||
return nil, fmt.Errorf("secret key must be %d bytes", params.BeaconConfig().BLSSecretKeyLength)
|
||||
}
|
||||
secKey := &bls12.SecretKey{}
|
||||
err := secKey.Deserialize(privKey)
|
||||
if err != nil {
|
||||
return nil, common.ErrSecretUnmarshal
|
||||
}
|
||||
wrappedKey := &bls12SecretKey{p: secKey}
|
||||
if wrappedKey.IsZero() {
|
||||
return nil, common.ErrZeroKey
|
||||
}
|
||||
return wrappedKey, err
|
||||
}
|
||||
|
||||
// PublicKey obtains the public key corresponding to the BLS secret key.
|
||||
func (s *bls12SecretKey) PublicKey() common.PublicKey {
|
||||
return &PublicKey{p: s.p.GetPublicKey()}
|
||||
}
|
||||
|
||||
// Sign a message using a secret key - in a beacon/validator client.
|
||||
//
|
||||
// In IETF draft BLS specification:
|
||||
// Sign(SK, message) -> signature: a signing algorithm that generates
|
||||
// a deterministic signature given a secret key SK and a message.
|
||||
//
|
||||
// In ETH2.0 specification:
|
||||
// def Sign(SK: int, message: Bytes) -> BLSSignature
|
||||
func (s *bls12SecretKey) Sign(msg []byte) common.Signature {
|
||||
if featureconfig.Get().SkipBLSVerify {
|
||||
return &Signature{}
|
||||
}
|
||||
signature := s.p.SignByte(msg)
|
||||
return &Signature{s: signature}
|
||||
}
|
||||
|
||||
// Marshal a secret key into a LittleEndian byte slice.
|
||||
func (s *bls12SecretKey) Marshal() []byte {
|
||||
keyBytes := s.p.Serialize()
|
||||
if len(keyBytes) < params.BeaconConfig().BLSSecretKeyLength {
|
||||
emptyBytes := make([]byte, params.BeaconConfig().BLSSecretKeyLength-len(keyBytes))
|
||||
keyBytes = append(emptyBytes, keyBytes...)
|
||||
}
|
||||
return keyBytes
|
||||
}
|
||||
|
||||
// IsZero checks if the secret key is a zero key.
|
||||
func (s *bls12SecretKey) IsZero() bool {
|
||||
return s.p.IsZero()
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
package herumi_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/common"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/herumi"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestMarshalUnmarshal(t *testing.T) {
|
||||
priv, err := herumi.RandKey()
|
||||
require.NoError(t, err)
|
||||
b := priv.Marshal()
|
||||
b32 := bytesutil.ToBytes32(b)
|
||||
pk, err := herumi.SecretKeyFromBytes(b32[:])
|
||||
require.NoError(t, err)
|
||||
pk2, err := herumi.SecretKeyFromBytes(b32[:])
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, pk.Marshal(), pk2.Marshal())
|
||||
}
|
||||
|
||||
func TestSecretKeyFromBytes(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []byte
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "Nil",
|
||||
err: errors.New("secret key must be 32 bytes"),
|
||||
},
|
||||
{
|
||||
name: "Empty",
|
||||
input: []byte{},
|
||||
err: errors.New("secret key must be 32 bytes"),
|
||||
},
|
||||
{
|
||||
name: "Short",
|
||||
input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
err: errors.New("secret key must be 32 bytes"),
|
||||
},
|
||||
{
|
||||
name: "Long",
|
||||
input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
err: errors.New("secret key must be 32 bytes"),
|
||||
},
|
||||
{
|
||||
name: "Bad",
|
||||
input: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
err: common.ErrSecretUnmarshal,
|
||||
},
|
||||
{
|
||||
name: "Good",
|
||||
input: []byte{0x25, 0x29, 0x5f, 0x0d, 0x1d, 0x59, 0x2a, 0x90, 0xb3, 0x33, 0xe2, 0x6e, 0x85, 0x14, 0x97, 0x08, 0x20, 0x8e, 0x9f, 0x8e, 0x8b, 0xc1, 0x8f, 0x6c, 0x77, 0xbd, 0x62, 0xf8, 0xad, 0x7a, 0x68, 0x66},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
res, err := herumi.SecretKeyFromBytes(test.input)
|
||||
if test.err != nil {
|
||||
assert.ErrorContains(t, test.err.Error(), err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.DeepEqual(t, test.input, res.Marshal())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSerialize(t *testing.T) {
|
||||
rk, err := herumi.RandKey()
|
||||
require.NoError(t, err)
|
||||
b := rk.Marshal()
|
||||
|
||||
_, err = herumi.SecretKeyFromBytes(b)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
package herumi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
bls12 "github.com/herumi/bls-eth-go-binary/bls"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/common"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/rand"
|
||||
)
|
||||
|
||||
// Signature used in the BLS signature scheme.
|
||||
type Signature struct {
|
||||
s *bls12.Sign
|
||||
}
|
||||
|
||||
// SignatureFromBytes creates a BLS signature from a LittleEndian byte slice.
|
||||
func SignatureFromBytes(sig []byte) (common.Signature, error) {
|
||||
if featureconfig.Get().SkipBLSVerify {
|
||||
return &Signature{}, nil
|
||||
}
|
||||
if len(sig) != params.BeaconConfig().BLSSignatureLength {
|
||||
return nil, fmt.Errorf("signature must be %d bytes", params.BeaconConfig().BLSSignatureLength)
|
||||
}
|
||||
signature := &bls12.Sign{}
|
||||
err := signature.Deserialize(sig)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not unmarshal bytes into signature")
|
||||
}
|
||||
return &Signature{s: signature}, nil
|
||||
}
|
||||
|
||||
// Verify a bls signature given a public key, a message.
|
||||
//
|
||||
// In IETF draft BLS specification:
|
||||
// Verify(PK, message, signature) -> VALID or INVALID: a verification
|
||||
// algorithm that outputs VALID if signature is a valid signature of
|
||||
// message under public key PK, and INVALID otherwise.
|
||||
//
|
||||
// In ETH2.0 specification:
|
||||
// def Verify(PK: BLSPubkey, message: Bytes, signature: BLSSignature) -> bool
|
||||
func (s *Signature) Verify(pubKey common.PublicKey, msg []byte) bool {
|
||||
if featureconfig.Get().SkipBLSVerify {
|
||||
return true
|
||||
}
|
||||
// Reject infinite public keys.
|
||||
if pubKey.(*PublicKey).p.IsZero() {
|
||||
return false
|
||||
}
|
||||
return s.s.VerifyByte(pubKey.(*PublicKey).p, msg)
|
||||
}
|
||||
|
||||
// AggregateVerify verifies each public key against its respective message. This is vulnerable to
|
||||
// rogue public-key attack. Each user must provide a proof-of-knowledge of the public key.
|
||||
//
|
||||
// Note: The msgs must be distinct. For maximum performance, this method does not ensure distinct
|
||||
// messages.
|
||||
//
|
||||
// In IETF draft BLS specification:
|
||||
// AggregateVerify((PK_1, message_1), ..., (PK_n, message_n),
|
||||
// signature) -> VALID or INVALID: an aggregate verification
|
||||
// algorithm that outputs VALID if signature is a valid aggregated
|
||||
// signature for a collection of public keys and messages, and
|
||||
// outputs INVALID otherwise.
|
||||
//
|
||||
// In ETH2.0 specification:
|
||||
// def AggregateVerify(pairs: Sequence[PK: BLSPubkey, message: Bytes], signature: BLSSignature) -> bool
|
||||
// Deprecated: Use FastAggregateVerify or use this method in spectests only.
|
||||
func (s *Signature) AggregateVerify(pubKeys []common.PublicKey, msgs [][32]byte) bool {
|
||||
if featureconfig.Get().SkipBLSVerify {
|
||||
return true
|
||||
}
|
||||
size := len(pubKeys)
|
||||
if size == 0 {
|
||||
return false
|
||||
}
|
||||
if size != len(msgs) {
|
||||
return false
|
||||
}
|
||||
msgSlices := make([]byte, 0, 32*len(msgs))
|
||||
rawKeys := make([]bls12.PublicKey, 0, len(pubKeys))
|
||||
for i := 0; i < size; i++ {
|
||||
msgSlices = append(msgSlices, msgs[i][:]...)
|
||||
rawKeys = append(rawKeys, *(pubKeys[i].(*PublicKey).p))
|
||||
}
|
||||
// Use "NoCheck" because we do not care if the messages are unique or not.
|
||||
return s.s.AggregateVerifyNoCheck(rawKeys, msgSlices)
|
||||
}
|
||||
|
||||
// FastAggregateVerify verifies all the provided public keys with their aggregated signature.
|
||||
//
|
||||
// In IETF draft BLS specification:
|
||||
// FastAggregateVerify(PK_1, ..., PK_n, message, signature) -> VALID
|
||||
// or INVALID: a verification algorithm for the aggregate of multiple
|
||||
// signatures on the same message. This function is faster than
|
||||
// AggregateVerify.
|
||||
//
|
||||
// In ETH2.0 specification:
|
||||
// def FastAggregateVerify(PKs: Sequence[BLSPubkey], message: Bytes, signature: BLSSignature) -> bool
|
||||
func (s *Signature) FastAggregateVerify(pubKeys []common.PublicKey, msg [32]byte) bool {
|
||||
if featureconfig.Get().SkipBLSVerify {
|
||||
return true
|
||||
}
|
||||
if len(pubKeys) == 0 {
|
||||
return false
|
||||
}
|
||||
rawKeys := make([]bls12.PublicKey, len(pubKeys))
|
||||
for i := 0; i < len(pubKeys); i++ {
|
||||
rawKeys[i] = *(pubKeys[i].(*PublicKey).p)
|
||||
}
|
||||
|
||||
return s.s.FastAggregateVerify(rawKeys, msg[:])
|
||||
}
|
||||
|
||||
// NewAggregateSignature creates a blank aggregate signature.
|
||||
func NewAggregateSignature() common.Signature {
|
||||
return &Signature{s: bls12.HashAndMapToSignature([]byte{'m', 'o', 'c', 'k'})}
|
||||
}
|
||||
|
||||
// AggregateSignatures converts a list of signatures into a single, aggregated sig.
|
||||
func AggregateSignatures(sigs []common.Signature) common.Signature {
|
||||
if len(sigs) == 0 {
|
||||
return nil
|
||||
}
|
||||
if featureconfig.Get().SkipBLSVerify {
|
||||
return sigs[0]
|
||||
}
|
||||
|
||||
signature := *sigs[0].Copy().(*Signature).s
|
||||
for i := 1; i < len(sigs); i++ {
|
||||
signature.Add(sigs[i].(*Signature).s)
|
||||
}
|
||||
return &Signature{s: &signature}
|
||||
}
|
||||
|
||||
// Aggregate is an alias for AggregateSignatures, defined to conform to BLS specification.
|
||||
//
|
||||
// In IETF draft BLS specification:
|
||||
// Aggregate(signature_1, ..., signature_n) -> signature: an
|
||||
// aggregation algorithm that compresses a collection of signatures
|
||||
// into a single signature.
|
||||
//
|
||||
// In ETH2.0 specification:
|
||||
// def Aggregate(signatures: Sequence[BLSSignature]) -> BLSSignature
|
||||
//
|
||||
// Deprecated: Use AggregateSignatures.
|
||||
func Aggregate(sigs []common.Signature) common.Signature {
|
||||
return AggregateSignatures(sigs)
|
||||
}
|
||||
|
||||
// VerifyMultipleSignatures verifies a non-singular set of signatures and its respective pubkeys and messages.
|
||||
// This method provides a safe way to verify multiple signatures at once. We pick a number randomly from 1 to max
|
||||
// uint64 and then multiply the signature by it. We continue doing this for all signatures and its respective pubkeys.
|
||||
// S* = S_1 * r_1 + S_2 * r_2 + ... + S_n * r_n
|
||||
// P'_{i,j} = P_{i,j} * r_i
|
||||
// e(S*, G) = \prod_{i=1}^n \prod_{j=1}^{m_i} e(P'_{i,j}, M_{i,j})
|
||||
// Using this we can verify multiple signatures safely.
|
||||
func VerifyMultipleSignatures(sigs []common.Signature, msgs [][32]byte, pubKeys []common.PublicKey) (bool, error) {
|
||||
if featureconfig.Get().SkipBLSVerify {
|
||||
return true, nil
|
||||
}
|
||||
if len(sigs) == 0 || len(pubKeys) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
length := len(sigs)
|
||||
if length != len(pubKeys) || length != len(msgs) {
|
||||
return false, errors.Errorf("provided signatures, pubkeys and messages have differing lengths. S: %d, P: %d,M %d",
|
||||
length, len(pubKeys), len(msgs))
|
||||
}
|
||||
// Use a secure source of RNG.
|
||||
newGen := rand.NewGenerator()
|
||||
randNums := make([]bls12.Fr, length)
|
||||
signatures := make([]bls12.G2, length)
|
||||
msgSlices := make([]byte, 0, 32*len(msgs))
|
||||
for i := 0; i < len(sigs); i++ {
|
||||
rNum := newGen.Uint64()
|
||||
if err := randNums[i].SetLittleEndian(bytesutil.Bytes8(rNum)); err != nil {
|
||||
return false, err
|
||||
}
|
||||
// Cast signature to a G2 value
|
||||
signatures[i] = *bls12.CastFromSign(sigs[i].(*Signature).s)
|
||||
|
||||
// Flatten message to single byte slice to make it compatible with herumi.
|
||||
msgSlices = append(msgSlices, msgs[i][:]...)
|
||||
}
|
||||
// Perform multi scalar multiplication on all the relevant G2 points
|
||||
// with our generated random numbers.
|
||||
finalSig := new(bls12.G2)
|
||||
bls12.G2MulVec(finalSig, signatures, randNums)
|
||||
|
||||
multiKeys := make([]bls12.PublicKey, length)
|
||||
for i := 0; i < len(pubKeys); i++ {
|
||||
if pubKeys[i] == nil {
|
||||
return false, errors.New("nil public key")
|
||||
}
|
||||
// Perform scalar multiplication for the corresponding g1 points.
|
||||
g1 := new(bls12.G1)
|
||||
bls12.G1Mul(g1, bls12.CastFromPublicKey(pubKeys[i].(*PublicKey).p), &randNums[i])
|
||||
multiKeys[i] = *bls12.CastToPublicKey(g1)
|
||||
}
|
||||
aggSig := bls12.CastToSign(finalSig)
|
||||
|
||||
return aggSig.AggregateVerifyNoCheck(multiKeys, msgSlices), nil
|
||||
}
|
||||
|
||||
// Marshal a signature into a LittleEndian byte slice.
|
||||
func (s *Signature) Marshal() []byte {
|
||||
if featureconfig.Get().SkipBLSVerify {
|
||||
return make([]byte, params.BeaconConfig().BLSSignatureLength)
|
||||
}
|
||||
|
||||
return s.s.Serialize()
|
||||
}
|
||||
|
||||
// Copy returns a full deep copy of a signature.
|
||||
func (s *Signature) Copy() common.Signature {
|
||||
sign := *s.s
|
||||
return &Signature{s: &sign}
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
package herumi
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
bls12 "github.com/herumi/bls-eth-go-binary/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/common"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestSignVerify(t *testing.T) {
|
||||
priv, err := RandKey()
|
||||
require.NoError(t, err)
|
||||
pub := priv.PublicKey()
|
||||
msg := []byte("hello")
|
||||
sig := priv.Sign(msg)
|
||||
assert.DeepEqual(t, true, sig.Verify(pub, msg))
|
||||
}
|
||||
|
||||
func TestAggregateVerify(t *testing.T) {
|
||||
pubkeys := make([]common.PublicKey, 0, 100)
|
||||
sigs := make([]common.Signature, 0, 100)
|
||||
var msgs [][32]byte
|
||||
for i := 0; i < 100; i++ {
|
||||
msg := [32]byte{'h', 'e', 'l', 'l', 'o', byte(i)}
|
||||
priv, err := RandKey()
|
||||
require.NoError(t, err)
|
||||
pub := priv.PublicKey()
|
||||
sig := priv.Sign(msg[:])
|
||||
pubkeys = append(pubkeys, pub)
|
||||
sigs = append(sigs, sig)
|
||||
msgs = append(msgs, msg)
|
||||
}
|
||||
aggSig := Aggregate(sigs)
|
||||
assert.DeepEqual(t, true, aggSig.AggregateVerify(pubkeys, msgs))
|
||||
}
|
||||
|
||||
func TestFastAggregateVerify(t *testing.T) {
|
||||
pubkeys := make([]common.PublicKey, 0, 100)
|
||||
sigs := make([]common.Signature, 0, 100)
|
||||
msg := [32]byte{'h', 'e', 'l', 'l', 'o'}
|
||||
for i := 0; i < 100; i++ {
|
||||
priv, err := RandKey()
|
||||
require.NoError(t, err)
|
||||
pub := priv.PublicKey()
|
||||
sig := priv.Sign(msg[:])
|
||||
pubkeys = append(pubkeys, pub)
|
||||
sigs = append(sigs, sig)
|
||||
}
|
||||
aggSig := AggregateSignatures(sigs)
|
||||
assert.DeepEqual(t, true, aggSig.FastAggregateVerify(pubkeys, msg))
|
||||
}
|
||||
|
||||
func TestMultipleSignatureVerification(t *testing.T) {
|
||||
pubkeys := make([]common.PublicKey, 0, 100)
|
||||
sigs := make([]common.Signature, 0, 100)
|
||||
var msgs [][32]byte
|
||||
for i := 0; i < 100; i++ {
|
||||
msg := [32]byte{'h', 'e', 'l', 'l', 'o', byte(i)}
|
||||
priv, err := RandKey()
|
||||
require.NoError(t, err)
|
||||
pub := priv.PublicKey()
|
||||
sig := priv.Sign(msg[:])
|
||||
pubkeys = append(pubkeys, pub)
|
||||
sigs = append(sigs, sig)
|
||||
msgs = append(msgs, msg)
|
||||
}
|
||||
verify, err := VerifyMultipleSignatures(sigs, msgs, pubkeys)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, verify, "Signature did not verify")
|
||||
}
|
||||
|
||||
func TestMultipleSignatureVerification_FailsCorrectly(t *testing.T) {
|
||||
pubkeys := make([]common.PublicKey, 0, 100)
|
||||
sigs := make([]common.Signature, 0, 100)
|
||||
var msgs [][32]byte
|
||||
for i := 0; i < 100; i++ {
|
||||
msg := [32]byte{'h', 'e', 'l', 'l', 'o', byte(i)}
|
||||
priv, err := RandKey()
|
||||
require.NoError(t, err)
|
||||
pub := priv.PublicKey()
|
||||
sig := priv.Sign(msg[:])
|
||||
pubkeys = append(pubkeys, pub)
|
||||
sigs = append(sigs, sig)
|
||||
msgs = append(msgs, msg)
|
||||
}
|
||||
// We mess with the last 2 signatures, where we modify their values
|
||||
// such that they wqould not fail in aggregate signature verification.
|
||||
lastSig := sigs[len(sigs)-1]
|
||||
secondLastSig := sigs[len(sigs)-2]
|
||||
// Convert to bls object
|
||||
rawSig := new(bls12.Sign)
|
||||
require.NoError(t, rawSig.Deserialize(secondLastSig.Marshal()))
|
||||
rawSig2 := new(bls12.Sign)
|
||||
require.NoError(t, rawSig2.Deserialize(lastSig.Marshal()))
|
||||
// set random field prime value
|
||||
fprime := new(bls12.Fp)
|
||||
fprime.SetInt64(100)
|
||||
|
||||
// set random field prime value.
|
||||
fprime2 := new(bls12.Fp)
|
||||
fprime2.SetInt64(50)
|
||||
|
||||
// make a combined fp2 object.
|
||||
fp2 := new(bls12.Fp2)
|
||||
fp2.D = [2]bls12.Fp{*fprime, *fprime2}
|
||||
|
||||
g2Point := new(bls12.G2)
|
||||
require.NoError(t, bls12.MapToG2(g2Point, fp2))
|
||||
// We now add/subtract the respective g2 points by a fixed
|
||||
// value. This would cause singluar verification to fail but
|
||||
// not aggregate verification.
|
||||
firstG2 := bls12.CastFromSign(rawSig)
|
||||
secondG2 := bls12.CastFromSign(rawSig2)
|
||||
bls12.G2Add(firstG2, firstG2, g2Point)
|
||||
bls12.G2Sub(secondG2, secondG2, g2Point)
|
||||
|
||||
lastSig, err := SignatureFromBytes(rawSig.Serialize())
|
||||
require.NoError(t, err)
|
||||
secondLastSig, err = SignatureFromBytes(rawSig2.Serialize())
|
||||
require.NoError(t, err)
|
||||
sigs[len(sigs)-1] = lastSig
|
||||
sigs[len(sigs)-2] = secondLastSig
|
||||
|
||||
// This method is expected to pass, as it would not
|
||||
// be able to detect bad signatures
|
||||
aggSig := AggregateSignatures(sigs)
|
||||
if !aggSig.AggregateVerify(pubkeys, msgs) {
|
||||
t.Error("Signature did not verify")
|
||||
}
|
||||
// This method would be expected to fail.
|
||||
verify, err := VerifyMultipleSignatures(sigs, msgs, pubkeys)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, verify, "Signature verified when it was not supposed to")
|
||||
}
|
||||
|
||||
func TestFastAggregateVerify_ReturnsFalseOnEmptyPubKeyList(t *testing.T) {
|
||||
var pubkeys []common.PublicKey
|
||||
msg := [32]byte{'h', 'e', 'l', 'l', 'o'}
|
||||
|
||||
aggSig := NewAggregateSignature()
|
||||
if aggSig.FastAggregateVerify(pubkeys, msg) != false {
|
||||
t.Error("Expected FastAggregateVerify to return false with empty input " +
|
||||
"of public keys.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignatureFromBytes(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []byte
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "Nil",
|
||||
err: errors.New("signature must be 96 bytes"),
|
||||
},
|
||||
{
|
||||
name: "Empty",
|
||||
input: []byte{},
|
||||
err: errors.New("signature must be 96 bytes"),
|
||||
},
|
||||
{
|
||||
name: "Short",
|
||||
input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
err: errors.New("signature must be 96 bytes"),
|
||||
},
|
||||
{
|
||||
name: "Long",
|
||||
input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
err: errors.New("signature must be 96 bytes"),
|
||||
},
|
||||
{
|
||||
name: "Bad",
|
||||
input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
err: errors.New("could not unmarshal bytes into signature: err blsSignatureDeserialize 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
|
||||
},
|
||||
{
|
||||
name: "Good",
|
||||
input: []byte{0xab, 0xb0, 0x12, 0x4c, 0x75, 0x74, 0xf2, 0x81, 0xa2, 0x93, 0xf4, 0x18, 0x5c, 0xad, 0x3c, 0xb2, 0x26, 0x81, 0xd5, 0x20, 0x91, 0x7c, 0xe4, 0x66, 0x65, 0x24, 0x3e, 0xac, 0xb0, 0x51, 0x00, 0x0d, 0x8b, 0xac, 0xf7, 0x5e, 0x14, 0x51, 0x87, 0x0c, 0xa6, 0xb3, 0xb9, 0xe6, 0xc9, 0xd4, 0x1a, 0x7b, 0x02, 0xea, 0xd2, 0x68, 0x5a, 0x84, 0x18, 0x8a, 0x4f, 0xaf, 0xd3, 0x82, 0x5d, 0xaf, 0x6a, 0x98, 0x96, 0x25, 0xd7, 0x19, 0xcc, 0xd2, 0xd8, 0x3a, 0x40, 0x10, 0x1f, 0x4a, 0x45, 0x3f, 0xca, 0x62, 0x87, 0x8c, 0x89, 0x0e, 0xca, 0x62, 0x23, 0x63, 0xf9, 0xdd, 0xb8, 0xf3, 0x67, 0xa9, 0x1e, 0x84},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
res, err := SignatureFromBytes(test.input)
|
||||
if test.err != nil {
|
||||
assert.ErrorContains(t, test.err.Error(), err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.DeepEqual(t, test.input, res.Marshal())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopy(t *testing.T) {
|
||||
signatureA := &Signature{s: bls12.HashAndMapToSignature([]byte("foo"))}
|
||||
signatureB, ok := signatureA.Copy().(*Signature)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
assert.NotEqual(t, signatureA, signatureB)
|
||||
assert.NotEqual(t, signatureA.s, signatureB.s)
|
||||
assert.DeepEqual(t, signatureA, signatureB)
|
||||
|
||||
signatureA.s.Add(bls12.HashAndMapToSignature([]byte("bar")))
|
||||
assert.DeepNotEqual(t, signatureA, signatureB)
|
||||
}
|
||||
@@ -34,7 +34,6 @@ go_test(
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bls/common:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
"@com_github_ghodss_yaml//:go_default_library",
|
||||
|
||||
@@ -9,21 +9,12 @@ import (
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/common"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestAggregateYaml(t *testing.T) {
|
||||
flags := &featureconfig.Flags{}
|
||||
reset := featureconfig.InitWithReset(flags)
|
||||
t.Run("herumi", testAggregateYaml)
|
||||
reset()
|
||||
|
||||
flags.EnableBlst = true
|
||||
reset = featureconfig.InitWithReset(flags)
|
||||
t.Run("blst", testAggregateYaml)
|
||||
reset()
|
||||
}
|
||||
|
||||
func testAggregateYaml(t *testing.T) {
|
||||
|
||||
@@ -10,21 +10,12 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/common"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestAggregateVerifyYaml(t *testing.T) {
|
||||
flags := &featureconfig.Flags{}
|
||||
reset := featureconfig.InitWithReset(flags)
|
||||
t.Run("herumi", testAggregateVerifyYaml)
|
||||
reset()
|
||||
|
||||
flags.EnableBlst = true
|
||||
reset = featureconfig.InitWithReset(flags)
|
||||
t.Run("blst", testAggregateVerifyYaml)
|
||||
reset()
|
||||
}
|
||||
|
||||
func testAggregateVerifyYaml(t *testing.T) {
|
||||
|
||||
@@ -10,21 +10,12 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/common"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestFastAggregateVerifyYaml(t *testing.T) {
|
||||
flags := &featureconfig.Flags{}
|
||||
reset := featureconfig.InitWithReset(flags)
|
||||
t.Run("herumi", testFastAggregateVerifyYaml)
|
||||
reset()
|
||||
|
||||
flags.EnableBlst = true
|
||||
reset = featureconfig.InitWithReset(flags)
|
||||
t.Run("blst", testFastAggregateVerifyYaml)
|
||||
reset()
|
||||
}
|
||||
|
||||
func testFastAggregateVerifyYaml(t *testing.T) {
|
||||
|
||||
@@ -12,21 +12,12 @@ import (
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/common"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestSignMessageYaml(t *testing.T) {
|
||||
flags := &featureconfig.Flags{}
|
||||
reset := featureconfig.InitWithReset(flags)
|
||||
t.Run("herumi", testSignMessageYaml)
|
||||
reset()
|
||||
|
||||
flags.EnableBlst = true
|
||||
reset = featureconfig.InitWithReset(flags)
|
||||
t.Run("blst", testSignMessageYaml)
|
||||
reset()
|
||||
}
|
||||
|
||||
func testSignMessageYaml(t *testing.T) {
|
||||
|
||||
@@ -9,21 +9,12 @@ import (
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/common"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestVerifyMessageYaml(t *testing.T) {
|
||||
flags := &featureconfig.Flags{}
|
||||
reset := featureconfig.InitWithReset(flags)
|
||||
t.Run("herumi", testVerifyMessageYaml)
|
||||
reset()
|
||||
|
||||
flags.EnableBlst = true
|
||||
reset = featureconfig.InitWithReset(flags)
|
||||
t.Run("blst", testVerifyMessageYaml)
|
||||
reset()
|
||||
}
|
||||
|
||||
func testVerifyMessageYaml(t *testing.T) {
|
||||
|
||||
@@ -41,7 +41,6 @@ type Flags struct {
|
||||
// Feature related flags.
|
||||
WriteSSZStateTransitions bool // WriteSSZStateTransitions to tmp directory.
|
||||
SkipBLSVerify bool // Skips BLS verification across the runtime.
|
||||
EnableBlst bool // Enables new BLS library from supranational.
|
||||
SlasherProtection bool // SlasherProtection protects validator fron sending over a slashable offense over the network using external slasher.
|
||||
EnablePeerScorer bool // EnablePeerScorer enables experimental peer scoring in p2p.
|
||||
EnableLargerGossipHistory bool // EnableLargerGossipHistory increases the gossip history we store in our caches.
|
||||
@@ -171,11 +170,6 @@ func ConfigureBeaconChain(ctx *cli.Context) {
|
||||
if ctx.Bool(checkPtInfoCache.Name) {
|
||||
log.Warn("Advance check point info cache is no longer supported and will soon be deleted")
|
||||
}
|
||||
cfg.EnableBlst = true
|
||||
if ctx.Bool(disableBlst.Name) {
|
||||
log.WithField(disableBlst.Name, disableBlst.Usage).Warn(enabledFeatureFlag)
|
||||
cfg.EnableBlst = false
|
||||
}
|
||||
if ctx.Bool(enableLargerGossipHistory.Name) {
|
||||
log.WithField(enableLargerGossipHistory.Name, enableLargerGossipHistory.Usage).Warn(enabledFeatureFlag)
|
||||
cfg.EnableLargerGossipHistory = true
|
||||
@@ -231,11 +225,6 @@ func ConfigureValidator(ctx *cli.Context) {
|
||||
log.WithField(disableAttestingHistoryDBCache.Name, disableAttestingHistoryDBCache.Usage).Warn(enabledFeatureFlag)
|
||||
cfg.DisableAttestingHistoryDBCache = true
|
||||
}
|
||||
cfg.EnableBlst = true
|
||||
if ctx.Bool(disableBlst.Name) {
|
||||
log.WithField(disableBlst.Name, disableBlst.Usage).Warn(enabledFeatureFlag)
|
||||
cfg.EnableBlst = false
|
||||
}
|
||||
if ctx.Bool(attestTimely.Name) {
|
||||
log.WithField(attestTimely.Name, attestTimely.Usage).Warn(enabledFeatureFlag)
|
||||
cfg.AttestTimely = true
|
||||
|
||||
@@ -32,6 +32,11 @@ var (
|
||||
Usage: deprecatedUsage,
|
||||
Hidden: true,
|
||||
}
|
||||
deprecatedDisableBlst = &cli.BoolFlag{
|
||||
Name: "disable-blst",
|
||||
Usage: deprecatedUsage,
|
||||
Hidden: true,
|
||||
}
|
||||
)
|
||||
|
||||
var deprecatedFlags = []cli.Flag{
|
||||
@@ -40,4 +45,5 @@ var deprecatedFlags = []cli.Flag{
|
||||
deprecatedDisableSyncBacktracking,
|
||||
deprecatedDisablePruningDepositProofs,
|
||||
deprecatedDisableEth1DataMajorityVote,
|
||||
deprecatedDisableBlst,
|
||||
}
|
||||
|
||||
@@ -62,10 +62,6 @@ var (
|
||||
Name: "attestation-aggregation-force-opt-maxcover",
|
||||
Usage: "When enabled, forces --attestation-aggregation-strategy=opt_max_cover setting.",
|
||||
}
|
||||
disableBlst = &cli.BoolFlag{
|
||||
Name: "disable-blst",
|
||||
Usage: "Disables the new BLS library, blst, from Supranational",
|
||||
}
|
||||
disableAccountsV2 = &cli.BoolFlag{
|
||||
Name: "disable-accounts-v2",
|
||||
Usage: "Disables usage of v2 for Prysm validator accounts",
|
||||
@@ -143,7 +139,6 @@ var ValidatorFlags = append(deprecatedFlags, []cli.Flag{
|
||||
PraterTestnet,
|
||||
Mainnet,
|
||||
disableAccountsV2,
|
||||
disableBlst,
|
||||
dynamicKeyReloadDebounceInterval,
|
||||
attestTimely,
|
||||
enableSlashingProtectionPruning,
|
||||
@@ -172,7 +167,6 @@ var BeaconChainFlags = append(deprecatedFlags, []cli.Flag{
|
||||
PyrmontTestnet,
|
||||
PraterTestnet,
|
||||
Mainnet,
|
||||
disableBlst,
|
||||
enablePeerScorer,
|
||||
enableLargerGossipHistory,
|
||||
checkPtInfoCache,
|
||||
|
||||
Reference in New Issue
Block a user