diff --git a/.bazelrc b/.bazelrc index 6a6b3f7c5..14f31769e 100644 --- a/.bazelrc +++ b/.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" diff --git a/.buildkite-bazelrc b/.buildkite-bazelrc index 5c9039c52..02952f06a 100644 --- a/.buildkite-bazelrc +++ b/.buildkite-bazelrc @@ -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/ diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index f91015923..af134b4c9 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -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 diff --git a/beacon-chain/blockchain/process_block.go b/beacon-chain/blockchain/process_block.go index d9cdd6d89..e8b7090e7 100644 --- a/beacon-chain/blockchain/process_block.go +++ b/beacon-chain/blockchain/process_block.go @@ -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 } diff --git a/beacon-chain/core/blocks/attestation.go b/beacon-chain/core/blocks/attestation.go index 8b8b9316b..c99126cf2 100644 --- a/beacon-chain/core/blocks/attestation.go +++ b/beacon-chain/core/blocks/attestation.go @@ -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) } diff --git a/beacon-chain/core/blocks/deposit.go b/beacon-chain/core/blocks/deposit.go index 543580709..38dc82ecf 100644 --- a/beacon-chain/core/blocks/deposit.go +++ b/beacon-chain/core/blocks/deposit.go @@ -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") diff --git a/beacon-chain/core/blocks/signature.go b/beacon-chain/core/blocks/signature.go index db8a3d43b..e84cdd9d0 100644 --- a/beacon-chain/core/blocks/signature.go +++ b/beacon-chain/core/blocks/signature.go @@ -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[:]) - if err != nil { - return nil, errors.Wrap(err, "could not deserialize validator public key") - } - if pk == nil { - pk = p - } else { - pk.Aggregate(p) - } + pubkeys[i] = pubkeyAtIdx[:] } - pks[i] = pk + aggP, err := bls.AggregatePublicKeys(pubkeys) + if err != nil { + return nil, err + } + pks[i] = aggP root, err := helpers.ComputeSigningRoot(ia.Data, domain) if err != nil { diff --git a/beacon-chain/core/helpers/signing_root.go b/beacon-chain/core/helpers/signing_root.go index 333633c81..b79ad462c 100644 --- a/beacon-chain/core/helpers/signing_root.go +++ b/beacon-chain/core/helpers/signing_root.go @@ -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 diff --git a/deps.bzl b/deps.bzl index 77dc98393..487603815 100644 --- a/deps.bzl +++ b/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", diff --git a/go.mod b/go.mod index 0b2e2b079..db3f1b028 100644 --- a/go.mod +++ b/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 diff --git a/go.sum b/go.sum index 35feca34b..67ca1cbb0 100644 --- a/go.sum +++ b/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= diff --git a/shared/bls/BUILD.bazel b/shared/bls/BUILD.bazel index 4df4c0c44..8f03dcd91 100644 --- a/shared/bls/BUILD.bazel +++ b/shared/bls/BUILD.bazel @@ -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", ], ) diff --git a/shared/bls/bls.go b/shared/bls/bls.go index 8b5f5d50f..0dc0cee85 100644 --- a/shared/bls/bls.go +++ b/shared/bls/bls.go @@ -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) +} diff --git a/shared/bls/blst/BUILD.bazel b/shared/bls/blst/BUILD.bazel new file mode 100644 index 000000000..351446254 --- /dev/null +++ b/shared/bls/blst/BUILD.bazel @@ -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", + ], +) diff --git a/shared/bls/blst/aliases.go b/shared/bls/blst/aliases.go new file mode 100644 index 000000000..27b89a463 --- /dev/null +++ b/shared/bls/blst/aliases.go @@ -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 diff --git a/shared/bls/blst/bls_benchmark_test.go b/shared/bls/blst/bls_benchmark_test.go new file mode 100644 index 000000000..1e25aa118 --- /dev/null +++ b/shared/bls/blst/bls_benchmark_test.go @@ -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 + } +} diff --git a/shared/bls/blst/doc.go b/shared/bls/blst/doc.go new file mode 100644 index 000000000..5c03488ed --- /dev/null +++ b/shared/bls/blst/doc.go @@ -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 diff --git a/shared/bls/blst/init.go b/shared/bls/blst/init.go new file mode 100644 index 000000000..a88d7f587 --- /dev/null +++ b/shared/bls/blst/init.go @@ -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) +} diff --git a/shared/bls/blst/public_key.go b/shared/bls/blst/public_key.go new file mode 100644 index 000000000..42d2cf420 --- /dev/null +++ b/shared/bls/blst/public_key.go @@ -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 +} diff --git a/shared/bls/blst/public_key_test.go b/shared/bls/blst/public_key_test.go new file mode 100644 index 000000000..a33df46cd --- /dev/null +++ b/shared/bls/blst/public_key_test.go @@ -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") +} diff --git a/shared/bls/blst/secret_key.go b/shared/bls/blst/secret_key.go new file mode 100644 index 000000000..7bb5dea6a --- /dev/null +++ b/shared/bls/blst/secret_key.go @@ -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 +} diff --git a/shared/bls/blst/secret_key_test.go b/shared/bls/blst/secret_key_test.go new file mode 100644 index 000000000..9ac10ad0b --- /dev/null +++ b/shared/bls/blst/secret_key_test.go @@ -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) +} diff --git a/shared/bls/blst/signature.go b/shared/bls/blst/signature.go new file mode 100644 index 000000000..d2c1600b8 --- /dev/null +++ b/shared/bls/blst/signature.go @@ -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) +} diff --git a/shared/bls/blst/signature_test.go b/shared/bls/blst/signature_test.go new file mode 100644 index 000000000..125d4ba0e --- /dev/null +++ b/shared/bls/blst/signature_test.go @@ -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)) + } + }) + } +} diff --git a/shared/bls/blst/stub.go b/shared/bls/blst/stub.go new file mode 100644 index 000000000..bcd66219c --- /dev/null +++ b/shared/bls/blst/stub.go @@ -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") +} diff --git a/shared/bls/herumi/public_key.go b/shared/bls/herumi/public_key.go index 862df9f67..abf94116c 100644 --- a/shared/bls/herumi/public_key.go +++ b/shared/bls/herumi/public_key.go @@ -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() diff --git a/shared/bls/signature_set.go b/shared/bls/signature_set.go index 2fe75fea5..dee930e3b 100644 --- a/shared/bls/signature_set.go +++ b/shared/bls/signature_set.go @@ -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{}, } diff --git a/shared/bls/spectest/BUILD.bazel b/shared/bls/spectest/BUILD.bazel index cbf6c02ae..98aad8fb6 100644 --- a/shared/bls/spectest/BUILD.bazel +++ b/shared/bls/spectest/BUILD.bazel @@ -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", diff --git a/shared/bls/spectest/aggregate_test.go b/shared/bls/spectest/aggregate_test.go index 2f9d9bcd1..9777d5c61 100644 --- a/shared/bls/spectest/aggregate_test.go +++ b/shared/bls/spectest/aggregate_test.go @@ -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 { diff --git a/shared/bls/spectest/aggregate_verify_test.go b/shared/bls/spectest/aggregate_verify_test.go index 5e42ac9f5..6b1ebddaa 100644 --- a/shared/bls/spectest/aggregate_verify_test.go +++ b/shared/bls/spectest/aggregate_verify_test.go @@ -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 { diff --git a/shared/bls/spectest/fast_aggregate_verify_test.go b/shared/bls/spectest/fast_aggregate_verify_test.go index 7a00cdd47..2d41da6ec 100644 --- a/shared/bls/spectest/fast_aggregate_verify_test.go +++ b/shared/bls/spectest/fast_aggregate_verify_test.go @@ -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 { diff --git a/shared/bls/spectest/sign_test.go b/shared/bls/spectest/sign_test.go index 67433273d..eb167dd58 100644 --- a/shared/bls/spectest/sign_test.go +++ b/shared/bls/spectest/sign_test.go @@ -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 { diff --git a/shared/bls/spectest/verify_test.go b/shared/bls/spectest/verify_test.go index a45245db5..3641bb04d 100644 --- a/shared/bls/spectest/verify_test.go +++ b/shared/bls/spectest/verify_test.go @@ -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 { diff --git a/shared/featureconfig/config.go b/shared/featureconfig/config.go index 4e489a0b3..3059e4945 100644 --- a/shared/featureconfig/config.go +++ b/shared/featureconfig/config.go @@ -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) } diff --git a/shared/featureconfig/flags.go b/shared/featureconfig/flags.go index cb0bc610a..313aa53cf 100644 --- a/shared/featureconfig/flags.go +++ b/shared/featureconfig/flags.go @@ -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, diff --git a/third_party/blst/blst.BUILD b/third_party/blst/blst.BUILD new file mode 100644 index 000000000..fe64030fb --- /dev/null +++ b/third_party/blst/blst.BUILD @@ -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", + ], +) diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel index 9f1d84395..d41244fd2 100644 --- a/tools/BUILD.bazel +++ b/tools/BUILD.bazel @@ -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"], diff --git a/tools/kubesec.bzl b/tools/kubesec.bzl deleted file mode 100644 index 2e969897b..000000000 --- a/tools/kubesec.bzl +++ /dev/null @@ -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), - }, -)