From c8af3df37dea168a6d83f49561660b74d16265c6 Mon Sep 17 00:00:00 2001 From: Skalman Date: Sat, 1 Jun 2024 08:38:55 +0000 Subject: [PATCH 01/12] - Implement boiler-plates for BLS12-381 crypto. - Make BEEFY pair crypto to be (ECDSA,BLS12-381) instead of (ECDSA,BLS12-377) --- .../client/consensus/beefy/src/keystore.rs | 23 ++-- substrate/client/keystore/src/local.rs | 39 ++++++- .../application-crypto/src/bls377.rs | 4 +- .../application-crypto/src/bls381.rs | 29 +++++ .../application-crypto/src/ecdsa_bls381.rs | 58 ++++++++++ .../primitives/application-crypto/src/lib.rs | 2 + .../primitives/consensus/beefy/src/lib.rs | 12 +-- substrate/primitives/core/src/bls.rs | 3 + substrate/primitives/core/src/lib.rs | 2 +- .../primitives/core/src/paired_crypto.rs | 100 ++++++++++++++++++ substrate/primitives/core/src/testing.rs | 2 + substrate/primitives/io/src/lib.rs | 36 ++++++- substrate/primitives/keystore/src/lib.rs | 95 ++++++++++++++++- substrate/primitives/keystore/src/testing.rs | 39 ++++++- 14 files changed, 419 insertions(+), 25 deletions(-) create mode 100644 substrate/primitives/application-crypto/src/ecdsa_bls381.rs diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index 8daf3440c7d2..6685407bb496 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -5,6 +5,7 @@ // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by + // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. @@ -20,7 +21,7 @@ use log::warn; use sp_application_crypto::{key_types::BEEFY as BEEFY_KEY_TYPE, AppCrypto, RuntimeAppPublic}; #[cfg(feature = "bls-experimental")] -use sp_core::ecdsa_bls377; +use sp_core::ecdsa_bls381; use sp_core::{ecdsa, keccak_256}; use sp_keystore::KeystorePtr; @@ -100,13 +101,13 @@ impl BeefyKeystore { }, #[cfg(feature = "bls-experimental")] - ecdsa_bls377::CRYPTO_ID => { - let public: ecdsa_bls377::Public = - ecdsa_bls377::Public::try_from(public.as_slice()).unwrap(); + ecdsa_bls381::CRYPTO_ID => { + let public: ecdsa_bls381::Public = + ecdsa_bls381::Public::try_from(public.as_slice()).unwrap(); let sig = store - .ecdsa_bls377_sign_with_keccak256(BEEFY_KEY_TYPE, &public, &message) + .ecdsa_bls381_sign_with_keccak256(BEEFY_KEY_TYPE, &public, &message) .map_err(|e| error::Error::Keystore(e.to_string()))? - .ok_or_else(|| error::Error::Signature("bls377_sign() failed".to_string()))?; + .ok_or_else(|| error::Error::Signature("bls381_sign() failed".to_string()))?; let sig_ref: &[u8] = sig.as_ref(); sig_ref.to_vec() }, @@ -146,8 +147,8 @@ impl BeefyKeystore { }), #[cfg(feature = "bls-experimental")] - ecdsa_bls377::CRYPTO_ID => store - .ecdsa_bls377_public_keys(BEEFY_KEY_TYPE) + ecdsa_bls381::CRYPTO_ID => store + .ecdsa_bls381_public_keys(BEEFY_KEY_TYPE) .drain(..) .map(|pk| AuthorityId::try_from(pk.as_ref())) .collect::, _>>() @@ -254,9 +255,9 @@ pub mod tests { AuthorityId::decode(&mut pk.as_ref()).unwrap() }, #[cfg(feature = "bls-experimental")] - ecdsa_bls377::CRYPTO_ID => { + ecdsa_bls381::CRYPTO_ID => { let pk = store - .ecdsa_bls377_generate_new(key_type, optional_seed.as_deref()) + .ecdsa_bls381_generate_new(key_type, optional_seed.as_deref()) .ok() .unwrap(); AuthorityId::decode(&mut pk.as_ref()).unwrap() @@ -452,7 +453,7 @@ pub mod tests { #[cfg(feature = "bls-experimental")] #[test] fn sign_error_for_ecdsa_n_bls() { - sign_error::("bls377_sign() failed"); + sign_error::("bls381_sign() failed"); } #[test] diff --git a/substrate/client/keystore/src/local.rs b/substrate/client/keystore/src/local.rs index 8b922c11cbca..146e2eb5b7cb 100644 --- a/substrate/client/keystore/src/local.rs +++ b/substrate/client/keystore/src/local.rs @@ -37,7 +37,7 @@ use sp_core::bandersnatch; } sp_keystore::bls_experimental_enabled! { -use sp_core::{bls377, bls381, ecdsa_bls377, KeccakHasher}; +use sp_core::{bls377, bls381, ecdsa_bls377, ecdsa_bls381, KeccakHasher}; } use crate::{Error, Result}; @@ -418,6 +418,43 @@ impl Keystore for LocalKeystore { Ok(sig) } + fn ecdsa_bls381_public_keys(&self, key_type: KeyTypeId) -> Vec { + self.public_keys::(key_type) + } + + /// Generate a new pair of paired-keys compatible with the '(ecdsa,bls381)' signature scheme. + /// + /// If `[seed]` is `Some` then the key will be ephemeral and stored in memory. + fn ecdsa_bls381_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> std::result::Result { + self.generate_new::(key_type, seed) + } + + fn ecdsa_bls381_sign( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls381::Public, + msg: &[u8], + ) -> std::result::Result, TraitError> { + self.sign::(key_type, public, msg) + } + + fn ecdsa_bls381_sign_with_keccak256( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls381::Public, + msg: &[u8], + ) -> std::result::Result, TraitError> { + let sig = self.0 + .read() + .key_pair_by_type::(public, key_type)? + .map(|pair| pair.sign_with_hasher::(msg)); + Ok(sig) + } + } } diff --git a/substrate/primitives/application-crypto/src/bls377.rs b/substrate/primitives/application-crypto/src/bls377.rs index 3bd01de139c9..8ae0bf319084 100644 --- a/substrate/primitives/application-crypto/src/bls377.rs +++ b/substrate/primitives/application-crypto/src/bls377.rs @@ -25,7 +25,9 @@ mod app { crate::app_crypto!(super, sp_core::testing::BLS377); } -pub use app::{Pair as AppPair, Public as AppPublic, Signature as AppSignature}; +#[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; diff --git a/substrate/primitives/application-crypto/src/bls381.rs b/substrate/primitives/application-crypto/src/bls381.rs index d990f2e14c8e..865a65c408d2 100644 --- a/substrate/primitives/application-crypto/src/bls381.rs +++ b/substrate/primitives/application-crypto/src/bls381.rs @@ -16,8 +16,10 @@ // limitations under the License. //! BLS12-381 crypto applications. +use crate::{KeyTypeId, RuntimePublic}; pub use sp_core::bls::bls381::*; +use sp_std::vec::Vec; mod app { crate::app_crypto!(super, sp_core::testing::BLS381); @@ -26,3 +28,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::bls381_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/application-crypto/src/ecdsa_bls381.rs b/substrate/primitives/application-crypto/src/ecdsa_bls381.rs new file mode 100644 index 000000000000..c7adb505bc54 --- /dev/null +++ b/substrate/primitives/application-crypto/src/ecdsa_bls381.rs @@ -0,0 +1,58 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! ECDSA and BLS12-381 paired crypto applications. + +use crate::{KeyTypeId, RuntimePublic}; +use sp_std::vec::Vec; + +pub use sp_core::paired_crypto::ecdsa_bls381::*; + +mod app { + crate::app_crypto!(super, sp_core::testing::ECDSA_BLS381); +} + +#[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::ecdsa_bls381_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/application-crypto/src/lib.rs b/substrate/primitives/application-crypto/src/lib.rs index 2355f1ba527d..b0ca659ffa6f 100644 --- a/substrate/primitives/application-crypto/src/lib.rs +++ b/substrate/primitives/application-crypto/src/lib.rs @@ -49,6 +49,8 @@ pub mod bls381; pub mod ecdsa; #[cfg(feature = "bls-experimental")] pub mod ecdsa_bls377; +#[cfg(feature = "bls-experimental")] +pub mod ecdsa_bls381; pub mod ed25519; pub mod sr25519; mod traits; diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 913184402aef..44a1e9477b16 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -142,10 +142,10 @@ pub mod ecdsa_crypto { #[cfg(feature = "bls-experimental")] pub mod bls_crypto { use super::{AuthorityIdBound, BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; - use sp_application_crypto::{app_crypto, bls377}; - use sp_core::{bls377::Pair as BlsPair, crypto::Wraps, Pair as _}; + use sp_application_crypto::{app_crypto, bls381}; + use sp_core::{bls381::Pair as BlsPair, crypto::Wraps, Pair as _}; - app_crypto!(bls377, KEY_TYPE); + app_crypto!(bls381, KEY_TYPE); /// Identity of a BEEFY authority using BLS as its crypto. pub type AuthorityId = Public; @@ -184,10 +184,10 @@ pub mod bls_crypto { #[cfg(feature = "bls-experimental")] pub mod ecdsa_bls_crypto { use super::{AuthorityIdBound, BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; - use sp_application_crypto::{app_crypto, ecdsa_bls377}; - use sp_core::{crypto::Wraps, ecdsa_bls377::Pair as EcdsaBlsPair}; + use sp_application_crypto::{app_crypto, ecdsa_bls381}; + use sp_core::{crypto::Wraps, ecdsa_bls381::Pair as EcdsaBlsPair}; - app_crypto!(ecdsa_bls377, KEY_TYPE); + app_crypto!(ecdsa_bls381, KEY_TYPE); /// Identity of a BEEFY authority using (ECDSA,BLS) as its crypto. pub type AuthorityId = Public; diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index bb04babb3f18..ed448ff753c6 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -68,6 +68,9 @@ pub mod bls381 { /// An identifier used to match public keys against BLS12-381 keys pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"bls8"); + #[doc(hidden)] + pub type Bls381Tag = TinyBLS381; + /// BLS12-381 key pair. pub type Pair = super::Pair; /// BLS12-381 public key. diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index 098bd135bfeb..e4962255cadd 100644 --- a/substrate/primitives/core/src/lib.rs +++ b/substrate/primitives/core/src/lib.rs @@ -80,7 +80,7 @@ pub mod sr25519; #[cfg(feature = "bls-experimental")] pub use bls::{bls377, bls381}; #[cfg(feature = "bls-experimental")] -pub use paired_crypto::ecdsa_bls377; +pub use paired_crypto::{ecdsa_bls377, ecdsa_bls381}; pub use self::{ hash::{convert_hash, H160, H256, H512}, diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 260e86b6ff9c..f600f01e2c48 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -126,6 +126,106 @@ pub mod ecdsa_bls377 { } } +/// ECDSA and BLS12-381 paired crypto scheme +#[cfg(feature = "bls-experimental")] +pub mod ecdsa_bls381 { + use crate::{bls381, crypto::CryptoTypeId, ecdsa}; + #[cfg(feature = "full_crypto")] + use crate::{ + crypto::{Pair as PairT, UncheckedFrom}, + Hasher, + }; + + /// An identifier used to match public keys against BLS12-381 keys + pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb8"); + + const PUBLIC_KEY_LEN: usize = + ecdsa::PUBLIC_KEY_SERIALIZED_SIZE + bls381::PUBLIC_KEY_SERIALIZED_SIZE; + const SIGNATURE_LEN: usize = + ecdsa::SIGNATURE_SERIALIZED_SIZE + bls381::SIGNATURE_SERIALIZED_SIZE; + + #[doc(hidden)] + pub struct EcdsaBls381Tag(ecdsa::EcdsaTag, bls381::Bls381Tag); + + impl super::PairedCryptoSubTagBound for EcdsaBls381Tag {} + + /// (ECDSA,BLS12-381) key-pair pair. + pub type Pair = + super::Pair; + + /// (ECDSA,BLS12-381) public key pair. + pub type Public = super::Public; + + /// (ECDSA,BLS12-381) signature pair. + pub type Signature = super::Signature; + + impl super::CryptoType for Public { + type Pair = Pair; + } + + impl super::CryptoType for Signature { + type Pair = Pair; + } + + impl super::CryptoType for Pair { + type Pair = Pair; + } + + #[cfg(feature = "full_crypto")] + impl Pair { + /// Hashes the `message` with the specified [`Hasher`] before signing with the ECDSA secret + /// component. + /// + /// The hasher does not affect the BLS12-381 component. This generates BLS12-381 Signature + /// according to IETF standard. + pub fn sign_with_hasher(&self, message: &[u8]) -> Signature + where + H: Hasher, + H::Out: Into<[u8; 32]>, + { + let msg_hash = H::hash(message).into(); + + let mut raw: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; + raw[..ecdsa::SIGNATURE_SERIALIZED_SIZE] + .copy_from_slice(self.left.sign_prehashed(&msg_hash).as_ref()); + raw[ecdsa::SIGNATURE_SERIALIZED_SIZE..] + .copy_from_slice(self.right.sign(message).as_ref()); + ::Signature::unchecked_from(raw) + } + + /// Hashes the `message` with the specified [`Hasher`] before verifying with the ECDSA + /// public component. + /// + /// The hasher does not affect the the BLS12-381 component. This verifies whether the + /// BLS12-381 signature was hashed and signed according to IETF standard + pub fn verify_with_hasher(sig: &Signature, message: &[u8], public: &Public) -> bool + where + H: Hasher, + H::Out: Into<[u8; 32]>, + { + let msg_hash = H::hash(message).into(); + + let Ok(left_pub) = public.0[..ecdsa::PUBLIC_KEY_SERIALIZED_SIZE].try_into() else { + return false + }; + let Ok(left_sig) = sig.0[..ecdsa::SIGNATURE_SERIALIZED_SIZE].try_into() else { + return false + }; + if !ecdsa::Pair::verify_prehashed(&left_sig, &msg_hash, &left_pub) { + return false + } + + let Ok(right_pub) = public.0[ecdsa::PUBLIC_KEY_SERIALIZED_SIZE..].try_into() else { + return false + }; + let Ok(right_sig) = sig.0[ecdsa::SIGNATURE_SERIALIZED_SIZE..].try_into() else { + return false + }; + bls381::Pair::verify(&right_sig, message, &right_pub) + } + } +} + /// Secure seed length. /// /// Currently only supporting sub-schemes whose seed is a 32-bytes array. diff --git a/substrate/primitives/core/src/testing.rs b/substrate/primitives/core/src/testing.rs index c26e23d442f1..378b3416db7c 100644 --- a/substrate/primitives/core/src/testing.rs +++ b/substrate/primitives/core/src/testing.rs @@ -33,6 +33,8 @@ pub const BLS377: KeyTypeId = KeyTypeId(*b"bls7"); pub const BLS381: KeyTypeId = KeyTypeId(*b"bls8"); /// Key type for (ECDSA,BLS12-377) key pair pub const ECDSA_BLS377: KeyTypeId = KeyTypeId(*b"ecb7"); +/// Key type for (ECDSA,BLS12-381) key pair +pub const ECDSA_BLS381: KeyTypeId = KeyTypeId(*b"ecb8"); /// Macro for exporting functions from wasm in with the expected signature for using it with the /// wasm executor. This is useful for tests where you need to call a function in wasm. diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index c8675a9a90bd..bedaa3d846c6 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -106,7 +106,7 @@ use sp_core::{ }; #[cfg(feature = "bls-experimental")] -use sp_core::{bls377, ecdsa_bls377}; +use sp_core::{bls377, bls381, ecdsa_bls377, ecdsa_bls381}; #[cfg(feature = "std")] use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration}; @@ -1236,6 +1236,40 @@ pub trait Crypto { .expect("`ecdsa_bls377_generate` failed") } + /// Generate an `bls12-381` 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. + #[cfg(feature = "bls-experimental")] + fn bls381_generate(&mut self, id: KeyTypeId, seed: Option>) -> bls381::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!") + .bls381_generate_new(id, seed) + .expect("`bls381_generate` failed") + } + + /// Generate an `(ecdsa,bls12-381)` 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. + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls381_generate( + &mut self, + id: KeyTypeId, + seed: Option>, + ) -> ecdsa_bls381::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!") + .ecdsa_bls381_generate_new(id, seed) + .expect("`ecdsa_bls381_generate` failed") + } + /// Generate a `bandersnatch` key pair for the given key type using an optional /// `seed` and store it in the keystore. /// diff --git a/substrate/primitives/keystore/src/lib.rs b/substrate/primitives/keystore/src/lib.rs index 64f0e3ea49e8..1e6cbd8cc4e2 100644 --- a/substrate/primitives/keystore/src/lib.rs +++ b/substrate/primitives/keystore/src/lib.rs @@ -27,7 +27,7 @@ pub mod testing; #[cfg(feature = "bandersnatch-experimental")] use sp_core::bandersnatch; #[cfg(feature = "bls-experimental")] -use sp_core::{bls377, bls381, ecdsa_bls377}; +use sp_core::{bls377, bls381, ecdsa_bls377, ecdsa_bls381}; use sp_core::{ crypto::{ByteArray, CryptoTypeId, KeyTypeId}, ecdsa, ed25519, sr25519, @@ -38,7 +38,7 @@ use alloc::{string::String, sync::Arc, vec::Vec}; /// Keystore error #[derive(Debug)] pub enum Error { - /// Public key type is not supported + /// Pub1lic key type is not supported KeyNotSupported(KeyTypeId), /// Validation error ValidationError(String), @@ -288,6 +288,10 @@ pub trait Keystore: Send + Sync { #[cfg(feature = "bls-experimental")] fn ecdsa_bls377_public_keys(&self, id: KeyTypeId) -> Vec; + /// Returns all (ecdsa,bls12-381) paired public keys for the given key type. + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls381_public_keys(&self, id: KeyTypeId) -> Vec; + /// Generate a new bls381 key pair for the given key type and an optional seed. /// /// Returns an `bls381::Public` key of the generated key pair or an `Err` if @@ -321,6 +325,17 @@ pub trait Keystore: Send + Sync { seed: Option<&str>, ) -> Result; + /// Generate a new (ecdsa,bls381) key pair for the given key type and an optional seed. + /// + /// Returns an `ecdsa_bls381::Public` key of the generated key pair or an `Err` if + /// something failed during key generation. + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls381_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> Result; + /// Generate a bls381 signature for a given message. /// /// Receives [`KeyTypeId`] and a [`bls381::Public`] key to be able to map @@ -387,6 +402,40 @@ pub trait Keystore: Send + Sync { msg: &[u8], ) -> Result, Error>; + /// Generate a (ecdsa,bls381) signature pair for a given message. + /// + /// Receives [`KeyTypeId`] and a [`ecdsa_bls381::Public`] key to be able to map + /// them to a private key that exists in the keystore. + /// + /// Returns an [`ecdsa_bls381::Signature`] or `None` in case the given `key_type` + /// and `public` combination doesn't exist in the keystore. + /// An `Err` will be returned if generating the signature itself failed. + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls381_sign( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls381::Public, + msg: &[u8], + ) -> Result, Error>; + + /// Hashes the `message` using keccak256 and then signs it using ECDSA + /// algorithm. It does not affect the behavior of BLS12-381 component. It generates + /// BLS12-381 Signature according to IETF standard. + /// + /// Receives [`KeyTypeId`] and a [`ecdsa_bls381::Public`] key to be able to map + /// them to a private key that exists in the keystore. + /// + /// Returns an [`ecdsa_bls381::Signature`] or `None` in case the given `key_type` + /// and `public` combination doesn't exist in the keystore. + /// An `Err` will be returned if generating the signature itself failed. + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls381_sign_with_keccak256( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls381::Public, + msg: &[u8], + ) -> Result, Error>; + /// Insert a new secret key. fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()>; @@ -413,6 +462,7 @@ pub trait Keystore: Send + Sync { /// - bls381 /// - bls377 /// - (ecdsa,bls377) paired keys + /// - (ecdsa,bls381) paired keys /// /// To support more schemes you can overwrite this method. /// @@ -468,7 +518,12 @@ pub trait Keystore: Send + Sync { .map_err(|_| Error::ValidationError("Invalid public key format".into()))?; self.ecdsa_bls377_sign(id, &public, msg)?.map(|s| s.encode()) }, - + #[cfg(feature = "bls-experimental")] + ecdsa_bls381::CRYPTO_ID => { + let public = ecdsa_bls381::Public::from_slice(public) + .map_err(|_| Error::ValidationError("Invalid public key format".into()))?; + self.ecdsa_bls381_sign(id, &public, msg)?.map(|s| s.encode()) + }, _ => return Err(Error::KeyNotSupported(id)), }; Ok(signature) @@ -636,6 +691,11 @@ impl Keystore for Arc { (**self).ecdsa_bls377_public_keys(id) } + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls381_public_keys(&self, id: KeyTypeId) -> Vec { + (**self).ecdsa_bls381_public_keys(id) + } + #[cfg(feature = "bls-experimental")] fn bls381_generate_new( &self, @@ -663,6 +723,15 @@ impl Keystore for Arc { (**self).ecdsa_bls377_generate_new(key_type, seed) } + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls381_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> Result { + (**self).ecdsa_bls381_generate_new(key_type, seed) + } + #[cfg(feature = "bls-experimental")] fn bls381_sign( &self, @@ -693,6 +762,16 @@ impl Keystore for Arc { (**self).ecdsa_bls377_sign(key_type, public, msg) } + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls381_sign( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls381::Public, + msg: &[u8], + ) -> Result, Error> { + (**self).ecdsa_bls381_sign(key_type, public, msg) + } + #[cfg(feature = "bls-experimental")] fn ecdsa_bls377_sign_with_keccak256( &self, @@ -703,6 +782,16 @@ impl Keystore for Arc { (**self).ecdsa_bls377_sign_with_keccak256(key_type, public, msg) } + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls381_sign_with_keccak256( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls381::Public, + msg: &[u8], + ) -> Result, Error> { + (**self).ecdsa_bls381_sign_with_keccak256(key_type, public, msg) + } + fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { (**self).insert(key_type, suri, public) } diff --git a/substrate/primitives/keystore/src/testing.rs b/substrate/primitives/keystore/src/testing.rs index 1403e4745ff1..a6182a0b163f 100644 --- a/substrate/primitives/keystore/src/testing.rs +++ b/substrate/primitives/keystore/src/testing.rs @@ -22,7 +22,7 @@ use crate::{Error, Keystore, KeystorePtr}; #[cfg(feature = "bandersnatch-experimental")] use sp_core::bandersnatch; #[cfg(feature = "bls-experimental")] -use sp_core::{bls377, bls381, ecdsa_bls377, KeccakHasher}; +use sp_core::{bls377, bls381, ecdsa_bls377, ecdsa_bls381, KeccakHasher}; use sp_core::{ crypto::{ByteArray, KeyTypeId, Pair, VrfSecret}, ecdsa, ed25519, sr25519, @@ -359,6 +359,43 @@ impl Keystore for MemoryKeystore { Ok(sig) } + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls381_public_keys(&self, key_type: KeyTypeId) -> Vec { + self.public_keys::(key_type) + } + + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls381_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> Result { + self.generate_new::(key_type, seed) + } + + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls381_sign( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls381::Public, + msg: &[u8], + ) -> Result, Error> { + self.sign::(key_type, public, msg) + } + + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls381_sign_with_keccak256( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls381::Public, + msg: &[u8], + ) -> Result, Error> { + let sig = self + .pair::(key_type, public) + .map(|pair| pair.sign_with_hasher::(msg)); + Ok(sig) + } + fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { self.keys .write() From f96f6d141f06ca0dc56b3413a1bccdc131c808f8 Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 2 Jul 2024 11:41:41 -0400 Subject: [PATCH 02/12] attempt at making bls crypto tests generic over BLS Engine --- substrate/primitives/core/src/bls.rs | 367 ++++++++++++++------------- 1 file changed, 189 insertions(+), 178 deletions(-) diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index ed448ff753c6..1126589d13d9 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -39,22 +39,22 @@ use w3f_bls::{ pub mod bls377 { pub use super::{PUBLIC_KEY_SERIALIZED_SIZE, SIGNATURE_SERIALIZED_SIZE}; use crate::crypto::CryptoTypeId; - use w3f_bls::TinyBLS377; + pub(crate) use w3f_bls::TinyBLS377 as BlsEngine; /// An identifier used to match public keys against BLS12-377 keys pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"bls7"); #[doc(hidden)] - pub type Bls377Tag = TinyBLS377; + pub type Bls377Tag = BlsEngine; /// BLS12-377 key pair. - pub type Pair = super::Pair; + pub type Pair = super::Pair; /// BLS12-377 public key. - pub type Public = super::Public; + pub type Public = super::Public; /// BLS12-377 signature. - pub type Signature = super::Signature; + pub type Signature = super::Signature; - impl super::HardJunctionId for TinyBLS377 { + impl super::HardJunctionId for BlsEngine { const ID: &'static str = "BLS12377HDKD"; } } @@ -63,22 +63,22 @@ pub mod bls377 { pub mod bls381 { pub use super::{PUBLIC_KEY_SERIALIZED_SIZE, SIGNATURE_SERIALIZED_SIZE}; use crate::crypto::CryptoTypeId; - use w3f_bls::TinyBLS381; + pub(crate) use w3f_bls::TinyBLS381 as BlsEngine; /// An identifier used to match public keys against BLS12-381 keys pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"bls8"); #[doc(hidden)] - pub type Bls381Tag = TinyBLS381; + pub type Bls381Tag = BlsEngine; /// BLS12-381 key pair. - pub type Pair = super::Pair; + pub type Pair = super::Pair; /// BLS12-381 public key. - pub type Public = super::Public; + pub type Public = super::Public; /// BLS12-381 signature. - pub type Signature = super::Signature; + pub type Signature = super::Signature; - impl super::HardJunctionId for TinyBLS381 { + impl super::HardJunctionId for BlsEngine { const ID: &'static str = "BLS12381HDKD"; } } @@ -238,183 +238,194 @@ mod tests { #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; use crate::crypto::DEV_PHRASE; - use bls377::{Pair, Signature}; + use bls377::{Pair as Bls377Pair, Signature as Bls377Signature}; + use bls381::{Pair as Bls381Pair, Signature as Bls381Signature}; - #[test] - fn default_phrase_should_be_used() { + fn default_phrase_should_be_used() { assert_eq!( - Pair::from_string("//Alice///password", None).unwrap().public(), - Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password")) + Pair::::from_string("//Alice///password", None).unwrap().public(), + Pair::::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password")) .unwrap() .public(), ); } #[test] - fn seed_and_derive_should_work() { - let seed = array_bytes::hex2array_unchecked( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", - ); - let pair = Pair::from_seed(&seed); - // we are using hash-to-field so this is not going to work - // assert_eq!(pair.seed(), seed); - let path = vec![DeriveJunction::Hard([0u8; 32])]; - let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; - assert_eq!( - derived.to_raw_vec(), - array_bytes::hex2array_unchecked::<_, 32>( - "3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12" - ) - ); - } - - #[test] - fn test_vector_should_work() { - let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", - )); - let public = pair.public(); - assert_eq!( - public, - Public::unchecked_from(array_bytes::hex2array_unchecked( - "7a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" - )) - ); - let message = b""; - let signature = - array_bytes::hex2array_unchecked("d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b" - ); - let signature = Signature::unchecked_from(signature); - assert!(pair.sign(&message[..]) == signature); - assert!(Pair::verify(&signature, &message[..], &public)); - } - - #[test] - fn test_vector_by_string_should_work() { - let pair = Pair::from_string( - "0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", - None, - ) - .unwrap(); - let public = pair.public(); - assert_eq!( - public, - Public::unchecked_from(array_bytes::hex2array_unchecked( - "7a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" - )) - ); - let message = b""; - let signature = - array_bytes::hex2array_unchecked("d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b" - ); - let expected_signature = Signature::unchecked_from(signature); - println!("signature is {:?}", pair.sign(&message[..])); - let signature = pair.sign(&message[..]); - assert!(signature == expected_signature); - assert!(Pair::verify(&signature, &message[..], &public)); - } - #[test] - fn generated_pair_should_work() { - let (pair, _) = Pair::generate(); - let public = pair.public(); - let message = b"Something important"; - let signature = pair.sign(&message[..]); - assert!(Pair::verify(&signature, &message[..], &public)); - assert!(!Pair::verify(&signature, b"Something else", &public)); - } - - #[test] - fn seeded_pair_should_work() { - let pair = Pair::from_seed(b"12345678901234567890123456789012"); - let public = pair.public(); - assert_eq!( - public, - Public::unchecked_from( - array_bytes::hex2array_unchecked( - "754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080") - ) - ); - let message = - array_bytes::hex2bytes_unchecked("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" - ); - let signature = pair.sign(&message[..]); - println!("Correct signature: {:?}", signature); - assert!(Pair::verify(&signature, &message[..], &public)); - assert!(!Pair::verify(&signature, "Other message", &public)); - } - - #[test] - fn generate_with_phrase_recovery_possible() { - let (pair1, phrase, _) = Pair::generate_with_phrase(None); - let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); - - assert_eq!(pair1.public(), pair2.public()); + fn default_phrase_should_be_used_for_bls377() { + default_phrase_should_be_used::(); } + #[test] - fn generate_with_password_phrase_recovery_possible() { - let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); - let (pair2, _) = Pair::from_phrase(&phrase, Some("password")).unwrap(); - - assert_eq!(pair1.public(), pair2.public()); + fn default_phrase_should_be_used_for_bls381() { + default_phrase_should_be_used::(); } - #[test] - fn generate_with_phrase_should_be_recoverable_with_from_string() { - let (pair, phrase, seed) = Pair::generate_with_phrase(None); - let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); - assert_eq!(pair.public(), repair_seed.public()); - assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); - let (repair_phrase, reseed) = - Pair::from_phrase(phrase.as_ref(), None).expect("seed slice is valid"); - assert_eq!(seed, reseed); - assert_eq!(pair.public(), repair_phrase.public()); - assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); - - let repair_string = Pair::from_string(phrase.as_str(), None).expect("seed slice is valid"); - assert_eq!(pair.public(), repair_string.public()); - assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); - } - - #[test] - fn password_does_something() { - let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); - let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); - - assert_ne!(pair1.public(), pair2.public()); - assert_ne!(pair1.to_raw_vec(), pair2.to_raw_vec()); - } - - #[test] - fn ss58check_roundtrip_works() { - let pair = Pair::from_seed(b"12345678901234567890123456789012"); - let public = pair.public(); - let s = public.to_ss58check(); - println!("Correct: {}", s); - let cmp = Public::from_ss58check(&s).unwrap(); - assert_eq!(cmp, public); - } - - #[test] - fn signature_serialization_works() { - let pair = Pair::from_seed(b"12345678901234567890123456789012"); - let message = b"Something important"; - let signature = pair.sign(&message[..]); - let serialized_signature = serde_json::to_string(&signature).unwrap(); - // Signature is 112 bytes, hexify * 2, so 224 chars + 2 quote chars - assert_eq!(serialized_signature.len(), 226); - let signature = serde_json::from_str(&serialized_signature).unwrap(); - assert!(Pair::verify(&signature, &message[..], &pair.public())); - } - - #[test] - fn signature_serialization_doesnt_panic() { - fn deserialize_signature(text: &str) -> Result { - serde_json::from_str(text) - } - assert!(deserialize_signature("Not valid json.").is_err()); - assert!(deserialize_signature("\"Not an actual signature.\"").is_err()); - // Poorly-sized - assert!(deserialize_signature("\"abc123\"").is_err()); - } + // #[test] + // fn seed_and_derive_should_work() { + // let seed = array_bytes::hex2array_unchecked( + // "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + // ); + // let pair = Pair::from_seed(&seed); + // // we are using hash-to-field so this is not going to work + // // assert_eq!(pair.seed(), seed); + // let path = vec![DeriveJunction::Hard([0u8; 32])]; + // let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; + // assert_eq!( + // derived.to_raw_vec(), + // array_bytes::hex2array_unchecked::<_, 32>( + // "3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12" + // ) + // ); + // } + + // #[test] + // fn test_vector_should_work() { + // let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( + // "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + // )); + // let public = pair.public(); + // assert_eq!( + // public, + // Public::unchecked_from(array_bytes::hex2array_unchecked( + // "7a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" + // )) + // ); + // let message = b""; + // let signature = + // array_bytes::hex2array_unchecked("d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b" + // ); + // let signature = Signature::unchecked_from(signature); + // assert!(pair.sign(&message[..]) == signature); + // assert!(Pair::verify(&signature, &message[..], &public)); + // } + + // #[test] + // fn test_vector_by_string_should_work() { + // let pair = Pair::from_string( + // "0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + // None, + // ) + // .unwrap(); + // let public = pair.public(); + // assert_eq!( + // public, + // Public::unchecked_from(array_bytes::hex2array_unchecked( + // "7a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" + // )) + // ); + // let message = b""; + // let signature = + // array_bytes::hex2array_unchecked("d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b" + // ); + // let expected_signature = Signature::unchecked_from(signature); + // println!("signature is {:?}", pair.sign(&message[..])); + // let signature = pair.sign(&message[..]); + // assert!(signature == expected_signature); + // assert!(Pair::verify(&signature, &message[..], &public)); + // } + // #[test] + // fn generated_pair_should_work() { + // let (pair, _) = Pair::generate(); + // let public = pair.public(); + // let message = b"Something important"; + // let signature = pair.sign(&message[..]); + // assert!(Pair::verify(&signature, &message[..], &public)); + // assert!(!Pair::verify(&signature, b"Something else", &public)); + // } + + // #[test] + // fn seeded_pair_should_work() { + // let pair = Pair::from_seed(b"12345678901234567890123456789012"); + // let public = pair.public(); + // assert_eq!( + // public, + // Public::unchecked_from( + // array_bytes::hex2array_unchecked( + // "754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080") + // ) + // ); + // let message = + // array_bytes::hex2bytes_unchecked("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" + // ); + // let signature = pair.sign(&message[..]); + // println!("Correct signature: {:?}", signature); + // assert!(Pair::verify(&signature, &message[..], &public)); + // assert!(!Pair::verify(&signature, "Other message", &public)); + // } + + // #[test] + // fn generate_with_phrase_recovery_possible() { + // let (pair1, phrase, _) = Pair::generate_with_phrase(None); + // let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); + + // assert_eq!(pair1.public(), pair2.public()); + // } + + // #[test] + // fn generate_with_password_phrase_recovery_possible() { + // let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); + // let (pair2, _) = Pair::from_phrase(&phrase, Some("password")).unwrap(); + + // assert_eq!(pair1.public(), pair2.public()); + // } + + // #[test] + // fn generate_with_phrase_should_be_recoverable_with_from_string() { + // let (pair, phrase, seed) = Pair::generate_with_phrase(None); + // let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); + // assert_eq!(pair.public(), repair_seed.public()); + // assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); + // let (repair_phrase, reseed) = + // Pair::from_phrase(phrase.as_ref(), None).expect("seed slice is valid"); + // assert_eq!(seed, reseed); + // assert_eq!(pair.public(), repair_phrase.public()); + // assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); + + // let repair_string = Pair::from_string(phrase.as_str(), None).expect("seed slice is valid"); + // assert_eq!(pair.public(), repair_string.public()); + // assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); + // } + + // #[test] + // fn password_does_something() { + // let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); + // let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); + + // assert_ne!(pair1.public(), pair2.public()); + // assert_ne!(pair1.to_raw_vec(), pair2.to_raw_vec()); + // } + + // #[test] + // fn ss58check_roundtrip_works() { + // let pair = Pair::from_seed(b"12345678901234567890123456789012"); + // let public = pair.public(); + // let s = public.to_ss58check(); + // println!("Correct: {}", s); + // let cmp = Public::from_ss58check(&s).unwrap(); + // assert_eq!(cmp, public); + // } + + // #[test] + // fn signature_serialization_works() { + // let pair = Pair::from_seed(b"12345678901234567890123456789012"); + // let message = b"Something important"; + // let signature = pair.sign(&message[..]); + // let serialized_signature = serde_json::to_string(&signature).unwrap(); + // // Signature is 112 bytes, hexify * 2, so 224 chars + 2 quote chars + // assert_eq!(serialized_signature.len(), 226); + // let signature = serde_json::from_str(&serialized_signature).unwrap(); + // assert!(Pair::verify(&signature, &message[..], &pair.public())); + // } + + // #[test] + // fn signature_serialization_doesnt_panic() { + // fn deserialize_signature(text: &str) -> Result { + // serde_json::from_str(text) + // } + // assert!(deserialize_signature("Not valid json.").is_err()); + // assert!(deserialize_signature("\"Not an actual signature.\"").is_err()); + // // Poorly-sized + // assert!(deserialize_signature("\"abc123\"").is_err()); + // } } From b47157cdc36aa66a8104d4937cedd793bcf566f3 Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 8 Jul 2024 14:18:48 -0400 Subject: [PATCH 03/12] Generalize `seed_and_derive_should_work` test for both bls12-377 and bls12-381 --- substrate/primitives/core/src/bls.rs | 62 +++++++++++++++++----------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 1126589d13d9..5313e33a2cd9 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -241,7 +241,7 @@ mod tests { use bls377::{Pair as Bls377Pair, Signature as Bls377Signature}; use bls381::{Pair as Bls381Pair, Signature as Bls381Signature}; - fn default_phrase_should_be_used() { + fn default_phrase_should_be_used() { assert_eq!( Pair::::from_string("//Alice///password", None).unwrap().public(), Pair::::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password")) @@ -251,33 +251,49 @@ mod tests { } #[test] - fn default_phrase_should_be_used_for_bls377() { - default_phrase_should_be_used::(); + fn default_phrase_should_be_used_for_bls377() { + default_phrase_should_be_used::(); } - #[test] - fn default_phrase_should_be_used_for_bls381() { - default_phrase_should_be_used::(); + fn default_phrase_should_be_used_for_bls381() { + default_phrase_should_be_used::(); } - // #[test] - // fn seed_and_derive_should_work() { - // let seed = array_bytes::hex2array_unchecked( - // "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", - // ); - // let pair = Pair::from_seed(&seed); - // // we are using hash-to-field so this is not going to work - // // assert_eq!(pair.seed(), seed); - // let path = vec![DeriveJunction::Hard([0u8; 32])]; - // let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; - // assert_eq!( - // derived.to_raw_vec(), - // array_bytes::hex2array_unchecked::<_, 32>( - // "3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12" - // ) - // ); - // } + fn seed_and_derive_should_work() -> Vec { + let seed = array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + ); + let pair = Pair::::from_seed(&seed); + // we are using hash-to-field so this is not going to work + // assert_eq!(pair.seed(), seed); + let path = vec![DeriveJunction::Hard([0u8; 32])]; + let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; + println!("derived is: {:?}", array_bytes::bytes2hex("", derived.to_raw_vec())); + derived.to_raw_vec() + } + + #[test] + fn seed_and_derive_should_work_for_bls377() { + let derived_as_raw_vector = seed_and_derive_should_work::(); + assert_eq!( + derived_as_raw_vector, + array_bytes::hex2array_unchecked::<_, 32>( + "3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12" + ) + ); + } + + #[test] + fn seed_and_derive_should_work_for_bls381() { + let derived_as_raw_vector = seed_and_derive_should_work::(); + assert_eq!( + derived_as_raw_vector, + array_bytes::hex2array_unchecked::<_, 32>( + "bb6ac58be00d3c7ae5608ca64180b5af628e79b58592b6067136bb46255cea27" + ) + ); + } // #[test] // fn test_vector_should_work() { From 8840c1ab2548db54dc92765f330c3b99c1563e8d Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 9 Jul 2024 11:56:45 -0400 Subject: [PATCH 04/12] make `test_vector_should_work` works for both bls377 and bls381 --- substrate/primitives/core/src/bls.rs | 60 ++++++++++++++++++---------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 5313e33a2cd9..24ae84521998 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -295,27 +295,47 @@ mod tests { ); } - // #[test] - // fn test_vector_should_work() { - // let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( - // "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", - // )); - // let public = pair.public(); - // assert_eq!( - // public, - // Public::unchecked_from(array_bytes::hex2array_unchecked( - // "7a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" - // )) - // ); - // let message = b""; - // let signature = - // array_bytes::hex2array_unchecked("d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b" - // ); - // let signature = Signature::unchecked_from(signature); - // assert!(pair.sign(&message[..]) == signature); - // assert!(Pair::verify(&signature, &message[..], &public)); - // } + fn test_vector_should_work( + hex_expected_pub_key: &str, + hex_expected_signature: &str, + ) { + let pair = Pair::::from_seed(&array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + )); + + let public = pair.public(); + let public_bytes: &[u8] = public.as_ref(); + println!("pub key is: {:?}", array_bytes::bytes2hex("", public_bytes)); + assert_eq!( + public, + Public::unchecked_from(array_bytes::hex2array_unchecked(hex_expected_pub_key)) + ); + let message = b""; + let signature = array_bytes::hex2array_unchecked(hex_expected_signature); + + let expected_signature = Signature::unchecked_from(signature); + let signature = pair.sign(&message[..]); + let signature_bytes: &[u8] = signature.as_ref(); + println!("signature is: {:?}", array_bytes::bytes2hex("", signature_bytes)); + assert!(signature == expected_signature); + assert!(Pair::verify(&signature, &message[..], &public)); + } + + #[test] + fn test_vector_should_work_for_bls377() { + test_vector_should_work::( + "7a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400", + "d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b" + ) + } + #[test] + fn test_vector_should_work_for_bls381() { + test_vector_should_work::( + "88ff6c3a32542bc85f2adf1c490a929b7fcee50faeb95af9a036349390e9b3ea7326247c4fc4ebf88050688fd6265de0806284eec09ba0949f5df05dc93a787a14509749f36e4a0981bb748d953435483740907bb5c2fe8ffd97e8509e1a038b05fb08488db628ea0638b8d48c3ddf62ed437edd8b23d5989d6c65820fc70f80fb39b486a3766813e021124aec29a566", + "8c29473f44ac4f0a8ac4dc8c8da09adf9d2faa2dbe0cfdce3ce7c920714196a1b7bf48dc05048e453c161ebc2db9f44fae060b3be77e14e66d1a5262f14d3da0c3a18e650018761a7402b31abc7dd803d466bdcb71bc28c77eb73c610cbff53c00130b79116831e520a04a8ef6630e6f" + ) + } // #[test] // fn test_vector_by_string_should_work() { // let pair = Pair::from_string( From 51d1762c18f5df5f3fb415a9191bbf013645777c Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 9 Jul 2024 15:56:30 -0400 Subject: [PATCH 05/12] all remaining `primitives/core/src/bls` tests are generalized for both bls377 and bls381 --- substrate/primitives/core/src/bls.rs | 358 +++++++++++++++++---------- 1 file changed, 222 insertions(+), 136 deletions(-) diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 24ae84521998..9f65f6d8f78f 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -238,8 +238,8 @@ mod tests { #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; use crate::crypto::DEV_PHRASE; - use bls377::{Pair as Bls377Pair, Signature as Bls377Signature}; - use bls381::{Pair as Bls381Pair, Signature as Bls381Signature}; + use bls377::Pair as Bls377Pair; + use bls381::Pair as Bls381Pair; fn default_phrase_should_be_used() { assert_eq!( @@ -296,13 +296,10 @@ mod tests { } fn test_vector_should_work( + pair: Pair, hex_expected_pub_key: &str, hex_expected_signature: &str, ) { - let pair = Pair::::from_seed(&array_bytes::hex2array_unchecked( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", - )); - let public = pair.public(); let public_bytes: &[u8] = public.as_ref(); println!("pub key is: {:?}", array_bytes::bytes2hex("", public_bytes)); @@ -323,7 +320,10 @@ mod tests { #[test] fn test_vector_should_work_for_bls377() { - test_vector_should_work::( + let pair = Bls377Pair::from_seed(&array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + )); + test_vector_should_work(pair, "7a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400", "d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b" ) @@ -331,137 +331,223 @@ mod tests { #[test] fn test_vector_should_work_for_bls381() { - test_vector_should_work::( + let pair = Bls381Pair::from_seed(&array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + )); + test_vector_should_work(pair, + "88ff6c3a32542bc85f2adf1c490a929b7fcee50faeb95af9a036349390e9b3ea7326247c4fc4ebf88050688fd6265de0806284eec09ba0949f5df05dc93a787a14509749f36e4a0981bb748d953435483740907bb5c2fe8ffd97e8509e1a038b05fb08488db628ea0638b8d48c3ddf62ed437edd8b23d5989d6c65820fc70f80fb39b486a3766813e021124aec29a566", + "8c29473f44ac4f0a8ac4dc8c8da09adf9d2faa2dbe0cfdce3ce7c920714196a1b7bf48dc05048e453c161ebc2db9f44fae060b3be77e14e66d1a5262f14d3da0c3a18e650018761a7402b31abc7dd803d466bdcb71bc28c77eb73c610cbff53c00130b79116831e520a04a8ef6630e6f" + ) + } + + #[test] + fn test_vector_by_string_should_work_for_bls377() { + let pair = Bls377Pair::from_string( + "0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + None, + ) + .unwrap(); + test_vector_should_work(pair, + "7a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400", + "d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b" + ) + } + + #[test] + fn test_vector_by_string_should_work_for_bls381() { + let pair = Bls381Pair::from_string( + "0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + None, + ) + .unwrap(); + test_vector_should_work(pair, "88ff6c3a32542bc85f2adf1c490a929b7fcee50faeb95af9a036349390e9b3ea7326247c4fc4ebf88050688fd6265de0806284eec09ba0949f5df05dc93a787a14509749f36e4a0981bb748d953435483740907bb5c2fe8ffd97e8509e1a038b05fb08488db628ea0638b8d48c3ddf62ed437edd8b23d5989d6c65820fc70f80fb39b486a3766813e021124aec29a566", "8c29473f44ac4f0a8ac4dc8c8da09adf9d2faa2dbe0cfdce3ce7c920714196a1b7bf48dc05048e453c161ebc2db9f44fae060b3be77e14e66d1a5262f14d3da0c3a18e650018761a7402b31abc7dd803d466bdcb71bc28c77eb73c610cbff53c00130b79116831e520a04a8ef6630e6f" ) } - // #[test] - // fn test_vector_by_string_should_work() { - // let pair = Pair::from_string( - // "0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", - // None, - // ) - // .unwrap(); - // let public = pair.public(); - // assert_eq!( - // public, - // Public::unchecked_from(array_bytes::hex2array_unchecked( - // "7a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" - // )) - // ); - // let message = b""; - // let signature = - // array_bytes::hex2array_unchecked("d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b" - // ); - // let expected_signature = Signature::unchecked_from(signature); - // println!("signature is {:?}", pair.sign(&message[..])); - // let signature = pair.sign(&message[..]); - // assert!(signature == expected_signature); - // assert!(Pair::verify(&signature, &message[..], &public)); - // } - // #[test] - // fn generated_pair_should_work() { - // let (pair, _) = Pair::generate(); - // let public = pair.public(); - // let message = b"Something important"; - // let signature = pair.sign(&message[..]); - // assert!(Pair::verify(&signature, &message[..], &public)); - // assert!(!Pair::verify(&signature, b"Something else", &public)); - // } - - // #[test] - // fn seeded_pair_should_work() { - // let pair = Pair::from_seed(b"12345678901234567890123456789012"); - // let public = pair.public(); - // assert_eq!( - // public, - // Public::unchecked_from( - // array_bytes::hex2array_unchecked( - // "754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080") - // ) - // ); - // let message = - // array_bytes::hex2bytes_unchecked("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" - // ); - // let signature = pair.sign(&message[..]); - // println!("Correct signature: {:?}", signature); - // assert!(Pair::verify(&signature, &message[..], &public)); - // assert!(!Pair::verify(&signature, "Other message", &public)); - // } - - // #[test] - // fn generate_with_phrase_recovery_possible() { - // let (pair1, phrase, _) = Pair::generate_with_phrase(None); - // let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); - - // assert_eq!(pair1.public(), pair2.public()); - // } - - // #[test] - // fn generate_with_password_phrase_recovery_possible() { - // let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); - // let (pair2, _) = Pair::from_phrase(&phrase, Some("password")).unwrap(); - - // assert_eq!(pair1.public(), pair2.public()); - // } - - // #[test] - // fn generate_with_phrase_should_be_recoverable_with_from_string() { - // let (pair, phrase, seed) = Pair::generate_with_phrase(None); - // let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); - // assert_eq!(pair.public(), repair_seed.public()); - // assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); - // let (repair_phrase, reseed) = - // Pair::from_phrase(phrase.as_ref(), None).expect("seed slice is valid"); - // assert_eq!(seed, reseed); - // assert_eq!(pair.public(), repair_phrase.public()); - // assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); - - // let repair_string = Pair::from_string(phrase.as_str(), None).expect("seed slice is valid"); - // assert_eq!(pair.public(), repair_string.public()); - // assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); - // } - - // #[test] - // fn password_does_something() { - // let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); - // let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); - - // assert_ne!(pair1.public(), pair2.public()); - // assert_ne!(pair1.to_raw_vec(), pair2.to_raw_vec()); - // } - - // #[test] - // fn ss58check_roundtrip_works() { - // let pair = Pair::from_seed(b"12345678901234567890123456789012"); - // let public = pair.public(); - // let s = public.to_ss58check(); - // println!("Correct: {}", s); - // let cmp = Public::from_ss58check(&s).unwrap(); - // assert_eq!(cmp, public); - // } - - // #[test] - // fn signature_serialization_works() { - // let pair = Pair::from_seed(b"12345678901234567890123456789012"); - // let message = b"Something important"; - // let signature = pair.sign(&message[..]); - // let serialized_signature = serde_json::to_string(&signature).unwrap(); - // // Signature is 112 bytes, hexify * 2, so 224 chars + 2 quote chars - // assert_eq!(serialized_signature.len(), 226); - // let signature = serde_json::from_str(&serialized_signature).unwrap(); - // assert!(Pair::verify(&signature, &message[..], &pair.public())); - // } - - // #[test] - // fn signature_serialization_doesnt_panic() { - // fn deserialize_signature(text: &str) -> Result { - // serde_json::from_str(text) - // } - // assert!(deserialize_signature("Not valid json.").is_err()); - // assert!(deserialize_signature("\"Not an actual signature.\"").is_err()); - // // Poorly-sized - // assert!(deserialize_signature("\"abc123\"").is_err()); - // } + + fn test_pair(pair: Pair) -> (String, String) { + let public = pair.public(); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + assert!(Pair::verify(&signature, &message[..], &public)); + assert!(!Pair::verify(&signature, b"Something else", &public)); + let public_bytes: &[u8] = public.as_ref(); + let signature_bytes: &[u8] = signature.as_ref(); + println!( + "pub,signature is: {:?}", + (array_bytes::bytes2hex("", public_bytes), array_bytes::bytes2hex("", signature_bytes)) + ); + (array_bytes::bytes2hex("", public_bytes), array_bytes::bytes2hex("", signature_bytes)) + } + + #[test] + fn generated_pair_should_work_for_bls377() { + let (pair, _) = Bls377Pair::generate(); + test_pair(pair); + } + + #[test] + fn generated_pair_should_work_for_bls381() { + let (pair, _) = Bls381Pair::generate(); + test_pair(pair); + } + + #[test] + fn seeded_pair_should_work_for_bls377() { + let pair = Bls377Pair::from_seed(b"12345678901234567890123456789012"); + let (public, _) = test_pair(pair); + assert_eq!( + public, + "754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080" + ); + } + + #[test] + fn seeded_pair_should_work_for_bls381() { + let pair = Bls381Pair::from_seed(b"12345678901234567890123456789012"); + let (public, _) = test_pair(pair); + assert_eq!( + public, + "abe9554cc2cab7fdc391a4e07ed0f45544cf0fe235babedf553c098d37dd162d9402a0aed95c00ed01349a6017a3d864adcc9756e98b7931aa3526b1511730c9cbacf3cbe781ae5efefdb177b301bca0229a5cf87432251cd31341c9b88aea9501005fa16e814ad31a95fcc396633baf563f6306e982ddec978faa0399ba73c1c1a87fa4791b3f5bbb719c1401b2af37" + ); + } + + fn test_recover_with_phrase( + pair: Pair, + phrase: String, + password: Option<&str>, + ) { + let (recovered_pair, _) = Pair::from_phrase(&phrase, password).unwrap(); + + assert_eq!(pair.public(), recovered_pair.public()); + } + + #[test] + fn generate_with_phrase_recovery_possible_for_bls377() { + let (pair, phrase, _) = Bls377Pair::generate_with_phrase(None); + test_recover_with_phrase(pair, phrase, None); + } + + #[test] + fn generate_with_phrase_recovery_possible_for_bls381() { + let (pair, phrase, _) = Bls381Pair::generate_with_phrase(None); + test_recover_with_phrase(pair, phrase, None); + } + + #[test] + fn generate_with_password_phrase_recovery_possible_for_bls377() { + let (pair, phrase, _) = Bls377Pair::generate_with_phrase(Some("password")); + test_recover_with_phrase(pair, phrase, Some("password")); + } + + #[test] + fn generate_with_password_phrase_recovery_possible_for_bls381() { + let (pair, phrase, _) = Bls381Pair::generate_with_phrase(Some("password")); + test_recover_with_phrase(pair, phrase, Some("password")); + } + + fn test_recover_from_seed_and_string(pair: Pair, phrase: String, seed: Seed) { + let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_seed.public()); + assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); + let (repair_phrase, reseed) = + Pair::from_phrase(phrase.as_ref(), None).expect("seed slice is valid"); + assert_eq!(seed, reseed); + assert_eq!(pair.public(), repair_phrase.public()); + assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); + + let repair_string = Pair::from_string(phrase.as_str(), None).expect("seed slice is valid"); + assert_eq!(pair.public(), repair_string.public()); + assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec()); + } + + #[test] + fn generate_with_phrase_should_be_recoverable_with_from_string_for_bls377() { + let (pair, phrase, seed) = Bls377Pair::generate_with_phrase(None); + test_recover_from_seed_and_string(pair, phrase, seed); + } + + #[test] + fn generate_with_phrase_should_be_recoverable_with_from_string_for_bls381() { + let (pair, phrase, seed) = Bls381Pair::generate_with_phrase(None); + test_recover_from_seed_and_string(pair, phrase, seed); + } + + fn password_does_something() { + let (pair1, phrase, _) = Pair::::generate_with_phrase(Some("password")); + let (pair2, _) = Pair::::from_phrase(&phrase, None).unwrap(); + + assert_ne!(pair1.public(), pair2.public()); + assert_ne!(pair1.to_raw_vec(), pair2.to_raw_vec()); + } + + #[test] + fn password_does_something_for_bls377() { + password_does_something::(); + } + + #[test] + fn password_does_something_for_bls381() { + password_does_something::(); + } + + fn ss58check_roundtrip_works() { + let pair = Pair::::from_seed(b"12345678901234567890123456789012"); + let public = pair.public(); + let s = public.to_ss58check(); + println!("Correct: {}", s); + let cmp = Public::from_ss58check(&s).unwrap(); + assert_eq!(cmp, public); + } + + #[test] + fn ss58check_roundtrip_works_for_bls377() { + ss58check_roundtrip_works::(); + } + + #[test] + fn ss58check_roundtrip_works_for_bls381() { + ss58check_roundtrip_works::(); + } + + fn signature_serialization_works() { + let pair = Pair::::from_seed(b"12345678901234567890123456789012"); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + let serialized_signature = serde_json::to_string(&signature).unwrap(); + // Signature is 112 bytes, hexify * 2, so 224 chars + 2 quote chars + assert_eq!(serialized_signature.len(), 226); + let signature = serde_json::from_str(&serialized_signature).unwrap(); + assert!(Pair::::verify(&signature, &message[..], &pair.public())); + } + #[test] + fn signature_serialization_works_for_bls377() { + signature_serialization_works::(); + } + + #[test] + fn signature_serialization_works_for_bls381() { + signature_serialization_works::(); + } + fn signature_serialization_doesnt_panic() { + fn deserialize_signature( + text: &str, + ) -> Result, serde_json::error::Error> { + serde_json::from_str(text) + } + assert!(deserialize_signature::("Not valid json.").is_err()); + assert!(deserialize_signature::("\"Not an actual signature.\"").is_err()); + // Poorly-sized + assert!(deserialize_signature::("\"abc123\"").is_err()); + } + #[test] + fn signature_serialization_doesnt_panic_for_bls377() { + signature_serialization_doesnt_panic::(); + } + + #[test] + fn signature_serialization_doesnt_panic_for_bls381() { + signature_serialization_doesnt_panic::(); + } } From 2bf6318398210b307ab16bb5c4b8b78cad65f6d8 Mon Sep 17 00:00:00 2001 From: Skalman Date: Wed, 10 Jul 2024 15:50:06 -0400 Subject: [PATCH 06/12] update beefy commitment and witness tests to use BLS12-381 --- substrate/primitives/consensus/beefy/src/commitment.rs | 3 ++- substrate/primitives/consensus/beefy/src/witness.rs | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/substrate/primitives/consensus/beefy/src/commitment.rs b/substrate/primitives/consensus/beefy/src/commitment.rs index 8d3a6c6aa90f..35b6dd8d9a75 100644 --- a/substrate/primitives/consensus/beefy/src/commitment.rs +++ b/substrate/primitives/consensus/beefy/src/commitment.rs @@ -476,13 +476,14 @@ mod tests { //when let encoded = codec::Encode::encode(&ecdsa_and_bls_signed); let decoded = TestBlsSignedCommitment::decode(&mut &*encoded); + println!("encoded: {:?}", array_bytes::bytes2hex("", encoded.clone())); // then assert_eq!(decoded, Ok(ecdsa_and_bls_signed)); assert_eq!( encoded, array_bytes::hex2bytes_unchecked( - "046d68343048656c6c6f20576f726c642105000000000000000000000000000000000000000000000004300400000008558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba015dd1c9b2237e54baa93d232cdf83a430b58a5efbc2f86ca1bab173a315ff6f15bef161425750c028055e9a23947b73002889a8b22168628438875a8ef25d76db998a80187b50719471286f054f3b3809b77a0cd87d7fe9c1a9d5d562683e25a70610f0804e92340549a43a7159b77b0c2d6e1f8105c337a86cdd9aaacdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b6a0046395a71681be3d0c2a001074884b6998c82331bd57ffa0a02cbfd02483c765b9216eab6a1fc119206236bf7971be68acaebff7400edee943240006a6096c9cfa65e9eb4e67f025c27112d14b4574fb208c439500f45cf3a8060f6cf009044f3141cce0364a7c2710a19b1bdf4abf27f86e5e3db08bddd35a7d12" + "046d68343048656c6c6f20576f726c642105000000000000000000000000000000000000000000000004300400000008558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba0182022df4689ef25499205f7154a1a62eb2d6d5c4a3657efed321e2c277998130d1b01a264c928afb79534cb0fa9dcf79f67ed4e6bf2de576bb936146f2fa60fa56b8651677cc764ea4fe317c62294c2a0c5966e439653eed0572fded5e2461c888518e0769718dcce9f3ff612fb89d262d6e1f8105c337a86cdd9aaacdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b6a0046395a71681be3d0c2a00a90973bea76fac3a4e2d76a25ec3926d6a5a20aacee15ec0756cd268088ed5612b67b4a49349cee70bc1185078d17c7f7df9d944e8be30022d9680d0437c4ba4600d74050692e8ee9b96e37df2a39d1cb4b4af4b6a058342dd9e8c7481a3a0b8975ad8614c953e950253aa327698d842" ) ); } diff --git a/substrate/primitives/consensus/beefy/src/witness.rs b/substrate/primitives/consensus/beefy/src/witness.rs index cfffc94254a4..f27660cc0ca5 100644 --- a/substrate/primitives/consensus/beefy/src/witness.rs +++ b/substrate/primitives/consensus/beefy/src/witness.rs @@ -90,7 +90,7 @@ mod tests { #[cfg(feature = "bls-experimental")] use w3f_bls::{ single_pop_aggregator::SignatureAggregatorAssumingPoP, Message, SerializableToBytes, - Signed, TinyBLS377, + Signed, TinyBLS381, }; type TestCommitment = Commitment; @@ -198,7 +198,7 @@ mod tests { // 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 = + let mut aggregatedsigs: SignatureAggregatorAssumingPoP = SignatureAggregatorAssumingPoP::new(Message::new(b"", b"mock payload")); for sig in sigs { @@ -206,7 +206,7 @@ mod tests { Some(sig) => { let serialized_sig : Vec = (*sig.1).to_vec(); aggregatedsigs.add_signature( - &w3f_bls::Signature::::from_bytes( + &w3f_bls::Signature::::from_bytes( serialized_sig.as_slice() ).unwrap() ); @@ -219,7 +219,7 @@ mod tests { // 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()) + w3f_bls::Signature::::from_bytes(witness.signature_accumulator.as_slice()) .unwrap(); } From 8ff01559addabef45ad21ecb04138e13bdd171ed Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Thu, 11 Jul 2024 14:34:30 -0400 Subject: [PATCH 07/12] Apply clean up suggestions from code review Co-authored-by: Davide Galassi --- substrate/client/consensus/beefy/src/keystore.rs | 1 - substrate/client/keystore/src/local.rs | 2 +- substrate/primitives/consensus/beefy/src/commitment.rs | 1 - substrate/primitives/core/src/bls.rs | 5 ----- substrate/primitives/keystore/src/lib.rs | 2 +- 5 files changed, 2 insertions(+), 9 deletions(-) diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index 6685407bb496..888a11db89cb 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -5,7 +5,6 @@ // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by - // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. diff --git a/substrate/client/keystore/src/local.rs b/substrate/client/keystore/src/local.rs index 146e2eb5b7cb..3b8edcb85186 100644 --- a/substrate/client/keystore/src/local.rs +++ b/substrate/client/keystore/src/local.rs @@ -418,7 +418,7 @@ impl Keystore for LocalKeystore { Ok(sig) } - fn ecdsa_bls381_public_keys(&self, key_type: KeyTypeId) -> Vec { + fn ecdsa_bls381_public_keys(&self, key_type: KeyTypeId) -> Vec { self.public_keys::(key_type) } diff --git a/substrate/primitives/consensus/beefy/src/commitment.rs b/substrate/primitives/consensus/beefy/src/commitment.rs index 35b6dd8d9a75..5d4338aca10f 100644 --- a/substrate/primitives/consensus/beefy/src/commitment.rs +++ b/substrate/primitives/consensus/beefy/src/commitment.rs @@ -476,7 +476,6 @@ mod tests { //when let encoded = codec::Encode::encode(&ecdsa_and_bls_signed); let decoded = TestBlsSignedCommitment::decode(&mut &*encoded); - println!("encoded: {:?}", array_bytes::bytes2hex("", encoded.clone())); // then assert_eq!(decoded, Ok(ecdsa_and_bls_signed)); diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 9f65f6d8f78f..eb61d5858352 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -313,7 +313,6 @@ mod tests { let expected_signature = Signature::unchecked_from(signature); let signature = pair.sign(&message[..]); let signature_bytes: &[u8] = signature.as_ref(); - println!("signature is: {:?}", array_bytes::bytes2hex("", signature_bytes)); assert!(signature == expected_signature); assert!(Pair::verify(&signature, &message[..], &public)); } @@ -374,10 +373,6 @@ mod tests { assert!(!Pair::verify(&signature, b"Something else", &public)); let public_bytes: &[u8] = public.as_ref(); let signature_bytes: &[u8] = signature.as_ref(); - println!( - "pub,signature is: {:?}", - (array_bytes::bytes2hex("", public_bytes), array_bytes::bytes2hex("", signature_bytes)) - ); (array_bytes::bytes2hex("", public_bytes), array_bytes::bytes2hex("", signature_bytes)) } diff --git a/substrate/primitives/keystore/src/lib.rs b/substrate/primitives/keystore/src/lib.rs index 1e6cbd8cc4e2..c6d3a83683d1 100644 --- a/substrate/primitives/keystore/src/lib.rs +++ b/substrate/primitives/keystore/src/lib.rs @@ -38,7 +38,7 @@ use alloc::{string::String, sync::Arc, vec::Vec}; /// Keystore error #[derive(Debug)] pub enum Error { - /// Pub1lic key type is not supported + /// Public key type is not supported KeyNotSupported(KeyTypeId), /// Validation error ValidationError(String), From b75a7c9f684138c80d9bbe7eb7b5b9216526b2ff Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 22 Jul 2024 17:41:18 -0400 Subject: [PATCH 08/12] Remove bls377 and ecdsa_bls377 from io and application_crypto --- .../application-crypto/src/bls377.rs | 57 ------------------ .../application-crypto/src/ecdsa_bls377.rs | 58 ------------------- .../primitives/application-crypto/src/lib.rs | 4 -- substrate/primitives/io/src/lib.rs | 36 +----------- 4 files changed, 1 insertion(+), 154 deletions(-) delete mode 100644 substrate/primitives/application-crypto/src/bls377.rs delete mode 100644 substrate/primitives/application-crypto/src/ecdsa_bls377.rs diff --git a/substrate/primitives/application-crypto/src/bls377.rs b/substrate/primitives/application-crypto/src/bls377.rs deleted file mode 100644 index 8ae0bf319084..000000000000 --- a/substrate/primitives/application-crypto/src/bls377.rs +++ /dev/null @@ -1,57 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! BLS12-377 crypto applications. -use crate::{KeyTypeId, RuntimePublic}; - -pub use sp_core::bls::bls377::*; -use sp_std::vec::Vec; - -mod app { - crate::app_crypto!(super, sp_core::testing::BLS377); -} - -#[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/application-crypto/src/ecdsa_bls377.rs b/substrate/primitives/application-crypto/src/ecdsa_bls377.rs deleted file mode 100644 index 8dee73095fb2..000000000000 --- a/substrate/primitives/application-crypto/src/ecdsa_bls377.rs +++ /dev/null @@ -1,58 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! ECDSA and BLS12-377 paired crypto applications. - -use crate::{KeyTypeId, RuntimePublic}; -use sp_std::vec::Vec; - -pub use sp_core::paired_crypto::ecdsa_bls377::*; - -mod app { - crate::app_crypto!(super, sp_core::testing::ECDSA_BLS377); -} - -#[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::ecdsa_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/application-crypto/src/lib.rs b/substrate/primitives/application-crypto/src/lib.rs index b0ca659ffa6f..76afcff668d7 100644 --- a/substrate/primitives/application-crypto/src/lib.rs +++ b/substrate/primitives/application-crypto/src/lib.rs @@ -43,13 +43,9 @@ pub use sp_std::{ops::Deref, vec::Vec}; #[cfg(feature = "bandersnatch-experimental")] pub mod bandersnatch; #[cfg(feature = "bls-experimental")] -pub mod bls377; -#[cfg(feature = "bls-experimental")] pub mod bls381; pub mod ecdsa; #[cfg(feature = "bls-experimental")] -pub mod ecdsa_bls377; -#[cfg(feature = "bls-experimental")] pub mod ecdsa_bls381; pub mod ed25519; pub mod sr25519; diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index fe2dda27c3f5..a172b77eb70f 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -106,7 +106,7 @@ use sp_core::{ }; #[cfg(feature = "bls-experimental")] -use sp_core::{bls377, bls381, ecdsa_bls377, ecdsa_bls381}; +use sp_core::{bls381, ecdsa_bls381}; #[cfg(feature = "std")] use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration}; @@ -1202,40 +1202,6 @@ pub trait Crypto { Ok(pubkey.serialize()) } - /// 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. - #[cfg(feature = "bls-experimental")] - 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") - } - - /// Generate an `(ecdsa,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. - #[cfg(feature = "bls-experimental")] - fn ecdsa_bls377_generate( - &mut self, - id: KeyTypeId, - seed: Option>, - ) -> ecdsa_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!") - .ecdsa_bls377_generate_new(id, seed) - .expect("`ecdsa_bls377_generate` failed") - } - /// Generate an `bls12-381` key for the given key type using an optional `seed` and /// store it in the keystore. /// From b234464e1203ab0d5f4f99de8034d76e4eb8f750 Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 23 Jul 2024 13:29:34 -0400 Subject: [PATCH 09/12] Add 'sp-std' application crypto after merge. Remove redundant variable in bls test. --- Cargo.lock | 1 + substrate/primitives/application-crypto/Cargo.toml | 1 + substrate/primitives/core/src/bls.rs | 7 +++---- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 99dfbafafe28..691b2c4981b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19859,6 +19859,7 @@ dependencies = [ "serde", "sp-core", "sp-io", + "sp-std 14.0.0", ] [[package]] diff --git a/substrate/primitives/application-crypto/Cargo.toml b/substrate/primitives/application-crypto/Cargo.toml index c0508d377f8b..b0c343097c10 100644 --- a/substrate/primitives/application-crypto/Cargo.toml +++ b/substrate/primitives/application-crypto/Cargo.toml @@ -18,6 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] +sp-std = { workspace = true } sp-core = { workspace = true } codec = { features = ["derive"], workspace = true } scale-info = { features = ["derive"], workspace = true } diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index f69cc9aa6fff..00b4e12d251b 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -28,7 +28,7 @@ use crate::crypto::{ SignatureBytes, UncheckedFrom, }; -use alloc::vec::Vec; +use sp_std::vec::Vec; use w3f_bls::{ DoublePublicKey, DoublePublicKeyScheme, DoubleSignature, EngineBLS, Keypair, Message, @@ -308,11 +308,10 @@ mod tests { Public::unchecked_from(array_bytes::hex2array_unchecked(hex_expected_pub_key)) ); let message = b""; - let signature = array_bytes::hex2array_unchecked(hex_expected_signature); + let expected_signature_bytes = array_bytes::hex2array_unchecked(hex_expected_signature); - let expected_signature = Signature::unchecked_from(signature); + let expected_signature = Signature::unchecked_from(expected_signature_bytes); let signature = pair.sign(&message[..]); - let signature_bytes: &[u8] = signature.as_ref(); assert!(signature == expected_signature); assert!(Pair::verify(&signature, &message[..], &public)); } From 6f9eceecac88f192c06afeb68f9fdbd29ac79267 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 24 Jul 2024 10:14:15 +0200 Subject: [PATCH 10/12] Remove usage of sp-std from sp-application-crypto --- Cargo.lock | 1 - substrate/primitives/application-crypto/Cargo.toml | 1 - substrate/primitives/application-crypto/src/bls381.rs | 3 ++- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ccc0bbf18f2d..13e6b716e662 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19859,7 +19859,6 @@ dependencies = [ "serde", "sp-core", "sp-io", - "sp-std 14.0.0", ] [[package]] diff --git a/substrate/primitives/application-crypto/Cargo.toml b/substrate/primitives/application-crypto/Cargo.toml index b0c343097c10..c0508d377f8b 100644 --- a/substrate/primitives/application-crypto/Cargo.toml +++ b/substrate/primitives/application-crypto/Cargo.toml @@ -18,7 +18,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-std = { workspace = true } sp-core = { workspace = true } codec = { features = ["derive"], workspace = true } scale-info = { features = ["derive"], workspace = true } diff --git a/substrate/primitives/application-crypto/src/bls381.rs b/substrate/primitives/application-crypto/src/bls381.rs index 865a65c408d2..d4006720ce2e 100644 --- a/substrate/primitives/application-crypto/src/bls381.rs +++ b/substrate/primitives/application-crypto/src/bls381.rs @@ -18,8 +18,9 @@ //! BLS12-381 crypto applications. use crate::{KeyTypeId, RuntimePublic}; +use alloc::vec::Vec; + pub use sp_core::bls::bls381::*; -use sp_std::vec::Vec; mod app { crate::app_crypto!(super, sp_core::testing::BLS381); From db9451d6b844850d70e0145634070dd3962390af Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 24 Jul 2024 10:39:22 +0200 Subject: [PATCH 11/12] Prune bls12-377 from keystore interface --- substrate/client/keystore/src/local.rs | 69 +-------- substrate/primitives/keystore/src/lib.rs | 154 +------------------ substrate/primitives/keystore/src/testing.rs | 73 +-------- 3 files changed, 10 insertions(+), 286 deletions(-) diff --git a/substrate/client/keystore/src/local.rs b/substrate/client/keystore/src/local.rs index 3b8edcb85186..91c52bfcd50a 100644 --- a/substrate/client/keystore/src/local.rs +++ b/substrate/client/keystore/src/local.rs @@ -37,7 +37,7 @@ use sp_core::bandersnatch; } sp_keystore::bls_experimental_enabled! { -use sp_core::{bls377, bls381, ecdsa_bls377, ecdsa_bls381, KeccakHasher}; +use sp_core::{bls381, ecdsa_bls381, KeccakHasher}; } use crate::{Error, Result}; @@ -357,68 +357,7 @@ impl Keystore for LocalKeystore { self.sign::(key_type, public, msg) } - fn bls377_public_keys(&self, key_type: KeyTypeId) -> Vec { - self.public_keys::(key_type) - } - - /// Generate a new pair compatible with the 'bls377' signature scheme. - /// - /// If `[seed]` is `Some` then the key will be ephemeral and stored in memory. - fn bls377_generate_new( - &self, - key_type: KeyTypeId, - seed: Option<&str>, - ) -> std::result::Result { - self.generate_new::(key_type, seed) - } - - fn bls377_sign( - &self, - key_type: KeyTypeId, - public: &bls377::Public, - msg: &[u8], - ) -> std::result::Result, TraitError> { - self.sign::(key_type, public, msg) - } - - fn ecdsa_bls377_public_keys(&self, key_type: KeyTypeId) -> Vec { - self.public_keys::(key_type) - } - - /// Generate a new pair of paired-keys compatible with the '(ecdsa,bls377)' signature scheme. - /// - /// If `[seed]` is `Some` then the key will be ephemeral and stored in memory. - fn ecdsa_bls377_generate_new( - &self, - key_type: KeyTypeId, - seed: Option<&str>, - ) -> std::result::Result { - self.generate_new::(key_type, seed) - } - - fn ecdsa_bls377_sign( - &self, - key_type: KeyTypeId, - public: &ecdsa_bls377::Public, - msg: &[u8], - ) -> std::result::Result, TraitError> { - self.sign::(key_type, public, msg) - } - - fn ecdsa_bls377_sign_with_keccak256( - &self, - key_type: KeyTypeId, - public: &ecdsa_bls377::Public, - msg: &[u8], - ) -> std::result::Result, TraitError> { - let sig = self.0 - .read() - .key_pair_by_type::(public, key_type)? - .map(|pair| pair.sign_with_hasher::(msg)); - Ok(sig) - } - - fn ecdsa_bls381_public_keys(&self, key_type: KeyTypeId) -> Vec { + fn ecdsa_bls381_public_keys(&self, key_type: KeyTypeId) -> Vec { self.public_keys::(key_type) } @@ -442,7 +381,7 @@ impl Keystore for LocalKeystore { self.sign::(key_type, public, msg) } - fn ecdsa_bls381_sign_with_keccak256( + fn ecdsa_bls381_sign_with_keccak256( &self, key_type: KeyTypeId, public: &ecdsa_bls381::Public, @@ -454,8 +393,6 @@ impl Keystore for LocalKeystore { .map(|pair| pair.sign_with_hasher::(msg)); Ok(sig) } - - } } diff --git a/substrate/primitives/keystore/src/lib.rs b/substrate/primitives/keystore/src/lib.rs index c6d3a83683d1..42ad2c600d02 100644 --- a/substrate/primitives/keystore/src/lib.rs +++ b/substrate/primitives/keystore/src/lib.rs @@ -27,7 +27,7 @@ pub mod testing; #[cfg(feature = "bandersnatch-experimental")] use sp_core::bandersnatch; #[cfg(feature = "bls-experimental")] -use sp_core::{bls377, bls381, ecdsa_bls377, ecdsa_bls381}; +use sp_core::{bls381, ecdsa_bls381}; use sp_core::{ crypto::{ByteArray, CryptoTypeId, KeyTypeId}, ecdsa, ed25519, sr25519, @@ -280,14 +280,6 @@ pub trait Keystore: Send + Sync { #[cfg(feature = "bls-experimental")] fn bls381_public_keys(&self, id: KeyTypeId) -> Vec; - /// Returns all bls12-377 public keys for the given key type. - #[cfg(feature = "bls-experimental")] - fn bls377_public_keys(&self, id: KeyTypeId) -> Vec; - - /// Returns all (ecdsa,bls12-377) paired public keys for the given key type. - #[cfg(feature = "bls-experimental")] - fn ecdsa_bls377_public_keys(&self, id: KeyTypeId) -> Vec; - /// Returns all (ecdsa,bls12-381) paired public keys for the given key type. #[cfg(feature = "bls-experimental")] fn ecdsa_bls381_public_keys(&self, id: KeyTypeId) -> Vec; @@ -303,28 +295,6 @@ pub trait Keystore: Send + Sync { seed: Option<&str>, ) -> Result; - /// Generate a new bls377 key pair for the given key type and an optional seed. - /// - /// Returns an `bls377::Public` key of the generated key pair or an `Err` if - /// something failed during key generation. - #[cfg(feature = "bls-experimental")] - fn bls377_generate_new( - &self, - key_type: KeyTypeId, - seed: Option<&str>, - ) -> Result; - - /// Generate a new (ecdsa,bls377) key pair for the given key type and an optional seed. - /// - /// Returns an `ecdsa_bls377::Public` key of the generated key pair or an `Err` if - /// something failed during key generation. - #[cfg(feature = "bls-experimental")] - fn ecdsa_bls377_generate_new( - &self, - key_type: KeyTypeId, - seed: Option<&str>, - ) -> Result; - /// Generate a new (ecdsa,bls381) key pair for the given key type and an optional seed. /// /// Returns an `ecdsa_bls381::Public` key of the generated key pair or an `Err` if @@ -352,56 +322,6 @@ pub trait Keystore: Send + Sync { msg: &[u8], ) -> Result, Error>; - /// Generate a bls377 signature for a given message. - /// - /// Receives [`KeyTypeId`] and a [`bls377::Public`] key to be able to map - /// them to a private key that exists in the keystore. - /// - /// Returns an [`bls377::Signature`] or `None` in case the given `key_type` - /// and `public` combination doesn't exist in the keystore. - /// An `Err` will be returned if generating the signature itself failed. - #[cfg(feature = "bls-experimental")] - fn bls377_sign( - &self, - key_type: KeyTypeId, - public: &bls377::Public, - msg: &[u8], - ) -> Result, Error>; - - /// Generate a (ecdsa,bls377) signature pair for a given message. - /// - /// Receives [`KeyTypeId`] and a [`ecdsa_bls377::Public`] key to be able to map - /// them to a private key that exists in the keystore. - /// - /// Returns an [`ecdsa_bls377::Signature`] or `None` in case the given `key_type` - /// and `public` combination doesn't exist in the keystore. - /// An `Err` will be returned if generating the signature itself failed. - #[cfg(feature = "bls-experimental")] - fn ecdsa_bls377_sign( - &self, - key_type: KeyTypeId, - public: &ecdsa_bls377::Public, - msg: &[u8], - ) -> Result, Error>; - - /// Hashes the `message` using keccak256 and then signs it using ECDSA - /// algorithm. It does not affect the behavior of BLS12-377 component. It generates - /// BLS12-377 Signature according to IETF standard. - /// - /// Receives [`KeyTypeId`] and a [`ecdsa_bls377::Public`] key to be able to map - /// them to a private key that exists in the keystore. - /// - /// Returns an [`ecdsa_bls377::Signature`] or `None` in case the given `key_type` - /// and `public` combination doesn't exist in the keystore. - /// An `Err` will be returned if generating the signature itself failed. - #[cfg(feature = "bls-experimental")] - fn ecdsa_bls377_sign_with_keccak256( - &self, - key_type: KeyTypeId, - public: &ecdsa_bls377::Public, - msg: &[u8], - ) -> Result, Error>; - /// Generate a (ecdsa,bls381) signature pair for a given message. /// /// Receives [`KeyTypeId`] and a [`ecdsa_bls381::Public`] key to be able to map @@ -460,8 +380,6 @@ pub trait Keystore: Send + Sync { /// - ecdsa /// - bandersnatch /// - bls381 - /// - bls377 - /// - (ecdsa,bls377) paired keys /// - (ecdsa,bls381) paired keys /// /// To support more schemes you can overwrite this method. @@ -507,18 +425,6 @@ pub trait Keystore: Send + Sync { self.bls381_sign(id, &public, msg)?.map(|s| s.encode()) }, #[cfg(feature = "bls-experimental")] - bls377::CRYPTO_ID => { - let public = bls377::Public::from_slice(public) - .map_err(|_| Error::ValidationError("Invalid public key format".into()))?; - self.bls377_sign(id, &public, msg)?.map(|s| s.encode()) - }, - #[cfg(feature = "bls-experimental")] - ecdsa_bls377::CRYPTO_ID => { - let public = ecdsa_bls377::Public::from_slice(public) - .map_err(|_| Error::ValidationError("Invalid public key format".into()))?; - self.ecdsa_bls377_sign(id, &public, msg)?.map(|s| s.encode()) - }, - #[cfg(feature = "bls-experimental")] ecdsa_bls381::CRYPTO_ID => { let public = ecdsa_bls381::Public::from_slice(public) .map_err(|_| Error::ValidationError("Invalid public key format".into()))?; @@ -681,16 +587,6 @@ impl Keystore for Arc { (**self).bls381_public_keys(id) } - #[cfg(feature = "bls-experimental")] - fn bls377_public_keys(&self, id: KeyTypeId) -> Vec { - (**self).bls377_public_keys(id) - } - - #[cfg(feature = "bls-experimental")] - fn ecdsa_bls377_public_keys(&self, id: KeyTypeId) -> Vec { - (**self).ecdsa_bls377_public_keys(id) - } - #[cfg(feature = "bls-experimental")] fn ecdsa_bls381_public_keys(&self, id: KeyTypeId) -> Vec { (**self).ecdsa_bls381_public_keys(id) @@ -705,24 +601,6 @@ impl Keystore for Arc { (**self).bls381_generate_new(key_type, seed) } - #[cfg(feature = "bls-experimental")] - fn bls377_generate_new( - &self, - key_type: KeyTypeId, - seed: Option<&str>, - ) -> Result { - (**self).bls377_generate_new(key_type, seed) - } - - #[cfg(feature = "bls-experimental")] - fn ecdsa_bls377_generate_new( - &self, - key_type: KeyTypeId, - seed: Option<&str>, - ) -> Result { - (**self).ecdsa_bls377_generate_new(key_type, seed) - } - #[cfg(feature = "bls-experimental")] fn ecdsa_bls381_generate_new( &self, @@ -742,26 +620,6 @@ impl Keystore for Arc { (**self).bls381_sign(key_type, public, msg) } - #[cfg(feature = "bls-experimental")] - fn bls377_sign( - &self, - key_type: KeyTypeId, - public: &bls377::Public, - msg: &[u8], - ) -> Result, Error> { - (**self).bls377_sign(key_type, public, msg) - } - - #[cfg(feature = "bls-experimental")] - fn ecdsa_bls377_sign( - &self, - key_type: KeyTypeId, - public: &ecdsa_bls377::Public, - msg: &[u8], - ) -> Result, Error> { - (**self).ecdsa_bls377_sign(key_type, public, msg) - } - #[cfg(feature = "bls-experimental")] fn ecdsa_bls381_sign( &self, @@ -772,16 +630,6 @@ impl Keystore for Arc { (**self).ecdsa_bls381_sign(key_type, public, msg) } - #[cfg(feature = "bls-experimental")] - fn ecdsa_bls377_sign_with_keccak256( - &self, - key_type: KeyTypeId, - public: &ecdsa_bls377::Public, - msg: &[u8], - ) -> Result, Error> { - (**self).ecdsa_bls377_sign_with_keccak256(key_type, public, msg) - } - #[cfg(feature = "bls-experimental")] fn ecdsa_bls381_sign_with_keccak256( &self, diff --git a/substrate/primitives/keystore/src/testing.rs b/substrate/primitives/keystore/src/testing.rs index a6182a0b163f..745f42e3477a 100644 --- a/substrate/primitives/keystore/src/testing.rs +++ b/substrate/primitives/keystore/src/testing.rs @@ -22,7 +22,7 @@ use crate::{Error, Keystore, KeystorePtr}; #[cfg(feature = "bandersnatch-experimental")] use sp_core::bandersnatch; #[cfg(feature = "bls-experimental")] -use sp_core::{bls377, bls381, ecdsa_bls377, ecdsa_bls381, KeccakHasher}; +use sp_core::{bls381, ecdsa_bls381, KeccakHasher}; use sp_core::{ crypto::{ByteArray, KeyTypeId, Pair, VrfSecret}, ecdsa, ed25519, sr25519, @@ -298,67 +298,6 @@ impl Keystore for MemoryKeystore { self.sign::(key_type, public, msg) } - #[cfg(feature = "bls-experimental")] - fn bls377_public_keys(&self, key_type: KeyTypeId) -> Vec { - self.public_keys::(key_type) - } - - #[cfg(feature = "bls-experimental")] - fn bls377_generate_new( - &self, - key_type: KeyTypeId, - seed: Option<&str>, - ) -> Result { - self.generate_new::(key_type, seed) - } - - #[cfg(feature = "bls-experimental")] - fn bls377_sign( - &self, - key_type: KeyTypeId, - public: &bls377::Public, - msg: &[u8], - ) -> Result, Error> { - self.sign::(key_type, public, msg) - } - - #[cfg(feature = "bls-experimental")] - fn ecdsa_bls377_public_keys(&self, key_type: KeyTypeId) -> Vec { - self.public_keys::(key_type) - } - - #[cfg(feature = "bls-experimental")] - fn ecdsa_bls377_generate_new( - &self, - key_type: KeyTypeId, - seed: Option<&str>, - ) -> Result { - self.generate_new::(key_type, seed) - } - - #[cfg(feature = "bls-experimental")] - fn ecdsa_bls377_sign( - &self, - key_type: KeyTypeId, - public: &ecdsa_bls377::Public, - msg: &[u8], - ) -> Result, Error> { - self.sign::(key_type, public, msg) - } - - #[cfg(feature = "bls-experimental")] - fn ecdsa_bls377_sign_with_keccak256( - &self, - key_type: KeyTypeId, - public: &ecdsa_bls377::Public, - msg: &[u8], - ) -> Result, Error> { - let sig = self - .pair::(key_type, public) - .map(|pair| pair.sign_with_hasher::(msg)); - Ok(sig) - } - #[cfg(feature = "bls-experimental")] fn ecdsa_bls381_public_keys(&self, key_type: KeyTypeId) -> Vec { self.public_keys::(key_type) @@ -545,13 +484,13 @@ mod tests { #[test] #[cfg(feature = "bls-experimental")] - fn ecdsa_bls377_sign_with_keccak_works() { + fn ecdsa_bls381_sign_with_keccak_works() { use sp_core::testing::ECDSA_BLS377; let store = MemoryKeystore::new(); let suri = "//Alice"; - let pair = ecdsa_bls377::Pair::from_string(suri, None).unwrap(); + let pair = ecdsa_bls381::Pair::from_string(suri, None).unwrap(); let msg = b"this should be a normal unhashed message not a hash of a message because bls scheme comes with its own hashing"; @@ -559,16 +498,16 @@ mod tests { store.insert(ECDSA_BLS377, suri, pair.public().as_ref()).unwrap(); let res = store - .ecdsa_bls377_sign_with_keccak256(ECDSA_BLS377, &pair.public(), &msg[..]) + .ecdsa_bls381_sign_with_keccak256(ECDSA_BLS377, &pair.public(), &msg[..]) .unwrap(); assert!(res.is_some()); // does not verify with default out-of-the-box verification - assert!(!ecdsa_bls377::Pair::verify(&res.unwrap(), &msg[..], &pair.public())); + assert!(!ecdsa_bls381::Pair::verify(&res.unwrap(), &msg[..], &pair.public())); // should verify using keccak256 as hasher - assert!(ecdsa_bls377::Pair::verify_with_hasher::( + assert!(ecdsa_bls381::Pair::verify_with_hasher::( &res.unwrap(), msg, &pair.public() From 45437aa0f4771ee0aeb0e11f850c12e7bce96a49 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 24 Jul 2024 10:42:37 +0200 Subject: [PATCH 12/12] Use alloc::vec::Vec --- substrate/primitives/core/src/bls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 00b4e12d251b..f721a6ae08d1 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -28,7 +28,7 @@ use crate::crypto::{ SignatureBytes, UncheckedFrom, }; -use sp_std::vec::Vec; +use alloc::vec::Vec; use w3f_bls::{ DoublePublicKey, DoublePublicKeyScheme, DoubleSignature, EngineBLS, Keypair, Message,