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()