From 9f242137b0fe1968f8b57993efb0d806e8265d1d Mon Sep 17 00:00:00 2001 From: will Date: Wed, 12 Oct 2022 23:40:42 +0000 Subject: [PATCH] Add a new bls test (#3235) ## Issue Addressed Which issue # does this PR address? #2629 ## Proposed Changes Please list or describe the changes introduced by this PR. 1. ci would dowload the bls test cases from https://github.com/ethereum/bls12-381-tests/ 2. all the bls test cases(except eth ones) would use cases in the archive from step one 3. The bls test cases from https://github.com/ethereum/consensus-spec-tests would stay there and no use . For the future , these bls test cases would be remove suggested from https://github.com/ethereum/consensus-spec-tests/issues/25 . So it would do no harm and compatible for future cases. ## Additional Info Please provide any additional information. For example, future considerations or information useful for reviewers. Question: I am not sure if I should implement tests about `deserialization_G1`, `deserialization_G2` and `hash_to_G2` for the issue. --- crypto/bls/src/lib.rs | 8 +++ testing/ef_tests/.gitignore | 1 + testing/ef_tests/Makefile | 21 +++++- testing/ef_tests/check_all_files_accessed.py | 8 ++- testing/ef_tests/src/cases.rs | 2 + .../ef_tests/src/cases/bls_aggregate_sigs.rs | 8 +-- .../src/cases/bls_aggregate_verify.rs | 8 +-- .../ef_tests/src/cases/bls_batch_verify.rs | 67 +++++++++++++++++ .../src/cases/bls_eth_aggregate_pubkeys.rs | 4 +- .../cases/bls_eth_fast_aggregate_verify.rs | 4 +- .../src/cases/bls_fast_aggregate_verify.rs | 8 +-- testing/ef_tests/src/cases/bls_sign_msg.rs | 8 +-- testing/ef_tests/src/cases/bls_verify_msg.rs | 8 +-- testing/ef_tests/src/cases/common.rs | 34 +++++---- testing/ef_tests/src/handler.rs | 71 +++++++++++++++++-- testing/ef_tests/tests/tests.rs | 6 ++ 16 files changed, 211 insertions(+), 55 deletions(-) create mode 100644 testing/ef_tests/src/cases/bls_batch_verify.rs diff --git a/crypto/bls/src/lib.rs b/crypto/bls/src/lib.rs index eacbc2b26..750e1bd5b 100644 --- a/crypto/bls/src/lib.rs +++ b/crypto/bls/src/lib.rs @@ -90,6 +90,7 @@ pub mod generics { pub use crate::generic_secret_key::GenericSecretKey; pub use crate::generic_signature::GenericSignature; pub use crate::generic_signature_bytes::GenericSignatureBytes; + pub use crate::generic_signature_set::WrappedSignature; } /// Defines all the fundamental BLS points which should be exported by this crate by making @@ -109,6 +110,13 @@ macro_rules! define_mod { pub type AggregatePublicKey = GenericAggregatePublicKey; pub type Signature = GenericSignature; + pub type BlsWrappedSignature<'a> = WrappedSignature< + 'a, + bls_variant::PublicKey, + bls_variant::AggregatePublicKey, + bls_variant::Signature, + bls_variant::AggregateSignature, + >; pub type AggregateSignature = GenericAggregateSignature< bls_variant::PublicKey, bls_variant::AggregatePublicKey, diff --git a/testing/ef_tests/.gitignore b/testing/ef_tests/.gitignore index f3638b7bf..6a2ca1fe7 100644 --- a/testing/ef_tests/.gitignore +++ b/testing/ef_tests/.gitignore @@ -1,2 +1,3 @@ /consensus-spec-tests .accessed_file_log.txt +/bls12-381-tests diff --git a/testing/ef_tests/Makefile b/testing/ef_tests/Makefile index dc89cb5d5..fac1ab905 100644 --- a/testing/ef_tests/Makefile +++ b/testing/ef_tests/Makefile @@ -4,23 +4,38 @@ TARBALLS = $(patsubst %,%-$(TESTS_TAG).tar.gz,$(TESTS)) REPO_NAME := consensus-spec-tests OUTPUT_DIR := ./$(REPO_NAME) - BASE_URL := https://github.com/ethereum/$(REPO_NAME)/releases/download/$(TESTS_TAG) +BLS_TEST_REPO_NAME := bls12-381-tests +BLS_TEST_TAG := v0.1.1 +BLS_TEST = bls_tests_yaml +BLS_TARBALL = $(patsubst %,%-$(BLS_TEST_TAG).tar.gz,$(BLS_TEST)) +BLS_OUTPUT_DIR := $(OUTPUT_DIR)/$(BLS_TEST_REPO_NAME) +BLS_BASE_URL := https://github.com/ethereum/$(BLS_TEST_REPO_NAME)/releases/download/$(BLS_TEST_TAG) + +all: + make $(OUTPUT_DIR) + make $(BLS_OUTPUT_DIR) + $(OUTPUT_DIR): $(TARBALLS) mkdir $(OUTPUT_DIR) for test_tarball in $^; do \ tar -xzf $$test_tarball -C $(OUTPUT_DIR);\ done +$(BLS_OUTPUT_DIR): + mkdir $(BLS_OUTPUT_DIR) + wget $(BLS_BASE_URL)/$(BLS_TEST).tar.gz -O $(BLS_TARBALL) + tar -xzf $(BLS_TARBALL) -C $(BLS_OUTPUT_DIR) + %-$(TESTS_TAG).tar.gz: wget $(BASE_URL)/$*.tar.gz -O $@ clean-test-files: - rm -rf $(OUTPUT_DIR) + rm -rf $(OUTPUT_DIR) $(BLS_OUTPUT_DIR) clean-archives: - rm -f $(TARBALLS) + rm -f $(TARBALLS) $(BLS_TARBALL) clean: clean-test-files clean-archives diff --git a/testing/ef_tests/check_all_files_accessed.py b/testing/ef_tests/check_all_files_accessed.py index a10ccf1e6..158e87581 100755 --- a/testing/ef_tests/check_all_files_accessed.py +++ b/testing/ef_tests/check_all_files_accessed.py @@ -46,7 +46,13 @@ excluded_paths = [ # One of the EF researchers likes to pack the tarballs on a Mac ".*\.DS_Store.*", # More Mac weirdness. - "tests/mainnet/bellatrix/operations/deposit/pyspec_tests/deposit_with_previous_fork_version__valid_ineffective/._meta.yaml" + "tests/mainnet/bellatrix/operations/deposit/pyspec_tests/deposit_with_previous_fork_version__valid_ineffective/._meta.yaml", + # bls tests are moved to bls12-381-tests directory + "tests/general/phase0/bls", + # some bls tests are not included now + "bls12-381-tests/deserialization_G1", + "bls12-381-tests/deserialization_G2", + "bls12-381-tests/hash_to_G2" ] def normalize_path(path): diff --git a/testing/ef_tests/src/cases.rs b/testing/ef_tests/src/cases.rs index 64f4aa753..ae70f1e07 100644 --- a/testing/ef_tests/src/cases.rs +++ b/testing/ef_tests/src/cases.rs @@ -6,6 +6,7 @@ use types::ForkName; mod bls_aggregate_sigs; mod bls_aggregate_verify; +mod bls_batch_verify; mod bls_eth_aggregate_pubkeys; mod bls_eth_fast_aggregate_verify; mod bls_fast_aggregate_verify; @@ -29,6 +30,7 @@ mod transition; pub use self::fork_choice::*; pub use bls_aggregate_sigs::*; pub use bls_aggregate_verify::*; +pub use bls_batch_verify::*; pub use bls_eth_aggregate_pubkeys::*; pub use bls_eth_fast_aggregate_verify::*; pub use bls_fast_aggregate_verify::*; diff --git a/testing/ef_tests/src/cases/bls_aggregate_sigs.rs b/testing/ef_tests/src/cases/bls_aggregate_sigs.rs index e0d0dd76a..81e186a66 100644 --- a/testing/ef_tests/src/cases/bls_aggregate_sigs.rs +++ b/testing/ef_tests/src/cases/bls_aggregate_sigs.rs @@ -1,6 +1,6 @@ use super::*; use crate::case_result::compare_result; -use crate::cases::common::BlsCase; +use crate::impl_bls_load_case; use bls::{AggregateSignature, Signature}; use serde_derive::Deserialize; @@ -10,13 +10,9 @@ pub struct BlsAggregateSigs { pub output: String, } -impl BlsCase for BlsAggregateSigs {} +impl_bls_load_case!(BlsAggregateSigs); impl Case for BlsAggregateSigs { - fn is_enabled_for_fork(fork_name: ForkName) -> bool { - fork_name == ForkName::Base - } - fn result(&self, _case_index: usize, _fork_name: ForkName) -> Result<(), Error> { let mut aggregate_signature = AggregateSignature::infinity(); diff --git a/testing/ef_tests/src/cases/bls_aggregate_verify.rs b/testing/ef_tests/src/cases/bls_aggregate_verify.rs index ea7a7664f..e9539dc15 100644 --- a/testing/ef_tests/src/cases/bls_aggregate_verify.rs +++ b/testing/ef_tests/src/cases/bls_aggregate_verify.rs @@ -1,6 +1,6 @@ use super::*; use crate::case_result::compare_result; -use crate::cases::common::BlsCase; +use crate::impl_bls_load_case; use bls::{AggregateSignature, PublicKeyBytes}; use serde_derive::Deserialize; use types::Hash256; @@ -18,13 +18,9 @@ pub struct BlsAggregateVerify { pub output: bool, } -impl BlsCase for BlsAggregateVerify {} +impl_bls_load_case!(BlsAggregateVerify); impl Case for BlsAggregateVerify { - fn is_enabled_for_fork(fork_name: ForkName) -> bool { - fork_name == ForkName::Base - } - fn result(&self, _case_index: usize, _fork_name: ForkName) -> Result<(), Error> { let messages = self .input diff --git a/testing/ef_tests/src/cases/bls_batch_verify.rs b/testing/ef_tests/src/cases/bls_batch_verify.rs new file mode 100644 index 000000000..de8721d67 --- /dev/null +++ b/testing/ef_tests/src/cases/bls_batch_verify.rs @@ -0,0 +1,67 @@ +use super::*; +use crate::case_result::compare_result; +use crate::impl_bls_load_case; +use bls::{verify_signature_sets, BlsWrappedSignature, PublicKeyBytes, Signature, SignatureSet}; +use serde_derive::Deserialize; +use std::borrow::Cow; +use std::str::FromStr; +use types::Hash256; + +#[derive(Debug, Clone, Deserialize)] +pub struct BlsBatchVerifyInput { + pubkeys: Vec, + messages: Vec, + signatures: Vec, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct BlsBatchVerify { + pub input: BlsBatchVerifyInput, + pub output: bool, +} + +impl_bls_load_case!(BlsBatchVerify); + +impl Case for BlsBatchVerify { + fn result(&self, _case_index: usize, _fork_name: ForkName) -> Result<(), Error> { + let messages = self + .input + .messages + .iter() + .map(|s| Hash256::from_str(s).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))) + .collect::, _>>()?; + + let pubkeys = self + .input + .pubkeys + .iter() + .map(|pkb| { + pkb.decompress() + .map_err(|_| Error::FailedToParseTest("pubkeys parse error".to_string())) + }) + .collect::, _>>()?; + + let signatures = self + .input + .signatures + .iter() + .map(|s| { + Signature::from_str(s).map_err(|e| Error::FailedToParseTest(format!("{:?}", e))) + }) + .collect::, _>>()?; + + let signature_set = messages + .iter() + .zip(pubkeys.iter()) + .zip(signatures.iter()) + .map(|((&message, pubkey), signature)| { + let wraped_signature = BlsWrappedSignature::from(signature); + SignatureSet::single_pubkey(wraped_signature, Cow::Borrowed(pubkey), message) + }) + .collect::>(); + + let signature_valid = verify_signature_sets(signature_set.iter()); + + compare_result::(&Ok(signature_valid), &Some(self.output)) + } +} diff --git a/testing/ef_tests/src/cases/bls_eth_aggregate_pubkeys.rs b/testing/ef_tests/src/cases/bls_eth_aggregate_pubkeys.rs index 2ecc3b603..c41fbca39 100644 --- a/testing/ef_tests/src/cases/bls_eth_aggregate_pubkeys.rs +++ b/testing/ef_tests/src/cases/bls_eth_aggregate_pubkeys.rs @@ -1,6 +1,6 @@ use super::*; use crate::case_result::compare_result; -use crate::cases::common::BlsCase; +use crate::impl_bls_load_case; use bls::{AggregatePublicKey, PublicKeyBytes}; use serde_derive::Deserialize; @@ -10,7 +10,7 @@ pub struct BlsEthAggregatePubkeys { pub output: Option, } -impl BlsCase for BlsEthAggregatePubkeys {} +impl_bls_load_case!(BlsEthAggregatePubkeys, "data.yaml"); impl Case for BlsEthAggregatePubkeys { fn is_enabled_for_fork(fork_name: ForkName) -> bool { diff --git a/testing/ef_tests/src/cases/bls_eth_fast_aggregate_verify.rs b/testing/ef_tests/src/cases/bls_eth_fast_aggregate_verify.rs index 62f9eb30c..80e018459 100644 --- a/testing/ef_tests/src/cases/bls_eth_fast_aggregate_verify.rs +++ b/testing/ef_tests/src/cases/bls_eth_fast_aggregate_verify.rs @@ -1,6 +1,6 @@ use super::*; use crate::case_result::compare_result; -use crate::cases::common::BlsCase; +use crate::impl_bls_load_case; use bls::{AggregateSignature, PublicKeyBytes}; use serde_derive::Deserialize; use std::convert::TryInto; @@ -20,7 +20,7 @@ pub struct BlsEthFastAggregateVerify { pub output: bool, } -impl BlsCase for BlsEthFastAggregateVerify {} +impl_bls_load_case!(BlsEthFastAggregateVerify, "data.yaml"); impl Case for BlsEthFastAggregateVerify { fn is_enabled_for_fork(fork_name: ForkName) -> bool { diff --git a/testing/ef_tests/src/cases/bls_fast_aggregate_verify.rs b/testing/ef_tests/src/cases/bls_fast_aggregate_verify.rs index 9722c05dc..608995db9 100644 --- a/testing/ef_tests/src/cases/bls_fast_aggregate_verify.rs +++ b/testing/ef_tests/src/cases/bls_fast_aggregate_verify.rs @@ -1,6 +1,6 @@ use super::*; use crate::case_result::compare_result; -use crate::cases::common::BlsCase; +use crate::impl_bls_load_case; use bls::{AggregateSignature, PublicKeyBytes}; use serde_derive::Deserialize; use std::convert::TryInto; @@ -20,13 +20,9 @@ pub struct BlsFastAggregateVerify { pub output: bool, } -impl BlsCase for BlsFastAggregateVerify {} +impl_bls_load_case!(BlsFastAggregateVerify); impl Case for BlsFastAggregateVerify { - fn is_enabled_for_fork(fork_name: ForkName) -> bool { - fork_name == ForkName::Base - } - fn result(&self, _case_index: usize, _fork_name: ForkName) -> Result<(), Error> { let message = Hash256::from_slice( &hex::decode(&self.input.message[2..]) diff --git a/testing/ef_tests/src/cases/bls_sign_msg.rs b/testing/ef_tests/src/cases/bls_sign_msg.rs index ad6b40cb7..53c13b569 100644 --- a/testing/ef_tests/src/cases/bls_sign_msg.rs +++ b/testing/ef_tests/src/cases/bls_sign_msg.rs @@ -1,6 +1,6 @@ use super::*; use crate::case_result::compare_result; -use crate::cases::common::BlsCase; +use crate::impl_bls_load_case; use bls::SecretKey; use serde_derive::Deserialize; use types::Hash256; @@ -17,13 +17,9 @@ pub struct BlsSign { pub output: Option, } -impl BlsCase for BlsSign {} +impl_bls_load_case!(BlsSign); impl Case for BlsSign { - fn is_enabled_for_fork(fork_name: ForkName) -> bool { - fork_name == ForkName::Base - } - fn result(&self, _case_index: usize, _fork_name: ForkName) -> Result<(), Error> { // Convert private_key and message to required types let sk = hex::decode(&self.input.privkey[2..]) diff --git a/testing/ef_tests/src/cases/bls_verify_msg.rs b/testing/ef_tests/src/cases/bls_verify_msg.rs index 190c09d52..779b3cf75 100644 --- a/testing/ef_tests/src/cases/bls_verify_msg.rs +++ b/testing/ef_tests/src/cases/bls_verify_msg.rs @@ -1,6 +1,6 @@ use super::*; use crate::case_result::compare_result; -use crate::cases::common::BlsCase; +use crate::impl_bls_load_case; use bls::{PublicKeyBytes, Signature, SignatureBytes}; use serde_derive::Deserialize; use std::convert::TryInto; @@ -19,13 +19,9 @@ pub struct BlsVerify { pub output: bool, } -impl BlsCase for BlsVerify {} +impl_bls_load_case!(BlsVerify); impl Case for BlsVerify { - fn is_enabled_for_fork(fork_name: ForkName) -> bool { - fork_name == ForkName::Base - } - fn result(&self, _case_index: usize, _fork_name: ForkName) -> Result<(), Error> { let message = hex::decode(&self.input.message[2..]) .map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?; diff --git a/testing/ef_tests/src/cases/common.rs b/testing/ef_tests/src/cases/common.rs index e77e56193..e15a2e2ca 100644 --- a/testing/ef_tests/src/cases/common.rs +++ b/testing/ef_tests/src/cases/common.rs @@ -1,24 +1,11 @@ -use crate::cases::LoadCase; -use crate::decode::yaml_decode_file; -use crate::error::Error; use serde_derive::Deserialize; use ssz::Encode; use ssz_derive::{Decode, Encode}; use std::convert::TryFrom; use std::fmt::Debug; -use std::path::Path; use tree_hash::TreeHash; use types::ForkName; -/// Trait for all BLS cases to eliminate some boilerplate. -pub trait BlsCase: serde::de::DeserializeOwned {} - -impl LoadCase for T { - fn load_from_dir(path: &Path, _fork_name: ForkName) -> Result { - yaml_decode_file(&path.join("data.yaml")) - } -} - /// Macro to wrap U128 and U256 so they deserialize correctly. macro_rules! uint_wrapper { ($wrapper_name:ident, $wrapped_type:ty) => { @@ -80,3 +67,24 @@ pub fn previous_fork(fork_name: ForkName) -> ForkName { ForkName::Merge => ForkName::Altair, // TODO: Check this when tests are released.. } } + +#[macro_export] +macro_rules! impl_bls_load_case { + ($case_name:ident) => { + use $crate::decode::yaml_decode_file; + impl LoadCase for $case_name { + fn load_from_dir(path: &Path, _fork_name: ForkName) -> Result { + yaml_decode_file(&path) + } + } + }; + + ($case_name:ident, $sub_path_name:expr) => { + use $crate::decode::yaml_decode_file; + impl LoadCase for $case_name { + fn load_from_dir(path: &Path, _fork_name: ForkName) -> Result { + yaml_decode_file(&path.join($sub_path_name)) + } + } + }; +} diff --git a/testing/ef_tests/src/handler.rs b/testing/ef_tests/src/handler.rs index 13c0a8c54..92d5db7fd 100644 --- a/testing/ef_tests/src/handler.rs +++ b/testing/ef_tests/src/handler.rs @@ -49,8 +49,9 @@ pub trait Handler { let as_directory = |entry: Result| -> Option { entry .ok() - .filter(|e| e.file_type().map(|ty| ty.is_dir()).unwrap_or(false)) + .filter(|e| e.file_type().map(|ty| ty.is_dir()).unwrap()) }; + let test_cases = fs::read_dir(&handler_path) .unwrap_or_else(|e| panic!("handler dir {} exists: {:?}", handler_path.display(), e)) .filter_map(as_directory) @@ -58,6 +59,7 @@ pub trait Handler { .filter_map(as_directory) .map(|test_case_dir| { let path = test_case_dir.path(); + let case = Self::Case::load_from_dir(&path, fork_name).expect("test should load"); (path, case) }) @@ -75,7 +77,7 @@ pub trait Handler { } } -macro_rules! bls_handler { +macro_rules! bls_eth_handler { ($runner_name: ident, $case_name:ident, $handler_name:expr) => { #[derive(Derivative)] #[derivative(Default(bound = ""))] @@ -95,8 +97,69 @@ macro_rules! bls_handler { }; } +macro_rules! bls_handler { + ($runner_name: ident, $case_name:ident, $handler_name:expr) => { + #[derive(Derivative)] + #[derivative(Default(bound = ""))] + pub struct $runner_name; + + impl Handler for $runner_name { + type Case = cases::$case_name; + + fn runner_name() -> &'static str { + "bls" + } + + fn config_name() -> &'static str { + "bls12-381-tests" + } + + fn handler_name(&self) -> String { + $handler_name.into() + } + + fn run(&self) { + let fork_name = ForkName::Base; + let fork_name_str = fork_name.to_string(); + let handler_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("consensus-spec-tests") + .join(Self::config_name()) + .join(self.handler_name()); + + let as_file = |entry: Result| -> Option { + entry + .ok() + .filter(|e| e.file_type().map(|ty| ty.is_file()).unwrap_or(false)) + }; + let test_cases: Vec<(PathBuf, Self::Case)> = fs::read_dir(&handler_path) + .expect("handler dir exists") + .filter_map(as_file) + .map(|test_case_path| { + let path = test_case_path.path(); + let case = + Self::Case::load_from_dir(&path, fork_name).expect("test should load"); + + (path, case) + }) + .collect(); + + let results = Cases { test_cases }.test_results(fork_name, Self::use_rayon()); + + let name = format!( + "{}/{}/{}", + fork_name_str, + Self::runner_name(), + self.handler_name() + ); + crate::results::assert_tests_pass(&name, &handler_path, &results); + } + } + }; +} + bls_handler!(BlsAggregateSigsHandler, BlsAggregateSigs, "aggregate"); bls_handler!(BlsSignMsgHandler, BlsSign, "sign"); +bls_handler!(BlsBatchVerifyHandler, BlsBatchVerify, "batch_verify"); bls_handler!(BlsVerifyMsgHandler, BlsVerify, "verify"); bls_handler!( BlsAggregateVerifyHandler, @@ -108,12 +171,12 @@ bls_handler!( BlsFastAggregateVerify, "fast_aggregate_verify" ); -bls_handler!( +bls_eth_handler!( BlsEthAggregatePubkeysHandler, BlsEthAggregatePubkeys, "eth_aggregate_pubkeys" ); -bls_handler!( +bls_eth_handler!( BlsEthFastAggregateVerifyHandler, BlsEthFastAggregateVerify, "eth_fast_aggregate_verify" diff --git a/testing/ef_tests/tests/tests.rs b/testing/ef_tests/tests/tests.rs index 31abbd159..2c8b9d223 100644 --- a/testing/ef_tests/tests/tests.rs +++ b/testing/ef_tests/tests/tests.rs @@ -118,6 +118,12 @@ fn bls_verify() { BlsVerifyMsgHandler::default().run(); } +#[test] +#[cfg(not(feature = "fake_crypto"))] +fn bls_batch_verify() { + BlsBatchVerifyHandler::default().run(); +} + #[test] #[cfg(not(feature = "fake_crypto"))] fn bls_aggregate_verify() {