Refactor BLS (#6395)

* refactor BLS to expose an interface rather than a single implementation
* Split up tests, gofmt, goimports, docs
* godoc for signature.Copy()
* more godocs
* revert gomod / deps changes
* rm newline
* revert proto changes
* rename bls12 to herumi for clarity
This commit is contained in:
Preston Van Loon
2020-06-24 17:47:51 -07:00
committed by GitHub
parent d0e2e0e979
commit fb8be4d555
65 changed files with 901 additions and 728 deletions

View File

@@ -758,7 +758,7 @@ func VerifyIndexedAttestation(ctx context.Context, beaconState *stateTrie.Beacon
return err
}
indices := indexedAtt.AttestingIndices
pubkeys := []*bls.PublicKey{}
pubkeys := []bls.PublicKey{}
if len(indices) > 0 {
for i := 0; i < len(indices); i++ {
pubkeyAtIdx := beaconState.PubkeyAtIndex(indices[i])
@@ -847,8 +847,8 @@ func verifyAttestationsWithDomain(ctx context.Context, beaconState *stateTrie.Be
return nil
}
sigs := make([]*bls.Signature, len(atts))
pks := make([]*bls.PublicKey, len(atts))
sigs := make([]bls.Signature, len(atts))
pks := make([]bls.PublicKey, len(atts))
msgs := make([][32]byte, len(atts))
for i, a := range atts {
sig, err := bls.SignatureFromBytes(a.Signature)
@@ -862,7 +862,7 @@ func verifyAttestationsWithDomain(ctx context.Context, beaconState *stateTrie.Be
}
ia := attestationutil.ConvertToIndexed(ctx, a, c)
indices := ia.AttestingIndices
var pk *bls.PublicKey
var pk bls.PublicKey
for i := 0; i < len(indices); i++ {
pubkeyAtIdx := beaconState.PubkeyAtIndex(indices[i])
p, err := bls.PublicKeyFromBytes(pubkeyAtIdx[:])

View File

@@ -836,7 +836,7 @@ func TestProcessAttesterSlashings_AppliesCorrectStatus(t *testing.T) {
}
sig0 := privKeys[0].Sign(signingRoot[:])
sig1 := privKeys[1].Sign(signingRoot[:])
aggregateSig := bls.AggregateSignatures([]*bls.Signature{sig0, sig1})
aggregateSig := bls.AggregateSignatures([]bls.Signature{sig0, sig1})
att1.Signature = aggregateSig.Marshal()[:]
att2 := &ethpb.IndexedAttestation{
@@ -852,7 +852,7 @@ func TestProcessAttesterSlashings_AppliesCorrectStatus(t *testing.T) {
}
sig0 = privKeys[0].Sign(signingRoot[:])
sig1 = privKeys[1].Sign(signingRoot[:])
aggregateSig = bls.AggregateSignatures([]*bls.Signature{sig0, sig1})
aggregateSig = bls.AggregateSignatures([]bls.Signature{sig0, sig1})
att2.Signature = aggregateSig.Marshal()[:]
slashings := []*ethpb.AttesterSlashing{
@@ -1148,7 +1148,7 @@ func TestProcessAttestations_OK(t *testing.T) {
if err != nil {
t.Error(err)
}
sigs := make([]*bls.Signature, len(attestingIndices))
sigs := make([]bls.Signature, len(attestingIndices))
for i, indice := range attestingIndices {
sig := privKeys[indice].Sign(hashTreeRoot[:])
sigs[i] = sig
@@ -1212,7 +1212,7 @@ func TestProcessAggregatedAttestation_OverlappingBits(t *testing.T) {
if err != nil {
t.Error(err)
}
sigs := make([]*bls.Signature, len(attestingIndices1))
sigs := make([]bls.Signature, len(attestingIndices1))
for i, indice := range attestingIndices1 {
sig := privKeys[indice].Sign(hashTreeRoot[:])
sigs[i] = sig
@@ -1240,7 +1240,7 @@ func TestProcessAggregatedAttestation_OverlappingBits(t *testing.T) {
if err != nil {
t.Error(err)
}
sigs = make([]*bls.Signature, len(attestingIndices2))
sigs = make([]bls.Signature, len(attestingIndices2))
for i, indice := range attestingIndices2 {
sig := privKeys[indice].Sign(hashTreeRoot[:])
sigs[i] = sig
@@ -1294,7 +1294,7 @@ func TestProcessAggregatedAttestation_NoOverlappingBits(t *testing.T) {
if err != nil {
t.Error(err)
}
sigs := make([]*bls.Signature, len(attestingIndices1))
sigs := make([]bls.Signature, len(attestingIndices1))
for i, indice := range attestingIndices1 {
sig := privKeys[indice].Sign(hashTreeRoot[:])
sigs[i] = sig
@@ -1321,7 +1321,7 @@ func TestProcessAggregatedAttestation_NoOverlappingBits(t *testing.T) {
if err != nil {
t.Error(err)
}
sigs = make([]*bls.Signature, len(attestingIndices2))
sigs = make([]bls.Signature, len(attestingIndices2))
for i, indice := range attestingIndices2 {
sig := privKeys[indice].Sign(hashTreeRoot[:])
sigs[i] = sig
@@ -1540,7 +1540,7 @@ func TestVerifyIndexedAttestation_OK(t *testing.T) {
if err != nil {
t.Error(err)
}
var sig []*bls.Signature
var sig []bls.Signature
for _, idx := range tt.attestation.AttestingIndices {
validatorSig := keys[idx].Sign(root[:])
sig = append(sig, validatorSig)
@@ -2107,7 +2107,7 @@ func TestVerifyAttestations_VerifiesMultipleAttestations(t *testing.T) {
if err != nil {
t.Fatal(err)
}
var sigs []*bls.Signature
var sigs []bls.Signature
for i, u := range comm1 {
att1.AggregationBits.SetBitAt(uint64(i), true)
sigs = append(sigs, keys[u].Sign(root[:]))
@@ -2189,7 +2189,7 @@ func TestVerifyAttestations_HandlesPlannedFork(t *testing.T) {
if err != nil {
t.Fatal(err)
}
var sigs []*bls.Signature
var sigs []bls.Signature
for i, u := range comm1 {
att1.AggregationBits.SetBitAt(uint64(i), true)
sigs = append(sigs, keys[u].Sign(root[:]))

View File

@@ -50,7 +50,7 @@ func TestProcessAttesterSlashings_RegressionSlashableIndices(t *testing.T) {
if err != nil {
t.Errorf("Could not get signing root of beacon block header: %v", err)
}
aggSigs := []*bls.Signature{}
aggSigs := []bls.Signature{}
for _, index := range setA {
sig := privKeys[index].Sign(signingRoot[:])
aggSigs = append(aggSigs, sig)
@@ -70,7 +70,7 @@ func TestProcessAttesterSlashings_RegressionSlashableIndices(t *testing.T) {
if err != nil {
t.Errorf("Could not get signing root of beacon block header: %v", err)
}
aggSigs = []*bls.Signature{}
aggSigs = []bls.Signature{}
for _, index := range setB {
sig := privKeys[index].Sign(signingRoot[:])
aggSigs = append(aggSigs, sig)

View File

@@ -17,7 +17,7 @@ import (
// domain = get_domain(state, DOMAIN_SELECTION_PROOF, compute_epoch_at_slot(slot))
// signing_root = compute_signing_root(slot, domain)
// return bls.Sign(privkey, signing_root)
func SlotSignature(state *stateTrie.BeaconState, slot uint64, privKey *bls.SecretKey) (*bls.Signature, error) {
func SlotSignature(state *stateTrie.BeaconState, slot uint64, privKey bls.SecretKey) (bls.Signature, error) {
d, err := Domain(state.Fork(), CurrentEpoch(state), params.BeaconConfig().DomainBeaconAttester, state.GenesisValidatorRoot())
if err != nil {
return nil, err
@@ -54,8 +54,8 @@ func IsAggregator(committeeCount uint64, slotSig []byte) (bool, error) {
// def get_aggregate_signature(attestations: Sequence[Attestation]) -> BLSSignature:
// signatures = [attestation.signature for attestation in attestations]
// return bls_aggregate_signatures(signatures)
func AggregateSignature(attestations []*ethpb.Attestation) (*bls.Signature, error) {
sigs := make([]*bls.Signature, len(attestations))
func AggregateSignature(attestations []*ethpb.Attestation) (bls.Signature, error) {
sigs := make([]bls.Signature, len(attestations))
var err error
for i := 0; i < len(sigs); i++ {
sigs[i], err = bls.SignatureFromBytes(attestations[i].Signature)

View File

@@ -88,7 +88,7 @@ func TestAttestation_IsAggregator(t *testing.T) {
func TestAttestation_AggregateSignature(t *testing.T) {
t.Run("verified", func(t *testing.T) {
pubkeys := make([]*bls.PublicKey, 0, 100)
pubkeys := make([]bls.PublicKey, 0, 100)
atts := make([]*ethpb.Attestation, 0, 100)
msg := bytesutil.ToBytes32([]byte("hello"))
for i := 0; i < 100; i++ {
@@ -109,7 +109,7 @@ func TestAttestation_AggregateSignature(t *testing.T) {
})
t.Run("not verified", func(t *testing.T) {
pubkeys := make([]*bls.PublicKey, 0, 100)
pubkeys := make([]bls.PublicKey, 0, 100)
atts := make([]*ethpb.Attestation, 0, 100)
msg := []byte("hello")
for i := 0; i < 100; i++ {

View File

@@ -451,7 +451,7 @@ func TestProcessBlock_PassesProcessingConditions(t *testing.T) {
}
sig0 := privKeys[0].Sign(hashTreeRoot[:])
sig1 := privKeys[1].Sign(hashTreeRoot[:])
aggregateSig := bls.AggregateSignatures([]*bls.Signature{sig0, sig1})
aggregateSig := bls.AggregateSignatures([]bls.Signature{sig0, sig1})
att1.Signature = aggregateSig.Marshal()[:]
mockRoot3 := [32]byte{'B'}
@@ -468,7 +468,7 @@ func TestProcessBlock_PassesProcessingConditions(t *testing.T) {
}
sig0 = privKeys[0].Sign(hashTreeRoot[:])
sig1 = privKeys[1].Sign(hashTreeRoot[:])
aggregateSig = bls.AggregateSignatures([]*bls.Signature{sig0, sig1})
aggregateSig = bls.AggregateSignatures([]bls.Signature{sig0, sig1})
att2.Signature = aggregateSig.Marshal()[:]
attesterSlashings := []*ethpb.AttesterSlashing{
@@ -511,7 +511,7 @@ func TestProcessBlock_PassesProcessingConditions(t *testing.T) {
if err != nil {
t.Error(err)
}
sigs := make([]*bls.Signature, len(attestingIndices))
sigs := make([]bls.Signature, len(attestingIndices))
for i, indice := range attestingIndices {
sig := privKeys[indice].Sign(hashTreeRoot[:])
sigs[i] = sig
@@ -875,7 +875,7 @@ func TestProcessBlk_AttsBasedOnValidatorCount(t *testing.T) {
if err != nil {
t.Fatal(err)
}
sigs := make([]*bls.Signature, len(attestingIndices))
sigs := make([]bls.Signature, len(attestingIndices))
for i, indice := range attestingIndices {
hashTreeRoot, err := helpers.ComputeSigningRoot(att.Data, domain)
if err != nil {

View File

@@ -15,7 +15,7 @@ import (
"github.com/prysmaticlabs/prysm/shared/testutil"
)
func validAttesterSlashingForValIdx(t *testing.T, beaconState *state.BeaconState, privs []*bls.SecretKey, valIdx ...uint64) *ethpb.AttesterSlashing {
func validAttesterSlashingForValIdx(t *testing.T, beaconState *state.BeaconState, privs []bls.SecretKey, valIdx ...uint64) *ethpb.AttesterSlashing {
slashings := []*ethpb.AttesterSlashing{}
for _, idx := range valIdx {
slashing, err := testutil.GenerateAttesterSlashingForValidator(beaconState, privs[idx], idx)
@@ -24,8 +24,8 @@ func validAttesterSlashingForValIdx(t *testing.T, beaconState *state.BeaconState
}
slashings = append(slashings, slashing)
}
allSig1 := []*bls.Signature{}
allSig2 := []*bls.Signature{}
allSig1 := []bls.Signature{}
allSig2 := []bls.Signature{}
for _, slashing := range slashings {
sig1 := slashing.Attestation_1.Signature
sig2 := slashing.Attestation_2.Signature

View File

@@ -251,7 +251,7 @@ func TestSubmitAggregateAndProof_AggregateNotOk(t *testing.T) {
}
}
func generateAtt(state *beaconstate.BeaconState, index uint64, privKeys []*bls.SecretKey) (*ethpb.Attestation, error) {
func generateAtt(state *beaconstate.BeaconState, index uint64, privKeys []bls.SecretKey) (*ethpb.Attestation, error) {
aggBits := bitfield.NewBitlist(4)
aggBits.SetBitAt(index, true)
aggBits.SetBitAt(index+1, true)
@@ -273,7 +273,7 @@ func generateAtt(state *beaconstate.BeaconState, index uint64, privKeys []*bls.S
return nil, err
}
sigs := make([]*bls.Signature, len(attestingIndices))
sigs := make([]bls.Signature, len(attestingIndices))
zeroSig := [96]byte{}
att.Signature = zeroSig[:]
@@ -291,7 +291,7 @@ func generateAtt(state *beaconstate.BeaconState, index uint64, privKeys []*bls.S
return att, nil
}
func generateUnaggregatedAtt(state *beaconstate.BeaconState, index uint64, privKeys []*bls.SecretKey) (*ethpb.Attestation, error) {
func generateUnaggregatedAtt(state *beaconstate.BeaconState, index uint64, privKeys []bls.SecretKey) (*ethpb.Attestation, error) {
aggBits := bitfield.NewBitlist(4)
aggBits.SetBitAt(index, true)
att := &ethpb.Attestation{
@@ -312,7 +312,7 @@ func generateUnaggregatedAtt(state *beaconstate.BeaconState, index uint64, privK
return nil, err
}
sigs := make([]*bls.Signature, len(attestingIndices))
sigs := make([]bls.Signature, len(attestingIndices))
zeroSig := [96]byte{}
att.Signature = zeroSig[:]

View File

@@ -1430,7 +1430,7 @@ func TestFilterAttestation_OK(t *testing.T) {
if err != nil {
t.Fatal(err)
}
sigs := make([]*bls.Signature, len(attestingIndices))
sigs := make([]bls.Signature, len(attestingIndices))
zeroSig := [96]byte{}
atts[i].Signature = zeroSig[:]

View File

@@ -158,7 +158,7 @@ func TestProcessPendingAtts_HasBlockSaveAggregatedAtt(t *testing.T) {
if err != nil {
t.Error(err)
}
sigs := make([]*bls.Signature, len(attestingIndices))
sigs := make([]bls.Signature, len(attestingIndices))
for i, indice := range attestingIndices {
sig := privKeys[indice].Sign(hashTreeRoot[:])
sigs[i] = sig

View File

@@ -415,7 +415,7 @@ func TestValidateAggregateAndProofWithNewStateMgmt_CanValidate(t *testing.T) {
if err != nil {
t.Error(err)
}
sigs := make([]*bls.Signature, len(attestingIndices))
sigs := make([]bls.Signature, len(attestingIndices))
for i, indice := range attestingIndices {
sig := privKeys[indice].Sign(hashTreeRoot[:])
sigs[i] = sig
@@ -539,7 +539,7 @@ func TestVerifyIndexInCommittee_SeenAggregatorEpoch(t *testing.T) {
if err != nil {
t.Error(err)
}
sigs := make([]*bls.Signature, len(attestingIndices))
sigs := make([]bls.Signature, len(attestingIndices))
for i, indice := range attestingIndices {
sig := privKeys[indice].Sign(hashTreeRoot[:])
sigs[i] = sig

View File

@@ -50,7 +50,7 @@ func setupValidAttesterSlashing(t *testing.T) (*ethpb.AttesterSlashing, *stateTr
}
sig0 := privKeys[0].Sign(hashTreeRoot[:])
sig1 := privKeys[1].Sign(hashTreeRoot[:])
aggregateSig := bls.AggregateSignatures([]*bls.Signature{sig0, sig1})
aggregateSig := bls.AggregateSignatures([]bls.Signature{sig0, sig1})
att1.Signature = aggregateSig.Marshal()[:]
att2 := &ethpb.IndexedAttestation{
@@ -66,7 +66,7 @@ func setupValidAttesterSlashing(t *testing.T) (*ethpb.AttesterSlashing, *stateTr
}
sig0 = privKeys[0].Sign(hashTreeRoot[:])
sig1 = privKeys[1].Sign(hashTreeRoot[:])
aggregateSig = bls.AggregateSignatures([]*bls.Signature{sig0, sig1})
aggregateSig = bls.AggregateSignatures([]bls.Signature{sig0, sig1})
att2.Signature = aggregateSig.Marshal()[:]
slashing := &ethpb.AttesterSlashing{

View File

@@ -78,7 +78,7 @@ func AggregatePair(a1 *ethpb.Attestation, a2 *ethpb.Attestation) (*ethpb.Attesta
return nil, err
}
aggregatedSig := aggregateSignatures([]*bls.Signature{baseSig, newSig})
aggregatedSig := aggregateSignatures([]bls.Signature{baseSig, newSig})
baseAtt.Signature = aggregatedSig.Marshal()
baseAtt.AggregationBits = newBits

View File

@@ -86,7 +86,7 @@ func (al attList) aggregate(coverage bitfield.Bitlist) (*ethpb.Attestation, erro
if len(al) < 2 {
return nil, errors.Wrap(ErrInvalidAttestationCount, "cannot aggregate")
}
signs := make([]*bls.Signature, len(al))
signs := make([]bls.Signature, len(al))
for i := 0; i < len(al); i++ {
sig, err := signatureFromBytes(al[i].Signature)
if err != nil {

View File

@@ -94,7 +94,7 @@ func AttestingIndices(bf bitfield.Bitfield, committee []uint64) []uint64 {
// domain = get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch)
// signing_root = compute_signing_root(indexed_attestation.data, domain)
// return bls.FastAggregateVerify(pubkeys, signing_root, indexed_attestation.signature)
func VerifyIndexedAttestationSig(ctx context.Context, indexedAtt *ethpb.IndexedAttestation, pubKeys []*bls.PublicKey, domain []byte) error {
func VerifyIndexedAttestationSig(ctx context.Context, indexedAtt *ethpb.IndexedAttestation, pubKeys []bls.PublicKey, domain []byte) error {
ctx, span := trace.StartSpan(ctx, "attestationutil.VerifyIndexedAttestationSig")
defer span.End()
indices := indexedAtt.AttestingIndices

View File

@@ -1,50 +1,16 @@
load("@prysm//tools/go:def.bzl", "go_library")
load("@io_bazel_rules_go//go:def.bzl", "go_test")
# 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 = ["bls.go"],
srcs = [
"bls.go",
"constants.go",
"interface.go",
],
importpath = "github.com/prysmaticlabs/prysm/shared/bls",
visibility = ["//visibility:public"],
deps = [
"//shared/featureconfig:go_default_library",
"//shared/params: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",
size = "small",
srcs = ["bls_test.go"],
embed = [":go_default_library"],
deps = ["//shared/bytesutil: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 = [
"//shared/bls:go_default_library",
"//shared/bytesutil:go_default_library",
"//shared/hashutil:go_default_library",
"@herumi_bls_eth_go_binary//:go_default_library",
"//shared/bls/herumi:go_default_library",
"//shared/bls/iface:go_default_library",
],
)

View File

@@ -4,281 +4,36 @@
package bls
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/featureconfig"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/bls/herumi"
"github.com/prysmaticlabs/prysm/shared/bls/iface"
)
func init() {
if err := bls12.Init(bls12.BLS12_381); err != nil {
panic(err)
}
if err := bls12.SetETHmode(bls12.EthModeDraft07); err != nil {
panic(err)
}
}
// DomainByteLength length of domain byte array.
const DomainByteLength = 4
var maxKeys = int64(100000)
var pubkeyCache, _ = ristretto.NewCache(&ristretto.Config{
NumCounters: maxKeys,
MaxCost: 1 << 22, // ~4mb is cache max size
BufferItems: 64,
})
// CurveOrder for the BLS12-381 curve.
const CurveOrder = "52435875175126190479447740508185965837690552500527637822603658699938581184513"
// Signature used in the BLS signature scheme.
type Signature struct {
s *bls12.Sign
}
// PublicKey used in the BLS signature scheme.
type PublicKey struct {
p *bls12.PublicKey
}
// SecretKey used in the BLS signature scheme.
type SecretKey struct {
p *bls12.SecretKey
}
// RandKey creates a new private key using a random method provided as an io.Reader.
func RandKey() *SecretKey {
secKey := &bls12.SecretKey{}
secKey.SetByCSPRNG()
return &SecretKey{secKey}
}
// SecretKeyFromBytes creates a BLS private key from a BigEndian byte slice.
func SecretKeyFromBytes(privKey []byte) (*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, errors.Wrap(err, "could not unmarshal bytes into secret key")
}
return &SecretKey{p: secKey}, err
func SecretKeyFromBytes(privKey []byte) (SecretKey, error) {
return herumi.SecretKeyFromBytes(privKey)
}
// PublicKeyFromBytes creates a BLS public key from a BigEndian byte slice.
func PublicKeyFromBytes(pubKey []byte) (*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()
}
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}
copiedKey, err := pubKeyObj.Copy()
if err != nil {
return nil, errors.Wrap(err, "could not copy public key")
}
pubkeyCache.Set(string(pubKey), copiedKey, 48)
return pubKeyObj, nil
func PublicKeyFromBytes(pubKey []byte) (PublicKey, error) {
return herumi.PublicKeyFromBytes(pubKey)
}
// SignatureFromBytes creates a BLS signature from a LittleEndian byte slice.
func SignatureFromBytes(sig []byte) (*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
}
// PublicKey obtains the public key corresponding to the BLS secret key.
func (s *SecretKey) PublicKey() *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 *SecretKey) Sign(msg []byte) *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 *SecretKey) 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
}
// 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() (*PublicKey, error) {
np := *p.p
return &PublicKey{p: &np}, nil
}
// Aggregate two public keys.
func (p *PublicKey) Aggregate(p2 *PublicKey) *PublicKey {
if featureconfig.Get().SkipBLSVerify {
return p
}
p.p.Add(p2.p)
return p
}
// 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 *PublicKey, msg []byte) bool {
if featureconfig.Get().SkipBLSVerify {
return true
}
return s.s.VerifyByte(pubKey.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.
//
// 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) -> boo
func (s *Signature) AggregateVerify(pubKeys []*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].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 []*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].p
}
return s.s.FastAggregateVerify(rawKeys, msg[:])
}
// NewAggregateSignature creates a blank aggregate signature.
func NewAggregateSignature() *Signature {
return &Signature{s: bls12.HashAndMapToSignature([]byte{'m', 'o', 'c', 'k'})}
func SignatureFromBytes(sig []byte) (Signature, error) {
return herumi.SignatureFromBytes(sig)
}
// AggregateSignatures converts a list of signatures into a single, aggregated sig.
func AggregateSignatures(sigs []*Signature) *Signature {
if len(sigs) == 0 {
return nil
}
if featureconfig.Get().SkipBLSVerify {
return sigs[0]
}
// Copy signature
signature := *sigs[0].s
for i := 1; i < len(sigs); i++ {
signature.Add(sigs[i].s)
}
return &Signature{s: &signature}
func AggregateSignatures(sigs []iface.Signature) iface.Signature {
return herumi.AggregateSignatures(sigs)
}
// 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 []*Signature) *Signature {
return AggregateSignatures(sigs)
// NewAggregateSignature creates a blank aggregate signature.
func NewAggregateSignature() iface.Signature {
return herumi.NewAggregateSignature()
}
// 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()
// RandKey creates a new private key using a random input.
func RandKey() iface.SecretKey {
return herumi.RandKey()
}

View File

@@ -1,285 +0,0 @@
package bls_test
import (
"bytes"
"errors"
"testing"
"github.com/prysmaticlabs/prysm/shared/bls"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
)
func TestMarshalUnmarshal(t *testing.T) {
b := bls.RandKey().Marshal()
b32 := bytesutil.ToBytes32(b)
pk, err := bls.SecretKeyFromBytes(b32[:])
if err != nil {
t.Fatal(err)
}
pk2, err := bls.SecretKeyFromBytes(b32[:])
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(pk.Marshal(), pk2.Marshal()) {
t.Errorf("Keys not equal, received %#x == %#x", pk.Marshal(), pk2.Marshal())
}
}
func TestSignVerify(t *testing.T) {
priv := bls.RandKey()
pub := priv.PublicKey()
msg := []byte("hello")
sig := priv.Sign(msg)
if !sig.Verify(pub, msg) {
t.Error("Signature did not verify")
}
}
func TestAggregateVerify(t *testing.T) {
pubkeys := make([]*bls.PublicKey, 0, 100)
sigs := make([]*bls.Signature, 0, 100)
var msgs [][32]byte
for i := 0; i < 100; i++ {
msg := [32]byte{'h', 'e', 'l', 'l', 'o', byte(i)}
priv := bls.RandKey()
pub := priv.PublicKey()
sig := priv.Sign(msg[:])
pubkeys = append(pubkeys, pub)
sigs = append(sigs, sig)
msgs = append(msgs, msg)
}
aggSig := bls.Aggregate(sigs)
if !aggSig.AggregateVerify(pubkeys, msgs) {
t.Error("Signature did not verify")
}
}
func TestFastAggregateVerify(t *testing.T) {
pubkeys := make([]*bls.PublicKey, 0, 100)
sigs := make([]*bls.Signature, 0, 100)
msg := [32]byte{'h', 'e', 'l', 'l', 'o'}
for i := 0; i < 100; i++ {
priv := bls.RandKey()
pub := priv.PublicKey()
sig := priv.Sign(msg[:])
pubkeys = append(pubkeys, pub)
sigs = append(sigs, sig)
}
aggSig := bls.AggregateSignatures(sigs)
if !aggSig.FastAggregateVerify(pubkeys, msg) {
t.Error("Signature did not verify")
}
}
func TestFastAggregateVerify_ReturnsFalseOnEmptyPubKeyList(t *testing.T) {
var pubkeys []*bls.PublicKey
sigs := make([]*bls.Signature, 0, 100)
msg := [32]byte{'h', 'e', 'l', 'l', 'o'}
aggSig := bls.AggregateSignatures(sigs)
if aggSig.FastAggregateVerify(pubkeys, msg) != false {
t.Error("Expected FastAggregateVerify to return false with empty input " +
"of public keys.")
}
}
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: errors.New("could not unmarshal bytes into secret key: err blsSecretKeyDeserialize ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
},
{
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 := bls.SecretKeyFromBytes(test.input)
if test.err != nil {
if err == nil {
t.Errorf("No error returned: expected %v", test.err)
} else if test.err.Error() != err.Error() {
t.Errorf("Unexpected error returned: expected %v, received %v", test.err, err)
}
} else {
if err != nil {
t.Errorf("Unexpected error returned: %v", err)
} else {
if bytes.Compare(res.Marshal(), test.input) != 0 {
t.Errorf("Unexpected result: expected %x, received %x", test.input, res.Marshal())
}
}
}
})
}
}
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 := bls.PublicKeyFromBytes(test.input)
if test.err != nil {
if err == nil {
t.Errorf("No error returned: expected %v", test.err)
} else if test.err.Error() != err.Error() {
t.Errorf("Unexpected error returned: expected %v, received %v", test.err, err)
}
} else {
if err != nil {
t.Errorf("Unexpected error returned: %v", err)
} else {
if bytes.Compare(res.Marshal(), test.input) != 0 {
t.Errorf("Unexpected result: expected %x, received %x", test.input, res.Marshal())
}
}
}
})
}
}
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 := bls.SignatureFromBytes(test.input)
if test.err != nil {
if err == nil {
t.Errorf("No error returned: expected %v", test.err)
} else if test.err.Error() != err.Error() {
t.Errorf("Unexpected error returned: expected %v, received %v", test.err, err)
}
} else {
if err != nil {
t.Errorf("Unexpected error returned: %v", err)
} else {
if bytes.Compare(res.Marshal(), test.input) != 0 {
t.Errorf("Unexpected result: expected %x, received %x", test.input, res.Marshal())
}
}
}
})
}
}
func TestPublicKey_Copy(t *testing.T) {
pubkeyA := bls.RandKey().PublicKey()
pubkeyBytes := pubkeyA.Marshal()
pubkeyB, err := pubkeyA.Copy()
if err != nil {
t.Fatal(err)
}
pubkeyB.Aggregate(bls.RandKey().PublicKey())
if !bytes.Equal(pubkeyA.Marshal(), pubkeyBytes) {
t.Fatal("Pubkey was mutated after copy")
}
}
func TestSerialize(t *testing.T) {
rk := bls.RandKey()
b := rk.Marshal()
if _, err := bls.SecretKeyFromBytes(b); err != nil {
t.Error(err)
}
}

7
shared/bls/constants.go Normal file
View File

@@ -0,0 +1,7 @@
package bls
// DomainByteLength length of domain byte array.
const DomainByteLength = 4
// CurveOrder for the BLS12-381 curve.
const CurveOrder = "52435875175126190479447740508185965837690552500527637822603658699938581184513"

View File

@@ -0,0 +1,66 @@
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 = [
"docs.go",
"init.go",
"public_key.go",
"secret_key.go",
"signature.go",
],
importpath = "github.com/prysmaticlabs/prysm/shared/bls/herumi",
visibility = [
"//shared/bls:__pkg__",
],
deps = [
"//shared/bls/iface:go_default_library",
"//shared/featureconfig:go_default_library",
"//shared/params: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/iface:go_default_library",
"//shared/bytesutil: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/iface:go_default_library",
"//shared/bytesutil:go_default_library",
"//shared/hashutil:go_default_library",
"@herumi_bls_eth_go_binary//:go_default_library",
],
)

View File

@@ -1,23 +1,24 @@
package bls_test
package herumi_test
import (
"testing"
bls2 "github.com/herumi/bls-eth-go-binary/bls"
"github.com/prysmaticlabs/prysm/shared/bls"
"github.com/herumi/bls-eth-go-binary/bls"
"github.com/prysmaticlabs/prysm/shared/bls/herumi"
"github.com/prysmaticlabs/prysm/shared/bls/iface"
"github.com/prysmaticlabs/prysm/shared/hashutil"
)
func BenchmarkPairing(b *testing.B) {
if err := bls2.Init(bls2.BLS12_381); err != nil {
if err := bls.Init(bls.BLS12_381); err != nil {
b.Fatal(err)
}
if err := bls2.SetETHmode(bls2.EthModeDraft05); err != nil {
if err := bls.SetETHmode(bls.EthModeDraft07); err != nil {
panic(err)
}
newGt := &bls2.GT{}
newG1 := &bls2.G1{}
newG2 := &bls2.G2{}
newGt := &bls.GT{}
newG1 := &bls.G1{}
newG2 := &bls.G2{}
newGt.SetInt64(10)
hash := hashutil.Hash([]byte{})
@@ -33,12 +34,12 @@ func BenchmarkPairing(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
bls2.Pairing(newGt, newG1, newG2)
bls.Pairing(newGt, newG1, newG2)
}
}
func BenchmarkSignature_Verify(b *testing.B) {
sk := bls.RandKey()
sk := herumi.RandKey()
msg := []byte("Some msg")
sig := sk.Sign(msg)
@@ -54,18 +55,18 @@ func BenchmarkSignature_Verify(b *testing.B) {
func BenchmarkSignature_AggregateVerify(b *testing.B) {
sigN := 128 // MAX_ATTESTATIONS per block.
var pks []*bls.PublicKey
var sigs []*bls.Signature
var pks []iface.PublicKey
var sigs []iface.Signature
var msgs [][32]byte
for i := 0; i < sigN; i++ {
msg := [32]byte{'s', 'i', 'g', 'n', 'e', 'd', byte(i)}
sk := bls.RandKey()
sk := herumi.RandKey()
sig := sk.Sign(msg[:])
pks = append(pks, sk.PublicKey())
sigs = append(sigs, sig)
msgs = append(msgs, msg)
}
aggregated := bls.Aggregate(sigs)
aggregated := herumi.Aggregate(sigs)
b.ResetTimer()
b.ReportAllocs()
@@ -77,12 +78,12 @@ func BenchmarkSignature_AggregateVerify(b *testing.B) {
}
func BenchmarkSecretKey_Marshal(b *testing.B) {
key := bls.RandKey()
key := herumi.RandKey()
d := key.Marshal()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := bls.SecretKeyFromBytes(d)
_, err := herumi.SecretKeyFromBytes(d)
_ = err
}
}

View File

@@ -0,0 +1,6 @@
// 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

12
shared/bls/herumi/init.go Normal file
View File

@@ -0,0 +1,12 @@
package herumi
import "github.com/herumi/bls-eth-go-binary/bls"
func init() {
if err := bls.Init(bls.BLS12_381); err != nil {
panic(err)
}
if err := bls.SetETHmode(bls.EthModeDraft07); err != nil {
panic(err)
}
}

View File

@@ -0,0 +1,65 @@
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/iface"
"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) (iface.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}
pubkeyCache.Set(string(pubKey), pubKeyObj.Copy(), 48)
return pubKeyObj, 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() iface.PublicKey {
np := *p.p
return &PublicKey{p: &np}
}
// Aggregate two public keys.
func (p *PublicKey) Aggregate(p2 iface.PublicKey) iface.PublicKey {
if featureconfig.Get().SkipBLSVerify {
return p
}
p.p.Add(p2.(*PublicKey).p)
return p
}

View File

@@ -0,0 +1,80 @@
package herumi_test
import (
"bytes"
"errors"
"testing"
"github.com/prysmaticlabs/prysm/shared/bls/herumi"
)
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 {
if err == nil {
t.Errorf("No error returned: expected %v", test.err)
} else if test.err.Error() != err.Error() {
t.Errorf("Unexpected error returned: expected %v, received %v", test.err, err)
}
} else {
if err != nil {
t.Errorf("Unexpected error returned: %v", err)
} else {
if bytes.Compare(res.Marshal(), test.input) != 0 {
t.Errorf("Unexpected result: expected %x, received %x", test.input, res.Marshal())
}
}
}
})
}
}
func TestPublicKey_Copy(t *testing.T) {
pubkeyA := herumi.RandKey().PublicKey()
pubkeyBytes := pubkeyA.Marshal()
pubkeyB := pubkeyA.Copy()
pubkeyB.Aggregate(herumi.RandKey().PublicKey())
if !bytes.Equal(pubkeyA.Marshal(), pubkeyBytes) {
t.Fatal("Pubkey was mutated after copy")
}
}

View File

@@ -0,0 +1,67 @@
package herumi
import (
"fmt"
bls12 "github.com/herumi/bls-eth-go-binary/bls"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/shared/bls/iface"
"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() iface.SecretKey {
secKey := &bls12.SecretKey{}
secKey.SetByCSPRNG()
return &bls12SecretKey{secKey}
}
// SecretKeyFromBytes creates a BLS private key from a BigEndian byte slice.
func SecretKeyFromBytes(privKey []byte) (iface.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, errors.Wrap(err, "could not unmarshal bytes into secret key")
}
return &bls12SecretKey{p: secKey}, err
}
// PublicKey obtains the public key corresponding to the BLS secret key.
func (s *bls12SecretKey) PublicKey() iface.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) iface.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
}

View File

@@ -0,0 +1,94 @@
package herumi_test
import (
"bytes"
"errors"
"testing"
"github.com/prysmaticlabs/prysm/shared/bls/herumi"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
)
func TestMarshalUnmarshal(t *testing.T) {
b := herumi.RandKey().Marshal()
b32 := bytesutil.ToBytes32(b)
pk, err := herumi.SecretKeyFromBytes(b32[:])
if err != nil {
t.Fatal(err)
}
pk2, err := herumi.SecretKeyFromBytes(b32[:])
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(pk.Marshal(), pk2.Marshal()) {
t.Errorf("Keys not equal, received %#x == %#x", 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: errors.New("could not unmarshal bytes into secret key: err blsSecretKeyDeserialize ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
},
{
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 {
if err == nil {
t.Errorf("No error returned: expected %v", test.err)
} else if test.err.Error() != err.Error() {
t.Errorf("Unexpected error returned: expected %v, received %v", test.err, err)
}
} else {
if err != nil {
t.Errorf("Unexpected error returned: %v", err)
} else {
if bytes.Compare(res.Marshal(), test.input) != 0 {
t.Errorf("Unexpected result: expected %x, received %x", test.input, res.Marshal())
}
}
}
})
}
}
func TestSerialize(t *testing.T) {
rk := herumi.RandKey()
b := rk.Marshal()
if _, err := herumi.SecretKeyFromBytes(b); err != nil {
t.Error(err)
}
}

View File

@@ -0,0 +1,157 @@
package herumi
import (
"fmt"
bls12 "github.com/herumi/bls-eth-go-binary/bls"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/shared/bls/iface"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/params"
)
// 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) (iface.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 iface.PublicKey, msg []byte) bool {
if featureconfig.Get().SkipBLSVerify {
return true
}
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.
//
// 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) -> boo
func (s *Signature) AggregateVerify(pubKeys []iface.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 []iface.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() iface.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 []iface.Signature) iface.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 []iface.Signature) iface.Signature {
return AggregateSignatures(sigs)
}
// 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() iface.Signature {
return &Signature{s: &*s.s}
}

View File

@@ -0,0 +1,127 @@
package herumi_test
import (
"bytes"
"errors"
"testing"
"github.com/prysmaticlabs/prysm/shared/bls/iface"
"github.com/prysmaticlabs/prysm/shared/bls/herumi"
)
func TestSignVerify(t *testing.T) {
priv := herumi.RandKey()
pub := priv.PublicKey()
msg := []byte("hello")
sig := priv.Sign(msg)
if !sig.Verify(pub, msg) {
t.Error("Signature did not verify")
}
}
func TestAggregateVerify(t *testing.T) {
pubkeys := make([]iface.PublicKey, 0, 100)
sigs := make([]iface.Signature, 0, 100)
var msgs [][32]byte
for i := 0; i < 100; i++ {
msg := [32]byte{'h', 'e', 'l', 'l', 'o', byte(i)}
priv := herumi.RandKey()
pub := priv.PublicKey()
sig := priv.Sign(msg[:])
pubkeys = append(pubkeys, pub)
sigs = append(sigs, sig)
msgs = append(msgs, msg)
}
aggSig := herumi.Aggregate(sigs)
if !aggSig.AggregateVerify(pubkeys, msgs) {
t.Error("Signature did not verify")
}
}
func TestFastAggregateVerify(t *testing.T) {
pubkeys := make([]iface.PublicKey, 0, 100)
sigs := make([]iface.Signature, 0, 100)
msg := [32]byte{'h', 'e', 'l', 'l', 'o'}
for i := 0; i < 100; i++ {
priv := herumi.RandKey()
pub := priv.PublicKey()
sig := priv.Sign(msg[:])
pubkeys = append(pubkeys, pub)
sigs = append(sigs, sig)
}
aggSig := herumi.AggregateSignatures(sigs)
if !aggSig.FastAggregateVerify(pubkeys, msg) {
t.Error("Signature did not verify")
}
}
func TestFastAggregateVerify_ReturnsFalseOnEmptyPubKeyList(t *testing.T) {
var pubkeys []iface.PublicKey
msg := [32]byte{'h', 'e', 'l', 'l', 'o'}
aggSig := herumi.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 := herumi.SignatureFromBytes(test.input)
if test.err != nil {
if err == nil {
t.Errorf("No error returned: expected %v", test.err)
} else if test.err.Error() != err.Error() {
t.Errorf("Unexpected error returned: expected %v, received %v", test.err, err)
}
} else {
if err != nil {
t.Errorf("Unexpected error returned: %v", err)
} else {
if bytes.Compare(res.Marshal(), test.input) != 0 {
t.Errorf("Unexpected result: expected %x, received %x", test.input, res.Marshal())
}
}
}
})
}
}

View File

@@ -0,0 +1,8 @@
load("@prysm//tools/go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["interface.go"],
importpath = "github.com/prysmaticlabs/prysm/shared/bls/iface",
visibility = ["//shared/bls:__subpackages__"],
)

View File

@@ -0,0 +1,29 @@
// Package iface provides the BLS interfaces that are implemented by the various BLS wrappers.
//
// This package should not be used by downstream consumers. These interfaces are re-exporter by
// github.com/prysmaticlabs/prysm/shared/bls. This package exists to prevent an import circular
// dependency.
package iface
// SecretKey represents a BLS secret or private key.
type SecretKey interface {
PublicKey() PublicKey
Sign(msg []byte) Signature
Marshal() []byte
}
// PublicKey represents a BLS public key.
type PublicKey interface {
Marshal() []byte
Copy() PublicKey
Aggregate(p2 PublicKey) PublicKey
}
// Signature represents a BLS signature.
type Signature interface {
Verify(pubKey PublicKey, msg []byte) bool
AggregateVerify(pubKeys []PublicKey, msgs [][32]byte) bool
FastAggregateVerify(pubKeys []PublicKey, msg [32]byte) bool
Marshal() []byte
Copy() Signature
}

14
shared/bls/interface.go Normal file
View File

@@ -0,0 +1,14 @@
package bls
import (
"github.com/prysmaticlabs/prysm/shared/bls/iface"
)
// PublicKey represents a BLS public key.
type PublicKey = iface.PublicKey
// SecretKey represents a BLS secret or private key.
type SecretKey = iface.SecretKey
// Signature represents a BLS signature.
type Signature = iface.Signature

View File

@@ -32,6 +32,7 @@ go_test(
tags = ["spectest"],
deps = [
"//shared/bls:go_default_library",
"//shared/bls/iface:go_default_library",
"//shared/bytesutil:go_default_library",
"//shared/testutil:go_default_library",
"@com_github_ghodss_yaml//:go_default_library",

View File

@@ -9,6 +9,7 @@ import (
"github.com/ghodss/yaml"
"github.com/prysmaticlabs/prysm/shared/bls"
"github.com/prysmaticlabs/prysm/shared/bls/iface"
"github.com/prysmaticlabs/prysm/shared/testutil"
)
@@ -25,7 +26,7 @@ func TestAggregateYaml(t *testing.T) {
if err := yaml.Unmarshal(file, test); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
var sigs []*bls.Signature
var sigs []iface.Signature
for _, s := range test.Input {
sigBytes, err := hex.DecodeString(s[2:])
if err != nil {

View File

@@ -7,6 +7,7 @@ import (
"github.com/ghodss/yaml"
"github.com/prysmaticlabs/prysm/shared/bls"
"github.com/prysmaticlabs/prysm/shared/bls/iface"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/testutil"
)
@@ -25,7 +26,7 @@ func TestAggregateVerifyYaml(t *testing.T) {
t.Fatalf("Failed to unmarshal: %v", err)
}
pubkeys := make([]*bls.PublicKey, 0, len(test.Input.Pubkeys))
pubkeys := make([]iface.PublicKey, 0, len(test.Input.Pubkeys))
msgs := make([][32]byte, 0, len(test.Input.Messages))
for _, pubKey := range test.Input.Pubkeys {
pkBytes, err := hex.DecodeString(pubKey[2:])

View File

@@ -7,6 +7,7 @@ import (
"github.com/ghodss/yaml"
"github.com/prysmaticlabs/prysm/shared/bls"
"github.com/prysmaticlabs/prysm/shared/bls/iface"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/testutil"
)
@@ -25,7 +26,7 @@ func TestFastAggregateVerifyYaml(t *testing.T) {
t.Fatalf("Failed to unmarshal: %v", err)
}
pubkeys := make([]*bls.PublicKey, len(test.Input.Pubkeys))
pubkeys := make([]iface.PublicKey, len(test.Input.Pubkeys))
for j, raw := range test.Input.Pubkeys {
pkBytes, err := hex.DecodeString(raw[2:])
if err != nil {

View File

@@ -98,7 +98,7 @@ func generateDepositsFromData(depositDataItems []*ethpb.Deposit_Data, offset int
}
// DepositDataFromKeys generates a list of deposit data items from a set of BLS validator keys.
func DepositDataFromKeys(privKeys []*bls.SecretKey, pubKeys []*bls.PublicKey) ([]*ethpb.Deposit_Data, [][]byte, error) {
func DepositDataFromKeys(privKeys []bls.SecretKey, pubKeys []bls.PublicKey) ([]*ethpb.Deposit_Data, [][]byte, error) {
type depositData struct {
items []*ethpb.Deposit_Data
roots [][]byte
@@ -123,7 +123,7 @@ func DepositDataFromKeys(privKeys []*bls.SecretKey, pubKeys []*bls.PublicKey) ([
return depositDataItems, depositDataRoots, nil
}
func depositDataFromKeys(privKeys []*bls.SecretKey, pubKeys []*bls.PublicKey) ([]*ethpb.Deposit_Data, [][]byte, error) {
func depositDataFromKeys(privKeys []bls.SecretKey, pubKeys []bls.PublicKey) ([]*ethpb.Deposit_Data, [][]byte, error) {
dataRoots := make([][]byte, len(privKeys))
depositDataItems := make([]*ethpb.Deposit_Data, len(privKeys))
for i := 0; i < len(privKeys); i++ {
@@ -142,7 +142,7 @@ func depositDataFromKeys(privKeys []*bls.SecretKey, pubKeys []*bls.PublicKey) ([
}
// Generates a deposit data item from BLS keys and signs the hash tree root of the data.
func createDepositData(privKey *bls.SecretKey, pubKey *bls.PublicKey) (*ethpb.Deposit_Data, error) {
func createDepositData(privKey bls.SecretKey, pubKey bls.PublicKey) (*ethpb.Deposit_Data, error) {
di := &ethpb.Deposit_Data{
PublicKey: pubKey.Marshal(),
WithdrawalCredentials: withdrawalCredentialsHash(pubKey.Marshal()),

View File

@@ -18,12 +18,12 @@ const (
// DeterministicallyGenerateKeys creates BLS private keys using a fixed curve order according to
// the algorithm specified in the Eth2.0-Specs interop mock start section found here:
// https://github.com/ethereum/eth2.0-pm/blob/a085c9870f3956d6228ed2a40cd37f0c6580ecd7/interop/mocked_start/README.md
func DeterministicallyGenerateKeys(startIndex, numKeys uint64) ([]*bls.SecretKey, []*bls.PublicKey, error) {
privKeys := make([]*bls.SecretKey, numKeys)
pubKeys := make([]*bls.PublicKey, numKeys)
func DeterministicallyGenerateKeys(startIndex, numKeys uint64) ([]bls.SecretKey, []bls.PublicKey, error) {
privKeys := make([]bls.SecretKey, numKeys)
pubKeys := make([]bls.PublicKey, numKeys)
type keys struct {
secrets []*bls.SecretKey
publics []*bls.PublicKey
secrets []bls.SecretKey
publics []bls.PublicKey
}
results, err := mputil.Scatter(int(numKeys), func(offset int, entries int, _ *sync.RWMutex) (interface{}, error) {
secs, pubs, err := deterministicallyGenerateKeys(uint64(offset)+startIndex, uint64(entries))
@@ -43,9 +43,9 @@ func DeterministicallyGenerateKeys(startIndex, numKeys uint64) ([]*bls.SecretKey
return privKeys, pubKeys, nil
}
func deterministicallyGenerateKeys(startIndex, numKeys uint64) ([]*bls.SecretKey, []*bls.PublicKey, error) {
privKeys := make([]*bls.SecretKey, numKeys)
pubKeys := make([]*bls.PublicKey, numKeys)
func deterministicallyGenerateKeys(startIndex, numKeys uint64) ([]bls.SecretKey, []bls.PublicKey, error) {
privKeys := make([]bls.SecretKey, numKeys)
pubKeys := make([]bls.PublicKey, numKeys)
for i := startIndex; i < startIndex+numKeys; i++ {
enc := make([]byte, 32)
binary.LittleEndian.PutUint32(enc, uint32(i))

View File

@@ -56,9 +56,9 @@ const (
type Key struct {
ID uuid.UUID // Version 4 "random" for unique id not derived from key data
PublicKey *bls.PublicKey // Represents the public key of the user.
PublicKey bls.PublicKey // Represents the public key of the user.
SecretKey *bls.SecretKey // Represents the private key of the user.
SecretKey bls.SecretKey // Represents the private key of the user.
}
type keyStore interface {
@@ -138,7 +138,7 @@ func (k *Key) UnmarshalJSON(j []byte) (err error) {
}
// NewKeyFromBLS creates a new keystore Key type using a BLS private key.
func NewKeyFromBLS(blsKey *bls.SecretKey) (*Key, error) {
func NewKeyFromBLS(blsKey bls.SecretKey) (*Key, error) {
id := uuid.NewRandom()
pubkey := blsKey.PublicKey()
key := &Key{

View File

@@ -51,7 +51,7 @@ func ensureInt(x interface{}) int {
// keyFileName implements the naming convention for keyfiles:
// UTC--<created_at UTC ISO8601>-<first 8 character of address hex>
func keyFileName(pubkey *bls.PublicKey) string {
func keyFileName(pubkey bls.PublicKey) string {
ts := roughtime.Now().UTC()
return fmt.Sprintf("UTC--%s--%s", toISO8601(ts), hex.EncodeToString(pubkey.Marshal())[:8])
}

View File

@@ -64,7 +64,7 @@ func NewBeaconBlock() *ethpb.SignedBeaconBlock {
// Use BlockGenConfig to declare the conditions you would like the block generated under.
func GenerateFullBlock(
bState *stateTrie.BeaconState,
privs []*bls.SecretKey,
privs []bls.SecretKey,
conf *BlockGenConfig,
slot uint64,
) (*ethpb.SignedBeaconBlock, error) {
@@ -184,7 +184,7 @@ func GenerateFullBlock(
// GenerateProposerSlashingForValidator for a specific validator index.
func GenerateProposerSlashingForValidator(
bState *stateTrie.BeaconState,
priv *bls.SecretKey,
priv bls.SecretKey,
idx uint64,
) (*ethpb.ProposerSlashing, error) {
header1 := &ethpb.SignedBeaconBlockHeader{
@@ -230,7 +230,7 @@ func GenerateProposerSlashingForValidator(
func generateProposerSlashings(
bState *stateTrie.BeaconState,
privs []*bls.SecretKey,
privs []bls.SecretKey,
numSlashings uint64,
) ([]*ethpb.ProposerSlashing, error) {
proposerSlashings := make([]*ethpb.ProposerSlashing, numSlashings)
@@ -251,7 +251,7 @@ func generateProposerSlashings(
// GenerateAttesterSlashingForValidator for a specific validator index.
func GenerateAttesterSlashingForValidator(
bState *stateTrie.BeaconState,
priv *bls.SecretKey,
priv bls.SecretKey,
idx uint64,
) (*ethpb.AttesterSlashing, error) {
currentEpoch := helpers.CurrentEpoch(bState)
@@ -280,7 +280,7 @@ func GenerateAttesterSlashingForValidator(
return nil, err
}
sig := priv.Sign(dataRoot[:])
att1.Signature = bls.AggregateSignatures([]*bls.Signature{sig}).Marshal()
att1.Signature = bls.AggregateSignatures([]bls.Signature{sig}).Marshal()
att2 := &ethpb.IndexedAttestation{
Data: &ethpb.AttestationData{
@@ -302,7 +302,7 @@ func GenerateAttesterSlashingForValidator(
return nil, err
}
sig = priv.Sign(dataRoot[:])
att2.Signature = bls.AggregateSignatures([]*bls.Signature{sig}).Marshal()
att2.Signature = bls.AggregateSignatures([]bls.Signature{sig}).Marshal()
return &ethpb.AttesterSlashing{
Attestation_1: att1,
@@ -312,7 +312,7 @@ func GenerateAttesterSlashingForValidator(
func generateAttesterSlashings(
bState *stateTrie.BeaconState,
privs []*bls.SecretKey,
privs []bls.SecretKey,
numSlashings uint64,
) ([]*ethpb.AttesterSlashing, error) {
attesterSlashings := make([]*ethpb.AttesterSlashing, numSlashings)
@@ -340,7 +340,7 @@ func generateAttesterSlashings(
// for the same data with their aggregation bits split uniformly.
//
// If you request 4 attestations, but there are 8 committees, you will get 4 fully aggregated attestations.
func GenerateAttestations(bState *stateTrie.BeaconState, privs []*bls.SecretKey, numToGen uint64, slot uint64, randomRoot bool) ([]*ethpb.Attestation, error) {
func GenerateAttestations(bState *stateTrie.BeaconState, privs []bls.SecretKey, numToGen uint64, slot uint64, randomRoot bool) ([]*ethpb.Attestation, error) {
currentEpoch := helpers.SlotToEpoch(slot)
attestations := []*ethpb.Attestation{}
generateHeadState := false
@@ -447,7 +447,7 @@ func GenerateAttestations(bState *stateTrie.BeaconState, privs []*bls.SecretKey,
bitsPerAtt := committeeSize / uint64(attsPerCommittee)
for i := uint64(0); i < committeeSize; i += bitsPerAtt {
aggregationBits := bitfield.NewBitlist(committeeSize)
sigs := []*bls.Signature{}
sigs := []bls.Signature{}
for b := i; b < i+bitsPerAtt; b++ {
aggregationBits.SetBitAt(b, true)
sigs = append(sigs, privs[committee[b]].Sign(dataRoot[:]))
@@ -491,7 +491,7 @@ func generateDepositsAndEth1Data(
func generateVoluntaryExits(
bState *stateTrie.BeaconState,
privs []*bls.SecretKey,
privs []bls.SecretKey,
numExits uint64,
) ([]*ethpb.SignedVoluntaryExit, error) {
currentEpoch := helpers.CurrentEpoch(bState)

View File

@@ -23,7 +23,7 @@ var lock sync.Mutex
// Caches
var cachedDeposits []*ethpb.Deposit
var privKeys []*bls.SecretKey
var privKeys []bls.SecretKey
var trie *trieutil.SparseMerkleTrie
// DeterministicDepositsAndKeys returns the entered amount of deposits and secret keys.
@@ -31,7 +31,7 @@ var trie *trieutil.SparseMerkleTrie
// account is key n and the withdrawal account is key n+1. As such,
// if all secret keys for n validators are required then numDeposits
// should be n+1.
func DeterministicDepositsAndKeys(numDeposits uint64) ([]*ethpb.Deposit, []*bls.SecretKey, error) {
func DeterministicDepositsAndKeys(numDeposits uint64) ([]*ethpb.Deposit, []bls.SecretKey, error) {
lock.Lock()
defer lock.Unlock()
var err error
@@ -152,7 +152,7 @@ func DeterministicEth1Data(size int) (*ethpb.Eth1Data, error) {
}
// DeterministicGenesisState returns a genesis state made using the deterministic deposits.
func DeterministicGenesisState(t testing.TB, numValidators uint64) (*stateTrie.BeaconState, []*bls.SecretKey) {
func DeterministicGenesisState(t testing.TB, numValidators uint64) (*stateTrie.BeaconState, []bls.SecretKey) {
deposits, privKeys, err := DeterministicDepositsAndKeys(numValidators)
if err != nil {
t.Fatal(errors.Wrapf(err, "failed to get %d deposits", numValidators))
@@ -196,14 +196,14 @@ func DepositTrieFromDeposits(deposits []*ethpb.Deposit) (*trieutil.SparseMerkleT
// ResetCache clears out the old trie, private keys and deposits.
func ResetCache() {
trie = nil
privKeys = []*bls.SecretKey{}
privKeys = []bls.SecretKey{}
cachedDeposits = []*ethpb.Deposit{}
}
// DeterministicDepositsAndKeysSameValidator returns the entered amount of deposits and secret keys
// of the same validator. This is for negative test cases such as same deposits from same validators in a block don't
// result in duplicated validator indices.
func DeterministicDepositsAndKeysSameValidator(numDeposits uint64) ([]*ethpb.Deposit, []*bls.SecretKey, error) {
func DeterministicDepositsAndKeysSameValidator(numDeposits uint64) ([]*ethpb.Deposit, []bls.SecretKey, error) {
lock.Lock()
defer lock.Unlock()
var err error

View File

@@ -16,7 +16,7 @@ import (
)
// RandaoReveal returns a signature of the requested epoch using the beacon proposer private key.
func RandaoReveal(beaconState *stateTrie.BeaconState, epoch uint64, privKeys []*bls.SecretKey) ([]byte, error) {
func RandaoReveal(beaconState *stateTrie.BeaconState, epoch uint64, privKeys []bls.SecretKey) ([]byte, error) {
// We fetch the proposer's index as that is whom the RANDAO will be verified against.
proposerIdx, err := helpers.BeaconProposerIndex(beaconState)
if err != nil {
@@ -41,8 +41,8 @@ func RandaoReveal(beaconState *stateTrie.BeaconState, epoch uint64, privKeys []*
func BlockSignature(
bState *stateTrie.BeaconState,
block *ethpb.BeaconBlock,
privKeys []*bls.SecretKey,
) (*bls.Signature, error) {
privKeys []bls.SecretKey,
) (bls.Signature, error) {
var err error
s, err := state.CalculateStateRoot(context.Background(), bState, &ethpb.SignedBeaconBlock{Block: block})
if err != nil {

View File

@@ -71,7 +71,7 @@ func (ss *Server) IsSlashableAttestation(ctx context.Context, req *ethpb.Indexed
if err != nil {
return nil, err
}
pubkeys := []*bls.PublicKey{}
pubkeys := []bls.PublicKey{}
for _, pkBytes := range pkMap {
pk, err := bls.PublicKeyFromBytes(pkBytes[:])
if err != nil {

View File

@@ -86,7 +86,7 @@ func TestServer_IsSlashableAttestation(t *testing.T) {
if err != nil {
t.Error(err)
}
var sig []*bls.Signature
var sig []bls.Signature
for _, idx := range incomingAtt.AttestingIndices {
validatorSig := keys[idx].Sign(root[:])
sig = append(sig, validatorSig)
@@ -104,7 +104,7 @@ func TestServer_IsSlashableAttestation(t *testing.T) {
if err != nil {
t.Error(err)
}
sig = []*bls.Signature{}
sig = []bls.Signature{}
for _, idx := range savedAttestation.AttestingIndices {
validatorSig := keys[idx].Sign(root[:])
sig = append(sig, validatorSig)
@@ -195,7 +195,7 @@ func TestServer_IsSlashableAttestationNoUpdate(t *testing.T) {
if err != nil {
t.Error(err)
}
sig := []*bls.Signature{}
sig := []bls.Signature{}
for _, idx := range savedAttestation.AttestingIndices {
validatorSig := keys[idx].Sign(root[:])
sig = append(sig, validatorSig)

View File

@@ -149,7 +149,7 @@ go_library(
copts = OPTS,
visibility = [
# Additional access will require security approval.
"@prysm//shared/bls:__pkg__",
"@prysm//shared/bls/herumi:__pkg__",
"@com_github_wealdtech_go_eth2_types_v2//:__pkg__",
],
clinkopts = select({

View File

@@ -2,10 +2,10 @@ package main
import (
"flag"
"github.com/prysmaticlabs/prysm/shared/bls"
"log"
"os"
"github.com/prysmaticlabs/prysm/shared/bls"
"github.com/prysmaticlabs/prysm/shared/interop"
"github.com/prysmaticlabs/prysm/tools/unencrypted-keys-gen/keygen"
)

View File

@@ -226,7 +226,7 @@ func (v *validator) signAtt(ctx context.Context, pubKey [48]byte, data *ethpb.At
return nil, err
}
var sig *bls.Signature
var sig bls.Signature
if protectingKeymanager, supported := v.keyManager.(keymanager.ProtectingKeyManager); supported {
sig, err = protectingKeymanager.SignAttestation(pubKey, bytesutil.ToBytes32(domain.SignatureDomain), data)
} else {

View File

@@ -189,7 +189,7 @@ func (v *validator) signBlock(ctx context.Context, pubKey [48]byte, epoch uint64
if err != nil {
return nil, errors.Wrap(err, "could not get domain data")
}
var sig *bls.Signature
var sig bls.Signature
if protectingKeymanager, supported := v.keyManager.(keymanager.ProtectingKeyManager); supported {
bodyRoot, err := stateutil.BlockBodyRoot(b.Body)
if err != nil {

View File

@@ -180,7 +180,7 @@ func (v *ValidatorService) Status() error {
}
// signObject signs a generic object, with protection if available.
func (v *validator) signObject(pubKey [48]byte, object interface{}, domain []byte) (*bls.Signature, error) {
func (v *validator) signObject(pubKey [48]byte, object interface{}, domain []byte) (bls.Signature, error) {
if protectingKeymanager, supported := v.keyManager.(keymanager.ProtectingKeyManager); supported {
root, err := ssz.HashTreeRoot(object)
if err != nil {

View File

@@ -36,11 +36,11 @@ func keySetup() {
copy(validatorPubKey[:], validatorKey.PublicKey.Marshal())
keyMap[validatorPubKey] = validatorKey
sks := make([]*bls.SecretKey, 1)
sks := make([]bls.SecretKey, 1)
sks[0] = validatorKey.SecretKey
testKeyManager = keymanager.NewDirect(sks)
sks = make([]*bls.SecretKey, 3)
sks = make([]bls.SecretKey, 3)
for i := 0; i < 3; i++ {
vKey, err := keystore.NewKey()
if err != nil {

View File

@@ -809,7 +809,7 @@ func TestRolesAt_OK(t *testing.T) {
v, m, finish := setup(t)
defer finish()
sks := make([]*bls.SecretKey, 4)
sks := make([]bls.SecretKey, 4)
sks[0] = bls.RandKey()
sks[1] = bls.RandKey()
sks[2] = bls.RandKey()
@@ -880,7 +880,7 @@ func TestRolesAt_DoesNotAssignProposer_Slot0(t *testing.T) {
v, m, finish := setup(t)
defer finish()
sks := make([]*bls.SecretKey, 3)
sks := make([]bls.SecretKey, 3)
sks[0] = bls.RandKey()
sks[1] = bls.RandKey()
sks[2] = bls.RandKey()

View File

@@ -155,7 +155,7 @@ func (v *validator) signAtt(ctx context.Context, pubKey [48]byte, data *ethpb.At
return nil, err
}
var sig *bls.Signature
var sig bls.Signature
if protectingKeymanager, supported := v.keyManager.(keymanager.ProtectingKeyManager); supported {
sig, err = protectingKeymanager.SignAttestation(pubKey, bytesutil.ToBytes32(domain.SignatureDomain), data)
} else {

View File

@@ -191,7 +191,7 @@ func (v *validator) signBlock(ctx context.Context, pubKey [48]byte, epoch uint64
if err != nil {
return nil, errors.Wrap(err, "could not get domain data")
}
var sig *bls.Signature
var sig bls.Signature
if protectingKeymanager, supported := v.keyManager.(keymanager.ProtectingKeyManager); supported {
bodyRoot, err := stateutil.BlockBodyRoot(b.Body)
if err != nil {

View File

@@ -172,7 +172,7 @@ func (v *ValidatorService) Status() error {
}
// signObject signs a generic object, with protection if available.
func (v *validator) signObject(pubKey [48]byte, object interface{}, domain []byte) (*bls.Signature, error) {
func (v *validator) signObject(pubKey [48]byte, object interface{}, domain []byte) (bls.Signature, error) {
if protectingKeymanager, supported := v.keyManager.(keymanager.ProtectingKeyManager); supported {
root, err := ssz.HashTreeRoot(object)
if err != nil {

View File

@@ -36,11 +36,11 @@ func keySetup() {
copy(validatorPubKey[:], validatorKey.PublicKey.Marshal())
keyMap[validatorPubKey] = validatorKey
sks := make([]*bls.SecretKey, 1)
sks := make([]bls.SecretKey, 1)
sks[0] = validatorKey.SecretKey
testKeyManager = keymanager.NewDirect(sks)
sks = make([]*bls.SecretKey, 3)
sks = make([]bls.SecretKey, 3)
for i := 0; i < 3; i++ {
vKey, err := keystore.NewKey()
if err != nil {

View File

@@ -639,7 +639,7 @@ func TestRolesAt_OK(t *testing.T) {
v, m, finish := setup(t)
defer finish()
sks := make([]*bls.SecretKey, 4)
sks := make([]bls.SecretKey, 4)
sks[0] = bls.RandKey()
sks[1] = bls.RandKey()
sks[2] = bls.RandKey()
@@ -710,7 +710,7 @@ func TestRolesAt_DoesNotAssignProposer_Slot0(t *testing.T) {
v, m, finish := setup(t)
defer finish()
sks := make([]*bls.SecretKey, 3)
sks := make([]bls.SecretKey, 3)
sks[0] = bls.RandKey()
sks[1] = bls.RandKey()
sks[2] = bls.RandKey()

View File

@@ -8,16 +8,16 @@ import (
// Direct is a key manager that holds all secret keys directly.
type Direct struct {
// Key to the map is the bytes of the public key.
publicKeys map[[48]byte]*bls.PublicKey
publicKeys map[[48]byte]bls.PublicKey
// Key to the map is the bytes of the public key.
secretKeys map[[48]byte]*bls.SecretKey
secretKeys map[[48]byte]bls.SecretKey
}
// NewDirect creates a new direct key manager from the secret keys provided to it.
func NewDirect(sks []*bls.SecretKey) *Direct {
func NewDirect(sks []bls.SecretKey) *Direct {
res := &Direct{
publicKeys: make(map[[48]byte]*bls.PublicKey),
secretKeys: make(map[[48]byte]*bls.SecretKey),
publicKeys: make(map[[48]byte]bls.PublicKey),
secretKeys: make(map[[48]byte]bls.SecretKey),
}
for _, sk := range sks {
publicKey := sk.PublicKey()
@@ -38,7 +38,7 @@ func (km *Direct) FetchValidatingKeys() ([][48]byte, error) {
}
// Sign signs a message for the validator to broadcast.
func (km *Direct) Sign(pubKey [48]byte, root [32]byte) (*bls.Signature, error) {
func (km *Direct) Sign(pubKey [48]byte, root [32]byte) (bls.Signature, error) {
if secretKey, exists := km.secretKeys[pubKey]; exists {
return secretKey.Sign(root[:]), nil
}

View File

@@ -42,8 +42,8 @@ func NewInterop(input string) (*Interop, string, error) {
km := &Interop{
Direct: &Direct{
publicKeys: make(map[[48]byte]*bls.PublicKey),
secretKeys: make(map[[48]byte]*bls.SecretKey),
publicKeys: make(map[[48]byte]bls.PublicKey),
secretKeys: make(map[[48]byte]bls.SecretKey),
},
}
for i := 0; uint64(i) < opts.Keys; i++ {

View File

@@ -79,8 +79,8 @@ func NewKeystore(input string) (KeyManager, string, error) {
km := &Unencrypted{
Direct: &Direct{
publicKeys: make(map[[48]byte]*bls.PublicKey),
secretKeys: make(map[[48]byte]*bls.SecretKey),
publicKeys: make(map[[48]byte]bls.PublicKey),
secretKeys: make(map[[48]byte]bls.SecretKey),
},
}
for _, key := range keyMap {

View File

@@ -21,7 +21,7 @@ func TestDirectListValidatingKeysNil(t *testing.T) {
}
func TestDirectListValidatingKeysSingle(t *testing.T) {
sks := make([]*bls.SecretKey, 0)
sks := make([]bls.SecretKey, 0)
sks = append(sks, bls.RandKey())
direct := keymanager.NewDirect(sks)
keys, err := direct.FetchValidatingKeys()
@@ -34,7 +34,7 @@ func TestDirectListValidatingKeysSingle(t *testing.T) {
}
func TestDirectListValidatingKeysMultiple(t *testing.T) {
sks := make([]*bls.SecretKey, 0)
sks := make([]bls.SecretKey, 0)
numKeys := 256
for i := 0; i < numKeys; i++ {
sks = append(sks, bls.RandKey())
@@ -50,7 +50,7 @@ func TestDirectListValidatingKeysMultiple(t *testing.T) {
}
func TestSignNoSuchKey(t *testing.T) {
sks := make([]*bls.SecretKey, 0)
sks := make([]bls.SecretKey, 0)
// sks = append(sks, bls.RandKey())
direct := keymanager.NewDirect(sks)
@@ -62,7 +62,7 @@ func TestSignNoSuchKey(t *testing.T) {
}
func TestSign(t *testing.T) {
sks := make([]*bls.SecretKey, 0)
sks := make([]bls.SecretKey, 0)
sks = append(sks, bls.RandKey())
direct := keymanager.NewDirect(sks)

View File

@@ -58,15 +58,15 @@ func NewUnencrypted(input string) (*Unencrypted, string, error) {
if err != nil {
return nil, unencryptedOptsHelp, err
}
sks := make([]*bls.SecretKey, 0, len(keyMap))
sks := make([]bls.SecretKey, 0, len(keyMap))
for _, key := range keyMap {
sks = append(sks, key)
}
km := &Unencrypted{
Direct: &Direct{
publicKeys: make(map[[48]byte]*bls.PublicKey),
secretKeys: make(map[[48]byte]*bls.SecretKey),
publicKeys: make(map[[48]byte]bls.PublicKey),
secretKeys: make(map[[48]byte]bls.SecretKey),
},
}
for i := 0; i < len(sks); i++ {
@@ -87,7 +87,7 @@ type unencryptedKeys struct {
}
// unencryptedKeysFromReader loads the unencrypted keys from the given reader.
func unencryptedKeysFromReader(reader io.Reader) ([]*bls.SecretKey, error) {
func unencryptedKeysFromReader(reader io.Reader) ([]bls.SecretKey, error) {
log.Warn("Loading encrypted keys from disk. Do not do this in production!")
data, err := ioutil.ReadAll(reader)
@@ -99,7 +99,7 @@ func unencryptedKeysFromReader(reader io.Reader) ([]*bls.SecretKey, error) {
return nil, err
}
res := make([]*bls.SecretKey, 0, len(ctnr.Keys))
res := make([]bls.SecretKey, 0, len(ctnr.Keys))
for i := range ctnr.Keys {
secretKey, err := bls.SecretKeyFromBytes(ctnr.Keys[i].ValidatorKey)
if err != nil {

View File

@@ -22,18 +22,18 @@ type KeyManager interface {
FetchValidatingKeys() ([][48]byte, error)
// Sign signs a message for the validator to broadcast.
// Note that the domain should already be part of the root, but it is passed along for security purposes.
Sign(pubKey [48]byte, root [32]byte) (*bls.Signature, error)
Sign(pubKey [48]byte, root [32]byte) (bls.Signature, error)
}
// ProtectingKeyManager provides access to a keymanager that protects its clients from slashing events.
type ProtectingKeyManager interface {
// SignGeneric signs a generic root.
// Note that the domain should already be part of the root, but it is provided for authorisation purposes.
SignGeneric(pubKey [48]byte, root [32]byte, domain [32]byte) (*bls.Signature, error)
SignGeneric(pubKey [48]byte, root [32]byte, domain [32]byte) (bls.Signature, error)
// SignProposal signs a block proposal for the validator to broadcast.
SignProposal(pubKey [48]byte, domain [32]byte, data *ethpb.BeaconBlockHeader) (*bls.Signature, error)
SignProposal(pubKey [48]byte, domain [32]byte, data *ethpb.BeaconBlockHeader) (bls.Signature, error)
// SignAttestation signs an attestation for the validator to broadcast.
SignAttestation(pubKey [48]byte, domain [32]byte, data *ethpb.AttestationData) (*bls.Signature, error)
SignAttestation(pubKey [48]byte, domain [32]byte, data *ethpb.AttestationData) (bls.Signature, error)
}

View File

@@ -155,12 +155,12 @@ func (km *Remote) FetchValidatingKeys() ([][48]byte, error) {
}
// Sign without protection is not supported by remote keymanagers.
func (km *Remote) Sign(pubKey [48]byte, root [32]byte) (*bls.Signature, error) {
func (km *Remote) Sign(pubKey [48]byte, root [32]byte) (bls.Signature, error) {
return nil, errors.New("remote keymanager does not support unprotected signing")
}
// SignGeneric signs a generic message for the validator to broadcast.
func (km *Remote) SignGeneric(pubKey [48]byte, root [32]byte, domain [32]byte) (*bls.Signature, error) {
func (km *Remote) SignGeneric(pubKey [48]byte, root [32]byte, domain [32]byte) (bls.Signature, error) {
accountInfo, exists := km.accounts[pubKey]
if !exists {
return nil, ErrNoSuchKey
@@ -186,7 +186,7 @@ func (km *Remote) SignGeneric(pubKey [48]byte, root [32]byte, domain [32]byte) (
}
// SignProposal signs a block proposal for the validator to broadcast.
func (km *Remote) SignProposal(pubKey [48]byte, domain [32]byte, data *ethpb.BeaconBlockHeader) (*bls.Signature, error) {
func (km *Remote) SignProposal(pubKey [48]byte, domain [32]byte, data *ethpb.BeaconBlockHeader) (bls.Signature, error) {
accountInfo, exists := km.accounts[pubKey]
if !exists {
return nil, ErrNoSuchKey
@@ -218,7 +218,7 @@ func (km *Remote) SignProposal(pubKey [48]byte, domain [32]byte, data *ethpb.Bea
}
// SignAttestation signs an attestation for the validator to broadcast.
func (km *Remote) SignAttestation(pubKey [48]byte, domain [32]byte, data *ethpb.AttestationData) (*bls.Signature, error) {
func (km *Remote) SignAttestation(pubKey [48]byte, domain [32]byte, data *ethpb.AttestationData) (bls.Signature, error) {
accountInfo, exists := km.accounts[pubKey]
if !exists {
return nil, ErrNoSuchKey

View File

@@ -134,7 +134,7 @@ func (km *Wallet) FetchValidatingKeys() ([][48]byte, error) {
}
// Sign signs a message for the validator to broadcast.
func (km *Wallet) Sign(pubKey [48]byte, root [32]byte) (*bls.Signature, error) {
func (km *Wallet) Sign(pubKey [48]byte, root [32]byte) (bls.Signature, error) {
account, exists := km.accounts[pubKey]
if !exists {
return nil, ErrNoSuchKey