From 18e1d433605724229076821f113ee04b0a9cd42b Mon Sep 17 00:00:00 2001 From: Nishant Das Date: Fri, 17 Sep 2021 09:32:23 +0800 Subject: [PATCH] Update blst to v0.3.5 and add BLS spec tests (#9611) * add new dep * add changes so far * fix all tests Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com> --- WORKSPACE | 17 +++++ crypto/bls/common/BUILD.bazel | 2 +- deps.bzl | 6 +- go.mod | 2 +- go.sum | 4 +- testing/bls/BUILD.bazel | 51 ++++++++++++++ testing/bls/aggregate_test.go | 44 ++++++++++++ testing/bls/aggregate_test.yaml.go | 9 +++ testing/bls/aggregate_verify_test.go | 64 ++++++++++++++++++ testing/bls/aggregate_verify_test.yaml.go | 13 ++++ testing/bls/batch_verify_test.go | 63 +++++++++++++++++ testing/bls/batch_verify_test.yaml.go | 13 ++++ testing/bls/deserialization_G1_test.go | 41 ++++++++++++ testing/bls/deserialization_G1_test.yaml.go | 11 +++ testing/bls/deserialization_G2_test.go | 33 +++++++++ testing/bls/deserialization_G2_test.yaml.go | 11 +++ testing/bls/fast_aggregate_verify_test.go | 67 +++++++++++++++++++ .../bls/fast_aggregate_verify_test.yaml.go | 15 +++++ testing/bls/hash_to_G2_test.go | 44 ++++++++++++ testing/bls/hash_to_G2_test.yaml.go | 14 ++++ testing/bls/sign_test.go | 55 +++++++++++++++ testing/bls/sign_test.yaml.go | 12 ++++ testing/bls/utils/BUILD.bazel | 14 ++++ testing/bls/utils/utils.go | 32 +++++++++ testing/bls/verify_test.go | 57 ++++++++++++++++ testing/bls/verify_test.yaml.go | 13 ++++ 26 files changed, 700 insertions(+), 7 deletions(-) create mode 100644 testing/bls/BUILD.bazel create mode 100644 testing/bls/aggregate_test.go create mode 100644 testing/bls/aggregate_test.yaml.go create mode 100644 testing/bls/aggregate_verify_test.go create mode 100644 testing/bls/aggregate_verify_test.yaml.go create mode 100644 testing/bls/batch_verify_test.go create mode 100644 testing/bls/batch_verify_test.yaml.go create mode 100644 testing/bls/deserialization_G1_test.go create mode 100644 testing/bls/deserialization_G1_test.yaml.go create mode 100644 testing/bls/deserialization_G2_test.go create mode 100644 testing/bls/deserialization_G2_test.yaml.go create mode 100644 testing/bls/fast_aggregate_verify_test.go create mode 100644 testing/bls/fast_aggregate_verify_test.yaml.go create mode 100644 testing/bls/hash_to_G2_test.go create mode 100644 testing/bls/hash_to_G2_test.yaml.go create mode 100644 testing/bls/sign_test.go create mode 100644 testing/bls/sign_test.yaml.go create mode 100644 testing/bls/utils/BUILD.bazel create mode 100644 testing/bls/utils/utils.go create mode 100644 testing/bls/verify_test.go create mode 100644 testing/bls/verify_test.yaml.go diff --git a/WORKSPACE b/WORKSPACE index 9a2ab2e3a..793946dec 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -199,6 +199,8 @@ filegroup( consensus_spec_version = "v1.1.0-beta.4" +bls_test_version = "v0.1.1" + http_archive( name = "consensus_spec_tests_general", build_file_content = """ @@ -263,6 +265,21 @@ filegroup( url = "https://github.com/ethereum/consensus-specs/archive/refs/tags/%s.tar.gz" % consensus_spec_version, ) +http_archive( + name = "bls_spec_tests", + build_file_content = """ +filegroup( + name = "test_data", + srcs = glob([ + "**/*.yaml", + ]), + visibility = ["//visibility:public"], +) + """, + sha256 = "93c7d006e7c5b882cbd11dc9ec6c5d0e07f4a8c6b27a32f964eb17cf2db9763a", + url = "https://github.com/ethereum/bls12-381-tests/releases/download/%s/bls_tests_yaml.tar.gz" % bls_test_version, +) + http_archive( name = "eth2_networks", build_file_content = """ diff --git a/crypto/bls/common/BUILD.bazel b/crypto/bls/common/BUILD.bazel index c5f6faaf4..74f5835c1 100644 --- a/crypto/bls/common/BUILD.bazel +++ b/crypto/bls/common/BUILD.bazel @@ -10,6 +10,6 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/crypto/bls/common", visibility = [ "//crypto/bls:__subpackages__", - "//testing/spectest:__subpackages__", + "//testing:__subpackages__", ], ) diff --git a/deps.bzl b/deps.bzl index 28208d3fb..e07780daf 100644 --- a/deps.bzl +++ b/deps.bzl @@ -3337,11 +3337,11 @@ def prysm_deps(): http_archive( name = "com_github_supranational_blst", urls = [ - "https://github.com/supranational/blst/archive/624d0351000111276aa70a32145945d2645e49a9.tar.gz", + "https://github.com/supranational/blst/archive/0eab29bb46449d45be14df98ce38cbb8f9a05918.tar.gz", ], - strip_prefix = "blst-624d0351000111276aa70a32145945d2645e49a9", + strip_prefix = "blst-0eab29bb46449d45be14df98ce38cbb8f9a05918", build_file = "//third_party:blst/blst.BUILD", - sha256 = "6118737ddc0652f3a874fbe29e09a80c66c604d933b8cd478e5f2b7454860c6e", + sha256 = "29e818ea9636a604d86f53a2bab7ad5cba20ff043606edb81f3a384ff58393cd", ) go_repository( name = "com_github_syndtr_goleveldb", diff --git a/go.mod b/go.mod index 17cdbe3ca..e68c32ada 100644 --- a/go.mod +++ b/go.mod @@ -94,7 +94,7 @@ require ( github.com/sirupsen/logrus v1.6.0 github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969 github.com/stretchr/testify v1.7.0 - github.com/supranational/blst v0.3.4 + github.com/supranational/blst v0.3.5 github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e github.com/trailofbits/go-mutexasserts v0.0.0-20200708152505-19999e7d3cef github.com/tyler-smith/go-bip39 v1.1.0 diff --git a/go.sum b/go.sum index 7b3a3a9d2..c404ecffb 100644 --- a/go.sum +++ b/go.sum @@ -1275,8 +1275,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/supranational/blst v0.3.4 h1:iZE9lBMoywK2uy2U/5hDOvobQk9FnOQ2wNlu9GmRCoA= -github.com/supranational/blst v0.3.4/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/supranational/blst v0.3.5 h1:/pey7U712GgJBSD1XTiJ5iBqjYIH3QNdrjRoGXlJJ60= +github.com/supranational/blst v0.3.5/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.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs= github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= diff --git a/testing/bls/BUILD.bazel b/testing/bls/BUILD.bazel new file mode 100644 index 000000000..7e361cab6 --- /dev/null +++ b/testing/bls/BUILD.bazel @@ -0,0 +1,51 @@ +load("@prysm//tools/go:def.bzl", "go_library", "go_test") + +# gazelle:resolve go github.com/supranational/blst/bindings/go @com_github_supranational_blst//:go_default_library + +go_test( + name = "go_default_test", + size = "small", + srcs = [ + "aggregate_test.go", + "aggregate_verify_test.go", + "batch_verify_test.go", + "deserialization_G1_test.go", + "deserialization_G2_test.go", + "fast_aggregate_verify_test.go", + "hash_to_G2_test.go", + "sign_test.go", + "verify_test.go", + ], + data = glob(["*.yaml"]) + [ + "@bls_spec_tests//:test_data", + ], + embed = [":go_default_library"], + shard_count = 4, + tags = ["spectest"], + deps = [ + "//crypto/bls:go_default_library", + "//crypto/bls/common:go_default_library", + "//shared/bytesutil:go_default_library", + "//shared/testutil/require:go_default_library", + "//testing/bls/utils:go_default_library", + "@com_github_ghodss_yaml//:go_default_library", + "@com_github_supranational_blst//:go_default_library", + ], +) + +go_library( + name = "go_default_library", + srcs = [ + "aggregate_test.yaml.go", + "aggregate_verify_test.yaml.go", + "batch_verify_test.yaml.go", + "deserialization_G1_test.yaml.go", + "deserialization_G2_test.yaml.go", + "fast_aggregate_verify_test.yaml.go", + "hash_to_G2_test.yaml.go", + "sign_test.yaml.go", + "verify_test.yaml.go", + ], + importpath = "github.com/prysmaticlabs/prysm/testing/bls", + visibility = ["//visibility:public"], +) diff --git a/testing/bls/aggregate_test.go b/testing/bls/aggregate_test.go new file mode 100644 index 000000000..a736b89ba --- /dev/null +++ b/testing/bls/aggregate_test.go @@ -0,0 +1,44 @@ +package bls + +import ( + "encoding/hex" + "testing" + + "github.com/ghodss/yaml" + "github.com/prysmaticlabs/prysm/crypto/bls" + "github.com/prysmaticlabs/prysm/crypto/bls/common" + "github.com/prysmaticlabs/prysm/shared/testutil/require" + "github.com/prysmaticlabs/prysm/testing/bls/utils" +) + +func TestAggregate(t *testing.T) { + t.Run("blst", testAggregate) +} + +func testAggregate(t *testing.T) { + fNames, fContent := utils.RetrieveFiles("aggregate", t) + for i, folder := range fNames { + t.Run(folder, func(t *testing.T) { + test := &AggregateTest{} + require.NoError(t, yaml.Unmarshal(fContent[i], test)) + var sigs []common.Signature + for _, s := range test.Input { + sigBytes, err := hex.DecodeString(s[2:]) + require.NoError(t, err) + sig, err := bls.SignatureFromBytes(sigBytes) + require.NoError(t, err) + sigs = append(sigs, sig) + } + if len(test.Input) == 0 { + if test.Output != "" { + t.Fatalf("Output Aggregate is not of zero length:Output %s", test.Output) + } + return + } + sig := bls.AggregateSignatures(sigs) + outputBytes, err := hex.DecodeString(test.Output[2:]) + require.NoError(t, err) + require.DeepEqual(t, outputBytes, sig.Marshal()) + }) + } +} diff --git a/testing/bls/aggregate_test.yaml.go b/testing/bls/aggregate_test.yaml.go new file mode 100644 index 000000000..ef3ae80e6 --- /dev/null +++ b/testing/bls/aggregate_test.yaml.go @@ -0,0 +1,9 @@ +// Code generated by yaml_to_go. DO NOT EDIT. +// source: aggregate.yaml + +package bls + +type AggregateTest struct { + Input []string `json:"input"` + Output string `json:"output" ssz:"size=96"` +} diff --git a/testing/bls/aggregate_verify_test.go b/testing/bls/aggregate_verify_test.go new file mode 100644 index 000000000..5608d476d --- /dev/null +++ b/testing/bls/aggregate_verify_test.go @@ -0,0 +1,64 @@ +package bls + +import ( + "encoding/hex" + "errors" + "testing" + + "github.com/ghodss/yaml" + "github.com/prysmaticlabs/prysm/crypto/bls" + "github.com/prysmaticlabs/prysm/crypto/bls/common" + "github.com/prysmaticlabs/prysm/shared/bytesutil" + "github.com/prysmaticlabs/prysm/shared/testutil/require" + "github.com/prysmaticlabs/prysm/testing/bls/utils" +) + +func TestAggregateVerify(t *testing.T) { + t.Run("blst", testAggregateVerify) +} + +func testAggregateVerify(t *testing.T) { + fNames, fContent := utils.RetrieveFiles("aggregate_verify", t) + + for i, file := range fNames { + t.Run(file, func(t *testing.T) { + test := &AggregateVerifyTest{} + require.NoError(t, yaml.Unmarshal(fContent[i], test)) + pubkeys := make([]common.PublicKey, 0, len(test.Input.Pubkeys)) + msgs := make([][32]byte, 0, len(test.Input.Messages)) + for _, pubKey := range test.Input.Pubkeys { + pkBytes, err := hex.DecodeString(pubKey[2:]) + require.NoError(t, err) + pk, err := bls.PublicKeyFromBytes(pkBytes) + if err != nil { + if test.Output == false && errors.Is(err, common.ErrInfinitePubKey) { + return + } + t.Fatalf("cannot unmarshal pubkey: %v", err) + } + pubkeys = append(pubkeys, pk) + } + for _, msg := range test.Input.Messages { + msgBytes, err := hex.DecodeString(msg[2:]) + require.NoError(t, err) + require.Equal(t, 32, len(msgBytes)) + msgs = append(msgs, bytesutil.ToBytes32(msgBytes)) + } + sigBytes, err := hex.DecodeString(test.Input.Signature[2:]) + require.NoError(t, err) + sig, err := bls.SignatureFromBytes(sigBytes) + if err != nil { + if test.Output == false { + return + } + t.Fatalf("Cannot unmarshal input to signature: %v", err) + } + + verified := sig.AggregateVerify(pubkeys, msgs) + if verified != test.Output { + t.Fatalf("Signature does not match the expected verification output. "+ + "Expected %#v but received %#v for test case %d", test.Output, verified, i) + } + }) + } +} diff --git a/testing/bls/aggregate_verify_test.yaml.go b/testing/bls/aggregate_verify_test.yaml.go new file mode 100644 index 000000000..0c5b0f754 --- /dev/null +++ b/testing/bls/aggregate_verify_test.yaml.go @@ -0,0 +1,13 @@ +// Code generated by yaml_to_go. DO NOT EDIT. +// source: aggregate_verify.yaml + +package bls + +type AggregateVerifyTest struct { + Input struct { + Pubkeys []string `json:"pubkeys"` + Messages []string `json:"messages"` + Signature string `json:"signature"` + } `json:"input"` + Output bool `json:"output"` +} diff --git a/testing/bls/batch_verify_test.go b/testing/bls/batch_verify_test.go new file mode 100644 index 000000000..538bcd09f --- /dev/null +++ b/testing/bls/batch_verify_test.go @@ -0,0 +1,63 @@ +package bls + +import ( + "encoding/hex" + "errors" + "testing" + + "github.com/ghodss/yaml" + "github.com/prysmaticlabs/prysm/crypto/bls" + "github.com/prysmaticlabs/prysm/crypto/bls/common" + "github.com/prysmaticlabs/prysm/shared/bytesutil" + "github.com/prysmaticlabs/prysm/shared/testutil/require" + "github.com/prysmaticlabs/prysm/testing/bls/utils" +) + +func TestBatchVerify(t *testing.T) { + t.Run("blst", testBatchVerify) +} + +func testBatchVerify(t *testing.T) { + fNames, fContent := utils.RetrieveFiles("batch_verify", t) + + for i, file := range fNames { + t.Run(file, func(t *testing.T) { + test := &BatchVerifyTest{} + require.NoError(t, yaml.Unmarshal(fContent[i], test)) + + pubkeys := make([]common.PublicKey, len(test.Input.Pubkeys)) + messages := make([][32]byte, len(test.Input.Messages)) + signatures := make([][]byte, len(test.Input.Signatures)) + for j, raw := range test.Input.Pubkeys { + pkBytes, err := hex.DecodeString(raw[2:]) + require.NoError(t, err) + pk, err := bls.PublicKeyFromBytes(pkBytes) + if err != nil { + if test.Output == false && errors.Is(err, common.ErrInfinitePubKey) { + return + } + t.Fatalf("cannot unmarshal pubkey: %v", err) + } + pubkeys[j] = pk + } + for j, raw := range test.Input.Messages { + msgBytes, err := hex.DecodeString(raw[2:]) + require.NoError(t, err) + messages[j] = bytesutil.ToBytes32(msgBytes) + } + for j, raw := range test.Input.Signatures { + sigBytes, err := hex.DecodeString(raw[2:]) + require.NoError(t, err) + signatures[j] = sigBytes + } + + verified, err := bls.VerifyMultipleSignatures(signatures, messages, pubkeys) + require.NoError(t, err) + if verified != test.Output { + t.Fatalf("Signature does not match the expected verification output. "+ + "Expected %#v but received %#v for test case %d", test.Output, verified, i) + } + t.Log("Success") + }) + } +} diff --git a/testing/bls/batch_verify_test.yaml.go b/testing/bls/batch_verify_test.yaml.go new file mode 100644 index 000000000..1cf9c2526 --- /dev/null +++ b/testing/bls/batch_verify_test.yaml.go @@ -0,0 +1,13 @@ +// Code generated by yaml_to_go. DO NOT EDIT. +// source: batch_verify.yaml + +package bls + +type BatchVerifyTest struct { + Input struct { + Pubkeys []string `json:"pubkeys"` + Messages []string `json:"messages"` + Signatures []string `json:"signatures"` + } `json:"input"` + Output bool `json:"output"` +} diff --git a/testing/bls/deserialization_G1_test.go b/testing/bls/deserialization_G1_test.go new file mode 100644 index 000000000..18537e911 --- /dev/null +++ b/testing/bls/deserialization_G1_test.go @@ -0,0 +1,41 @@ +package bls + +import ( + "encoding/hex" + "strings" + "testing" + + "github.com/ghodss/yaml" + "github.com/prysmaticlabs/prysm/crypto/bls" + "github.com/prysmaticlabs/prysm/crypto/bls/common" + "github.com/prysmaticlabs/prysm/shared/testutil/require" + "github.com/prysmaticlabs/prysm/testing/bls/utils" +) + +func TestDeserializationG1(t *testing.T) { + t.Run("blst", testDeserializationG1) +} + +func testDeserializationG1(t *testing.T) { + fNames, fContent := utils.RetrieveFiles("deserialization_G1", t) + + for i, file := range fNames { + content := fContent[i] + t.Run(file, func(t *testing.T) { + test := &DeserializationG1Test{} + require.NoError(t, yaml.Unmarshal(content, test)) + rawKey, err := hex.DecodeString(test.Input.Pubkey) + require.NoError(t, err) + + _, err = bls.PublicKeyFromBytes(rawKey) + // Exit early if we encounter an infinite key here. + if strings.Contains(file, "deserialization_succeeds_infinity_with_true_b_flag") && + err == common.ErrInfinitePubKey { + t.Log("Success") + return + } + require.Equal(t, test.Output, err == nil) + t.Log("Success") + }) + } +} diff --git a/testing/bls/deserialization_G1_test.yaml.go b/testing/bls/deserialization_G1_test.yaml.go new file mode 100644 index 000000000..73a184b70 --- /dev/null +++ b/testing/bls/deserialization_G1_test.yaml.go @@ -0,0 +1,11 @@ +// Code generated by yaml_to_go. DO NOT EDIT. +// source: hash_to_G2.yaml + +package bls + +type DeserializationG1Test struct { + Input struct { + Pubkey string `json:"pubkey"` + } `json:"input"` + Output bool `json:"output"` +} diff --git a/testing/bls/deserialization_G2_test.go b/testing/bls/deserialization_G2_test.go new file mode 100644 index 000000000..392e87fb3 --- /dev/null +++ b/testing/bls/deserialization_G2_test.go @@ -0,0 +1,33 @@ +package bls + +import ( + "encoding/hex" + "testing" + + "github.com/ghodss/yaml" + "github.com/prysmaticlabs/prysm/crypto/bls" + "github.com/prysmaticlabs/prysm/shared/testutil/require" + "github.com/prysmaticlabs/prysm/testing/bls/utils" +) + +func TestDeserializationG2(t *testing.T) { + t.Run("blst", testDeserializationG2) +} + +func testDeserializationG2(t *testing.T) { + fNames, fContent := utils.RetrieveFiles("deserialization_G2", t) + + for i, file := range fNames { + content := fContent[i] + t.Run(file, func(t *testing.T) { + test := &DeserializationG2Test{} + require.NoError(t, yaml.Unmarshal(content, test)) + rawKey, err := hex.DecodeString(test.Input.Signature) + require.NoError(t, err) + + _, err = bls.SignatureFromBytes(rawKey) + require.Equal(t, test.Output, err == nil) + t.Log("Success") + }) + } +} diff --git a/testing/bls/deserialization_G2_test.yaml.go b/testing/bls/deserialization_G2_test.yaml.go new file mode 100644 index 000000000..3941758ed --- /dev/null +++ b/testing/bls/deserialization_G2_test.yaml.go @@ -0,0 +1,11 @@ +// Code generated by yaml_to_go. DO NOT EDIT. +// source: hash_to_G2.yaml + +package bls + +type DeserializationG2Test struct { + Input struct { + Signature string `json:"signature"` + } `json:"input"` + Output bool `json:"output"` +} diff --git a/testing/bls/fast_aggregate_verify_test.go b/testing/bls/fast_aggregate_verify_test.go new file mode 100644 index 000000000..dfc188179 --- /dev/null +++ b/testing/bls/fast_aggregate_verify_test.go @@ -0,0 +1,67 @@ +package bls + +import ( + "encoding/hex" + "errors" + "testing" + + "github.com/ghodss/yaml" + "github.com/prysmaticlabs/prysm/crypto/bls" + "github.com/prysmaticlabs/prysm/crypto/bls/common" + "github.com/prysmaticlabs/prysm/shared/bytesutil" + "github.com/prysmaticlabs/prysm/shared/testutil/require" + "github.com/prysmaticlabs/prysm/testing/bls/utils" +) + +func TestFastAggregateVerify(t *testing.T) { + t.Run("blst", testFastAggregateVerify) +} + +func testFastAggregateVerify(t *testing.T) { + fNames, fContent := utils.RetrieveFiles("fast_aggregate_verify", t) + + for i, file := range fNames { + t.Run(file, func(t *testing.T) { + test := &FastAggregateVerifyTest{} + require.NoError(t, yaml.Unmarshal(fContent[i], test)) + + pubkeys := make([]common.PublicKey, len(test.Input.Pubkeys)) + for j, raw := range test.Input.Pubkeys { + pkBytes, err := hex.DecodeString(raw[2:]) + require.NoError(t, err) + pk, err := bls.PublicKeyFromBytes(pkBytes) + if err != nil { + if test.Output == false && errors.Is(err, common.ErrInfinitePubKey) { + return + } + t.Fatalf("cannot unmarshal pubkey: %v", err) + } + pubkeys[j] = pk + } + + msg := test.Input.Message + // TODO(#7632): Remove when https://github.com/ethereum/consensus-spec-tests/issues/22 is resolved. + if msg == "" { + msg = test.Input.Messages + } + msgBytes, err := hex.DecodeString(msg[2:]) + require.NoError(t, err) + sigBytes, err := hex.DecodeString(test.Input.Signature[2:]) + require.NoError(t, err) + sig, err := bls.SignatureFromBytes(sigBytes) + if err != nil { + if test.Output == false { + return + } + t.Fatalf("Cannot unmarshal input to signature: %v", err) + } + + verified := sig.FastAggregateVerify(pubkeys, bytesutil.ToBytes32(msgBytes)) + if verified != test.Output { + t.Fatalf("Signature does not match the expected verification output. "+ + "Expected %#v but received %#v for test case %d", test.Output, verified, i) + } + t.Log("Success") + }) + } +} diff --git a/testing/bls/fast_aggregate_verify_test.yaml.go b/testing/bls/fast_aggregate_verify_test.yaml.go new file mode 100644 index 000000000..38e959449 --- /dev/null +++ b/testing/bls/fast_aggregate_verify_test.yaml.go @@ -0,0 +1,15 @@ +// Code generated by yaml_to_go. DO NOT EDIT. +// source: fast_aggregate_verify.yaml + +package bls + +type FastAggregateVerifyTest struct { + Input struct { + Pubkeys []string `json:"pubkeys"` + Message string `json:"message"` + // TODO(#7632): Remove when https://github.com/ethereum/consensus-spec-tests/issues/22 is resolved. + Messages string `json:"messages"` + Signature string `json:"signature"` + } `json:"input"` + Output bool `json:"output"` +} diff --git a/testing/bls/hash_to_G2_test.go b/testing/bls/hash_to_G2_test.go new file mode 100644 index 000000000..ce18ee8bd --- /dev/null +++ b/testing/bls/hash_to_G2_test.go @@ -0,0 +1,44 @@ +package bls + +import ( + "bytes" + "encoding/hex" + "strings" + "testing" + + "github.com/ghodss/yaml" + "github.com/prysmaticlabs/prysm/shared/testutil/require" + "github.com/prysmaticlabs/prysm/testing/bls/utils" + blst "github.com/supranational/blst/bindings/go" +) + +func TestHashToG2(t *testing.T) { + t.Run("blst", testHashToG2) +} + +func testHashToG2(t *testing.T) { + t.Skip("Hash To G2 needs co-ordinates exposed") + fNames, fContent := utils.RetrieveFiles("hash_to_G2", t) + + for i, file := range fNames { + content := fContent[i] + t.Run(file, func(t *testing.T) { + test := &HashToG2Test{} + require.NoError(t, yaml.Unmarshal(content, test)) + + msgBytes := []byte(test.Input.Message) + + splitX := strings.Split(test.Output.X, ",") + outputX, err := hex.DecodeString(splitX[0][2:]) + require.NoError(t, err) + + point := blst.HashToG2(msgBytes, nil) + val := point.Compress() + if !bytes.Equal(val, outputX) { + t.Fatalf("Retrieved X value does not match output. "+ + "Expected %#v but received %#v for test case %d", outputX, val, i) + } + t.Log("Success") + }) + } +} diff --git a/testing/bls/hash_to_G2_test.yaml.go b/testing/bls/hash_to_G2_test.yaml.go new file mode 100644 index 000000000..d58853e51 --- /dev/null +++ b/testing/bls/hash_to_G2_test.yaml.go @@ -0,0 +1,14 @@ +// Code generated by yaml_to_go. DO NOT EDIT. +// source: hash_to_G2.yaml + +package bls + +type HashToG2Test struct { + Input struct { + Message string `json:"msg"` + } `json:"input"` + Output struct { + X string `json:"x"` + Y string `json:"y"` + } `json:"output"` +} diff --git a/testing/bls/sign_test.go b/testing/bls/sign_test.go new file mode 100644 index 000000000..cc4111ffc --- /dev/null +++ b/testing/bls/sign_test.go @@ -0,0 +1,55 @@ +package bls + +import ( + "bytes" + "encoding/hex" + "errors" + "testing" + + "github.com/ghodss/yaml" + "github.com/prysmaticlabs/prysm/crypto/bls" + "github.com/prysmaticlabs/prysm/crypto/bls/common" + "github.com/prysmaticlabs/prysm/shared/testutil/require" + "github.com/prysmaticlabs/prysm/testing/bls/utils" +) + +func TestSign(t *testing.T) { + t.Run("blst", testSign) +} + +func testSign(t *testing.T) { + fNames, fContent := utils.RetrieveFiles("sign", t) + + for i, file := range fNames { + t.Run(file, func(t *testing.T) { + test := &SignMsgTest{} + require.NoError(t, yaml.Unmarshal(fContent[i], test)) + pkBytes, err := hex.DecodeString(test.Input.Privkey[2:]) + require.NoError(t, err) + sk, err := bls.SecretKeyFromBytes(pkBytes) + if err != nil { + if test.Output == "" && + (errors.Is(err, common.ErrZeroKey) || errors.Is(err, common.ErrSecretUnmarshal)) { + return + } + t.Fatalf("cannot unmarshal secret key: %v", err) + } + msgBytes, err := hex.DecodeString(test.Input.Message[2:]) + require.NoError(t, err) + sig := sk.Sign(msgBytes) + + if !sig.Verify(sk.PublicKey(), msgBytes) { + t.Fatal("could not verify signature") + } + + outputBytes, err := hex.DecodeString(test.Output[2:]) + require.NoError(t, err) + + if !bytes.Equal(outputBytes, sig.Marshal()) { + t.Fatalf("Test Case %d: Signature does not match the expected output. "+ + "Expected %#x but received %#x", i, outputBytes, sig.Marshal()) + } + t.Log("Success") + }) + } +} diff --git a/testing/bls/sign_test.yaml.go b/testing/bls/sign_test.yaml.go new file mode 100644 index 000000000..d8d932f86 --- /dev/null +++ b/testing/bls/sign_test.yaml.go @@ -0,0 +1,12 @@ +// Code generated by yaml_to_go. DO NOT EDIT. +// source: sign_msg.yaml + +package bls + +type SignMsgTest struct { + Input struct { + Privkey string `json:"privkey"` + Message string `json:"message"` + } `json:"input"` + Output string `json:"output"` +} diff --git a/testing/bls/utils/BUILD.bazel b/testing/bls/utils/BUILD.bazel new file mode 100644 index 000000000..1b9de7023 --- /dev/null +++ b/testing/bls/utils/BUILD.bazel @@ -0,0 +1,14 @@ +load("@prysm//tools/go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + testonly = True, + srcs = ["utils.go"], + importpath = "github.com/prysmaticlabs/prysm/testing/bls/utils", + visibility = ["//testing/bls:__subpackages__"], + deps = [ + "//shared/fileutil:go_default_library", + "//shared/testutil/require:go_default_library", + "@io_bazel_rules_go//go/tools/bazel:go_default_library", + ], +) diff --git a/testing/bls/utils/utils.go b/testing/bls/utils/utils.go new file mode 100644 index 000000000..324af9192 --- /dev/null +++ b/testing/bls/utils/utils.go @@ -0,0 +1,32 @@ +package utils + +import ( + "io/ioutil" + "path" + "strings" + "testing" + + "github.com/bazelbuild/rules_go/go/tools/bazel" + "github.com/prysmaticlabs/prysm/shared/fileutil" + "github.com/prysmaticlabs/prysm/shared/testutil/require" +) + +func RetrieveFiles(name string, t *testing.T) ([]string, [][]byte) { + filepath, err := bazel.Runfile(name) + require.NoError(t, err) + testFiles, err := ioutil.ReadDir(filepath) + require.NoError(t, err) + + fileNames := []string{} + fileContent := [][]byte{} + require.Equal(t, false, len(testFiles) == 0, "no files exist in directory") + for _, f := range testFiles { + // Remove .yml suffix + fName := strings.TrimSuffix(f.Name(), ".yaml") + fileNames = append(fileNames, fName) + data, err := fileutil.ReadFileAsBytes(path.Join(filepath, f.Name())) + require.NoError(t, err) + fileContent = append(fileContent, data) + } + return fileNames, fileContent +} diff --git a/testing/bls/verify_test.go b/testing/bls/verify_test.go new file mode 100644 index 000000000..4740b2338 --- /dev/null +++ b/testing/bls/verify_test.go @@ -0,0 +1,57 @@ +package bls + +import ( + "encoding/hex" + "errors" + "testing" + + "github.com/ghodss/yaml" + "github.com/prysmaticlabs/prysm/crypto/bls" + "github.com/prysmaticlabs/prysm/crypto/bls/common" + "github.com/prysmaticlabs/prysm/shared/testutil/require" + "github.com/prysmaticlabs/prysm/testing/bls/utils" +) + +func TestVerify(t *testing.T) { + t.Run("blst", testVerify) +} + +func testVerify(t *testing.T) { + fNames, fContent := utils.RetrieveFiles("verify", t) + + for i, file := range fNames { + t.Run(file, func(t *testing.T) { + test := &VerifyMsgTest{} + require.NoError(t, yaml.Unmarshal(fContent[i], test)) + + pkBytes, err := hex.DecodeString(test.Input.Pubkey[2:]) + require.NoError(t, err) + pk, err := bls.PublicKeyFromBytes(pkBytes) + if err != nil { + if test.Output == false && errors.Is(err, common.ErrInfinitePubKey) { + return + } + t.Fatalf("cannot unmarshal pubkey: %v", err) + } + msgBytes, err := hex.DecodeString(test.Input.Message[2:]) + require.NoError(t, err) + + sigBytes, err := hex.DecodeString(test.Input.Signature[2:]) + require.NoError(t, err) + sig, err := bls.SignatureFromBytes(sigBytes) + if err != nil { + if test.Output == false { + return + } + t.Fatalf("Cannot unmarshal input to signature: %v", err) + } + + verified := sig.Verify(pk, msgBytes) + if verified != test.Output { + t.Fatalf("Signature does not match the expected verification output. "+ + "Expected %#v but received %#v for test case %d", test.Output, verified, i) + } + t.Log("Success") + }) + } +} diff --git a/testing/bls/verify_test.yaml.go b/testing/bls/verify_test.yaml.go new file mode 100644 index 000000000..0a317384f --- /dev/null +++ b/testing/bls/verify_test.yaml.go @@ -0,0 +1,13 @@ +// Code generated by yaml_to_go. DO NOT EDIT. +// source: verify.yaml + +package bls + +type VerifyMsgTest struct { + Input struct { + Pubkey string `json:"pubkey"` + Message string `json:"message"` + Signature string `json:"signature"` + } `json:"input"` + Output bool `json:"output"` +}