diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 93a8e5e988..8effc229ca 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -10614,11 +10614,11 @@ dependencies = [ "sp-application-crypto", "sp-core", "sp-io", - "sp-keystore", "sp-mmr-primitives", "sp-runtime", "sp-std", "strum", + "w3f-bls", ] [[package]] @@ -10675,7 +10675,6 @@ dependencies = [ "futures", "hash-db", "hash256-std-hasher", - "hex-literal", "impl-serde", "lazy_static", "libsecp256k1", diff --git a/substrate/client/consensus/beefy/src/communication/gossip.rs b/substrate/client/consensus/beefy/src/communication/gossip.rs index d60622b03e..8c025ca067 100644 --- a/substrate/client/consensus/beefy/src/communication/gossip.rs +++ b/substrate/client/consensus/beefy/src/communication/gossip.rs @@ -41,7 +41,7 @@ use crate::{ LOG_TARGET, }; use sp_consensus_beefy::{ - crypto::{AuthorityId, Signature}, + ecdsa_crypto::{AuthorityId, Signature}, ValidatorSet, ValidatorSetId, VoteMessage, }; @@ -476,9 +476,10 @@ pub(crate) mod tests { use super::*; use crate::keystore::BeefyKeystore; use sc_network_test::Block; + use sp_application_crypto::key_types::BEEFY as BEEFY_KEY_TYPE; use sp_consensus_beefy::{ - crypto::Signature, known_payloads, Commitment, Keyring, MmrRootHash, Payload, - SignedCommitment, VoteMessage, KEY_TYPE, + ecdsa_crypto::Signature, known_payloads, Commitment, Keyring, MmrRootHash, Payload, + SignedCommitment, VoteMessage, }; use sp_keystore::{testing::MemoryKeystore, Keystore}; @@ -536,7 +537,7 @@ pub(crate) mod tests { pub fn sign_commitment(who: &Keyring, commitment: &Commitment) -> Signature { let store = MemoryKeystore::new(); - store.ecdsa_generate_new(KEY_TYPE, Some(&who.to_seed())).unwrap(); + store.ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&who.to_seed())).unwrap(); let beefy_keystore: BeefyKeystore = Some(store.into()).into(); beefy_keystore.sign(&who.public(), &commitment.encode()).unwrap() } diff --git a/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs b/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs index 10105ff2d4..ef462a54fc 100644 --- a/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs +++ b/substrate/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs @@ -26,7 +26,7 @@ use sc_network::{ request_responses::{IfDisconnected, RequestFailure}, NetworkRequest, PeerId, ProtocolName, }; -use sp_consensus_beefy::{crypto::AuthorityId, ValidatorSet}; +use sp_consensus_beefy::{ecdsa_crypto::AuthorityId, ValidatorSet}; use sp_runtime::traits::{Block, NumberFor}; use std::{collections::VecDeque, result::Result, sync::Arc}; diff --git a/substrate/client/consensus/beefy/src/import.rs b/substrate/client/consensus/beefy/src/import.rs index bda8169d95..80f8cebe48 100644 --- a/substrate/client/consensus/beefy/src/import.rs +++ b/substrate/client/consensus/beefy/src/import.rs @@ -22,7 +22,7 @@ use log::debug; use sp_api::{ProvideRuntimeApi, TransactionFor}; use sp_consensus::Error as ConsensusError; -use sp_consensus_beefy::{BeefyApi, BEEFY_ENGINE_ID}; +use sp_consensus_beefy::{ecdsa_crypto::AuthorityId, BeefyApi, BEEFY_ENGINE_ID}; use sp_runtime::{ traits::{Block as BlockT, Header as HeaderT, NumberFor}, EncodedJustification, @@ -83,7 +83,7 @@ where Block: BlockT, BE: Backend, Runtime: ProvideRuntimeApi, - Runtime::Api: BeefyApi + Send, + Runtime::Api: BeefyApi + Send, { fn decode_and_verify( &self, @@ -125,7 +125,7 @@ where > + Send + Sync, Runtime: ProvideRuntimeApi + Send + Sync, - Runtime::Api: BeefyApi, + Runtime::Api: BeefyApi, { type Error = ConsensusError; type Transaction = TransactionFor; diff --git a/substrate/client/consensus/beefy/src/justification.rs b/substrate/client/consensus/beefy/src/justification.rs index 4855457fd2..483184e237 100644 --- a/substrate/client/consensus/beefy/src/justification.rs +++ b/substrate/client/consensus/beefy/src/justification.rs @@ -20,7 +20,7 @@ use crate::keystore::BeefyKeystore; use codec::{DecodeAll, Encode}; use sp_consensus::Error as ConsensusError; use sp_consensus_beefy::{ - crypto::{AuthorityId, Signature}, + ecdsa_crypto::{AuthorityId, Signature}, ValidatorSet, ValidatorSetId, VersionedFinalityProof, }; use sp_runtime::traits::{Block as BlockT, NumberFor}; diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index 795d4cc8ad..925bb08828 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -16,15 +16,15 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use sp_application_crypto::RuntimeAppPublic; +use sp_application_crypto::{key_types::BEEFY as BEEFY_KEY_TYPE, RuntimeAppPublic}; use sp_core::keccak_256; use sp_keystore::KeystorePtr; use log::warn; use sp_consensus_beefy::{ - crypto::{Public, Signature}, - BeefyAuthorityId, KEY_TYPE, + ecdsa_crypto::{Public, Signature}, + BeefyAuthorityId, }; use crate::{error, LOG_TARGET}; @@ -50,7 +50,7 @@ impl BeefyKeystore { // we do check for multiple private keys as a key store sanity check. let public: Vec = keys .iter() - .filter(|k| store.has_keys(&[(k.to_raw_vec(), KEY_TYPE)])) + .filter(|k| store.has_keys(&[(k.to_raw_vec(), BEEFY_KEY_TYPE)])) .cloned() .collect(); @@ -78,7 +78,7 @@ impl BeefyKeystore { let public = public.as_ref(); let sig = store - .ecdsa_sign_prehashed(KEY_TYPE, public, &msg) + .ecdsa_sign_prehashed(BEEFY_KEY_TYPE, public, &msg) .map_err(|e| error::Error::Keystore(e.to_string()))? .ok_or_else(|| error::Error::Signature("ecdsa_sign_prehashed() failed".to_string()))?; @@ -96,7 +96,7 @@ impl BeefyKeystore { let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?; let pk: Vec = - store.ecdsa_public_keys(KEY_TYPE).drain(..).map(Public::from).collect(); + store.ecdsa_public_keys(BEEFY_KEY_TYPE).drain(..).map(Public::from).collect(); Ok(pk) } @@ -117,7 +117,7 @@ impl From> for BeefyKeystore { #[cfg(test)] pub mod tests { - use sp_consensus_beefy::{crypto, Keyring}; + use sp_consensus_beefy::{ecdsa_crypto, Keyring}; use sp_core::{ecdsa, Pair}; use sp_keystore::testing::MemoryKeystore; @@ -156,35 +156,51 @@ pub mod tests { #[test] fn pair_works() { - let want = crypto::Pair::from_string("//Alice", None).expect("Pair failed").to_raw_vec(); + let want = ecdsa_crypto::Pair::from_string("//Alice", None) + .expect("Pair failed") + .to_raw_vec(); let got = Keyring::Alice.pair().to_raw_vec(); assert_eq!(want, got); - let want = crypto::Pair::from_string("//Bob", None).expect("Pair failed").to_raw_vec(); + let want = ecdsa_crypto::Pair::from_string("//Bob", None) + .expect("Pair failed") + .to_raw_vec(); let got = Keyring::Bob.pair().to_raw_vec(); assert_eq!(want, got); - let want = crypto::Pair::from_string("//Charlie", None).expect("Pair failed").to_raw_vec(); + let want = ecdsa_crypto::Pair::from_string("//Charlie", None) + .expect("Pair failed") + .to_raw_vec(); let got = Keyring::Charlie.pair().to_raw_vec(); assert_eq!(want, got); - let want = crypto::Pair::from_string("//Dave", None).expect("Pair failed").to_raw_vec(); + let want = ecdsa_crypto::Pair::from_string("//Dave", None) + .expect("Pair failed") + .to_raw_vec(); let got = Keyring::Dave.pair().to_raw_vec(); assert_eq!(want, got); - let want = crypto::Pair::from_string("//Eve", None).expect("Pair failed").to_raw_vec(); + let want = ecdsa_crypto::Pair::from_string("//Eve", None) + .expect("Pair failed") + .to_raw_vec(); let got = Keyring::Eve.pair().to_raw_vec(); assert_eq!(want, got); - let want = crypto::Pair::from_string("//Ferdie", None).expect("Pair failed").to_raw_vec(); + let want = ecdsa_crypto::Pair::from_string("//Ferdie", None) + .expect("Pair failed") + .to_raw_vec(); let got = Keyring::Ferdie.pair().to_raw_vec(); assert_eq!(want, got); - let want = crypto::Pair::from_string("//One", None).expect("Pair failed").to_raw_vec(); + let want = ecdsa_crypto::Pair::from_string("//One", None) + .expect("Pair failed") + .to_raw_vec(); let got = Keyring::One.pair().to_raw_vec(); assert_eq!(want, got); - let want = crypto::Pair::from_string("//Two", None).expect("Pair failed").to_raw_vec(); + let want = ecdsa_crypto::Pair::from_string("//Two", None) + .expect("Pair failed") + .to_raw_vec(); let got = Keyring::Two.pair().to_raw_vec(); assert_eq!(want, got); } @@ -193,8 +209,8 @@ pub mod tests { fn authority_id_works() { let store = keystore(); - let alice: crypto::Public = store - .ecdsa_generate_new(KEY_TYPE, Some(&Keyring::Alice.to_seed())) + let alice: ecdsa_crypto::Public = store + .ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&Keyring::Alice.to_seed())) .ok() .unwrap() .into(); @@ -219,8 +235,8 @@ pub mod tests { fn sign_works() { let store = keystore(); - let alice: crypto::Public = store - .ecdsa_generate_new(KEY_TYPE, Some(&Keyring::Alice.to_seed())) + let alice: ecdsa_crypto::Public = store + .ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&Keyring::Alice.to_seed())) .ok() .unwrap() .into(); @@ -239,7 +255,10 @@ pub mod tests { fn sign_error() { let store = keystore(); - store.ecdsa_generate_new(KEY_TYPE, Some(&Keyring::Bob.to_seed())).ok().unwrap(); + store + .ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&Keyring::Bob.to_seed())) + .ok() + .unwrap(); let store: BeefyKeystore = Some(store).into(); @@ -268,8 +287,8 @@ pub mod tests { fn verify_works() { let store = keystore(); - let alice: crypto::Public = store - .ecdsa_generate_new(KEY_TYPE, Some(&Keyring::Alice.to_seed())) + let alice: ecdsa_crypto::Public = store + .ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&Keyring::Alice.to_seed())) .ok() .unwrap() .into(); @@ -305,11 +324,11 @@ pub mod tests { let _ = add_key(TEST_TYPE, None); // BEEFY keys - let _ = add_key(KEY_TYPE, Some(Keyring::Dave.to_seed().as_str())); - let _ = add_key(KEY_TYPE, Some(Keyring::Eve.to_seed().as_str())); + let _ = add_key(BEEFY_KEY_TYPE, Some(Keyring::Dave.to_seed().as_str())); + let _ = add_key(BEEFY_KEY_TYPE, Some(Keyring::Eve.to_seed().as_str())); - let key1: crypto::Public = add_key(KEY_TYPE, None).into(); - let key2: crypto::Public = add_key(KEY_TYPE, None).into(); + let key1: ecdsa_crypto::Public = add_key(BEEFY_KEY_TYPE, None).into(); + let key2: ecdsa_crypto::Public = add_key(BEEFY_KEY_TYPE, None).into(); let store: BeefyKeystore = Some(store).into(); diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index c55849ff77..2d2cbd0482 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -46,7 +46,8 @@ use sp_blockchain::{ }; use sp_consensus::{Error as ConsensusError, SyncOracle}; use sp_consensus_beefy::{ - crypto::AuthorityId, BeefyApi, MmrRootHash, PayloadProvider, ValidatorSet, BEEFY_ENGINE_ID, + ecdsa_crypto::AuthorityId, BeefyApi, MmrRootHash, PayloadProvider, ValidatorSet, + BEEFY_ENGINE_ID, }; use sp_keystore::KeystorePtr; use sp_mmr_primitives::MmrApi; @@ -142,7 +143,7 @@ where + Send + Sync, RuntimeApi: ProvideRuntimeApi + Send + Sync, - RuntimeApi::Api: BeefyApi, + RuntimeApi::Api: BeefyApi, { // Voter -> RPC links let (to_rpc_justif_sender, from_voter_justif_stream) = @@ -224,7 +225,7 @@ pub async fn start_beefy_gadget( C: Client + BlockBackend, P: PayloadProvider, R: ProvideRuntimeApi, - R::Api: BeefyApi + MmrApi>, + R::Api: BeefyApi + MmrApi>, N: GossipNetwork + NetworkRequest + Send + Sync + 'static, S: GossipSyncing + SyncOracle + 'static, { @@ -339,7 +340,7 @@ where B: Block, BE: Backend, R: ProvideRuntimeApi, - R::Api: BeefyApi, + R::Api: BeefyApi, { // Initialize voter state from AUX DB if compatible. crate::aux_schema::load_persistent(backend)? @@ -374,7 +375,7 @@ where B: Block, BE: Backend, R: ProvideRuntimeApi, - R::Api: BeefyApi, + R::Api: BeefyApi, { let beefy_genesis = runtime .runtime_api() @@ -478,7 +479,7 @@ async fn wait_for_runtime_pallet( where B: Block, R: ProvideRuntimeApi, - R::Api: BeefyApi, + R::Api: BeefyApi, { info!(target: LOG_TARGET, "🥩 BEEFY gadget waiting for BEEFY pallet to become available..."); loop { @@ -518,7 +519,7 @@ fn expect_validator_set( where B: Block, R: ProvideRuntimeApi, - R::Api: BeefyApi, + R::Api: BeefyApi, { runtime .runtime_api() diff --git a/substrate/client/consensus/beefy/src/round.rs b/substrate/client/consensus/beefy/src/round.rs index d8948ff98c..6f400ce478 100644 --- a/substrate/client/consensus/beefy/src/round.rs +++ b/substrate/client/consensus/beefy/src/round.rs @@ -21,7 +21,7 @@ use crate::LOG_TARGET; use codec::{Decode, Encode}; use log::debug; use sp_consensus_beefy::{ - crypto::{AuthorityId, Signature}, + ecdsa_crypto::{AuthorityId, Signature}, Commitment, EquivocationProof, SignedCommitment, ValidatorSet, ValidatorSetId, VoteMessage, }; use sp_runtime::traits::{Block, NumberFor}; diff --git a/substrate/client/consensus/beefy/src/tests.rs b/substrate/client/consensus/beefy/src/tests.rs index 6bb6b1e548..1109a22638 100644 --- a/substrate/client/consensus/beefy/src/tests.rs +++ b/substrate/client/consensus/beefy/src/tests.rs @@ -48,14 +48,15 @@ use sc_network_test::{ use sc_utils::notification::NotificationReceiver; use serde::{Deserialize, Serialize}; use sp_api::{ApiRef, ProvideRuntimeApi}; +use sp_application_crypto::key_types::BEEFY as BEEFY_KEY_TYPE; use sp_consensus::BlockOrigin; use sp_consensus_beefy::{ - crypto::{AuthorityId, Signature}, + ecdsa_crypto::{AuthorityId, Signature}, known_payloads, mmr::{find_mmr_root_digest, MmrRootProvider}, BeefyApi, Commitment, ConsensusLog, EquivocationProof, Keyring as BeefyKeyring, MmrRootHash, OpaqueKeyOwnershipProof, Payload, SignedCommitment, ValidatorSet, ValidatorSetId, - VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, KEY_TYPE as BeefyKeyType, + VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, }; use sp_core::H256; use sp_keystore::{testing::MemoryKeystore, Keystore, KeystorePtr}; @@ -293,7 +294,7 @@ impl ProvideRuntimeApi for TestApi { } } sp_api::mock_impl_runtime_apis! { - impl BeefyApi for RuntimeApi { + impl BeefyApi for RuntimeApi { fn beefy_genesis() -> Option> { Some(self.inner.beefy_genesis) } @@ -352,7 +353,7 @@ pub(crate) fn make_beefy_ids(keys: &[BeefyKeyring]) -> Vec { pub(crate) fn create_beefy_keystore(authority: BeefyKeyring) -> KeystorePtr { let keystore = MemoryKeystore::new(); keystore - .ecdsa_generate_new(BeefyKeyType, Some(&authority.to_seed())) + .ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&authority.to_seed())) .expect("Creates authority key"); keystore.into() } @@ -386,7 +387,7 @@ fn initialize_beefy( ) -> impl Future where API: ProvideRuntimeApi + Sync + Send, - API::Api: BeefyApi + MmrApi>, + API::Api: BeefyApi + MmrApi>, { let tasks = FuturesUnordered::new(); diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 0bbe55767d..17a8891b06 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -41,7 +41,7 @@ use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; use sp_consensus::SyncOracle; use sp_consensus_beefy::{ check_equivocation_proof, - crypto::{AuthorityId, Signature}, + ecdsa_crypto::{AuthorityId, Signature}, BeefyApi, Commitment, ConsensusLog, EquivocationProof, PayloadProvider, ValidatorSet, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, }; @@ -348,7 +348,7 @@ where P: PayloadProvider, S: SyncOracle, R: ProvideRuntimeApi, - R::Api: BeefyApi, + R::Api: BeefyApi, { fn best_grandpa_block(&self) -> NumberFor { *self.persisted_state.voting_oracle.best_grandpa_block_header.number() diff --git a/substrate/frame/beefy-mmr/src/lib.rs b/substrate/frame/beefy-mmr/src/lib.rs index ec1519ac41..b12eb95f65 100644 --- a/substrate/frame/beefy-mmr/src/lib.rs +++ b/substrate/frame/beefy-mmr/src/lib.rs @@ -73,8 +73,8 @@ where /// Convert BEEFY secp256k1 public keys into Ethereum addresses pub struct BeefyEcdsaToEthereum; -impl Convert> for BeefyEcdsaToEthereum { - fn convert(beefy_id: sp_consensus_beefy::crypto::AuthorityId) -> Vec { +impl Convert> for BeefyEcdsaToEthereum { + fn convert(beefy_id: sp_consensus_beefy::ecdsa_crypto::AuthorityId) -> Vec { sp_core::ecdsa::Public::from(beefy_id) .to_eth_address() .map(|v| v.to_vec()) @@ -200,11 +200,12 @@ impl Pallet { .map(T::BeefyAuthorityToMerkleLeaf::convert) .collect::>(); let len = beefy_addresses.len() as u32; - let root = binary_merkle_tree::merkle_root::<::Hashing, _>( - beefy_addresses, - ) + let keyset_commitment = binary_merkle_tree::merkle_root::< + ::Hashing, + _, + >(beefy_addresses) .into(); - BeefyAuthoritySet { id, len, root } + BeefyAuthoritySet { id, len, keyset_commitment } } } diff --git a/substrate/frame/beefy-mmr/src/mock.rs b/substrate/frame/beefy-mmr/src/mock.rs index b17550653d..2c37ad4483 100644 --- a/substrate/frame/beefy-mmr/src/mock.rs +++ b/substrate/frame/beefy-mmr/src/mock.rs @@ -36,7 +36,7 @@ use sp_runtime::{ use crate as pallet_beefy_mmr; pub use sp_consensus_beefy::{ - crypto::AuthorityId as BeefyId, mmr::BeefyDataProvider, ConsensusLog, BEEFY_ENGINE_ID, + ecdsa_crypto::AuthorityId as BeefyId, mmr::BeefyDataProvider, ConsensusLog, BEEFY_ENGINE_ID, }; impl_opaque_keys! { diff --git a/substrate/frame/beefy-mmr/src/tests.rs b/substrate/frame/beefy-mmr/src/tests.rs index 067c3851ba..ec756f83df 100644 --- a/substrate/frame/beefy-mmr/src/tests.rs +++ b/substrate/frame/beefy-mmr/src/tests.rs @@ -119,7 +119,7 @@ fn should_contain_valid_leaf_data() { beefy_next_authority_set: BeefyNextAuthoritySet { id: 2, len: 2, - root: array_bytes::hex_n_into_unchecked( + keyset_commitment: array_bytes::hex_n_into_unchecked( "9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5" ) }, @@ -144,7 +144,7 @@ fn should_contain_valid_leaf_data() { beefy_next_authority_set: BeefyNextAuthoritySet { id: 3, len: 2, - root: array_bytes::hex_n_into_unchecked( + keyset_commitment: array_bytes::hex_n_into_unchecked( "9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5" ) }, @@ -167,12 +167,12 @@ fn should_update_authorities() { let want = array_bytes::hex_n_into_unchecked::<_, H256, 32>( "176e73f1bf656478b728e28dd1a7733c98621b8acf830bff585949763dca7a96", ); - assert_eq!(want, auth_set.root); + assert_eq!(want, auth_set.keyset_commitment); // next authority set should have same validators but different id assert_eq!(1, next_auth_set.id); assert_eq!(auth_set.len, next_auth_set.len); - assert_eq!(auth_set.root, next_auth_set.root); + assert_eq!(auth_set.keyset_commitment, next_auth_set.keyset_commitment); let announced_set = next_auth_set; init_block(1); @@ -188,7 +188,7 @@ fn should_update_authorities() { "9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5", ); assert_eq!(2, next_auth_set.len); - assert_eq!(want, next_auth_set.root); + assert_eq!(want, next_auth_set.keyset_commitment); let announced_set = next_auth_set; init_block(2); @@ -204,6 +204,6 @@ fn should_update_authorities() { "9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5", ); assert_eq!(2, next_auth_set.len); - assert_eq!(want, next_auth_set.root); + assert_eq!(want, next_auth_set.keyset_commitment); }); } diff --git a/substrate/frame/beefy/src/equivocation.rs b/substrate/frame/beefy/src/equivocation.rs index acbd3a2532..84c62fc47f 100644 --- a/substrate/frame/beefy/src/equivocation.rs +++ b/substrate/frame/beefy/src/equivocation.rs @@ -41,7 +41,7 @@ use frame_support::{ }; use frame_system::pallet_prelude::BlockNumberFor; use log::{error, info}; -use sp_consensus_beefy::{EquivocationProof, ValidatorSetId, KEY_TYPE}; +use sp_consensus_beefy::{EquivocationProof, ValidatorSetId, KEY_TYPE as BEEFY_KEY_TYPE}; use sp_runtime::{ transaction_validity::{ InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, @@ -172,7 +172,7 @@ where let (equivocation_proof, key_owner_proof) = evidence; // Check the membership proof to extract the offender's id - let key = (KEY_TYPE, equivocation_proof.offender_id().clone()); + let key = (BEEFY_KEY_TYPE, equivocation_proof.offender_id().clone()); let offender = P::check_proof(key, key_owner_proof).ok_or(InvalidTransaction::BadProof)?; // Check if the offence has already been reported, and if so then we can discard the report. @@ -206,7 +206,7 @@ where let validator_set_count = key_owner_proof.validator_count(); // Validate the key ownership proof extracting the id of the offender. - let offender = P::check_proof((KEY_TYPE, offender), key_owner_proof) + let offender = P::check_proof((BEEFY_KEY_TYPE, offender), key_owner_proof) .ok_or(Error::::InvalidKeyOwnershipProof)?; // Validate equivocation proof (check votes are different and signatures are valid). diff --git a/substrate/frame/beefy/src/mock.rs b/substrate/frame/beefy/src/mock.rs index 26a13fe16c..af770c0b49 100644 --- a/substrate/frame/beefy/src/mock.rs +++ b/substrate/frame/beefy/src/mock.rs @@ -39,7 +39,7 @@ use sp_staking::{EraIndex, SessionIndex}; use crate as pallet_beefy; pub use sp_consensus_beefy::{ - crypto::{AuthorityId as BeefyId, AuthoritySignature as BeefySignature}, + ecdsa_crypto::{AuthorityId as BeefyId, AuthoritySignature as BeefySignature}, ConsensusLog, EquivocationProof, BEEFY_ENGINE_ID, }; diff --git a/substrate/frame/beefy/src/tests.rs b/substrate/frame/beefy/src/tests.rs index 8a8c6ae109..e04dc330d0 100644 --- a/substrate/frame/beefy/src/tests.rs +++ b/substrate/frame/beefy/src/tests.rs @@ -20,7 +20,7 @@ use std::vec; use codec::Encode; use sp_consensus_beefy::{ check_equivocation_proof, generate_equivocation_proof, known_payloads::MMR_ROOT_ID, - Keyring as BeefyKeyring, Payload, ValidatorSet, + Keyring as BeefyKeyring, Payload, ValidatorSet, KEY_TYPE as BEEFY_KEY_TYPE, }; use sp_runtime::DigestItem; @@ -297,8 +297,7 @@ fn report_equivocation_current_set_works() { ); // create the key ownership proof - let key_owner_proof = - Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap(); + let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap(); // report the equivocation and the tx should be dispatched successfully assert_ok!(Beefy::report_equivocation_unsigned( @@ -354,8 +353,7 @@ fn report_equivocation_old_set_works() { let equivocation_key = &authorities[equivocation_authority_index]; // create the key ownership proof in the "old" set - let key_owner_proof = - Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap(); + let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap(); start_era(2); @@ -436,8 +434,7 @@ fn report_equivocation_invalid_set_id() { let equivocation_key = &authorities[equivocation_authority_index]; let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); - let key_owner_proof = - Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap(); + let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap(); let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); @@ -475,8 +472,7 @@ fn report_equivocation_invalid_session() { let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); // generate a key ownership proof at current era set id - let key_owner_proof = - Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap(); + let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap(); start_era(2); @@ -520,7 +516,7 @@ fn report_equivocation_invalid_key_owner_proof() { // generate a key ownership proof for the authority at index 1 let invalid_key_owner_proof = - Historical::prove((sp_consensus_beefy::KEY_TYPE, &invalid_owner_key)).unwrap(); + Historical::prove((BEEFY_KEY_TYPE, &invalid_owner_key)).unwrap(); let equivocation_authority_index = 0; let equivocation_key = &authorities[equivocation_authority_index]; @@ -568,8 +564,7 @@ fn report_equivocation_invalid_equivocation_proof() { let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); // generate a key ownership proof at set id in era 1 - let key_owner_proof = - Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap(); + let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap(); let assert_invalid_equivocation_proof = |equivocation_proof| { assert_err!( @@ -649,8 +644,7 @@ fn report_equivocation_validate_unsigned_prevents_duplicates() { (block_num, payload2, set_id, &equivocation_keyring), ); - let key_owner_proof = - Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap(); + let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap(); let call = Call::report_equivocation_unsigned { equivocation_proof: Box::new(equivocation_proof.clone()), @@ -755,8 +749,7 @@ fn valid_equivocation_reports_dont_pay_fees() { ); // create the key ownership proof. - let key_owner_proof = - Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap(); + let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap(); // check the dispatch info for the call. let info = Call::::report_equivocation_unsigned { diff --git a/substrate/primitives/application-crypto/Cargo.toml b/substrate/primitives/application-crypto/Cargo.toml index 7431fc1fd5..eb7f253f1b 100644 --- a/substrate/primitives/application-crypto/Cargo.toml +++ b/substrate/primitives/application-crypto/Cargo.toml @@ -54,4 +54,7 @@ full_crypto = [ # This feature adds BLS crypto primitives. It should not be used in production since # the BLS implementation and interface may still be subject to significant change. -bls-experimental = [ "sp-core/bls-experimental" ] +bls-experimental = [ + "sp-core/bls-experimental", + "sp-io/bls-experimental", +] diff --git a/substrate/primitives/application-crypto/src/bls377.rs b/substrate/primitives/application-crypto/src/bls377.rs index 7fbbec5466..ee17060564 100644 --- a/substrate/primitives/application-crypto/src/bls377.rs +++ b/substrate/primitives/application-crypto/src/bls377.rs @@ -16,6 +16,7 @@ // limitations under the License. //! BLS12-377 crypto applications. +use crate::{KeyTypeId, RuntimePublic}; pub use sp_core::bls::bls377::*; @@ -26,3 +27,30 @@ mod app { #[cfg(feature = "full_crypto")] pub use app::Pair as AppPair; pub use app::{Public as AppPublic, Signature as AppSignature}; + +impl RuntimePublic for Public { + type Signature = Signature; + + /// Dummy implementation. Returns an empty vector. + fn all(_key_type: KeyTypeId) -> Vec { + Vec::new() + } + + fn generate_pair(key_type: KeyTypeId, seed: Option>) -> Self { + sp_io::crypto::bls377_generate(key_type, seed) + } + + /// Dummy implementation. Returns `None`. + fn sign>(&self, _key_type: KeyTypeId, _msg: &M) -> Option { + None + } + + /// Dummy implementation. Returns `false`. + fn verify>(&self, _msg: &M, _signature: &Self::Signature) -> bool { + false + } + + fn to_raw_vec(&self) -> Vec { + sp_core::crypto::ByteArray::to_raw_vec(self) + } +} diff --git a/substrate/primitives/consensus/beefy/Cargo.toml b/substrate/primitives/consensus/beefy/Cargo.toml index 90cd3e7f21..e6445919e2 100644 --- a/substrate/primitives/consensus/beefy/Cargo.toml +++ b/substrate/primitives/consensus/beefy/Cargo.toml @@ -27,7 +27,7 @@ lazy_static = "1.4.0" [dev-dependencies] array-bytes = "6.1" -sp-keystore = { version = "0.27.0", path = "../../keystore" } +w3f-bls = { version = "0.1.3", features = ["std"]} [features] default = ["std"] @@ -42,7 +42,6 @@ std = [ "sp-mmr-primitives/std", "sp-runtime/std", "sp-std/std", - "sp-keystore/std" ] # Serde support without relying on std features. @@ -53,3 +52,10 @@ serde = [ "sp-core/serde", "sp-runtime/serde", ] + +# This feature adds BLS crypto primitives. It should not be used in production since +# the BLS implementation and interface may still be subject to significant change. +bls-experimental = [ + "sp-core/bls-experimental", + "sp-application-crypto/bls-experimental", +] diff --git a/substrate/primitives/consensus/beefy/src/commitment.rs b/substrate/primitives/consensus/beefy/src/commitment.rs index 8ad3cc3721..5b6ef9ae5a 100644 --- a/substrate/primitives/consensus/beefy/src/commitment.rs +++ b/substrate/primitives/consensus/beefy/src/commitment.rs @@ -249,30 +249,60 @@ impl From> for VersionedFinalityProof { #[cfg(test)] mod tests { + use super::*; - use crate::{crypto, known_payloads, KEY_TYPE}; + use crate::{ecdsa_crypto::Signature as EcdsaSignature, known_payloads}; use codec::Decode; use sp_core::{keccak_256, Pair}; - use sp_keystore::{testing::MemoryKeystore, KeystorePtr}; + + #[cfg(feature = "bls-experimental")] + use crate::bls_crypto::Signature as BlsSignature; type TestCommitment = Commitment; - type TestSignedCommitment = SignedCommitment; - type TestVersionedFinalityProof = VersionedFinalityProof; const LARGE_RAW_COMMITMENT: &[u8] = include_bytes!("../test-res/large-raw-commitment"); - // The mock signatures are equivalent to the ones produced by the BEEFY keystore - fn mock_signatures() -> (crypto::Signature, crypto::Signature) { - let store: KeystorePtr = MemoryKeystore::new().into(); + // Types for bls-less commitment + type TestEcdsaSignedCommitment = SignedCommitment; + type TestVersionedFinalityProof = VersionedFinalityProof; + // Types for commitment supporting aggregatable bls signature + #[cfg(feature = "bls-experimental")] + #[derive(Clone, Debug, PartialEq, codec::Encode, codec::Decode)] + struct BlsAggregatableSignature(BlsSignature); + + #[cfg(feature = "bls-experimental")] + #[derive(Clone, Debug, PartialEq, codec::Encode, codec::Decode)] + struct EcdsaBlsSignaturePair(EcdsaSignature, BlsSignature); + + #[cfg(feature = "bls-experimental")] + type TestBlsSignedCommitment = SignedCommitment; + + // Generates mock aggregatable ecdsa signature for generating test commitment + // BLS signatures + fn mock_ecdsa_signatures() -> (EcdsaSignature, EcdsaSignature) { let alice = sp_core::ecdsa::Pair::from_string("//Alice", None).unwrap(); - store.insert(KEY_TYPE, "//Alice", alice.public().as_ref()).unwrap(); let msg = keccak_256(b"This is the first message"); - let sig1 = store.ecdsa_sign_prehashed(KEY_TYPE, &alice.public(), &msg).unwrap().unwrap(); + let sig1 = alice.sign_prehashed(&msg); let msg = keccak_256(b"This is the second message"); - let sig2 = store.ecdsa_sign_prehashed(KEY_TYPE, &alice.public(), &msg).unwrap().unwrap(); + let sig2 = alice.sign_prehashed(&msg); + + (sig1.into(), sig2.into()) + } + + // Generates mock aggregatable bls signature for generating test commitment + // BLS signatures + #[cfg(feature = "bls-experimental")] + fn mock_bls_signatures() -> (BlsSignature, BlsSignature) { + let alice = sp_core::bls::Pair::from_string("//Alice", None).unwrap(); + + let msg = b"This is the first message"; + let sig1 = alice.sign(msg); + + let msg = b"This is the second message"; + let sig2 = alice.sign(msg); (sig1.into(), sig2.into()) } @@ -300,26 +330,26 @@ mod tests { } #[test] - fn signed_commitment_encode_decode() { + fn signed_commitment_encode_decode_ecdsa() { // given let payload = Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; - let sigs = mock_signatures(); + let ecdsa_sigs = mock_ecdsa_signatures(); - let signed = SignedCommitment { - commitment, - signatures: vec![None, None, Some(sigs.0), Some(sigs.1)], + let ecdsa_signed = SignedCommitment { + commitment: commitment.clone(), + signatures: vec![None, None, Some(ecdsa_sigs.0.clone()), Some(ecdsa_sigs.1.clone())], }; // when - let encoded = codec::Encode::encode(&signed); - let decoded = TestSignedCommitment::decode(&mut &*encoded); + let encoded = codec::Encode::encode(&ecdsa_signed); + let decoded = TestEcdsaSignedCommitment::decode(&mut &*encoded); // then - assert_eq!(decoded, Ok(signed)); + assert_eq!(decoded, Ok(ecdsa_signed)); assert_eq!( encoded, array_bytes::hex2bytes_unchecked( @@ -334,6 +364,44 @@ mod tests { ); } + #[test] + #[cfg(feature = "bls-experimental")] + fn signed_commitment_encode_decode_ecdsa_n_bls() { + // given + let payload = + Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); + let commitment: TestCommitment = + Commitment { payload, block_number: 5, validator_set_id: 0 }; + + let ecdsa_sigs = mock_ecdsa_signatures(); + + //including bls signature + let bls_signed_msgs = mock_bls_signatures(); + + let ecdsa_and_bls_signed = SignedCommitment { + commitment, + signatures: vec![ + None, + None, + Some(EcdsaBlsSignaturePair(ecdsa_sigs.0, bls_signed_msgs.0)), + Some(EcdsaBlsSignaturePair(ecdsa_sigs.1, bls_signed_msgs.1)), + ], + }; + + //when + let encoded = codec::Encode::encode(&ecdsa_and_bls_signed); + let decoded = TestBlsSignedCommitment::decode(&mut &*encoded); + + // then + assert_eq!(decoded, Ok(ecdsa_and_bls_signed)); + assert_eq!( + encoded, + array_bytes::hex2bytes_unchecked( + "046d68343048656c6c6f20576f726c642105000000000000000000000000000000000000000000000004300400000008558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01667603fc041cf9d7147d22bf54b15e5778893d6986b71a929747befd3b4d233fbe668bc480e8865116b94db46ca25a01e03c71955f2582604e415da68f2c3c406b9d5f4ad416230ec5453f05ac16a50d8d0923dfb0413cc956ae3fa6334465bd1f2cacec8e9cd606438390fe2a29dc052d6e1f8105c337a86cdd9aaacdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b6a0046395a71681be3d0c2a00df61d3b2be0963eb6caa243cc505d327aec73e1bb7ffe9a14b1354b0c406792ac6d6f47c06987c15dec9993f43eefa001d866fe0850d986702c414840f0d9ec0fdc04832ef91ae37c8d49e2f573ca50cb37f152801d489a19395cb04e5fc8f2ab6954b58a3bcc40ef9b6409d2ff7ef07" + ) + ); + } + #[test] fn signed_commitment_count_signatures() { // given @@ -342,7 +410,7 @@ mod tests { let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; - let sigs = mock_signatures(); + let sigs = mock_ecdsa_signatures(); let mut signed = SignedCommitment { commitment, @@ -389,7 +457,7 @@ mod tests { let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; - let sigs = mock_signatures(); + let sigs = mock_ecdsa_signatures(); let signed = SignedCommitment { commitment, @@ -416,7 +484,7 @@ mod tests { let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; - let sigs = mock_signatures(); + let sigs = mock_ecdsa_signatures(); let signatures: Vec> = (0..1024) .into_iter() @@ -426,7 +494,7 @@ mod tests { // when let encoded = codec::Encode::encode(&signed); - let decoded = TestSignedCommitment::decode(&mut &*encoded); + let decoded = TestEcdsaSignedCommitment::decode(&mut &*encoded); // then assert_eq!(decoded, Ok(signed)); diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 6132c01187..c69e26bf57 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -51,7 +51,7 @@ use sp_runtime::traits::{Hash, Keccak256, NumberFor}; use sp_std::prelude::*; /// Key type for BEEFY module. -pub const KEY_TYPE: sp_application_crypto::KeyTypeId = sp_application_crypto::KeyTypeId(*b"beef"); +pub const KEY_TYPE: sp_core::crypto::KeyTypeId = sp_application_crypto::key_types::BEEFY; /// Trait representing BEEFY authority id, including custom signature verification. /// @@ -63,23 +63,21 @@ pub trait BeefyAuthorityId: RuntimeAppPublic { fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool; } -/// BEEFY cryptographic types +/// BEEFY cryptographic types for ECDSA crypto /// -/// This module basically introduces three crypto types: -/// - `crypto::Pair` -/// - `crypto::Public` -/// - `crypto::Signature` +/// This module basically introduces four crypto types: +/// - `ecdsa_crypto::Pair` +/// - `ecdsa_crypto::Public` +/// - `ecdsa_crypto::Signature` +/// - `ecdsa_crypto::AuthorityId` /// /// Your code should use the above types as concrete types for all crypto related /// functionality. -/// -/// The current underlying crypto scheme used is ECDSA. This can be changed, -/// without affecting code restricted against the above listed crypto types. -pub mod crypto { - use super::{BeefyAuthorityId, Hash, RuntimeAppPublic}; +pub mod ecdsa_crypto { + use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE as BEEFY_KEY_TYPE}; use sp_application_crypto::{app_crypto, ecdsa}; use sp_core::crypto::Wraps; - app_crypto!(ecdsa, crate::KEY_TYPE); + app_crypto!(ecdsa, BEEFY_KEY_TYPE); /// Identity of a BEEFY authority using ECDSA as its crypto. pub type AuthorityId = Public; @@ -104,6 +102,44 @@ pub mod crypto { } } +/// BEEFY cryptographic types for BLS crypto +/// +/// This module basically introduces four crypto types: +/// - `bls_crypto::Pair` +/// - `bls_crypto::Public` +/// - `bls_crypto::Signature` +/// - `bls_crypto::AuthorityId` +/// +/// Your code should use the above types as concrete types for all crypto related +/// functionality. + +#[cfg(feature = "bls-experimental")] +pub mod bls_crypto { + use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE as BEEFY_KEY_TYPE}; + use sp_application_crypto::{app_crypto, bls377}; + use sp_core::{bls377::Pair as BlsPair, crypto::Wraps, Pair as _}; + app_crypto!(bls377, BEEFY_KEY_TYPE); + + /// Identity of a BEEFY authority using BLS as its crypto. + pub type AuthorityId = Public; + + /// Signature for a BEEFY authority using BLS as its crypto. + pub type AuthoritySignature = Signature; + + impl BeefyAuthorityId for AuthorityId + where + ::Output: Into<[u8; 32]>, + { + fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool { + // `w3f-bls` library uses IETF hashing standard and as such does not exposes + // a choice of hash to field function. + // We are directly calling into the library to avoid introducing new host call. + // and because BeefyAuthorityId::verify is being called in the runtime so we don't have + + BlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref()) + } + } +} /// The `ConsensusEngineId` of BEEFY. pub const BEEFY_ENGINE_ID: sp_runtime::ConsensusEngineId = *b"BEEF"; @@ -304,14 +340,15 @@ impl OpaqueKeyOwnershipProof { sp_api::decl_runtime_apis! { /// API necessary for BEEFY voters. - #[api_version(2)] - pub trait BeefyApi + #[api_version(3)] + pub trait BeefyApi where + AuthorityId : Codec + RuntimeAppPublic, { /// Return the block number where BEEFY consensus is enabled/started fn beefy_genesis() -> Option>; /// Return the current active BEEFY validator set - fn validator_set() -> Option>; + fn validator_set() -> Option>; /// Submits an unsigned extrinsic to report an equivocation. The caller /// must provide the equivocation proof and a key ownership proof @@ -323,7 +360,7 @@ sp_api::decl_runtime_apis! { /// hardcoded to return `None`). Only useful in an offchain context. fn submit_report_equivocation_unsigned_extrinsic( equivocation_proof: - EquivocationProof, crypto::AuthorityId, crypto::Signature>, + EquivocationProof, AuthorityId, ::Signature>, key_owner_proof: OpaqueKeyOwnershipProof, ) -> Option<()>; @@ -340,9 +377,10 @@ sp_api::decl_runtime_apis! { /// older states to be available. fn generate_key_ownership_proof( set_id: ValidatorSetId, - authority_id: crypto::AuthorityId, + authority_id: AuthorityId, ) -> Option; } + } #[cfg(test)] @@ -366,14 +404,14 @@ mod tests { } #[test] - fn beefy_verify_works() { + fn ecdsa_beefy_verify_works() { let msg = &b"test-message"[..]; - let (pair, _) = crypto::Pair::generate(); + let (pair, _) = ecdsa_crypto::Pair::generate(); - let keccak_256_signature: crypto::Signature = + let keccak_256_signature: ecdsa_crypto::Signature = pair.as_inner_ref().sign_prehashed(&keccak_256(msg)).into(); - let blake2_256_signature: crypto::Signature = + let blake2_256_signature: ecdsa_crypto::Signature = pair.as_inner_ref().sign_prehashed(&blake2_256(msg)).into(); // Verification works if same hashing function is used when signing and verifying. @@ -392,7 +430,7 @@ mod tests { )); // Other public key doesn't work - let (other_pair, _) = crypto::Pair::generate(); + let (other_pair, _) = ecdsa_crypto::Pair::generate(); assert!(!BeefyAuthorityId::::verify( &other_pair.public(), &keccak_256_signature, @@ -404,4 +442,20 @@ mod tests { msg, )); } + + #[test] + #[cfg(feature = "bls-experimental")] + fn bls_beefy_verify_works() { + let msg = &b"test-message"[..]; + let (pair, _) = bls_crypto::Pair::generate(); + + let signature: bls_crypto::Signature = pair.as_inner_ref().sign(&msg).into(); + + // Verification works if same hashing function is used when signing and verifying. + assert!(BeefyAuthorityId::::verify(&pair.public(), &signature, msg)); + + // Other public key doesn't work + let (other_pair, _) = bls_crypto::Pair::generate(); + assert!(!BeefyAuthorityId::::verify(&other_pair.public(), &signature, msg,)); + } } diff --git a/substrate/primitives/consensus/beefy/src/mmr.rs b/substrate/primitives/consensus/beefy/src/mmr.rs index c303cae2fd..991dc07c5a 100644 --- a/substrate/primitives/consensus/beefy/src/mmr.rs +++ b/substrate/primitives/consensus/beefy/src/mmr.rs @@ -26,7 +26,7 @@ //! but we imagine they will be useful for other chains that either want to bridge with Polkadot //! or are completely standalone, but heavily inspired by Polkadot. -use crate::{crypto::AuthorityId, ConsensusLog, MmrRootHash, Vec, BEEFY_ENGINE_ID}; +use crate::{ecdsa_crypto::AuthorityId, ConsensusLog, MmrRootHash, Vec, BEEFY_ENGINE_ID}; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::{ @@ -102,7 +102,7 @@ impl MmrLeafVersion { /// Details of a BEEFY authority set. #[derive(Debug, Default, PartialEq, Eq, Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BeefyAuthoritySet { +pub struct BeefyAuthoritySet { /// Id of the set. /// /// Id is required to correlate BEEFY signed commitments with the validator set. @@ -115,12 +115,19 @@ pub struct BeefyAuthoritySet { /// of signatures. We put set length here, so that these clients can verify the minimal /// number of required signatures. pub len: u32, - /// Merkle Root Hash built from BEEFY AuthorityIds. + + /// Commitment(s) to BEEFY AuthorityIds. /// /// This is used by Light Clients to confirm that the commitments are signed by the correct /// validator set. Light Clients using interactive protocol, might verify only subset of /// signatures, hence don't require the full list here (will receive inclusion proofs). - pub root: MerkleRoot, + /// + /// This could be Merkle Root Hash built from BEEFY ECDSA public keys and/or + /// polynomial commitment to the polynomial interpolating BLS public keys + /// which is used by APK proof based light clients to verify the validity + /// of aggregated BLS keys using APK proofs. + /// Multiple commitments can be tupled together. + pub keyset_commitment: AuthoritySetCommitment, } /// Details of the next BEEFY authority set. diff --git a/substrate/primitives/consensus/beefy/src/test_utils.rs b/substrate/primitives/consensus/beefy/src/test_utils.rs index 9e0758cdeb..b83f657af3 100644 --- a/substrate/primitives/consensus/beefy/src/test_utils.rs +++ b/substrate/primitives/consensus/beefy/src/test_utils.rs @@ -17,13 +17,13 @@ #![cfg(feature = "std")] -use crate::{crypto, Commitment, EquivocationProof, Payload, ValidatorSetId, VoteMessage}; +use crate::{ecdsa_crypto, Commitment, EquivocationProof, Payload, ValidatorSetId, VoteMessage}; use codec::Encode; use sp_core::{ecdsa, keccak_256, Pair}; use std::collections::HashMap; use strum::IntoEnumIterator; -/// Set of test accounts using [`crate::crypto`] types. +/// Set of test accounts using [`crate::ecdsa_crypto`] types. #[allow(missing_docs)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)] pub enum Keyring { @@ -39,19 +39,19 @@ pub enum Keyring { impl Keyring { /// Sign `msg`. - pub fn sign(self, msg: &[u8]) -> crypto::Signature { + pub fn sign(self, msg: &[u8]) -> ecdsa_crypto::Signature { // todo: use custom signature hashing type let msg = keccak_256(msg); ecdsa::Pair::from(self).sign_prehashed(&msg).into() } /// Return key pair. - pub fn pair(self) -> crypto::Pair { + pub fn pair(self) -> ecdsa_crypto::Pair { ecdsa::Pair::from_string(self.to_seed().as_str(), None).unwrap().into() } /// Return public key. - pub fn public(self) -> crypto::Public { + pub fn public(self) -> ecdsa_crypto::Public { self.pair().public() } @@ -61,19 +61,19 @@ impl Keyring { } /// Get Keyring from public key. - pub fn from_public(who: &crypto::Public) -> Option { - Self::iter().find(|&k| &crypto::Public::from(k) == who) + pub fn from_public(who: &ecdsa_crypto::Public) -> Option { + Self::iter().find(|&k| &ecdsa_crypto::Public::from(k) == who) } } lazy_static::lazy_static! { - static ref PRIVATE_KEYS: HashMap = + static ref PRIVATE_KEYS: HashMap = Keyring::iter().map(|i| (i, i.pair())).collect(); - static ref PUBLIC_KEYS: HashMap = + static ref PUBLIC_KEYS: HashMap = PRIVATE_KEYS.iter().map(|(&name, pair)| (name, pair.public())).collect(); } -impl From for crypto::Pair { +impl From for ecdsa_crypto::Pair { fn from(k: Keyring) -> Self { k.pair() } @@ -85,7 +85,7 @@ impl From for ecdsa::Pair { } } -impl From for crypto::Public { +impl From for ecdsa_crypto::Public { fn from(k: Keyring) -> Self { (*PUBLIC_KEYS).get(&k).cloned().unwrap() } @@ -95,7 +95,7 @@ impl From for crypto::Public { pub fn generate_equivocation_proof( vote1: (u64, Payload, ValidatorSetId, &Keyring), vote2: (u64, Payload, ValidatorSetId, &Keyring), -) -> EquivocationProof { +) -> EquivocationProof { let signed_vote = |block_number: u64, payload: Payload, validator_set_id: ValidatorSetId, diff --git a/substrate/primitives/consensus/beefy/src/witness.rs b/substrate/primitives/consensus/beefy/src/witness.rs index ff9a0401dc..3f2c2bcbe2 100644 --- a/substrate/primitives/consensus/beefy/src/witness.rs +++ b/substrate/primitives/consensus/beefy/src/witness.rs @@ -37,18 +37,21 @@ use crate::commitment::{Commitment, SignedCommitment}; /// Ethereum Mainnet), in a commit-reveal like scheme, where first we submit only the signed /// commitment witness and later on, the client picks only some signatures to verify at random. #[derive(Debug, PartialEq, Eq, codec::Encode, codec::Decode)] -pub struct SignedCommitmentWitness { +pub struct SignedCommitmentWitness { /// The full content of the commitment. pub commitment: Commitment, /// The bit vector of validators who signed the commitment. pub signed_by: Vec, // TODO [ToDr] Consider replacing with bitvec crate - /// A merkle root of signatures in the original signed commitment. - pub signatures_merkle_root: TMerkleRoot, + /// Either a merkle root of signatures in the original signed commitment or a single aggregated + /// BLS signature aggregating all original signatures. + pub signature_accumulator: TSignatureAccumulator, } -impl SignedCommitmentWitness { +impl + SignedCommitmentWitness +{ /// Convert [SignedCommitment] into [SignedCommitmentWitness]. /// /// This takes a [SignedCommitment], which contains full signatures @@ -57,53 +60,85 @@ impl SignedCommitmentWitness( + pub fn from_signed( signed: SignedCommitment, - merkelize: TMerkelize, + aggregator: TSignatureAggregator, ) -> (Self, Vec>) where - TMerkelize: FnOnce(&[Option]) -> TMerkleRoot, + TSignatureAggregator: FnOnce(&[Option]) -> TSignatureAccumulator, { let SignedCommitment { commitment, signatures } = signed; let signed_by = signatures.iter().map(|s| s.is_some()).collect(); - let signatures_merkle_root = merkelize(&signatures); + let signature_accumulator = aggregator(&signatures); - (Self { commitment, signed_by, signatures_merkle_root }, signatures) + (Self { commitment, signed_by, signature_accumulator }, signatures) } } #[cfg(test)] mod tests { use sp_core::{keccak_256, Pair}; - use sp_keystore::{testing::MemoryKeystore, KeystorePtr}; use super::*; use codec::Decode; - use crate::{crypto, known_payloads, Payload, KEY_TYPE}; + use crate::{ecdsa_crypto::Signature as EcdsaSignature, known_payloads, Payload}; + + #[cfg(feature = "bls-experimental")] + use crate::bls_crypto::Signature as BlsSignature; + + #[cfg(feature = "bls-experimental")] + use w3f_bls::{ + single_pop_aggregator::SignatureAggregatorAssumingPoP, Message, SerializableToBytes, + Signed, TinyBLS377, + }; type TestCommitment = Commitment; - type TestSignedCommitment = SignedCommitment; - type TestSignedCommitmentWitness = - SignedCommitmentWitness>>; + + // Types for ecdsa signed commitment. + type TestEcdsaSignedCommitment = SignedCommitment; + type TestEcdsaSignedCommitmentWitness = + SignedCommitmentWitness>>; + + #[cfg(feature = "bls-experimental")] + #[derive(Clone, Debug, PartialEq, codec::Encode, codec::Decode)] + struct EcdsaBlsSignaturePair(EcdsaSignature, BlsSignature); + + // types for commitment containing bls signature along side ecdsa signature + #[cfg(feature = "bls-experimental")] + type TestBlsSignedCommitment = SignedCommitment; + #[cfg(feature = "bls-experimental")] + type TestBlsSignedCommitmentWitness = SignedCommitmentWitness>; // The mock signatures are equivalent to the ones produced by the BEEFY keystore - fn mock_signatures() -> (crypto::Signature, crypto::Signature) { - let store: KeystorePtr = MemoryKeystore::new().into(); - + fn mock_ecdsa_signatures() -> (EcdsaSignature, EcdsaSignature) { let alice = sp_core::ecdsa::Pair::from_string("//Alice", None).unwrap(); - store.insert(KEY_TYPE, "//Alice", alice.public().as_ref()).unwrap(); let msg = keccak_256(b"This is the first message"); - let sig1 = store.ecdsa_sign_prehashed(KEY_TYPE, &alice.public(), &msg).unwrap().unwrap(); + let sig1 = alice.sign_prehashed(&msg); let msg = keccak_256(b"This is the second message"); - let sig2 = store.ecdsa_sign_prehashed(KEY_TYPE, &alice.public(), &msg).unwrap().unwrap(); + let sig2 = alice.sign_prehashed(&msg); (sig1.into(), sig2.into()) } - fn signed_commitment() -> TestSignedCommitment { + // Generates mock aggregatable bls signature for generating test commitment + // BLS signatures + #[cfg(feature = "bls-experimental")] + fn mock_bls_signatures() -> (BlsSignature, BlsSignature) { + let alice = sp_core::bls::Pair::from_string("//Alice", None).unwrap(); + + let msg = b"This is the first message"; + let sig1 = alice.sign(msg); + + let msg = b"This is the second message"; + let sig2 = alice.sign(msg); + + (sig1.into(), sig2.into()) + } + + fn ecdsa_signed_commitment() -> TestEcdsaSignedCommitment { let payload = Payload::from_single_entry( known_payloads::MMR_ROOT_ID, "Hello World!".as_bytes().to_vec(), @@ -111,35 +146,97 @@ mod tests { let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; - let sigs = mock_signatures(); + let sigs = mock_ecdsa_signatures(); SignedCommitment { commitment, signatures: vec![None, None, Some(sigs.0), Some(sigs.1)] } } + #[cfg(feature = "bls-experimental")] + fn ecdsa_and_bls_signed_commitment() -> TestBlsSignedCommitment { + let payload = Payload::from_single_entry( + known_payloads::MMR_ROOT_ID, + "Hello World!".as_bytes().to_vec(), + ); + let commitment: TestCommitment = + Commitment { payload, block_number: 5, validator_set_id: 0 }; + + let ecdsa_sigs = mock_ecdsa_signatures(); + let bls_sigs = mock_bls_signatures(); + + SignedCommitment { + commitment, + signatures: vec![ + None, + None, + Some(EcdsaBlsSignaturePair(ecdsa_sigs.0, bls_sigs.0)), + Some(EcdsaBlsSignaturePair(ecdsa_sigs.1, bls_sigs.1)), + ], + } + } + #[test] fn should_convert_signed_commitment_to_witness() { // given - let signed = signed_commitment(); + let signed = ecdsa_signed_commitment(); // when let (witness, signatures) = - TestSignedCommitmentWitness::from_signed(signed, |sigs| sigs.to_vec()); + TestEcdsaSignedCommitmentWitness::from_signed(signed, |sigs| sigs.to_vec()); // then - assert_eq!(witness.signatures_merkle_root, signatures); + assert_eq!(witness.signature_accumulator, signatures); + } + + #[test] + #[cfg(feature = "bls-experimental")] + fn should_convert_dually_signed_commitment_to_witness() { + // given + let signed = ecdsa_and_bls_signed_commitment(); + + // when + let (witness, _signatures) = + // from signed take a function as the aggregator + TestBlsSignedCommitmentWitness::from_signed::<_, _>(signed, |sigs| { + // we are going to aggregate the signatures here + let mut aggregatedsigs: SignatureAggregatorAssumingPoP = + SignatureAggregatorAssumingPoP::new(Message::new(b"", b"mock payload")); + + for sig in sigs { + match sig { + Some(sig) => { + let serialized_sig : Vec = (*sig.1).to_vec(); + aggregatedsigs.add_signature( + &w3f_bls::Signature::::from_bytes( + serialized_sig.as_slice() + ).unwrap() + ); + }, + None => (), + } + } + (&aggregatedsigs).signature().to_bytes() + }); + + // We can't use BlsSignature::try_from because it expected 112Bytes (CP (64) + BLS 48) + // single signature while we are having a BLS aggregated signature corresponding to no CP. + w3f_bls::Signature::::from_bytes(witness.signature_accumulator.as_slice()) + .unwrap(); } #[test] fn should_encode_and_decode_witness() { - // given - let signed = signed_commitment(); - let (witness, _) = TestSignedCommitmentWitness::from_signed(signed, |sigs| sigs.to_vec()); + // Given + let signed = ecdsa_signed_commitment(); + let (witness, _) = TestEcdsaSignedCommitmentWitness::from_signed::<_, _>( + signed, + |sigs: &[std::option::Option]| sigs.to_vec(), + ); - // when + // When let encoded = codec::Encode::encode(&witness); - let decoded = TestSignedCommitmentWitness::decode(&mut &*encoded); + let decoded = TestEcdsaSignedCommitmentWitness::decode(&mut &*encoded); - // then + // Then assert_eq!(decoded, Ok(witness)); assert_eq!( encoded, diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 65c3549814..59bdea961c 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -60,7 +60,6 @@ w3f-bls = { version = "0.1.3", default-features = false, optional = true} criterion = "0.4.0" serde_json = "1.0" sp-core-hashing-proc-macro = { version = "9.0.0", path = "./hashing/proc-macro" } -hex-literal = "0.3.4" [[bench]] name = "bench" diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 770f7d65ce..951aa1828e 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -34,7 +34,7 @@ use w3f_bls::{DoublePublicKey, DoubleSignature, EngineBLS, SerializableToBytes, #[cfg(feature = "full_crypto")] use w3f_bls::{DoublePublicKeyScheme, Keypair, Message, SecretKey}; -use sp_runtime_interface::pass_by::PassByInner; +use sp_runtime_interface::pass_by::{self, PassBy, PassByInner}; use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; /// BLS-377 specialized types @@ -165,6 +165,10 @@ impl PassByInner for Public { } } +impl PassBy for Public { + type PassBy = pass_by::Inner; +} + impl AsRef<[u8; PUBLIC_KEY_SERIALIZED_SIZE]> for Public { fn as_ref(&self) -> &[u8; PUBLIC_KEY_SERIALIZED_SIZE] { &self.inner @@ -514,7 +518,6 @@ mod test { use super::*; use crate::crypto::DEV_PHRASE; use bls377::{Pair, Signature}; - use hex_literal::hex; #[test] fn default_phrase_should_be_used() { @@ -529,7 +532,9 @@ mod test { // Only passes if the seed = (seed mod ScalarField) #[test] fn seed_and_derive_should_work() { - let seed = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f00"); + let seed = array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f00", + ); let pair = Pair::from_seed(&seed); // we are using hash to field so this is not going to work // assert_eq!(pair.seed(), seed); @@ -537,25 +542,27 @@ mod test { let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; assert_eq!( derived.to_raw_vec(), - hex!("a4f2269333b3e87c577aa00c4a2cd650b3b30b2e8c286a47c251279ff3a26e0d") + array_bytes::hex2array_unchecked::<_, 32>( + "a4f2269333b3e87c577aa00c4a2cd650b3b30b2e8c286a47c251279ff3a26e0d" + ) ); } #[test] fn test_vector_should_work() { - let pair = Pair::from_seed(&hex!( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", )); let public = pair.public(); assert_eq!( public, - Public::unchecked_from(hex!( + Public::unchecked_from(array_bytes::hex2array_unchecked( "7a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" )) ); let message = b""; let signature = - hex!("d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b" + array_bytes::hex2array_unchecked("d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b" ); let signature = Signature::unchecked_from(signature); assert!(pair.sign(&message[..]) == signature); @@ -572,13 +579,13 @@ mod test { let public = pair.public(); assert_eq!( public, - Public::unchecked_from(hex!( + Public::unchecked_from(array_bytes::hex2array_unchecked( "6dc6be608fab3c6bd894a606be86db346cc170db85c733853a371f3db54ae1b12052c0888d472760c81b537572a26f00db865e5963aef8634f9917571c51b538b564b2a9ceda938c8b930969ee3b832448e08e33a79e9ddd28af419a3ce45300f5dbc768b067781f44f3fe05a19e6b07b1c4196151ec3f8ea37e4f89a8963030d2101e931276bb9ebe1f20102239d780" )) ); let message = b""; let signature = - hex!("bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c" + array_bytes::hex2array_unchecked("bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c" ); let expected_signature = Signature::unchecked_from(signature); println!("signature is {:?}", pair.sign(&message[..])); @@ -603,12 +610,12 @@ mod test { assert_eq!( public, Public::unchecked_from( - hex!( + array_bytes::hex2array_unchecked( "754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080") ) ); let message = - hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" + array_bytes::hex2bytes_unchecked("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" ); let signature = pair.sign(&message[..]); println!("Correct signature: {:?}", signature); diff --git a/substrate/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index 061d60d94f..91e5898fda 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -1144,6 +1144,8 @@ pub mod key_types { pub const ACCOUNT: KeyTypeId = KeyTypeId(*b"acco"); /// Key type for Aura module, built-in. Identified as `aura`. pub const AURA: KeyTypeId = KeyTypeId(*b"aura"); + /// Key type for BEEFY module. + pub const BEEFY: KeyTypeId = KeyTypeId(*b"beef"); /// Key type for ImOnline module, built-in. Identified as `imon`. pub const IM_ONLINE: KeyTypeId = KeyTypeId(*b"imon"); /// Key type for AuthorityDiscovery module, built-in. Identified as `audi`. diff --git a/substrate/primitives/io/Cargo.toml b/substrate/primitives/io/Cargo.toml index fc87ff0bc6..141e74d526 100644 --- a/substrate/primitives/io/Cargo.toml +++ b/substrate/primitives/io/Cargo.toml @@ -92,3 +92,9 @@ disable_allocator = [] # host function to be supported by the host. Do *not* enable it for your # runtime without first upgrading your host client! improved_panic_error_reporting = [] + +# This feature adds BLS crypto primitives. It should not be used in production since +# the BLS implementation and interface may still be subject to significant change. +bls-experimental = [ + "sp-keystore/bls-experimental", +] diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index 0290335d43..4540fa5003 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -103,6 +103,9 @@ use sp_core::{ LogLevel, LogLevelFilter, OpaquePeerId, H256, }; +#[cfg(feature = "bls-experimental")] +use sp_core::bls377; + #[cfg(feature = "std")] use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration}; @@ -1186,6 +1189,21 @@ pub trait Crypto { .map_err(|_| EcdsaVerifyError::BadSignature)?; Ok(pubkey.serialize()) } + + #[cfg(feature = "bls-experimental")] + /// Generate an `bls12-377` key for the given key type using an optional `seed` and + /// store it in the keystore. + /// + /// The `seed` needs to be a valid utf8. + /// + /// Returns the public key. + fn bls377_generate(&mut self, id: KeyTypeId, seed: Option>) -> bls377::Public { + let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); + self.extension::() + .expect("No `keystore` associated for the current context!") + .bls377_generate_new(id, seed) + .expect("`bls377_generate` failed") + } } /// Interface that provides functions for hashing with different algorithms.