mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-22 03:30:35 +00:00
Add blst for BLS (#6539)
* Add blst third party dep * initial build * add init * blst passing tests * add feature flag * blst and herumi for spec tests * maybe this works for mac * Actually set feature flag * Add stub for VerifyMultipleSignatures for blst * verifyCompressed * use correct cores sizes * aggregate public keys * add multi-sig verification * encode not hash * revert back * go mod tidy * update blst to latest commit * add batch decompress * fix * add test * gofmt * update blst * go mod tidy * remove kubesec, fix * mod tidy * disable some remote cache * disable some remote cache * disable some remote cache * disable some remote cache * Switch to -D__ADX__ * update * tidy * fix build * Make blst for only linux,amd64 * gofmt * lint * lint * gazelle * fix build tag * more stub methods * shift adx instructions to x86 * fix arm64 * Revert "fix arm64" This reverts commit 4d34ac21b7509a1b385374e3039efecfcab614c1. * add one more in * Revert "Revert "fix arm64"" This reverts commit 1c8ae24ad16ff9811590f1058b9d98c90b63251a. * try darwin now * Revert "try darwin now" This reverts commit 6f884714b8e14a7a803b72157672b6e942047f37. * Add sha256 * remove TODO * checkpoint * finally builds * fix up * add tag * try again * explicit disabling * remove * select properly * fix * better * make CI happy too * Update .bazelrc * Update .bazelrc * fix tests * revert back * Update shared/bls/blst/public_key.go Co-authored-by: Victor Farazdagi <simple.square@gmail.com> * Update shared/bls/blst/public_key.go Co-authored-by: Victor Farazdagi <simple.square@gmail.com> * clean up tests * more clean up * clean up * add * Update shared/bls/blst/signature.go * Update shared/bls/blst/signature.go * Update .buildkite-bazelrc Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com> * try again * remove go tag * revert change * gaz * gazelle ignore Co-authored-by: nisdas <nishdas93@gmail.com> Co-authored-by: Victor Farazdagi <simple.square@gmail.com> Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
This commit is contained in:
parent
b0917db4c7
commit
14dbc2b74d
8
.bazelrc
8
.bazelrc
@ -33,9 +33,16 @@ build --define kafka_enabled=false
|
||||
test --define kafka_enabled=false
|
||||
run --define kafka_enabled=false
|
||||
|
||||
# Enable blst by default, we use a config so that our fuzzer stops complaining.
|
||||
build --config=blst_enabled
|
||||
test --config=blst_enabled
|
||||
run --config=blst_enabled
|
||||
|
||||
build:kafka_enabled --define kafka_enabled=true
|
||||
build:kafka_enabled --define gotags=kafka_enabled
|
||||
|
||||
build:blst_enabled --define blst_enabled=true
|
||||
|
||||
# Release flags
|
||||
build:release --workspace_status_command=./scripts/workspace_status.sh
|
||||
build:release --stamp
|
||||
@ -72,6 +79,7 @@ build:fuzz --linkopt -Wl,--no-as-needed
|
||||
build:fuzz --define=gc_goopts=-d=libfuzzer,checkptr
|
||||
build:fuzz --run_under=//tools:fuzz_wrapper
|
||||
build:fuzz --compilation_mode=opt
|
||||
build:fuzz --define=blst_enabled=false
|
||||
|
||||
test:fuzz --local_test_jobs="HOST_CPUS*.5"
|
||||
|
||||
|
@ -37,6 +37,9 @@ build --flaky_test_attempts=5
|
||||
# Enable kafka for CI tests only.
|
||||
test --config=kafka_enabled
|
||||
|
||||
# Disable blst for CI tests.
|
||||
test --define blst_enabled=true
|
||||
|
||||
build --bes_backend=grpcs://builds.prylabs.net:1985
|
||||
build --bes_results_url=https://builds.prylabs.net/invocation/
|
||||
|
||||
|
3
.github/workflows/go.yml
vendored
3
.github/workflows/go.yml
vendored
@ -43,7 +43,8 @@ jobs:
|
||||
go get -v -t -d ./...
|
||||
|
||||
- name: Build
|
||||
run: go build -v ./...
|
||||
# Use blst tag to allow go and bazel builds for blst.
|
||||
run: go build -v --tags=blst_enabled ./...
|
||||
|
||||
# Tests run via Bazel for now...
|
||||
# - name: Test
|
||||
|
@ -231,7 +231,7 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []*ethpb.SignedBeaconBl
|
||||
jCheckpoints := make([]*ethpb.Checkpoint, len(blks))
|
||||
fCheckpoints := make([]*ethpb.Checkpoint, len(blks))
|
||||
sigSet := &bls.SignatureSet{
|
||||
Signatures: []bls.Signature{},
|
||||
Signatures: [][]byte{},
|
||||
PublicKeys: []bls.PublicKey{},
|
||||
Messages: [][32]byte{},
|
||||
}
|
||||
@ -253,7 +253,7 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []*ethpb.SignedBeaconBl
|
||||
fCheckpoints[i] = preState.FinalizedCheckpoint()
|
||||
sigSet.Join(set)
|
||||
}
|
||||
verify, err := bls.VerifyMultipleSignatures(sigSet.Signatures, sigSet.Messages, sigSet.PublicKeys)
|
||||
verify, err := sigSet.Verify()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -336,7 +336,7 @@ func verifyAttestationsSigWithDomain(ctx context.Context, beaconState *stateTrie
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
verify, err := bls.VerifyMultipleSignatures(set.Signatures, set.Messages, set.PublicKeys)
|
||||
verify, err := set.Verify()
|
||||
if err != nil {
|
||||
return errors.Errorf("got error in multiple verification: %v", err)
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ func verifyDepositDataWithDomain(ctx context.Context, deps []*ethpb.Deposit, dom
|
||||
return nil
|
||||
}
|
||||
pks := make([]bls.PublicKey, len(deps))
|
||||
sigs := make([]bls.Signature, len(deps))
|
||||
sigs := make([][]byte, len(deps))
|
||||
msgs := make([][32]byte, len(deps))
|
||||
for i, dep := range deps {
|
||||
if ctx.Err() != nil {
|
||||
@ -241,17 +241,12 @@ func verifyDepositDataWithDomain(ctx context.Context, deps []*ethpb.Deposit, dom
|
||||
if dep == nil || dep.Data == nil {
|
||||
return errors.New("nil deposit")
|
||||
}
|
||||
|
||||
dpk, err := bls.PublicKeyFromBytes(dep.Data.PublicKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pks[i] = dpk
|
||||
dsig, err := bls.SignatureFromBytes(dep.Data.Signature)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sigs[i] = dsig
|
||||
sigs[i] = dep.Data.Signature
|
||||
root, err := ssz.SigningRoot(dep.Data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get signing root")
|
||||
|
@ -20,10 +20,6 @@ func retrieveSignatureSet(signedData []byte, pub []byte, signature []byte, domai
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not convert bytes to public key")
|
||||
}
|
||||
sig, err := bls.SignatureFromBytes(signature)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not convert bytes to signature")
|
||||
}
|
||||
signingData := &pb.SigningData{
|
||||
ObjectRoot: signedData,
|
||||
Domain: domain,
|
||||
@ -33,7 +29,7 @@ func retrieveSignatureSet(signedData []byte, pub []byte, signature []byte, domai
|
||||
return nil, errors.Wrap(err, "could not hash container")
|
||||
}
|
||||
return &bls.SignatureSet{
|
||||
Signatures: []bls.Signature{sig},
|
||||
Signatures: [][]byte{signature},
|
||||
PublicKeys: []bls.PublicKey{publicKey},
|
||||
Messages: [][32]byte{root},
|
||||
}, nil
|
||||
@ -52,7 +48,11 @@ func verifySignature(signedData []byte, pub []byte, signature []byte, domain []b
|
||||
sig := set.Signatures[0]
|
||||
publicKey := set.PublicKeys[0]
|
||||
root := set.Messages[0]
|
||||
if !sig.Verify(publicKey, root[:]) {
|
||||
rSig, err := bls.SignatureFromBytes(sig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !rSig.Verify(publicKey, root[:]) {
|
||||
return helpers.ErrSigFailedToVerify
|
||||
}
|
||||
return nil
|
||||
@ -129,15 +129,11 @@ func createAttestationSignatureSet(ctx context.Context, beaconState *stateTrie.B
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
sigs := make([]bls.Signature, len(atts))
|
||||
sigs := make([][]byte, 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sigs[i] = sig
|
||||
sigs[i] = a.Signature
|
||||
c, err := helpers.BeaconCommitteeFromState(beaconState, a.Data.Slot, a.Data.CommitteeIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -147,20 +143,16 @@ func createAttestationSignatureSet(ctx context.Context, beaconState *stateTrie.B
|
||||
return nil, err
|
||||
}
|
||||
indices := ia.AttestingIndices
|
||||
var pk bls.PublicKey
|
||||
pubkeys := make([][]byte, len(indices))
|
||||
for i := 0; i < len(indices); i++ {
|
||||
pubkeyAtIdx := beaconState.PubkeyAtIndex(indices[i])
|
||||
p, err := bls.PublicKeyFromBytes(pubkeyAtIdx[:])
|
||||
pubkeys[i] = pubkeyAtIdx[:]
|
||||
}
|
||||
aggP, err := bls.AggregatePublicKeys(pubkeys)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not deserialize validator public key")
|
||||
return nil, err
|
||||
}
|
||||
if pk == nil {
|
||||
pk = p
|
||||
} else {
|
||||
pk.Aggregate(p)
|
||||
}
|
||||
}
|
||||
pks[i] = pk
|
||||
pks[i] = aggP
|
||||
|
||||
root, err := helpers.ComputeSigningRoot(ia.Data, domain)
|
||||
if err != nil {
|
||||
|
@ -117,7 +117,11 @@ func VerifyBlockSigningRoot(blk *ethpb.BeaconBlock, pub []byte, signature []byte
|
||||
publicKey := set.PublicKeys[0]
|
||||
root := set.Messages[0]
|
||||
|
||||
if !sig.Verify(publicKey, root[:]) {
|
||||
rSig, err := bls.SignatureFromBytes(sig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !rSig.Verify(publicKey, root[:]) {
|
||||
return ErrSigFailedToVerify
|
||||
}
|
||||
return nil
|
||||
@ -130,10 +134,6 @@ func RetrieveBlockSignatureSet(blk *ethpb.BeaconBlock, pub []byte, signature []b
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not convert bytes to public key")
|
||||
}
|
||||
sig, err := bls.SignatureFromBytes(signature)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not convert bytes to signature")
|
||||
}
|
||||
root, err := signingData(func() ([32]byte, error) {
|
||||
// utilize custom block hashing function
|
||||
return blk.HashTreeRoot()
|
||||
@ -142,7 +142,7 @@ func RetrieveBlockSignatureSet(blk *ethpb.BeaconBlock, pub []byte, signature []b
|
||||
return nil, errors.Wrap(err, "could not compute signing root")
|
||||
}
|
||||
return &bls.SignatureSet{
|
||||
Signatures: []bls.Signature{sig},
|
||||
Signatures: [][]byte{signature},
|
||||
PublicKeys: []bls.PublicKey{publicKey},
|
||||
Messages: [][32]byte{root},
|
||||
}, nil
|
||||
|
21
deps.bzl
21
deps.bzl
@ -1,4 +1,5 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_repository", "maybe") # gazelle:keep
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # gazelle:keep
|
||||
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
||||
|
||||
# Prysm's third party / external dependencies.
|
||||
@ -2720,8 +2721,9 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "org_golang_google_grpc",
|
||||
importpath = "google.golang.org/grpc",
|
||||
sum = "h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=",
|
||||
version = "v1.29.1",
|
||||
sum = "h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE=",
|
||||
version = "v1.30.0",
|
||||
build_file_proto_mode = "disable_global",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_crypto",
|
||||
@ -2821,12 +2823,6 @@ def prysm_deps():
|
||||
sum = "h1:2AJaUQdgUZLoDZHrun21PW2Nx9+ll6cUzvn3IKhSIn0=",
|
||||
version = "v0.18.3",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_shyiko_kubesec",
|
||||
importpath = "github.com/shyiko/kubesec",
|
||||
sum = "h1:au/8ClCUc9HTpuGePltbhd98DZcsqZEyG9DoFILieR4=",
|
||||
version = "v0.0.0-20190816030733-7ce23ac7239c",
|
||||
)
|
||||
go_repository(
|
||||
name = "in_gopkg_confluentinc_confluent_kafka_go_v1",
|
||||
importpath = "gopkg.in/confluentinc/confluent-kafka-go.v1",
|
||||
@ -3436,6 +3432,15 @@ def prysm_deps():
|
||||
sum = "h1:90Ly+6UfUypEF6vvvW5rQIv9opIL8CbmW9FT20LDQoY=",
|
||||
version = "v0.0.0-20191129215211-8e5a1ed0cff0",
|
||||
)
|
||||
http_archive(
|
||||
name = "com_github_supranational_blst",
|
||||
urls = [
|
||||
"https://github.com/supranational/blst/archive/d75dab4fb87df7fc753d348b17be671c69b625f5.tar.gz",
|
||||
],
|
||||
strip_prefix = "blst-d75dab4fb87df7fc753d348b17be671c69b625f5",
|
||||
build_file = "//third_party:blst/blst.BUILD",
|
||||
sha256 = "c541403e73fb0553a55d7ebfef6db695f48f18855fff1a87c7fd08f69827da51",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_nbutton23_zxcvbn_go",
|
||||
importpath = "github.com/nbutton23/zxcvbn-go",
|
||||
|
1
go.mod
1
go.mod
@ -96,6 +96,7 @@ require (
|
||||
github.com/schollz/progressbar/v3 v3.3.4
|
||||
github.com/sirupsen/logrus v1.6.0
|
||||
github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969 // indirect
|
||||
github.com/supranational/blst v0.1.2-alpha.1.0.20200828152217-d75dab4fb87d
|
||||
github.com/tyler-smith/go-bip39 v1.0.2
|
||||
github.com/urfave/cli/v2 v2.2.0
|
||||
github.com/wealdtech/eth2-signer-api v1.3.0
|
||||
|
2
go.sum
2
go.sum
@ -1097,6 +1097,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
||||
github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/supranational/blst v0.1.2-alpha.1.0.20200828152217-d75dab4fb87d h1:+SGrEOwpPjlaMcSDLI5p/nLCiEZegXK8aKoELNtCcZE=
|
||||
github.com/supranational/blst v0.1.2-alpha.1.0.20200828152217-d75dab4fb87d/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
|
||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
|
||||
|
@ -11,7 +11,9 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/shared/bls",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//shared/bls/blst:go_default_library",
|
||||
"//shared/bls/herumi:go_default_library",
|
||||
"//shared/bls/iface:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -4,41 +4,98 @@
|
||||
package bls
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/blst"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/herumi"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/iface"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
)
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// AggregateSignatures converts a list of signatures into a single, aggregated sig.
|
||||
func AggregateSignatures(sigs []iface.Signature) iface.Signature {
|
||||
if featureconfig.Get().EnableBlst {
|
||||
return blst.AggregateSignatures(sigs)
|
||||
}
|
||||
return herumi.AggregateSignatures(sigs)
|
||||
}
|
||||
|
||||
// VerifyMultipleSignatures verifies multiple signatures for distinct messages securely.
|
||||
func VerifyMultipleSignatures(sigs []iface.Signature, msgs [][32]byte, pubKeys []iface.PublicKey) (bool, error) {
|
||||
return herumi.VerifyMultipleSignatures(sigs, msgs, pubKeys)
|
||||
func VerifyMultipleSignatures(sigs [][]byte, msgs [][32]byte, pubKeys []iface.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)
|
||||
}
|
||||
|
||||
// NewAggregateSignature creates a blank aggregate signature.
|
||||
func NewAggregateSignature() iface.Signature {
|
||||
if featureconfig.Get().EnableBlst {
|
||||
return blst.NewAggregateSignature()
|
||||
}
|
||||
return herumi.NewAggregateSignature()
|
||||
}
|
||||
|
||||
// RandKey creates a new private key using a random input.
|
||||
func RandKey() iface.SecretKey {
|
||||
if featureconfig.Get().EnableBlst {
|
||||
return blst.RandKey()
|
||||
}
|
||||
return herumi.RandKey()
|
||||
}
|
||||
|
||||
// VerifyCompressed signature.
|
||||
func VerifyCompressed(signature []byte, pub []byte, msg []byte) bool {
|
||||
if featureconfig.Get().EnableBlst {
|
||||
return blst.VerifyCompressed(signature, pub, msg)
|
||||
}
|
||||
sig, err := SignatureFromBytes(signature)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
pk, err := PublicKeyFromBytes(pub)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return sig.Verify(pk, msg)
|
||||
}
|
||||
|
151
shared/bls/blst/BUILD.bazel
Normal file
151
shared/bls/blst/BUILD.bazel
Normal file
@ -0,0 +1,151 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
# Build with --define=blst_enabled=false to exclude blst library.
|
||||
config_setting(
|
||||
name = "blst_enabled_linux_amd64",
|
||||
constraint_values = [
|
||||
"@platforms//os:linux",
|
||||
"@platforms//cpu:x86_64",
|
||||
],
|
||||
values = {
|
||||
"define": "blst_enabled=true",
|
||||
},
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "blst_enabled_linux_arm64",
|
||||
constraint_values = [
|
||||
"@platforms//os:linux",
|
||||
"@platforms//cpu:aarch64",
|
||||
],
|
||||
values = {
|
||||
"define": "blst_enabled=true",
|
||||
},
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "blst_enabled_android_amd64",
|
||||
constraint_values = [
|
||||
"@platforms//os:android",
|
||||
"@platforms//cpu:x86_64",
|
||||
],
|
||||
values = {
|
||||
"define": "blst_enabled=true",
|
||||
},
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "blst_enabled_android_arm64",
|
||||
constraint_values = [
|
||||
"@platforms//os:android",
|
||||
"@platforms//cpu:aarch64",
|
||||
],
|
||||
values = {
|
||||
"define": "blst_enabled=true",
|
||||
},
|
||||
)
|
||||
|
||||
# gazelle:resolve go github.com/supranational/blst/bindings/go @com_github_supranational_blst//:go_default_library
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs =
|
||||
selects.with_or({
|
||||
(
|
||||
":blst_enabled_linux_amd64",
|
||||
":blst_enabled_linux_arm64",
|
||||
":blst_enabled_android_amd64",
|
||||
":blst_enabled_android_arm64",
|
||||
): [
|
||||
"aliases.go",
|
||||
"doc.go",
|
||||
"init.go",
|
||||
"public_key.go",
|
||||
"secret_key.go",
|
||||
"signature.go",
|
||||
],
|
||||
"//conditions:default": [
|
||||
"stub.go",
|
||||
],
|
||||
}),
|
||||
importpath = "github.com/prysmaticlabs/prysm/shared/bls/blst",
|
||||
visibility = [
|
||||
"//shared/bls:__pkg__",
|
||||
],
|
||||
deps = selects.with_or({
|
||||
(
|
||||
":blst_enabled_linux_amd64",
|
||||
":blst_enabled_linux_arm64",
|
||||
":blst_enabled_android_amd64",
|
||||
":blst_enabled_android_arm64",
|
||||
): [
|
||||
"//shared/bls/iface: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",
|
||||
"@com_github_supranational_blst//:go_default_library",
|
||||
],
|
||||
"//conditions:default": ["//shared/bls/iface:go_default_library"],
|
||||
}),
|
||||
)
|
||||
|
||||
# gazelle:ignore
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = selects.with_or({
|
||||
(
|
||||
":blst_enabled_linux_amd64",
|
||||
":blst_enabled_linux_arm64",
|
||||
":blst_enabled_android_amd64",
|
||||
":blst_enabled_android_arm64",
|
||||
): [
|
||||
"public_key_test.go",
|
||||
"secret_key_test.go",
|
||||
"signature_test.go",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
deps = selects.with_or({
|
||||
(
|
||||
":blst_enabled_linux_amd64",
|
||||
":blst_enabled_linux_arm64",
|
||||
":blst_enabled_android_amd64",
|
||||
":blst_enabled_android_arm64",
|
||||
): [
|
||||
"//shared/bls/blst:go_default_library",
|
||||
"//shared/bls/iface:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/testutil/assert:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
# 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",
|
||||
],
|
||||
)
|
11
shared/bls/blst/aliases.go
Normal file
11
shared/bls/blst/aliases.go
Normal file
@ -0,0 +1,11 @@
|
||||
// +build linux,amd64 linux,arm64
|
||||
|
||||
package blst
|
||||
|
||||
import blst "github.com/supranational/blst/bindings/go"
|
||||
|
||||
// Internal types for blst.
|
||||
type blstPublicKey = blst.P1Affine
|
||||
type blstSignature = blst.P2Affine
|
||||
type blstAggregateSignature = blst.P2Aggregate
|
||||
type blstAggregatePublicKey = blst.P1Aggregate
|
91
shared/bls/blst/bls_benchmark_test.go
Normal file
91
shared/bls/blst/bls_benchmark_test.go
Normal file
@ -0,0 +1,91 @@
|
||||
// +build linux,amd64 linux,arm64
|
||||
|
||||
package blst_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"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 := bls.Init(bls.BLS12_381); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
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{})
|
||||
err := newG1.HashAndMapTo(hash[:])
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
err = newG2.HashAndMapTo(hash[:])
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
bls.Pairing(newGt, newG1, newG2)
|
||||
}
|
||||
|
||||
}
|
||||
func BenchmarkSignature_Verify(b *testing.B) {
|
||||
sk := herumi.RandKey()
|
||||
|
||||
msg := []byte("Some msg")
|
||||
sig := sk.Sign(msg)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if !sig.Verify(sk.PublicKey(), msg) {
|
||||
b.Fatal("could not verify sig")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSignature_AggregateVerify(b *testing.B) {
|
||||
sigN := 128 // MAX_ATTESTATIONS per block.
|
||||
|
||||
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 := herumi.RandKey()
|
||||
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++ {
|
||||
if !aggregated.AggregateVerify(pks, msgs) {
|
||||
b.Fatal("could not verify aggregate sig")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSecretKey_Marshal(b *testing.B) {
|
||||
key := herumi.RandKey()
|
||||
d := key.Marshal()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := herumi.SecretKeyFromBytes(d)
|
||||
_ = err
|
||||
}
|
||||
}
|
8
shared/bls/blst/doc.go
Normal file
8
shared/bls/blst/doc.go
Normal file
@ -0,0 +1,8 @@
|
||||
// Package blst 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 Supranational, blst.
|
||||
//
|
||||
// Only linux_amd64 is supported at the moment.
|
||||
package blst
|
18
shared/bls/blst/init.go
Normal file
18
shared/bls/blst/init.go
Normal file
@ -0,0 +1,18 @@
|
||||
// +build linux,amd64 linux,arm64
|
||||
|
||||
package blst
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
blst "github.com/supranational/blst/bindings/go"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Reserve 1 core for general application work
|
||||
maxProcs := runtime.GOMAXPROCS(0) - 1
|
||||
if maxProcs <= 0 {
|
||||
maxProcs = 1
|
||||
}
|
||||
blst.SetMaxProcs(maxProcs)
|
||||
}
|
99
shared/bls/blst/public_key.go
Normal file
99
shared/bls/blst/public_key.go
Normal file
@ -0,0 +1,99 @@
|
||||
// +build linux,amd64 linux,arm64
|
||||
|
||||
package blst
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/dgraph-io/ristretto"
|
||||
"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 *blstPublicKey
|
||||
}
|
||||
|
||||
// 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 := new(blstPublicKey).Uncompress(pubKey)
|
||||
if p == nil {
|
||||
return nil, errors.New("could not unmarshal bytes into public key")
|
||||
}
|
||||
pubKeyObj := &PublicKey{p: p}
|
||||
copiedKey := pubKeyObj.Copy()
|
||||
pubkeyCache.Set(string(pubKey), copiedKey, 48)
|
||||
return pubKeyObj, nil
|
||||
}
|
||||
|
||||
// AggregatePublicKeys aggregates the provided raw public keys into a single key.
|
||||
func AggregatePublicKeys(pubs [][]byte) (iface.PublicKey, error) {
|
||||
if featureconfig.Get().SkipBLSVerify {
|
||||
return &PublicKey{}, nil
|
||||
}
|
||||
agg := new(blstAggregatePublicKey)
|
||||
mulP1 := make([]*blstPublicKey, 0, len(pubs))
|
||||
for _, pubkey := range pubs {
|
||||
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 {
|
||||
mulP1 = append(mulP1, cv.(*PublicKey).Copy().(*PublicKey).p)
|
||||
continue
|
||||
}
|
||||
p := new(blstPublicKey).Uncompress(pubkey)
|
||||
if p == nil {
|
||||
return nil, errors.New("could not unmarshal bytes into public key")
|
||||
}
|
||||
pubKeyObj := &PublicKey{p: p}
|
||||
pubkeyCache.Set(string(pubkey), pubKeyObj.Copy(), 48)
|
||||
mulP1 = append(mulP1, p)
|
||||
}
|
||||
agg.Aggregate(mulP1)
|
||||
return &PublicKey{p: agg.ToAffine()}, nil
|
||||
}
|
||||
|
||||
// Marshal a public key into a LittleEndian byte slice.
|
||||
func (p *PublicKey) Marshal() []byte {
|
||||
return p.p.Compress()
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
agg := new(blstAggregatePublicKey)
|
||||
agg.Add(p.p)
|
||||
agg.Add(p2.(*PublicKey).p)
|
||||
p.p = agg.ToAffine()
|
||||
|
||||
return p
|
||||
}
|
73
shared/bls/blst/public_key_test.go
Normal file
73
shared/bls/blst/public_key_test.go
Normal file
@ -0,0 +1,73 @@
|
||||
// +build linux,amd64 linux,arm64
|
||||
|
||||
package blst_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/blst"
|
||||
"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"),
|
||||
},
|
||||
{
|
||||
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 := blst.PublicKeyFromBytes(test.input)
|
||||
if test.err != nil {
|
||||
assert.NotEqual(t, nil, err, "No error returned")
|
||||
assert.ErrorContains(t, test.err.Error(), err, "Unexpected error returned")
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.DeepEqual(t, 0, bytes.Compare(res.Marshal(), test.input))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublicKey_Copy(t *testing.T) {
|
||||
pubkeyA := blst.RandKey().PublicKey()
|
||||
pubkeyBytes := pubkeyA.Marshal()
|
||||
|
||||
pubkeyB := pubkeyA.Copy()
|
||||
pubkeyB.Aggregate(blst.RandKey().PublicKey())
|
||||
|
||||
require.DeepEqual(t, pubkeyA.Marshal(), pubkeyBytes, "Pubkey was mutated after copy")
|
||||
}
|
75
shared/bls/blst/secret_key.go
Normal file
75
shared/bls/blst/secret_key.go
Normal file
@ -0,0 +1,75 @@
|
||||
// +build linux,amd64 linux,arm64
|
||||
|
||||
package blst
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/iface"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/rand"
|
||||
blst "github.com/supranational/blst/bindings/go"
|
||||
)
|
||||
|
||||
// bls12SecretKey used in the BLS signature scheme.
|
||||
type bls12SecretKey struct {
|
||||
p *blst.SecretKey
|
||||
}
|
||||
|
||||
// RandKey creates a new private key using a random method provided as an io.Reader.
|
||||
func RandKey() iface.SecretKey {
|
||||
// Generate 32 bytes of randomness
|
||||
var ikm [32]byte
|
||||
_, err := rand.NewGenerator().Read(ikm[:])
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &bls12SecretKey{blst.KeyGen(ikm[:])}
|
||||
}
|
||||
|
||||
// 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 := new(blst.SecretKey).Deserialize(privKey)
|
||||
if secKey == nil {
|
||||
return nil, errors.New("could not unmarshal bytes into secret key")
|
||||
}
|
||||
|
||||
return &bls12SecretKey{p: secKey}, nil
|
||||
}
|
||||
|
||||
// PublicKey obtains the public key corresponding to the BLS secret key.
|
||||
func (s *bls12SecretKey) PublicKey() iface.PublicKey {
|
||||
return &PublicKey{p: new(blstPublicKey).From(s.p)}
|
||||
}
|
||||
|
||||
// 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 := new(blstSignature).Sign(s.p, msg, dst)
|
||||
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
|
||||
}
|
82
shared/bls/blst/secret_key_test.go
Normal file
82
shared/bls/blst/secret_key_test.go
Normal file
@ -0,0 +1,82 @@
|
||||
// +build linux,amd64 linux,arm64
|
||||
|
||||
package blst_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/blst"
|
||||
"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) {
|
||||
b := blst.RandKey().Marshal()
|
||||
b32 := bytesutil.ToBytes32(b)
|
||||
pk, err := blst.SecretKeyFromBytes(b32[:])
|
||||
require.NoError(t, err)
|
||||
pk2, err := blst.SecretKeyFromBytes(b32[:])
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, pk.Marshal(), pk2.Marshal(), "Keys not equal")
|
||||
}
|
||||
|
||||
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"),
|
||||
},
|
||||
{
|
||||
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 := blst.SecretKeyFromBytes(test.input)
|
||||
if test.err != nil {
|
||||
assert.NotEqual(t, nil, err, "No error returned")
|
||||
assert.ErrorContains(t, test.err.Error(), err, "Unexpected error returned")
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.DeepEqual(t, 0, bytes.Compare(res.Marshal(), test.input))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSerialize(t *testing.T) {
|
||||
rk := blst.RandKey()
|
||||
b := rk.Marshal()
|
||||
|
||||
_, err := blst.SecretKeyFromBytes(b)
|
||||
assert.NoError(t, err)
|
||||
}
|
215
shared/bls/blst/signature.go
Normal file
215
shared/bls/blst/signature.go
Normal file
@ -0,0 +1,215 @@
|
||||
// +build linux,amd64 linux,arm64
|
||||
|
||||
package blst
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/iface"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/rand"
|
||||
blst "github.com/supranational/blst/bindings/go"
|
||||
)
|
||||
|
||||
var dst = []byte("BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_")
|
||||
|
||||
const scalarBytes = 32
|
||||
const randBitsEntropy = 64
|
||||
|
||||
// Signature used in the BLS signature scheme.
|
||||
type Signature struct {
|
||||
s *blstSignature
|
||||
}
|
||||
|
||||
// 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 := new(blstSignature).Uncompress(sig)
|
||||
if signature == nil {
|
||||
return nil, errors.New("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.Verify(pubKey.(*PublicKey).p, msg, dst)
|
||||
}
|
||||
|
||||
// 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, len(msgs))
|
||||
rawKeys := make([]*blstPublicKey, len(msgs))
|
||||
for i := 0; i < size; i++ {
|
||||
msgSlices[i] = msgs[i][:]
|
||||
rawKeys[i] = pubKeys[i].(*PublicKey).p
|
||||
}
|
||||
return s.s.AggregateVerify(rawKeys, msgSlices, dst)
|
||||
}
|
||||
|
||||
// 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([]*blstPublicKey, len(pubKeys))
|
||||
for i := 0; i < len(pubKeys); i++ {
|
||||
rawKeys[i] = pubKeys[i].(*PublicKey).p
|
||||
}
|
||||
|
||||
return s.s.FastAggregateVerify(rawKeys, msg[:], dst)
|
||||
}
|
||||
|
||||
// NewAggregateSignature creates a blank aggregate signature.
|
||||
func NewAggregateSignature() iface.Signature {
|
||||
sig := blst.HashToG2([]byte{'m', 'o', 'c', 'k'}, dst).ToAffine()
|
||||
return &Signature{s: sig}
|
||||
}
|
||||
|
||||
// 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]
|
||||
}
|
||||
|
||||
rawSigs := make([]*blstSignature, len(sigs))
|
||||
for i := 0; i < len(sigs); i++ {
|
||||
rawSigs[i] = sigs[i].(*Signature).s
|
||||
}
|
||||
|
||||
signature := new(blstAggregateSignature).Aggregate(rawSigs)
|
||||
if signature == nil {
|
||||
return nil
|
||||
}
|
||||
return &Signature{s: signature.ToAffine()}
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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 [][]byte, msgs [][32]byte, pubKeys []iface.PublicKey) (bool, error) {
|
||||
if featureconfig.Get().SkipBLSVerify {
|
||||
return true, nil
|
||||
}
|
||||
if len(sigs) == 0 || len(pubKeys) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
rawSigs := new(blstSignature).BatchUncompress(sigs)
|
||||
|
||||
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))
|
||||
}
|
||||
mulP1Aff := make([]*blstPublicKey, length)
|
||||
rawMsgs := make([]blst.Message, length)
|
||||
|
||||
for i := 0; i < length; i++ {
|
||||
mulP1Aff[i] = pubKeys[i].(*PublicKey).p
|
||||
rawMsgs[i] = msgs[i][:]
|
||||
}
|
||||
// Secure source of RNG
|
||||
randGen := rand.NewGenerator()
|
||||
|
||||
randFunc := func(scalar *blst.Scalar) {
|
||||
var rbytes [scalarBytes]byte
|
||||
randGen.Read(rbytes[:])
|
||||
scalar.FromBEndian(rbytes[:])
|
||||
}
|
||||
dummySig := new(blstSignature)
|
||||
return dummySig.MultipleAggregateVerify(rawSigs, mulP1Aff, rawMsgs, dst, randFunc, randBitsEntropy), 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.Compress()
|
||||
}
|
||||
|
||||
// Copy returns a full deep copy of a signature.
|
||||
func (s *Signature) Copy() iface.Signature {
|
||||
return &Signature{s: &*s.s}
|
||||
}
|
||||
|
||||
// VerifyCompressed verifies that the compressed signature and pubkey
|
||||
// are valid from the message provided.
|
||||
func VerifyCompressed(signature []byte, pub []byte, msg []byte) bool {
|
||||
return new(blstSignature).VerifyCompressed(signature, pub, msg, dst)
|
||||
}
|
139
shared/bls/blst/signature_test.go
Normal file
139
shared/bls/blst/signature_test.go
Normal file
@ -0,0 +1,139 @@
|
||||
// +build linux,amd64 linux,arm64
|
||||
|
||||
package blst_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/blst"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/iface"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
)
|
||||
|
||||
func TestSignVerify(t *testing.T) {
|
||||
priv := blst.RandKey()
|
||||
pub := priv.PublicKey()
|
||||
msg := []byte("hello")
|
||||
sig := priv.Sign(msg)
|
||||
assert.Equal(t, true, sig.Verify(pub, msg), "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 := blst.RandKey()
|
||||
pub := priv.PublicKey()
|
||||
sig := priv.Sign(msg[:])
|
||||
pubkeys = append(pubkeys, pub)
|
||||
sigs = append(sigs, sig)
|
||||
msgs = append(msgs, msg)
|
||||
}
|
||||
aggSig := blst.Aggregate(sigs)
|
||||
assert.Equal(t, true, aggSig.AggregateVerify(pubkeys, msgs), "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 := blst.RandKey()
|
||||
pub := priv.PublicKey()
|
||||
sig := priv.Sign(msg[:])
|
||||
pubkeys = append(pubkeys, pub)
|
||||
sigs = append(sigs, sig)
|
||||
}
|
||||
aggSig := blst.AggregateSignatures(sigs)
|
||||
assert.Equal(t, true, aggSig.FastAggregateVerify(pubkeys, msg), "Signature did not verify")
|
||||
|
||||
}
|
||||
|
||||
func TestVerifyCompressed(t *testing.T) {
|
||||
priv := blst.RandKey()
|
||||
pub := priv.PublicKey()
|
||||
msg := []byte("hello")
|
||||
sig := priv.Sign(msg)
|
||||
assert.Equal(t, true, sig.Verify(pub, msg), "Non compressed signature did not verify")
|
||||
assert.Equal(t, true, blst.VerifyCompressed(sig.Marshal(), pub.Marshal(), msg), "Compressed signatures and pubkeys did not verify")
|
||||
}
|
||||
|
||||
func TestMultipleSignatureVerification(t *testing.T) {
|
||||
pubkeys := make([]iface.PublicKey, 0, 100)
|
||||
sigs := make([][]byte, 0, 100)
|
||||
var msgs [][32]byte
|
||||
for i := 0; i < 100; i++ {
|
||||
msg := [32]byte{'h', 'e', 'l', 'l', 'o', byte(i)}
|
||||
priv := blst.RandKey()
|
||||
pub := priv.PublicKey()
|
||||
sig := priv.Sign(msg[:]).Marshal()
|
||||
pubkeys = append(pubkeys, pub)
|
||||
sigs = append(sigs, sig)
|
||||
msgs = append(msgs, msg)
|
||||
}
|
||||
verify, err := blst.VerifyMultipleSignatures(sigs, msgs, pubkeys)
|
||||
assert.NoError(t, err, "Signature did not verify")
|
||||
assert.Equal(t, true, verify, "Signature did not verify")
|
||||
}
|
||||
|
||||
func TestFastAggregateVerify_ReturnsFalseOnEmptyPubKeyList(t *testing.T) {
|
||||
var pubkeys []iface.PublicKey
|
||||
msg := [32]byte{'h', 'e', 'l', 'l', 'o'}
|
||||
|
||||
aggSig := blst.NewAggregateSignature()
|
||||
assert.Equal(t, false, aggSig.FastAggregateVerify(pubkeys, msg), "Expected FastAggregateVerify to return false with empty input ")
|
||||
}
|
||||
|
||||
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"),
|
||||
},
|
||||
{
|
||||
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 := blst.SignatureFromBytes(test.input)
|
||||
if test.err != nil {
|
||||
assert.NotEqual(t, nil, err, "No error returned")
|
||||
assert.ErrorContains(t, test.err.Error(), err, "Unexpected error returned")
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.DeepEqual(t, 0, bytes.Compare(res.Marshal(), test.input))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
114
shared/bls/blst/stub.go
Normal file
114
shared/bls/blst/stub.go
Normal file
@ -0,0 +1,114 @@
|
||||
// +build darwin,amd64 windows,amd64 linux,amd64,!blst_enabled linux,arm64,!blst_enabled
|
||||
|
||||
package blst
|
||||
|
||||
import "github.com/prysmaticlabs/prysm/shared/bls/iface"
|
||||
|
||||
// SecretKey -- stub
|
||||
type SecretKey struct{}
|
||||
|
||||
// PublicKey -- stub
|
||||
func (s SecretKey) PublicKey() iface.PublicKey {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
||||
|
||||
// Sign -- stub
|
||||
func (s SecretKey) Sign(msg []byte) iface.Signature {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
||||
|
||||
// Marshal -- stub
|
||||
func (s SecretKey) Marshal() []byte {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
||||
|
||||
// PublicKey -- stub
|
||||
type PublicKey struct{}
|
||||
|
||||
// Marshal -- stub
|
||||
func (p PublicKey) Marshal() []byte {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
||||
|
||||
// Copy -- stub
|
||||
func (p PublicKey) Copy() iface.PublicKey {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
||||
|
||||
// Aggregate -- stub
|
||||
func (p PublicKey) Aggregate(p2 iface.PublicKey) iface.PublicKey {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
||||
|
||||
// Signature -- stub
|
||||
type Signature struct{}
|
||||
|
||||
// Verify -- stub
|
||||
func (s Signature) Verify(pubKey iface.PublicKey, msg []byte) bool {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
||||
|
||||
// AggregateVerify -- stub
|
||||
func (s Signature) AggregateVerify(pubKeys []iface.PublicKey, msgs [][32]byte) bool {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
||||
|
||||
// FastAggregateVerify -- stub
|
||||
func (s Signature) FastAggregateVerify(pubKeys []iface.PublicKey, msg [32]byte) bool {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
||||
|
||||
// Marshal -- stub
|
||||
func (s Signature) Marshal() []byte {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
||||
|
||||
// Copy -- stub
|
||||
func (s Signature) Copy() iface.Signature {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
||||
|
||||
// SecretKeyFromBytes -- stub
|
||||
func SecretKeyFromBytes(privKey []byte) (SecretKey, error) {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
||||
|
||||
// PublicKeyFromBytes -- stub
|
||||
func PublicKeyFromBytes(pubKey []byte) (PublicKey, error) {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
||||
|
||||
// SignatureFromBytes -- stub
|
||||
func SignatureFromBytes(sig []byte) (Signature, error) {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
||||
|
||||
// AggregatePublicKeys -- stub
|
||||
func AggregatePublicKeys(pubs [][]byte) (PublicKey, error) {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
||||
|
||||
// AggregateSignatures -- stub
|
||||
func AggregateSignatures(sigs []iface.Signature) iface.Signature {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
||||
|
||||
// VerifyMultipleSignatures -- stub
|
||||
func VerifyMultipleSignatures(sigs [][]byte, msgs [][32]byte, pubKeys []iface.PublicKey) (bool, error) {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
||||
|
||||
// NewAggregateSignature -- stub
|
||||
func NewAggregateSignature() iface.Signature {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
||||
|
||||
// RandKey -- stub
|
||||
func RandKey() iface.SecretKey {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
||||
|
||||
// VerifyCompressed -- stub
|
||||
func VerifyCompressed(signature []byte, pub []byte, msg []byte) bool {
|
||||
panic("blst is only supported on linux amd64")
|
||||
}
|
@ -44,6 +44,25 @@ func PublicKeyFromBytes(pubKey []byte) (iface.PublicKey, error) {
|
||||
return pubKeyObj, nil
|
||||
}
|
||||
|
||||
// AggregatePublicKeys aggregates the provided raw public keys into a single key.
|
||||
func AggregatePublicKeys(pubs [][]byte) (iface.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()
|
||||
|
@ -4,7 +4,7 @@ package bls
|
||||
// signatures and its respective public keys and
|
||||
// messages required to verify it.
|
||||
type SignatureSet struct {
|
||||
Signatures []Signature
|
||||
Signatures [][]byte
|
||||
PublicKeys []PublicKey
|
||||
Messages [][32]byte
|
||||
}
|
||||
@ -12,7 +12,7 @@ type SignatureSet struct {
|
||||
// NewSet constructs an empty signature set object.
|
||||
func NewSet() *SignatureSet {
|
||||
return &SignatureSet{
|
||||
Signatures: []Signature{},
|
||||
Signatures: [][]byte{},
|
||||
PublicKeys: []PublicKey{},
|
||||
Messages: [][32]byte{},
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ go_test(
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bls/iface: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,11 +9,24 @@ import (
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/iface"
|
||||
"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) {
|
||||
testFolders, testFolderPath := testutil.TestFolders(t, "general", "bls/aggregate/small")
|
||||
|
||||
for _, folder := range testFolders {
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/iface"
|
||||
@ -14,6 +16,18 @@ import (
|
||||
)
|
||||
|
||||
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) {
|
||||
testFolders, testFolderPath := testutil.TestFolders(t, "general", "bls/aggregate_verify/small")
|
||||
|
||||
for i, folder := range testFolders {
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls/iface"
|
||||
@ -14,6 +16,18 @@ import (
|
||||
)
|
||||
|
||||
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) {
|
||||
testFolders, testFolderPath := testutil.TestFolders(t, "general", "bls/fast_aggregate_verify/small")
|
||||
|
||||
for i, folder := range testFolders {
|
||||
|
@ -8,6 +8,8 @@ import (
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
@ -15,6 +17,18 @@ import (
|
||||
)
|
||||
|
||||
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) {
|
||||
testFolders, testFolderPath := testutil.TestFolders(t, "general", "bls/sign/small")
|
||||
|
||||
for i, folder := range testFolders {
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
@ -12,6 +14,18 @@ import (
|
||||
)
|
||||
|
||||
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) {
|
||||
testFolders, testFolderPath := testutil.TestFolders(t, "general", "bls/verify/small")
|
||||
|
||||
for i, folder := range testFolders {
|
||||
|
@ -42,6 +42,7 @@ type Flags struct {
|
||||
InitSyncNoVerify bool // InitSyncNoVerify when initial syncing w/o verifying block's contents.
|
||||
DisableDynamicCommitteeSubnets bool // Disables dynamic attestation committee subnets via p2p.
|
||||
SkipBLSVerify bool // Skips BLS verification across the runtime.
|
||||
EnableBlst bool // Enables new BLS library from supranational.
|
||||
EnableBackupWebhook bool // EnableBackupWebhook to allow database backups to trigger from monitoring port /db/backup.
|
||||
PruneEpochBoundaryStates bool // PruneEpochBoundaryStates prunes the epoch boundary state before last finalized check point.
|
||||
EnableSnappyDBCompression bool // EnableSnappyDBCompression in the database.
|
||||
@ -271,6 +272,10 @@ func ConfigureBeaconChain(ctx *cli.Context) {
|
||||
log.Warn("Disabling advanced check point info cache")
|
||||
cfg.UseCheckPointInfoCache = false
|
||||
}
|
||||
if ctx.Bool(enableBlst.Name) {
|
||||
log.Warn("Enabling new BLS library blst")
|
||||
cfg.EnableBlst = true
|
||||
}
|
||||
Init(cfg)
|
||||
}
|
||||
|
||||
|
@ -145,6 +145,10 @@ var (
|
||||
Name: "init-sync-verbose",
|
||||
Usage: "Enable logging every processed block during initial syncing.",
|
||||
}
|
||||
enableBlst = &cli.BoolFlag{
|
||||
Name: "blst",
|
||||
Usage: "Enable new BLS library, blst, from Supranational",
|
||||
}
|
||||
disableFinalizedDepositsCache = &cli.BoolFlag{
|
||||
Name: "disable-finalized-deposits-cache",
|
||||
Usage: "Disables utilization of cached finalized deposits",
|
||||
@ -652,6 +656,7 @@ var ValidatorFlags = append(deprecatedFlags, []cli.Flag{
|
||||
OnyxTestnet,
|
||||
spadinaTestnet,
|
||||
disableAccountsV2,
|
||||
enableBlst,
|
||||
}...)
|
||||
|
||||
// SlasherFlags contains a list of all the feature flags that apply to the slasher client.
|
||||
@ -694,6 +699,7 @@ var BeaconChainFlags = append(deprecatedFlags, []cli.Flag{
|
||||
disableBatchBlockVerify,
|
||||
initSyncVerbose,
|
||||
disableFinalizedDepositsCache,
|
||||
enableBlst,
|
||||
enableEth1DataMajorityVote,
|
||||
enableAttBroadcastDiscoveryAttempts,
|
||||
enablePeerScorer,
|
||||
|
106
third_party/blst/blst.BUILD
vendored
Normal file
106
third_party/blst/blst.BUILD
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"bindings/go/blst.go",
|
||||
"bindings/go/server.c",
|
||||
],
|
||||
cgo = True,
|
||||
copts = [
|
||||
"-D__BLST_CGO__",
|
||||
"-Ibindings",
|
||||
"-Isrc",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:amd64": [
|
||||
"-mno-avx",
|
||||
"-D__ADX__",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
cdeps = [":blst"],
|
||||
importpath = "github.com/supranational/blst/bindings/go",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"bindings/go/blst_htoc_test.go",
|
||||
"bindings/go/blst_minpk_test.go",
|
||||
"bindings/go/blst_minsig_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
data = glob([
|
||||
"bindings/go/hash_to_curve/*.json",
|
||||
]),
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "blst",
|
||||
srcs = [
|
||||
"bindings/blst.h",
|
||||
"bindings/blst_aux.h",
|
||||
],
|
||||
hdrs = [
|
||||
"bindings/blst.h",
|
||||
"bindings/blst_aux.h",
|
||||
],
|
||||
deps = [
|
||||
":src",
|
||||
":asm",
|
||||
],
|
||||
strip_include_prefix = "bindings",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "asm_hdrs",
|
||||
hdrs = glob([
|
||||
"build/**/*.s",
|
||||
"build/**/*.S",
|
||||
], exclude = ["build/assembly.s"]),
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "asm",
|
||||
srcs = [
|
||||
"build/assembly.S",
|
||||
],
|
||||
copts = [
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:amd64": [
|
||||
"-mno-avx",
|
||||
"-D__ADX__",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
deps = [":asm_hdrs"],
|
||||
linkstatic = True,
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "hdrs",
|
||||
hdrs = glob(
|
||||
[
|
||||
"src/*.c",
|
||||
"src/*.h",
|
||||
],
|
||||
exclude = [
|
||||
"src/server.c",
|
||||
"src/client_*.c",
|
||||
],
|
||||
),
|
||||
strip_include_prefix = "src",
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "src",
|
||||
srcs = [
|
||||
"src/server.c",
|
||||
],
|
||||
deps = [
|
||||
":hdrs",
|
||||
],
|
||||
)
|
@ -5,12 +5,6 @@ load("@io_bazel_rules_docker//cc:image.bzl", CC_DEFAULT_BASE = "DEFAULT_BASE")
|
||||
load("@io_bazel_rules_docker//go:image.bzl", GO_DEFAULT_BASE = "DEFAULT_BASE")
|
||||
load("//tools:build_settings.bzl", "base_image")
|
||||
|
||||
alias(
|
||||
name = "kubesec",
|
||||
actual = "@com_github_shyiko_kubesec//:kubesec",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
sh_binary(
|
||||
name = "fuzz_wrapper",
|
||||
srcs = ["fuzz_wrapper.sh"],
|
||||
|
@ -1,26 +0,0 @@
|
||||
"""TODO: Add doc here"""
|
||||
|
||||
def _k8s_encrypted_secret_impl(ctx):
|
||||
ctx.actions.run_shell(
|
||||
inputs = [ctx.file.template],
|
||||
outputs = [ctx.outputs.out],
|
||||
progress_message = "Decrypting %s" % ctx.file.template,
|
||||
tools = [ctx.executable._kubesec],
|
||||
command = "%s decrypt %s > %s" % (ctx.executable._kubesec.path, ctx.file.template.path, ctx.outputs.out.path),
|
||||
)
|
||||
|
||||
k8s_encrypted_secret = rule(
|
||||
implementation = _k8s_encrypted_secret_impl,
|
||||
attrs = {
|
||||
"_kubesec": attr.label(
|
||||
executable = True,
|
||||
cfg = "host",
|
||||
default = "//tools:kubesec",
|
||||
),
|
||||
"template": attr.label(
|
||||
allow_single_file = True,
|
||||
mandatory = True,
|
||||
),
|
||||
"out": attr.output(mandatory = True),
|
||||
},
|
||||
)
|
Loading…
Reference in New Issue
Block a user