diff --git a/client/keystore/src/local.rs b/client/keystore/src/local.rs index 7c906fe26f14f..b3c759d962d6e 100644 --- a/client/keystore/src/local.rs +++ b/client/keystore/src/local.rs @@ -18,12 +18,11 @@ //! Local keystore implementation use parking_lot::RwLock; -use sp_application_crypto::{bls, ecdsa, ed25519, sr25519, AppKey, AppPair, IsWrappedBy}; +use sp_application_crypto::{bls377, ecdsa, ed25519, sr25519, AppKey, AppPair, IsWrappedBy}; use sp_core::{ crypto::{ ByteArray, CryptoTypePublicPair, ExposeSecret, KeyTypeId, Pair as PairT, SecretString, }, - sr25519::{Pair as Sr25519Pair, Public as Sr25519Public}, Encode, }; use sp_keystore::{ @@ -231,11 +230,11 @@ impl Keystore for LocalKeystore { fn sr25519_vrf_sign( &self, key_type: KeyTypeId, - public: &Sr25519Public, + public: &sr25519::Public, transcript_data: VRFTranscriptData, ) -> std::result::Result, TraitError> { let transcript = make_transcript(transcript_data); - let pair = self.0.read().key_pair_by_type::(public, key_type)?; + let pair = self.0.read().key_pair_by_type::(public, key_type)?; if let Some(pair) = pair { let (inout, proof, _) = pair.as_ref().vrf_sign(transcript); @@ -257,7 +256,7 @@ impl Keystore for LocalKeystore { } /// Returns all bls public keys for the given key type. - fn bls_public_keys(&self, _id: KeyTypeId) -> Vec { + fn bls377_public_keys(&self, _id: KeyTypeId) -> Vec { unimplemented!() } @@ -266,11 +265,11 @@ impl Keystore for LocalKeystore { /// If the given seed is `Some(_)`, the key pair will only be stored in memory. /// /// Returns the public key of the generated key pair. - fn bls_generate_new( + fn bls377_generate_new( &self, _id: KeyTypeId, _seed: Option<&str>, - ) -> std::result::Result { + ) -> std::result::Result { unimplemented!() } @@ -286,12 +285,12 @@ impl Keystore for LocalKeystore { /// Returns an [`bls::Signature`] or `None` in case the given `id` and /// `public` combination doesn't exist in the keystore. An `Err` will be /// returned if generating the signature itself failed. - fn bls_sign( + fn bls377_sign( &self, _id: KeyTypeId, - _public: &bls::Public, + _public: &bls377::Public, _msg: &[u8], - ) -> std::result::Result, TraitError> { + ) -> std::result::Result, TraitError> { unimplemented!() } } diff --git a/primitives/application-crypto/src/bls.rs b/primitives/application-crypto/src/bls377.rs similarity index 62% rename from primitives/application-crypto/src/bls.rs rename to primitives/application-crypto/src/bls377.rs index 9e101ff64f7d7..2983eefd163d7 100644 --- a/primitives/application-crypto/src/bls.rs +++ b/primitives/application-crypto/src/bls377.rs @@ -15,18 +15,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! bls crypto types. +//! BLS12-377 crypto applications. use crate::{KeyTypeId, RuntimePublic}; use sp_std::vec::Vec; -pub use sp_core::bls::*; +pub use sp_core::bls::bls377::*; mod app { - use sp_core::testing::BLS; + use sp_core::testing::BLS377; - crate::app_crypto!(super, BLS); + crate::app_crypto!(super, BLS377); impl crate::traits::BoundToRuntimeAppPublic for Public { type Public = Self; @@ -40,20 +40,20 @@ pub use app::{Public as AppPublic, Signature as AppSignature}; impl RuntimePublic for Public { type Signature = Signature; - fn all(key_type: KeyTypeId) -> crate::Vec { - sp_io::crypto::bls_public_keys(key_type) + fn all(_key_type: KeyTypeId) -> crate::Vec { + unreachable!("no access to the host keystore from runtime") } - fn generate_pair(key_type: KeyTypeId, seed: Option>) -> Self { - sp_io::crypto::bls_generate(key_type, seed) + fn generate_pair(_key_type: KeyTypeId, _seed: Option>) -> Self { + unreachable!("no access to the host keystore from runtime") } - fn sign>(&self, key_type: KeyTypeId, msg: &M) -> Option { - sp_io::crypto::bls_sign(key_type, self, msg.as_ref()) + fn sign>(&self, _key_type: KeyTypeId, _msg: &M) -> Option { + unreachable!("no access to the host keystore from runtime") } - fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool { - sp_io::crypto::bls_verify(&signature, msg.as_ref(), self) + fn verify>(&self, _msg: &M, _signature: &Self::Signature) -> bool { + unreachable!("no access to the host keystore from runtime") } fn to_raw_vec(&self) -> Vec { diff --git a/primitives/application-crypto/src/lib.rs b/primitives/application-crypto/src/lib.rs index 9a6559b4d36b3..b14a5b0a979d1 100644 --- a/primitives/application-crypto/src/lib.rs +++ b/primitives/application-crypto/src/lib.rs @@ -44,7 +44,7 @@ pub use serde; #[doc(hidden)] pub use sp_std::{ops::Deref, vec::Vec}; -pub mod bls; +pub mod bls377; pub mod ecdsa; pub mod ed25519; pub mod sr25519; diff --git a/primitives/core/src/bls.rs b/primitives/core/src/bls.rs index 21945108c60cf..8c025ad427e7d 100644 --- a/primitives/core/src/bls.rs +++ b/primitives/core/src/bls.rs @@ -15,9 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// tag::description[] //! Simple BLS (Boneh–Lynn–Shacham) Signature API. -// end::description[] #[cfg(feature = "full_crypto")] use sp_std::vec::Vec; @@ -38,159 +36,262 @@ use crate::crypto::{ use crate::crypto::{DeriveJunction, Pair as TraitPair, SecretStringError}; #[cfg(feature = "std")] use bip39::{Language, Mnemonic, MnemonicType}; -use bls_like::{EngineBLS, BLS377}; +use bls_like::EngineBLS; #[cfg(feature = "full_crypto")] use bls_like::{Keypair, Message, SerializableToBytes}; -#[cfg(feature = "full_crypto")] use core::convert::TryFrom; #[cfg(feature = "std")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use sp_runtime_interface::pass_by::PassByInner; -use sp_std::ops::Deref; +use sp_std::{marker::PhantomData, ops::Deref}; #[cfg(feature = "std")] use substrate_bip39::seed_from_entropy; #[cfg(feature = "std")] use hex; -/// An identifier used to match public keys against bls377 keys -pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"bls7"); +/// BLS-377 specialized types +pub mod bls377 { + use crate::crypto::CryptoTypeId; + use bls_like::BLS377; + + /// An identifier used to match public keys against BLS12-377 keys + pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"bls7"); + + /// BLS12-377 key pair. + #[cfg(feature = "full_crypto")] + pub type Pair = super::Pair; + /// BLS12-377 public key. + pub type Public = super::Public; + /// BLS12-377 signature. + pub type Signature = super::Signature; +} + +/// BLS-381 specialized types +pub mod bls381 { + use crate::crypto::CryptoTypeId; + use bls_like::ZBLS; + + /// An identifier used to match public keys against BLS12-381 keys + pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"bls8"); + + /// BLS12-381 key pair. + #[cfg(feature = "full_crypto")] + pub type Pair = super::Pair; + /// BLS12-381 public key. + pub type Public = super::Public; + /// BLS12-381 signature. + pub type Signature = super::Signature; +} + +trait BlsBound: EngineBLS + Send + Sync + 'static {} + +impl BlsBound for T {} + +// Secret key serialized side +#[cfg(feature = "full_crypto")] +const SECRET_KEY_SERIALIZED_SIZE: usize = 32; + +// Public key serialized side +const PUBLIC_KEY_SERIALIZED_SIZE: usize = 48; + +// Signature serialized size +const SIGNATURE_SERIALIZED_SIZE: usize = 96; + +// TODO DAVXY REMOVE-ME (REMOVED FROM UPSTREAM) +/// Temporary crypto id +pub const TEMPORARY_CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"TEMP"); -/// A secret seed. It's not called a "secret key" because ring doesn't expose the secret keys +/// A secret seed. +/// +/// It's not called a "secret key" because ring doesn't expose the secret keys /// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we /// will need it later (such as for HDKD). #[cfg(feature = "full_crypto")] -type Seed = [u8; BLS377::SECRET_KEY_SIZE]; +type Seed = [u8; SECRET_KEY_SERIALIZED_SIZE]; /// A public key. -#[cfg_attr(feature = "full_crypto", derive(Hash))] -#[derive( - PartialEq, - Eq, - PartialOrd, - Ord, - Clone, - Copy, - Encode, - Decode, - PassByInner, - MaxEncodedLen, - TypeInfo, -)] -pub struct Public(pub [u8; BLS377::PUBLICKEY_SERIALIZED_SIZE]); +#[derive(Copy, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[scale_info(skip_type_params(T))] +pub struct Public { + inner: [u8; PUBLIC_KEY_SERIALIZED_SIZE], + _phantom: PhantomData T>, +} -/// A key pair. -#[cfg(feature = "full_crypto")] -pub struct Pair(Keypair); +impl Clone for Public { + fn clone(&self) -> Self { + Self { inner: self.inner.clone(), _phantom: PhantomData } + } +} + +impl PartialEq for Public { + fn eq(&self, other: &Self) -> bool { + self.inner == other.inner + } +} + +impl Eq for Public {} + +impl PartialOrd for Public { + fn partial_cmp(&self, other: &Self) -> Option { + self.inner.partial_cmp(&other.inner) + } +} + +impl Ord for Public { + fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { + self.inner.cmp(&other.inner) + } +} #[cfg(feature = "full_crypto")] -impl Clone for Pair { - fn clone(&self) -> Self { - Pair(self.0.clone()) +impl sp_std::hash::Hash for Public { + fn hash(&self, state: &mut H) { + self.inner.hash(state) + } +} + +impl Public { + /// A new instance from the given PUBLIC_KEY_SERIALIZED_SIZE-byte `data`. + /// + /// NOTE: No checking goes on to ensure this is a real public key. Only use it if + /// you are certain that the array actually is a pubkey. GIGO! + pub fn from_raw(data: [u8; PUBLIC_KEY_SERIALIZED_SIZE]) -> Self { + Public { inner: data, _phantom: PhantomData } + } + + /// A new instance from an H384. + /// + /// NOTE: No checking goes on to ensure this is a real public key. Only use it if + /// you are certain that the array actually is a pubkey. GIGO! + pub fn from_h384(x: H384) -> Self { + Self::from_raw(x.into()) + } +} + +impl ByteArray for Public { + const LEN: usize = PUBLIC_KEY_SERIALIZED_SIZE; +} + +impl PassByInner for Public { + type Inner = [u8; PUBLIC_KEY_SERIALIZED_SIZE]; + + fn into_inner(self) -> Self::Inner { + self.inner + } + + fn inner(&self) -> &Self::Inner { + &self.inner + } + + fn from_inner(inner: Self::Inner) -> Self { + Self { inner, _phantom: PhantomData } } } -impl AsRef<[u8; BLS377::PUBLICKEY_SERIALIZED_SIZE]> for Public { - fn as_ref(&self) -> &[u8; BLS377::PUBLICKEY_SERIALIZED_SIZE] { - &self.0 +impl AsRef<[u8; PUBLIC_KEY_SERIALIZED_SIZE]> for Public { + fn as_ref(&self) -> &[u8; PUBLIC_KEY_SERIALIZED_SIZE] { + &self.inner } } -impl AsRef<[u8]> for Public { +impl AsRef<[u8]> for Public { fn as_ref(&self) -> &[u8] { - &self.0[..] + &self.inner[..] } } -impl AsMut<[u8]> for Public { +impl AsMut<[u8]> for Public { fn as_mut(&mut self) -> &mut [u8] { - &mut self.0[..] + &mut self.inner[..] } } -impl Deref for Public { +impl Deref for Public { type Target = [u8]; fn deref(&self) -> &Self::Target { - &self.0 + &self.inner } } -impl sp_std::convert::TryFrom<&[u8]> for Public { +impl TryFrom<&[u8]> for Public { type Error = (); fn try_from(data: &[u8]) -> Result { - if data.len() != Self::LEN { + if data.len() != PUBLIC_KEY_SERIALIZED_SIZE { return Err(()) } - let mut r = [0u8; Self::LEN]; + let mut r = [0u8; PUBLIC_KEY_SERIALIZED_SIZE]; r.copy_from_slice(data); Ok(Self::unchecked_from(r)) } } -impl From for [u8; BLS377::PUBLICKEY_SERIALIZED_SIZE] { - fn from(x: Public) -> Self { - x.0 +impl From> for [u8; PUBLIC_KEY_SERIALIZED_SIZE] { + fn from(x: Public) -> Self { + x.inner } } #[cfg(feature = "full_crypto")] -impl From for Public { - fn from(x: Pair) -> Self { +impl From> for Public { + fn from(x: Pair) -> Self { x.public() } } -impl From for H384 { - fn from(x: Public) -> Self { - x.0.into() - } -} - -#[cfg(feature = "std")] -impl std::str::FromStr for Public { - type Err = crate::crypto::PublicError; - - fn from_str(s: &str) -> Result { - Self::from_ss58check(s) +impl From> for H384 { + fn from(x: Public) -> Self { + x.inner.into() } } -impl UncheckedFrom<[u8; BLS377::PUBLICKEY_SERIALIZED_SIZE]> for Public { - fn unchecked_from(x: [u8; BLS377::PUBLICKEY_SERIALIZED_SIZE]) -> Self { +impl UncheckedFrom<[u8; PUBLIC_KEY_SERIALIZED_SIZE]> for Public { + fn unchecked_from(x: [u8; PUBLIC_KEY_SERIALIZED_SIZE]) -> Self { Public::from_raw(x) } } -impl UncheckedFrom for Public { +impl UncheckedFrom for Public { fn unchecked_from(x: H384) -> Self { Public::from_h384(x) } } #[cfg(feature = "std")] -impl std::fmt::Display for Public { +impl std::str::FromStr for Public { + type Err = crate::crypto::PublicError; + + fn from_str(s: &str) -> Result { + Self::from_ss58check(s) + } +} + +#[cfg(feature = "std")] +impl std::fmt::Display for Public { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.to_ss58check()) } } -impl sp_std::fmt::Debug for Public { - #[cfg(feature = "std")] +#[cfg(feature = "std")] +impl sp_std::fmt::Debug for Public { fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { let s = self.to_ss58check(); - write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8]) + write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.inner), &s[0..8]) } +} - #[cfg(not(feature = "std"))] +#[cfg(not(feature = "std"))] +impl sp_std::fmt::Debug for Public { fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { Ok(()) } } #[cfg(feature = "std")] -impl Serialize for Public { +impl Serialize for Public { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -200,7 +301,7 @@ impl Serialize for Public { } #[cfg(feature = "std")] -impl<'de> Deserialize<'de> for Public { +impl<'de, T: BlsBound> Deserialize<'de> for Public { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, @@ -210,19 +311,99 @@ impl<'de> Deserialize<'de> for Public { } } -/// A signature (a 512-bit value). -#[cfg_attr(feature = "full_crypto", derive(Hash))] -#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] -pub struct Signature(pub [u8; BLS377::SIGNATURE_SERIALIZED_SIZE]); +impl TraitPublic for Public { + fn to_public_crypto_pair(&self) -> CryptoTypePublicPair { + CryptoTypePublicPair(TEMPORARY_CRYPTO_ID, self.to_raw_vec()) + } +} + +impl Derive for Public {} + +impl From> for CryptoTypePublicPair { + fn from(key: Public) -> Self { + (&key).into() + } +} + +impl From<&Public> for CryptoTypePublicPair { + fn from(key: &Public) -> Self { + CryptoTypePublicPair(TEMPORARY_CRYPTO_ID, key.to_raw_vec()) + } +} + +impl CryptoType for Public { + #[cfg(feature = "full_crypto")] + type Pair = Pair; +} + +/// A generic BLS signature. +#[derive(Copy, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[scale_info(skip_type_params(T))] +pub struct Signature { + inner: [u8; SIGNATURE_SERIALIZED_SIZE], + _phantom: PhantomData T>, +} + +impl Clone for Signature { + fn clone(&self) -> Self { + Self { inner: self.inner.clone(), _phantom: PhantomData } + } +} + +impl PartialEq for Signature { + fn eq(&self, other: &Self) -> bool { + self.inner == other.inner + } +} + +impl Eq for Signature {} -impl sp_std::convert::TryFrom<&[u8]> for Signature { +#[cfg(feature = "full_crypto")] +impl sp_std::hash::Hash for Signature { + fn hash(&self, state: &mut H) { + self.inner.hash(state) + } +} + +impl Signature { + /// A new instance from the given SIGNATURE_SERIALIZED_SIZE-byte `data`. + /// + /// NOTE: No checking goes on to ensure this is a real signature. Only use it if + /// you are certain that the array actually is a signature. GIGO! + pub fn from_raw(data: [u8; SIGNATURE_SERIALIZED_SIZE]) -> Self { + Signature { inner: data, _phantom: PhantomData } + } + + /// A new instance from the given slice that should be 64 bytes long. + /// + /// NOTE: No checking goes on to ensure this is a real signature. Only use it if + /// you are certain that the array actually is a signature. GIGO! + pub fn from_slice(data: &[u8]) -> Option { + if data.len() != SIGNATURE_SERIALIZED_SIZE { + return None + } + let mut r = [0u8; SIGNATURE_SERIALIZED_SIZE]; + r.copy_from_slice(data); + Some(Signature::from_raw(r)) + } + + /// A new instance from an H768. + /// + /// NOTE: No checking goes on to ensure this is a real signature. Only use it if + /// you are certain that the array actually is a signature. GIGO! + pub fn from_h768(hash: H768) -> Self { + Signature::from_raw(hash.into()) + } +} + +impl TryFrom<&[u8]> for Signature { type Error = (); fn try_from(data: &[u8]) -> Result { - if data.len() == BLS377::SIGNATURE_SERIALIZED_SIZE { - let mut inner = [0u8; BLS377::SIGNATURE_SERIALIZED_SIZE]; + if data.len() == SIGNATURE_SERIALIZED_SIZE { + let mut inner = [0u8; SIGNATURE_SERIALIZED_SIZE]; inner.copy_from_slice(data); - Ok(Signature(inner)) + Ok(Signature::from_raw(inner)) } else { Err(()) } @@ -230,17 +411,17 @@ impl sp_std::convert::TryFrom<&[u8]> for Signature { } #[cfg(feature = "std")] -impl Serialize for Signature { +impl Serialize for Signature { fn serialize(&self, serializer: S) -> Result where S: Serializer, { - serializer.serialize_str(&hex::encode(self)) + serializer.serialize_str(&hex::encode(self.inner)) } } #[cfg(feature = "std")] -impl<'de> Deserialize<'de> for Signature { +impl<'de, T> Deserialize<'de> for Signature { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, @@ -252,48 +433,40 @@ impl<'de> Deserialize<'de> for Signature { } } -impl Clone for Signature { - fn clone(&self) -> Self { - let mut r = [0u8; BLS377::SIGNATURE_SERIALIZED_SIZE]; - r.copy_from_slice(&self.0[..]); - Signature(r) +impl From> for H768 { + fn from(signature: Signature) -> H768 { + H768::from(signature.inner) } } -impl From for H768 { - fn from(v: Signature) -> H768 { - H768::from(v.0) +impl From> for [u8; SIGNATURE_SERIALIZED_SIZE] { + fn from(signature: Signature) -> [u8; SIGNATURE_SERIALIZED_SIZE] { + signature.inner } } -impl From for [u8; BLS377::SIGNATURE_SERIALIZED_SIZE] { - fn from(v: Signature) -> [u8; BLS377::SIGNATURE_SERIALIZED_SIZE] { - v.0 +impl AsRef<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature { + fn as_ref(&self) -> &[u8; SIGNATURE_SERIALIZED_SIZE] { + &self.inner } } -impl AsRef<[u8; BLS377::SIGNATURE_SERIALIZED_SIZE]> for Signature { - fn as_ref(&self) -> &[u8; BLS377::SIGNATURE_SERIALIZED_SIZE] { - &self.0 - } -} - -impl AsRef<[u8]> for Signature { +impl AsRef<[u8]> for Signature { fn as_ref(&self) -> &[u8] { - &self.0[..] + &self.inner[..] } } -impl AsMut<[u8]> for Signature { +impl AsMut<[u8]> for Signature { fn as_mut(&mut self) -> &mut [u8] { - &mut self.0[..] + &mut self.inner[..] } } -impl sp_std::fmt::Debug for Signature { +impl sp_std::fmt::Debug for Signature { #[cfg(feature = "std")] fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0)) + write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.inner)) } #[cfg(not(feature = "std"))] @@ -302,95 +475,25 @@ impl sp_std::fmt::Debug for Signature { } } -impl UncheckedFrom<[u8; BLS377::SIGNATURE_SERIALIZED_SIZE]> for Signature { - fn unchecked_from(data: [u8; BLS377::SIGNATURE_SERIALIZED_SIZE]) -> Signature { - Signature(data) - } -} - -impl Signature { - /// A new instance from the given BLS377::SIGNATURE_SERIALIZED_SIZE-byte `data`. - /// - /// NOTE: No checking goes on to ensure this is a real signature. Only use it if - /// you are certain that the array actually is a signature. GIGO! - pub fn from_raw(data: [u8; BLS377::SIGNATURE_SERIALIZED_SIZE]) -> Signature { - Signature(data) - } - - /// A new instance from the given slice that should be 64 bytes long. - /// - /// NOTE: No checking goes on to ensure this is a real signature. Only use it if - /// you are certain that the array actually is a signature. GIGO! - pub fn from_slice(data: &[u8]) -> Option { - let mut r = [0u8; BLS377::SIGNATURE_SERIALIZED_SIZE]; - r.copy_from_slice(data); - Some(Signature(r)) - } - - /// A new instance from an H768. - /// - /// NOTE: No checking goes on to ensure this is a real signature. Only use it if - /// you are certain that the array actually is a signature. GIGO! - pub fn from_h768(v: H768) -> Signature { - Signature(v.into()) - } -} - -// TODO: ADD just if and WHEN is required (if ever) -// /// A localized signature also contains sender information. -// #[cfg(feature = "std")] -// #[derive(PartialEq, Eq, Clone, Debug, Encode, Decode)] -// pub struct LocalizedSignature { -// /// The signer of the signature. -// pub signer: Public, -// /// The signature itself. -// pub signature: Signature, -// } - -impl Public { - /// A new instance from the given BLS377::PUBLICKEY_SERIALIZED_SIZE-byte `data`. - /// - /// NOTE: No checking goes on to ensure this is a real public key. Only use it if - /// you are certain that the array actually is a pubkey. GIGO! - pub fn from_raw(data: [u8; BLS377::PUBLICKEY_SERIALIZED_SIZE]) -> Self { - Public(data) - } - - /// A new instance from an H384. - /// - /// NOTE: No checking goes on to ensure this is a real public key. Only use it if - /// you are certain that the array actually is a pubkey. GIGO! - pub fn from_h384(x: H384) -> Self { - Public(x.into()) - } - - /// Return a slice filled with raw data. - pub fn as_array_ref(&self) -> &[u8; BLS377::PUBLICKEY_SERIALIZED_SIZE] { - self.as_ref() +impl UncheckedFrom<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature { + fn unchecked_from(data: [u8; SIGNATURE_SERIALIZED_SIZE]) -> Self { + Signature::from_raw(data) } } -impl ByteArray for Public { - const LEN: usize = BLS377::PUBLICKEY_SERIALIZED_SIZE; -} - -impl TraitPublic for Public { - fn to_public_crypto_pair(&self) -> CryptoTypePublicPair { - CryptoTypePublicPair(CRYPTO_ID, self.to_raw_vec()) - } +impl CryptoType for Signature { + #[cfg(feature = "full_crypto")] + type Pair = Pair; } -impl Derive for Public {} - -impl From for CryptoTypePublicPair { - fn from(key: Public) -> Self { - (&key).into() - } -} +/// A key pair. +#[cfg(feature = "full_crypto")] +pub struct Pair(Keypair); -impl From<&Public> for CryptoTypePublicPair { - fn from(key: &Public) -> Self { - CryptoTypePublicPair(CRYPTO_ID, key.to_raw_vec()) +#[cfg(feature = "full_crypto")] +impl Clone for Pair { + fn clone(&self) -> Self { + Pair(self.0.clone()) } } @@ -408,17 +511,39 @@ pub enum DeriveError { } #[cfg(feature = "full_crypto")] -impl TraitPair for Pair { - type Public = Public; +impl Pair { + /// Get the seed for this key. + pub fn seed(&self) -> Seed { + self.0.secret.to_bytes() + } + + // TODO DAVXY: is this required??? If yes add when it will be 😃 + // /// Exactly as `from_string` except that if no matches are found then, the the first 32 + // /// characters are taken (padded with spaces as necessary) and used as the MiniSecretKey. + // #[cfg(feature = "std")] + // pub fn from_legacy_string(s: &str, password_override: Option<&str>) -> Self { + // Self::from_string(s, password_override).unwrap_or_else(|_| { + // let mut padded_seed: Seed = [b' '; 32]; + // let len = s.len().min(32); + // padded_seed[..len].copy_from_slice(&s.as_bytes()[..len]); + // Self::from_seed(&padded_seed) + // }) + // } +} + +#[cfg(feature = "full_crypto")] +impl TraitPair for Pair { type Seed = Seed; - type Signature = Signature; + type Public = Public; + type Signature = Signature; + // TODO DAVXY: this is not required to be an associated type... type DeriveError = DeriveError; /// Generate new secure (random) key pair and provide the recovery phrase. /// /// You can recover the same key later with `from_phrase`. #[cfg(feature = "std")] - fn generate_with_phrase(password: Option<&str>) -> (Pair, String, Seed) { + fn generate_with_phrase(password: Option<&str>) -> (Self, String, Seed) { let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English); let phrase = mnemonic.phrase(); let (pair, seed) = Self::from_phrase(phrase, password) @@ -431,7 +556,7 @@ impl TraitPair for Pair { fn from_phrase( phrase: &str, password: Option<&str>, - ) -> Result<(Pair, Seed), SecretStringError> { + ) -> Result<(Self, Seed), SecretStringError> { let big_seed = seed_from_entropy( Mnemonic::from_phrase(phrase, Language::English) .map_err(|_| SecretStringError::InvalidPhrase)? @@ -447,7 +572,7 @@ impl TraitPair for Pair { /// Make a new key pair from secret seed material. /// /// You should never need to use this; generate(), generate_with_phrase - fn from_seed(seed: &Seed) -> Pair { + fn from_seed(seed: &Seed) -> Self { Self::from_seed_slice(&seed[..]).expect("seed has valid length; qed") } @@ -455,8 +580,8 @@ impl TraitPair for Pair { /// will return `None`. /// /// You should never need to use this; generate(), generate_with_phrase - fn from_seed_slice(seed_slice: &[u8]) -> Result { - if seed_slice.len() != BLS377::SECRET_KEY_SIZE { + fn from_seed_slice(seed_slice: &[u8]) -> Result { + if seed_slice.len() != SECRET_KEY_SERIALIZED_SIZE { return Err(SecretStringError::InvalidSeedLength) } let secret = bls_like::SecretKey::from_seed(seed_slice); @@ -469,7 +594,7 @@ impl TraitPair for Pair { &self, path: Iter, _seed: Option, - ) -> Result<(Pair, Option), DeriveError> { + ) -> Result<(Self, Option), DeriveError> { let mut acc = self.0.secret.to_bytes(); for j in path { match j { @@ -481,23 +606,23 @@ impl TraitPair for Pair { } /// Get the public key. - fn public(&self) -> Public { - let mut r = [0u8; BLS377::PUBLICKEY_SERIALIZED_SIZE]; + fn public(&self) -> Self::Public { + let mut raw = [0u8; PUBLIC_KEY_SERIALIZED_SIZE]; let pk = self.0.public.to_bytes(); - r.copy_from_slice(pk.as_slice()); - Public(r) + raw.copy_from_slice(pk.as_slice()); + Self::Public::from_raw(raw) } /// Sign a message. - fn sign(&self, message: &[u8]) -> Signature { + fn sign(&self, message: &[u8]) -> Self::Signature { let mut mutable_self = self.clone(); let r = mutable_self.0.sign(Message::new(b"", message)).to_bytes(); - Signature::from_raw(r) + Self::Signature::from_raw(r) } /// Verify a signature on a message. Returns true if the signature is good. fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { - Self::verify_weak(&sig.0[..], message.as_ref(), pubkey) + Self::verify_weak(&sig.inner[..], message.as_ref(), pubkey) } /// Verify a signature on a message. Returns true if the signature is good. @@ -505,12 +630,11 @@ impl TraitPair for Pair { /// This doesn't use the type system to ensure that `sig` and `pubkey` are the correct /// size. Use it only if you're coming from byte buffers and need the speed. fn verify_weak, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool { - let pubkey_array: [u8; BLS377::PUBLICKEY_SERIALIZED_SIZE] = match pubkey.as_ref().try_into() - { + let pubkey_array: [u8; PUBLIC_KEY_SERIALIZED_SIZE] = match pubkey.as_ref().try_into() { Ok(pk) => pk, Err(_) => return false, }; - let public_key = match bls_like::PublicKey::::from_bytes(&pubkey_array) { + let public_key = match bls_like::PublicKey::::from_bytes(&pubkey_array) { Ok(pk) => pk, Err(_) => return false, }; @@ -534,45 +658,17 @@ impl TraitPair for Pair { } #[cfg(feature = "full_crypto")] -impl Pair { - /// Get the seed for this key. - pub fn seed(&self) -> Seed { - self.0.secret.to_bytes() - } - - /// Exactly as `from_string` except that if no matches are found then, the the first 32 - /// characters are taken (padded with spaces as necessary) and used as the MiniSecretKey. - #[cfg(feature = "std")] - pub fn from_legacy_string(s: &str, password_override: Option<&str>) -> Pair { - Self::from_string(s, password_override).unwrap_or_else(|_| { - let mut padded_seed: Seed = [b' '; 32]; - let len = s.len().min(32); - padded_seed[..len].copy_from_slice(&s.as_bytes()[..len]); - Self::from_seed(&padded_seed) - }) - } -} -impl CryptoType for Public { - #[cfg(feature = "full_crypto")] - type Pair = Pair; -} - -impl CryptoType for Signature { - #[cfg(feature = "full_crypto")] - type Pair = Pair; -} - -#[cfg(feature = "full_crypto")] -impl CryptoType for Pair { - type Pair = Pair; +impl CryptoType for Pair { + type Pair = Pair; } +// Test set excercising the BLS12-377 implementation #[cfg(test)] mod test { use super::*; use crate::crypto::DEV_PHRASE; + use bls377::{Pair, Public, Signature}; use hex_literal::hex; - use serde_json; #[test] fn default_phrase_should_be_used() { @@ -599,6 +695,8 @@ mod test { ); } + // TODO FIXME Is this supposed to be successful? + // Where is the test vector defined? #[test] fn test_vector_should_work() { let pair = Pair::from_seed(&hex!( @@ -612,12 +710,16 @@ mod test { )) ); let message = b""; - let signature = hex!("0e5854002b249175764e463165aec0e38a46ddd44c2db29d6fec3022a3993b3390b001b53a04d155a4d216dd361df90087281be27c58ae22c7f1333820259ff5ae1b321126d1a001bf91ee088fb56ca9d4aa484d129ede7e701ced08df631581"); + let signature = + hex!("0e5854002b249175764e463165aec0e38a46ddd44c2db29d6fec3022a3993b3390b001b53a04d155a4d216dd361df90087281be27c58ae22c7f1333820259ff5ae1b321126d1a001bf91ee088fb56ca9d4aa484d129ede7e701ced08df631581" + ); let signature = Signature::from_raw(signature); assert!(pair.sign(&message[..]) == signature); assert!(Pair::verify(&signature, &message[..], &public)); } + // TODO FIXME Is this expected to be pass? + // Where the test vectors were taken? #[test] fn test_vector_by_string_should_work() { let pair = Pair::from_string( @@ -633,7 +735,9 @@ mod test { )) ); let message = b""; - let signature = hex!("9f7d07e0fdd6aa342f6defaade946b59bfeba8af45c243f86b208cd339b2c713421844e3007e0acafd0a529542ee050047b739fe5bfd311d884451542204e173d784e648eb55f4bd32da747f006120fadf4801c2b1c88f9745c50c2141b1d380"); + let signature = + hex!("9f7d07e0fdd6aa342f6defaade946b59bfeba8af45c243f86b208cd339b2c713421844e3007e0acafd0a529542ee050047b739fe5bfd311d884451542204e173d784e648eb55f4bd32da747f006120fadf4801c2b1c88f9745c50c2141b1d380" + ); let signature = Signature::from_raw(signature); assert!(pair.sign(&message[..]) == signature); assert!(Pair::verify(&signature, &message[..], &public)); @@ -660,7 +764,9 @@ mod test { "754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd59932124801") ) ); - let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); + let message = + hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" + ); let signature = pair.sign(&message[..]); println!("Correct signature: {:?}", signature); assert!(Pair::verify(&signature, &message[..], &public)); diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 6f562a5f6a1ca..468cf32a6384c 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -68,6 +68,8 @@ pub mod testing; pub mod traits; pub mod uint; +pub use bls::{bls377, bls381}; + pub use self::{ hash::{convert_hash, H160, H256, H512}, uint::{U256, U512}, diff --git a/primitives/core/src/testing.rs b/primitives/core/src/testing.rs index ed6c571f7e24e..6faf4ffa3042a 100644 --- a/primitives/core/src/testing.rs +++ b/primitives/core/src/testing.rs @@ -26,7 +26,9 @@ pub const SR25519: KeyTypeId = KeyTypeId(*b"sr25"); /// Key type for generic ECDSA key. pub const ECDSA: KeyTypeId = KeyTypeId(*b"ecds"); /// Key type for generic BLS12-377 key. -pub const BLS: KeyTypeId = KeyTypeId(*b"bls7"); +pub const BLS377: KeyTypeId = KeyTypeId(*b"bls7"); +/// Key type for generic BLS12-381 key. +pub const BLS381: KeyTypeId = KeyTypeId(*b"bls8"); /// 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/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 96762026fc6f3..709e1fa642f80 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -56,8 +56,6 @@ use sp_core::{ LogLevel, LogLevelFilter, OpaquePeerId, H256, }; -use sp_core::bls; - #[cfg(feature = "std")] use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration}; @@ -1115,54 +1113,6 @@ pub trait Crypto { .map_err(|_| EcdsaVerifyError::BadSignature)?; Ok(pubkey.serialize()) } - - /// Returns all `bls` public keys for the given key id from the keystore. - /// This is needed for beefy keystore. - fn bls_public_keys(&mut self, id: KeyTypeId) -> Vec { - self.extension::() - .expect("No `keystore` associated for the current context!") - .bls_public_keys(id) - } - - /// Generate an `bls12-377` key for the given key type using an optional seed and - /// store it in the keystore. - /// - /// The `seed` needs to be a valid utf8. - /// - /// Returns the public key. - fn bls_generate(&mut self, id: KeyTypeId, seed: Option>) -> bls::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!") - .bls_generate_new(id, seed) - .expect("`bls_generate` failed") - } - - /// Sign the given `msg` with the `bls12-377` key that corresponds to the given public key and - /// key type in the keystore. - /// - /// Returns the signature. - fn bls_sign( - &mut self, - id: KeyTypeId, - pub_key: &bls::Public, - msg: &[u8], - ) -> Option { - self.extension::() - .expect("No `keystore` associated for the current context!") - .sign_with(id, &pub_key.into(), msg) - .ok() - .flatten() - .and_then(|sig| bls::Signature::from_slice(&sig)) - } - - /// Verify an `bls12-377` signature. - /// - /// Returns `true` when the verification in successful regardless of - /// signature version. - fn bls_verify(sig: &bls::Signature, msg: &[u8], pubkey: &bls::Public) -> bool { - bls::Pair::verify(sig, msg, pubkey) - } } /// Interface that provides functions for hashing with different algorithms. diff --git a/primitives/keystore/src/lib.rs b/primitives/keystore/src/lib.rs index 1a5ff60e978e0..405a9ac010f9f 100644 --- a/primitives/keystore/src/lib.rs +++ b/primitives/keystore/src/lib.rs @@ -21,7 +21,7 @@ pub mod vrf; use crate::vrf::{VRFSignature, VRFTranscriptData}; use sp_core::{ - bls, + bls377, crypto::{CryptoTypePublicPair, KeyTypeId}, ecdsa, ed25519, sr25519, }; @@ -152,14 +152,18 @@ pub trait Keystore: Send + Sync { ) -> Result, Error>; /// Returns all bls public keys for the given key type. - fn bls_public_keys(&self, id: KeyTypeId) -> Vec; + fn bls377_public_keys(&self, id: KeyTypeId) -> Vec; /// Generate a new bls key pair for the given key type and an optional seed. /// /// If the given seed is `Some(_)`, the key pair will only be stored in memory. /// /// Returns the public key of the generated key pair. - fn bls_generate_new(&self, id: KeyTypeId, seed: Option<&str>) -> Result; + fn bls377_generate_new( + &self, + id: KeyTypeId, + seed: Option<&str>, + ) -> Result; /// Generate an BLS signature for a given message. /// @@ -173,12 +177,12 @@ pub trait Keystore: Send + Sync { /// Returns an [`bls::Signature`] or `None` in case the given `id` and /// `public` combination doesn't exist in the keystore. An `Err` will be /// returned if generating the signature itself failed. - fn bls_sign( + fn bls377_sign( &self, id: KeyTypeId, - public: &bls::Public, + public: &bls377::Public, msg: &[u8], - ) -> Result, Error>; + ) -> Result, Error>; } /// A shared pointer to a keystore implementation. diff --git a/primitives/keystore/src/testing.rs b/primitives/keystore/src/testing.rs index c302625127f2b..87848cc545e00 100644 --- a/primitives/keystore/src/testing.rs +++ b/primitives/keystore/src/testing.rs @@ -18,7 +18,7 @@ //! Types that should only be used for testing! use sp_core::{ - bls, + bls377, crypto::{ByteArray, CryptoTypePublicPair, KeyTypeId, Pair}, ecdsa, ed25519, sr25519, }; @@ -68,11 +68,11 @@ impl MemoryKeystore { }) } - fn bls_key_pair(&self, id: KeyTypeId, pub_key: &bls::Public) -> Option { + fn bls377_key_pair(&self, id: KeyTypeId, pub_key: &bls377::Public) -> Option { self.keys.read().get(&id).and_then(|inner| { inner .get(pub_key.as_slice()) - .map(|s| bls::Pair::from_string(s, None).expect("`bls` seed slice is valid")) + .map(|s| bls377::Pair::from_string(s, None).expect("`bls` seed slice is valid")) }) } } @@ -294,23 +294,27 @@ impl Keystore for MemoryKeystore { pair.map(|k| k.sign_prehashed(msg)).map(Ok).transpose() } - fn bls_public_keys(&self, id: KeyTypeId) -> Vec { + fn bls377_public_keys(&self, id: KeyTypeId) -> Vec { self.keys .read() .get(&id) .map(|keys| { keys.values() - .map(|s| bls::Pair::from_string(s, None).expect("`bls` seed slice is valid")) + .map(|s| bls377::Pair::from_string(s, None).expect("`bls` seed slice is valid")) .map(|p| p.public()) .collect() }) .unwrap_or_default() } - fn bls_generate_new(&self, id: KeyTypeId, seed: Option<&str>) -> Result { + fn bls377_generate_new( + &self, + id: KeyTypeId, + seed: Option<&str>, + ) -> Result { match seed { Some(seed) => { - let pair = bls::Pair::from_string(seed, None) + let pair = bls377::Pair::from_string(seed, None) .map_err(|_| Error::ValidationError("Generates an `bls` pair.".to_owned()))?; self.keys .write() @@ -320,7 +324,7 @@ impl Keystore for MemoryKeystore { Ok(pair.public()) }, None => { - let (pair, phrase, _) = bls::Pair::generate_with_phrase(None); + let (pair, phrase, _) = bls377::Pair::generate_with_phrase(None); self.keys .write() .entry(id) @@ -331,13 +335,13 @@ impl Keystore for MemoryKeystore { } } - fn bls_sign( + fn bls377_sign( &self, id: KeyTypeId, - public: &bls::Public, + public: &bls377::Public, msg: &[u8], - ) -> Result, Error> { - let pair = self.bls_key_pair(id, public); + ) -> Result, Error> { + let pair = self.bls377_key_pair(id, public); pair.map(|k| k.sign(msg)).map(Ok).transpose() } }