Support for keyring in runtimes (#2044)

This functionality is required for #1984.

This PR enables
[`sp-keyring`](https://github.com/paritytech/polkadot-sdk/blob/21d36b7b4229c4d5225944f197918cde23fda4ea/substrate/primitives/keyring/src/sr25519.rs#L31-L40)
in `no-std` environments, allowing to generate the public key (e.g.
`AccountKeyring::Alice.public().to_ss58check()`), which can be later
used in the any of built-in [_runtime-genesis-config_
variant](https://github.com/paritytech/polkadot-sdk/blob/21d36b7b4229c4d5225944f197918cde23fda4ea/polkadot/node/service/src/chain_spec.rs#L1066-L1073).


The proposal is as follows:
- expose [`core::Pair`
trait](https://github.com/paritytech/polkadot-sdk/blob/d6f15306282e3de848a09c9aa9cba6f95a7811f0/substrate/primitives/core/src/crypto.rs#L832)
in `no-std`,
- `full_crypto` feature enables `sign` method,
- `std` feature enables `generate_with_phrase` and `generate` methods
(randomness is required),
- All other functionality, currently gated by `full_crypto` will be
available unconditionally (`no-std`):
-- `from_string`
-- `from_string_with_seed`
-- `from seed`
-- `from_seed_slice`
-- `from_phrase`
-- `derive`
-- `verify`

---

Depends on https://github.com/rust-bitcoin/rust-bip39/pull/57

---------

Co-authored-by: command-bot <>
Co-authored-by: Davide Galassi <davxy@datawok.net>
This commit is contained in:
Michal Kucharczyk
2024-03-12 12:43:31 +01:00
committed by GitHub
parent 1ead59773e
commit a756baf3b2
30 changed files with 248 additions and 233 deletions
+1 -1
View File
@@ -17,7 +17,7 @@
//! Little util for parsing an address URI. Replaces regular expressions.
#[cfg(all(not(feature = "std"), any(feature = "serde", feature = "full_crypto")))]
#[cfg(not(feature = "std"))]
use sp_std::{
alloc::string::{String, ToString},
vec::Vec,
+11 -19
View File
@@ -22,19 +22,18 @@
#[cfg(feature = "serde")]
use crate::crypto::Ss58Codec;
use crate::crypto::{
ByteArray, CryptoType, CryptoTypeId, Derive, Public as TraitPublic, UncheckedFrom, VrfPublic,
};
#[cfg(feature = "full_crypto")]
use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError, VrfSecret};
use crate::crypto::VrfSecret;
use crate::crypto::{
ByteArray, CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, Pair as TraitPair,
Public as TraitPublic, SecretStringError, UncheckedFrom, VrfPublic,
};
#[cfg(feature = "serde")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
#[cfg(all(not(feature = "std"), feature = "serde"))]
use sp_std::alloc::{format, string::String};
use bandersnatch_vrfs::CanonicalSerialize;
#[cfg(feature = "full_crypto")]
use bandersnatch_vrfs::SecretKey;
use bandersnatch_vrfs::{CanonicalSerialize, SecretKey};
use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};
use scale_info::TypeInfo;
@@ -45,10 +44,8 @@ use sp_std::{vec, vec::Vec};
pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"band");
/// Context used to produce a plain signature without any VRF input/output.
#[cfg(feature = "full_crypto")]
pub const SIGNING_CTX: &[u8] = b"BandersnatchSigningContext";
#[cfg(feature = "full_crypto")]
const SEED_SERIALIZED_SIZE: usize = 32;
const PUBLIC_SERIALIZED_SIZE: usize = 33;
@@ -56,7 +53,6 @@ const SIGNATURE_SERIALIZED_SIZE: usize = 65;
const PREOUT_SERIALIZED_SIZE: usize = 33;
/// Bandersnatch public key.
#[cfg_attr(feature = "full_crypto", derive(Hash))]
#[derive(
Clone,
Copy,
@@ -69,6 +65,7 @@ const PREOUT_SERIALIZED_SIZE: usize = 33;
PassByInner,
MaxEncodedLen,
TypeInfo,
Hash,
)]
pub struct Public(pub [u8; PUBLIC_SERIALIZED_SIZE]);
@@ -116,7 +113,6 @@ impl ByteArray for Public {
impl TraitPublic for Public {}
impl CryptoType for Public {
#[cfg(feature = "full_crypto")]
type Pair = Pair;
}
@@ -154,8 +150,9 @@ impl<'de> Deserialize<'de> for Public {
///
/// The signature is created via the [`VrfSecret::vrf_sign`] using [`SIGNING_CTX`] as transcript
/// `label`.
#[cfg_attr(feature = "full_crypto", derive(Hash))]
#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, PassByInner, MaxEncodedLen, TypeInfo)]
#[derive(
Clone, Copy, PartialEq, Eq, Encode, Decode, PassByInner, MaxEncodedLen, TypeInfo, Hash,
)]
pub struct Signature([u8; SIGNATURE_SERIALIZED_SIZE]);
impl UncheckedFrom<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature {
@@ -194,7 +191,6 @@ impl ByteArray for Signature {
}
impl CryptoType for Signature {
#[cfg(feature = "full_crypto")]
type Pair = Pair;
}
@@ -211,18 +207,15 @@ impl sp_std::fmt::Debug for Signature {
}
/// The raw secret seed, which can be used to reconstruct the secret [`Pair`].
#[cfg(feature = "full_crypto")]
type Seed = [u8; SEED_SERIALIZED_SIZE];
/// Bandersnatch secret key.
#[cfg(feature = "full_crypto")]
#[derive(Clone)]
pub struct Pair {
secret: SecretKey,
seed: Seed,
}
#[cfg(feature = "full_crypto")]
impl Pair {
/// Get the key seed.
pub fn seed(&self) -> Seed {
@@ -230,7 +223,6 @@ impl Pair {
}
}
#[cfg(feature = "full_crypto")]
impl TraitPair for Pair {
type Seed = Seed;
type Public = Public;
@@ -287,6 +279,7 @@ impl TraitPair for Pair {
/// the constant label [`SIGNING_CTX`] and `data` without any additional data.
///
/// See [`vrf::VrfSignData`] for additional details.
#[cfg(feature = "full_crypto")]
fn sign(&self, data: &[u8]) -> Signature {
let data = vrf::VrfSignData::new_unchecked(SIGNING_CTX, &[data], None);
self.vrf_sign(&data).signature
@@ -305,7 +298,6 @@ impl TraitPair for Pair {
}
}
#[cfg(feature = "full_crypto")]
impl CryptoType for Pair {
type Pair = Pair;
}
+9 -22
View File
@@ -25,11 +25,11 @@
#[cfg(feature = "serde")]
use crate::crypto::Ss58Codec;
use crate::crypto::{ByteArray, CryptoType, Derive, Public as TraitPublic, UncheckedFrom};
#[cfg(feature = "full_crypto")]
use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError};
use crate::crypto::{
ByteArray, CryptoType, Derive, DeriveError, DeriveJunction, Pair as TraitPair,
Public as TraitPublic, SecretStringError, UncheckedFrom,
};
#[cfg(feature = "full_crypto")]
use sp_std::vec::Vec;
use codec::{Decode, Encode, MaxEncodedLen};
@@ -40,9 +40,10 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
#[cfg(all(not(feature = "std"), feature = "serde"))]
use sp_std::alloc::{format, string::String};
use w3f_bls::{DoublePublicKey, DoubleSignature, EngineBLS, SerializableToBytes, TinyBLS381};
#[cfg(feature = "full_crypto")]
use w3f_bls::{DoublePublicKeyScheme, Keypair, Message, SecretKey};
use w3f_bls::{
DoublePublicKey, DoublePublicKeyScheme, DoubleSignature, EngineBLS, Keypair, Message,
SecretKey, SerializableToBytes, TinyBLS381,
};
use sp_runtime_interface::pass_by::{self, PassBy, PassByInner};
use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref};
@@ -57,7 +58,6 @@ pub mod bls377 {
pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"bls7");
/// BLS12-377 key pair.
#[cfg(feature = "full_crypto")]
pub type Pair = super::Pair<TinyBLS377>;
/// BLS12-377 public key.
pub type Public = super::Public<TinyBLS377>;
@@ -79,7 +79,6 @@ pub mod bls381 {
pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"bls8");
/// BLS12-381 key pair.
#[cfg(feature = "full_crypto")]
pub type Pair = super::Pair<TinyBLS381>;
/// BLS12-381 public key.
pub type Public = super::Public<TinyBLS381>;
@@ -96,7 +95,6 @@ trait BlsBound: EngineBLS + HardJunctionId + Send + Sync + 'static {}
impl<T: EngineBLS + HardJunctionId + Send + Sync + 'static> BlsBound for T {}
/// Secret key serialized size
#[cfg(feature = "full_crypto")]
const SECRET_KEY_SERIALIZED_SIZE: usize =
<SecretKey<TinyBLS381> as SerializableToBytes>::SERIALIZED_BYTES_SIZE;
@@ -113,7 +111,6 @@ pub const SIGNATURE_SERIALIZED_SIZE: usize =
/// 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; SECRET_KEY_SERIALIZED_SIZE];
/// A public key.
@@ -150,7 +147,6 @@ impl<T> Ord for Public<T> {
}
}
#[cfg(feature = "full_crypto")]
impl<T> sp_std::hash::Hash for Public<T> {
fn hash<H: sp_std::hash::Hasher>(&self, state: &mut H) {
self.inner.hash(state)
@@ -226,7 +222,6 @@ impl<T> From<Public<T>> for [u8; PUBLIC_KEY_SERIALIZED_SIZE] {
}
}
#[cfg(feature = "full_crypto")]
impl<T: BlsBound> From<Pair<T>> for Public<T> {
fn from(x: Pair<T>) -> Self {
x.public()
@@ -296,7 +291,6 @@ impl<T: BlsBound> TraitPublic for Public<T> {}
impl<T> Derive for Public<T> {}
impl<T: BlsBound> CryptoType for Public<T> {
#[cfg(feature = "full_crypto")]
type Pair = Pair<T>;
}
@@ -322,7 +316,6 @@ impl<T> PartialEq for Signature<T> {
impl<T> Eq for Signature<T> {}
#[cfg(feature = "full_crypto")]
impl<T> sp_std::hash::Hash for Signature<T> {
fn hash<H: sp_std::hash::Hasher>(&self, state: &mut H) {
self.inner.hash(state)
@@ -412,15 +405,12 @@ impl<T> UncheckedFrom<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature<T> {
}
impl<T: BlsBound> CryptoType for Signature<T> {
#[cfg(feature = "full_crypto")]
type Pair = Pair<T>;
}
/// A key pair.
#[cfg(feature = "full_crypto")]
pub struct Pair<T: EngineBLS>(Keypair<T>);
#[cfg(feature = "full_crypto")]
impl<T: EngineBLS> Clone for Pair<T> {
fn clone(&self) -> Self {
Pair(self.0.clone())
@@ -432,15 +422,12 @@ trait HardJunctionId {
}
/// Derive a single hard junction.
#[cfg(feature = "full_crypto")]
fn derive_hard_junction<T: HardJunctionId>(secret_seed: &Seed, cc: &[u8; 32]) -> Seed {
(T::ID, secret_seed, cc).using_encoded(sp_crypto_hashing::blake2_256)
}
#[cfg(feature = "full_crypto")]
impl<T: EngineBLS> Pair<T> {}
#[cfg(feature = "full_crypto")]
impl<T: BlsBound> TraitPair for Pair<T> {
type Seed = Seed;
type Public = Public<T>;
@@ -480,6 +467,7 @@ impl<T: BlsBound> TraitPair for Pair<T> {
Self::Public::unchecked_from(raw)
}
#[cfg(feature = "full_crypto")]
fn sign(&self, message: &[u8]) -> Self::Signature {
let mut mutable_self = self.clone();
let r: [u8; SIGNATURE_SERIALIZED_SIZE] =
@@ -523,7 +511,6 @@ impl<T: BlsBound> TraitPair for Pair<T> {
}
}
#[cfg(feature = "full_crypto")]
impl<T: BlsBound> CryptoType for Pair<T> {
type Pair = Pair<T>;
}
+3 -21
View File
@@ -18,7 +18,6 @@
//! Cryptographic utilities.
use crate::{ed25519, sr25519};
#[cfg(feature = "std")]
use bip39::{Language, Mnemonic};
use codec::{Decode, Encode, MaxEncodedLen};
#[cfg(feature = "std")]
@@ -26,7 +25,6 @@ use itertools::Itertools;
#[cfg(feature = "std")]
use rand::{rngs::OsRng, RngCore};
use scale_info::TypeInfo;
#[cfg(feature = "std")]
pub use secrecy::{ExposeSecret, SecretString};
use sp_runtime_interface::pass_by::PassByInner;
#[doc(hidden)]
@@ -41,10 +39,7 @@ pub use ss58_registry::{from_known_address_format, Ss58AddressFormat, Ss58Addres
/// Trait to zeroize a memory buffer.
pub use zeroize::Zeroize;
#[cfg(feature = "std")]
pub use crate::address_uri::AddressUri;
#[cfg(any(feature = "std", feature = "full_crypto"))]
pub use crate::address_uri::Error as AddressUriError;
pub use crate::address_uri::{AddressUri, Error as AddressUriError};
/// The root phrase for our publicly known keys.
pub const DEV_PHRASE: &str =
@@ -82,7 +77,6 @@ impl<S, T: UncheckedFrom<S>> UncheckedInto<T> for S {
/// An error with the interpretation of a secret.
#[cfg_attr(feature = "std", derive(thiserror::Error))]
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg(feature = "full_crypto")]
pub enum SecretStringError {
/// The overall format was invalid (e.g. the seed phrase contained symbols).
#[cfg_attr(feature = "std", error("Invalid format {0}"))]
@@ -104,7 +98,6 @@ pub enum SecretStringError {
InvalidPath,
}
#[cfg(any(feature = "std", feature = "full_crypto"))]
impl From<AddressUriError> for SecretStringError {
fn from(e: AddressUriError) -> Self {
Self::InvalidFormat(e)
@@ -114,7 +107,6 @@ impl From<AddressUriError> for SecretStringError {
/// An error when deriving a key.
#[cfg_attr(feature = "std", derive(thiserror::Error))]
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg(feature = "full_crypto")]
pub enum DeriveError {
/// A soft key was found in the path (and is unsupported).
#[cfg_attr(feature = "std", error("Soft key in path"))]
@@ -125,7 +117,6 @@ pub enum DeriveError {
/// a new secret key from an existing secret key and, in the case of `SoftRaw` and `SoftIndex`
/// a new public key from an existing public key.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Encode, Decode)]
#[cfg(any(feature = "full_crypto", feature = "serde"))]
pub enum DeriveJunction {
/// Soft (vanilla) derivation. Public keys have a correspondent derivation.
Soft([u8; JUNCTION_ID_LEN]),
@@ -133,7 +124,6 @@ pub enum DeriveJunction {
Hard([u8; JUNCTION_ID_LEN]),
}
#[cfg(any(feature = "full_crypto", feature = "serde"))]
impl DeriveJunction {
/// Consume self to return a soft derive junction with the same chain code.
pub fn soften(self) -> Self {
@@ -192,7 +182,6 @@ impl DeriveJunction {
}
}
#[cfg(any(feature = "full_crypto", feature = "serde"))]
impl<T: AsRef<str>> From<T> for DeriveJunction {
fn from(j: T) -> DeriveJunction {
let j = j.as_ref();
@@ -812,7 +801,6 @@ mod dummy {
/// assert_eq!("0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a", suri.phrase.expose_secret());
/// assert!(suri.password.is_none());
/// ```
#[cfg(feature = "std")]
pub struct SecretUri {
/// The phrase to derive the private key.
///
@@ -824,7 +812,6 @@ pub struct SecretUri {
pub junctions: Vec<DeriveJunction>,
}
#[cfg(feature = "std")]
impl sp_std::str::FromStr for SecretUri {
type Err = SecretStringError;
@@ -845,7 +832,6 @@ impl sp_std::str::FromStr for SecretUri {
/// Trait suitable for typical cryptographic PKI key pair type.
///
/// For now it just specifies how to create a key from a phrase and derivation path.
#[cfg(feature = "full_crypto")]
pub trait Pair: CryptoType + Sized {
/// The type which is used to encode a public key.
type Public: Public + Hash;
@@ -878,21 +864,19 @@ pub trait Pair: CryptoType + Sized {
#[cfg(feature = "std")]
fn generate_with_phrase(password: Option<&str>) -> (Self, String, Self::Seed) {
let mnemonic = Mnemonic::generate(12).expect("Mnemonic generation always works; qed");
let phrase = mnemonic.word_iter().join(" ");
let phrase = mnemonic.words().join(" ");
let (pair, seed) = Self::from_phrase(&phrase, password)
.expect("All phrases generated by Mnemonic are valid; qed");
(pair, phrase.to_owned(), seed)
}
/// Returns the KeyPair from the English BIP39 seed `phrase`, or an error if it's invalid.
#[cfg(feature = "std")]
fn from_phrase(
phrase: &str,
password: Option<&str>,
) -> Result<(Self, Self::Seed), SecretStringError> {
let mnemonic = Mnemonic::parse_in(Language::English, phrase)
.map_err(|_| SecretStringError::InvalidPhrase)?;
let (entropy, entropy_len) = mnemonic.to_entropy_array();
let big_seed =
substrate_bip39::seed_from_entropy(&entropy[0..entropy_len], password.unwrap_or(""))
@@ -928,6 +912,7 @@ pub trait Pair: CryptoType + Sized {
fn from_seed_slice(seed: &[u8]) -> Result<Self, SecretStringError>;
/// Sign a message.
#[cfg(feature = "full_crypto")]
fn sign(&self, message: &[u8]) -> Self::Signature;
/// Verify a signature on a message. Returns true if the signature is good.
@@ -962,7 +947,6 @@ pub trait Pair: CryptoType + Sized {
/// Notably, integer junction indices may be legally prefixed with arbitrary number of zeros.
/// Similarly an empty password (ending the SURI with `///`) is perfectly valid and will
/// generally be equivalent to no password at all.
#[cfg(feature = "std")]
fn from_string_with_seed(
s: &str,
password_override: Option<&str>,
@@ -996,7 +980,6 @@ pub trait Pair: CryptoType + Sized {
/// Interprets the string `s` in order to generate a key pair.
///
/// See [`from_string_with_seed`](Pair::from_string_with_seed) for more extensive documentation.
#[cfg(feature = "std")]
fn from_string(s: &str, password_override: Option<&str>) -> Result<Self, SecretStringError> {
Self::from_string_with_seed(s, password_override).map(|x| x.0)
}
@@ -1054,7 +1037,6 @@ where
/// Type which has a particular kind of crypto associated with it.
pub trait CryptoType {
/// The pair key type of this crypto.
#[cfg(feature = "full_crypto")]
type Pair: Pair;
}
+11 -23
View File
@@ -24,16 +24,13 @@ use sp_runtime_interface::pass_by::PassByInner;
#[cfg(feature = "serde")]
use crate::crypto::Ss58Codec;
use crate::crypto::{
ByteArray, CryptoType, CryptoTypeId, Derive, Public as TraitPublic, UncheckedFrom,
ByteArray, CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, Pair as TraitPair,
Public as TraitPublic, SecretStringError, UncheckedFrom,
};
#[cfg(feature = "full_crypto")]
use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError};
#[cfg(all(not(feature = "std"), feature = "full_crypto"))]
use k256::ecdsa::SigningKey as SecretKey;
#[cfg(not(feature = "std"))]
use k256::ecdsa::VerifyingKey;
#[cfg(all(feature = "std", feature = "full_crypto"))]
use k256::ecdsa::{SigningKey as SecretKey, VerifyingKey};
#[cfg(feature = "std")]
use secp256k1::{
ecdsa::{RecoverableSignature, RecoveryId},
Message, PublicKey, SecretKey, SECP256K1,
@@ -42,7 +39,7 @@ use secp256k1::{
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
#[cfg(all(not(feature = "std"), feature = "serde"))]
use sp_std::alloc::{format, string::String};
#[cfg(feature = "full_crypto")]
#[cfg(not(feature = "std"))]
use sp_std::vec::Vec;
/// An identifier used to match public keys against ecdsa keys
@@ -57,11 +54,9 @@ pub const SIGNATURE_SERIALIZED_SIZE: usize = 65;
/// The secret seed.
///
/// The raw secret seed, which can be used to create the `Pair`.
#[cfg(feature = "full_crypto")]
type Seed = [u8; 32];
/// The ECDSA compressed public key.
#[cfg_attr(feature = "full_crypto", derive(Hash))]
#[derive(
Clone,
Copy,
@@ -74,6 +69,7 @@ type Seed = [u8; 32];
PartialEq,
PartialOrd,
Ord,
Hash,
)]
pub struct Public(pub [u8; PUBLIC_KEY_SERIALIZED_SIZE]);
@@ -221,8 +217,7 @@ impl<'de> Deserialize<'de> for Public {
}
/// A signature (a 512-bit value, plus 8 bits for recovery ID).
#[cfg_attr(feature = "full_crypto", derive(Hash))]
#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)]
#[derive(Hash, Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)]
pub struct Signature(pub [u8; SIGNATURE_SERIALIZED_SIZE]);
impl ByteArray for Signature {
@@ -345,13 +340,11 @@ impl Signature {
}
/// Recover the public key from this signature and a message.
#[cfg(feature = "full_crypto")]
pub fn recover<M: AsRef<[u8]>>(&self, message: M) -> Option<Public> {
self.recover_prehashed(&sp_crypto_hashing::blake2_256(message.as_ref()))
}
/// Recover the public key from this signature and a pre-hashed message.
#[cfg(feature = "full_crypto")]
pub fn recover_prehashed(&self, message: &[u8; 32]) -> Option<Public> {
#[cfg(feature = "std")]
{
@@ -380,7 +373,7 @@ impl From<(k256::ecdsa::Signature, k256::ecdsa::RecoveryId)> for Signature {
}
}
#[cfg(all(feature = "std", feature = "full_crypto"))]
#[cfg(feature = "std")]
impl From<RecoverableSignature> for Signature {
fn from(recsig: RecoverableSignature) -> Signature {
let mut r = Self::default();
@@ -393,20 +386,17 @@ impl From<RecoverableSignature> for Signature {
}
/// Derive a single hard junction.
#[cfg(feature = "full_crypto")]
fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed {
("Secp256k1HDKD", secret_seed, cc).using_encoded(sp_crypto_hashing::blake2_256)
}
/// A key pair.
#[cfg(feature = "full_crypto")]
#[derive(Clone)]
pub struct Pair {
public: Public,
secret: SecretKey,
}
#[cfg(feature = "full_crypto")]
impl TraitPair for Pair {
type Public = Public;
type Seed = Seed;
@@ -454,6 +444,7 @@ impl TraitPair for Pair {
}
/// Sign a message.
#[cfg(feature = "full_crypto")]
fn sign(&self, message: &[u8]) -> Signature {
self.sign_prehashed(&sp_crypto_hashing::blake2_256(message))
}
@@ -469,7 +460,6 @@ impl TraitPair for Pair {
}
}
#[cfg(feature = "full_crypto")]
impl Pair {
/// Get the seed for this key.
pub fn seed(&self) -> Seed {
@@ -496,6 +486,7 @@ impl Pair {
}
/// Sign a pre-hashed message
#[cfg(feature = "full_crypto")]
pub fn sign_prehashed(&self, message: &[u8; 32]) -> Signature {
#[cfg(feature = "std")]
{
@@ -550,7 +541,7 @@ impl Pair {
// NOTE: this solution is not effective when `Pair` is moved around memory.
// The very same problem affects other cryptographic backends that are just using
// `zeroize`for their secrets.
#[cfg(all(feature = "std", feature = "full_crypto"))]
#[cfg(feature = "std")]
impl Drop for Pair {
fn drop(&mut self) {
self.secret.non_secure_erase()
@@ -558,16 +549,13 @@ impl Drop for Pair {
}
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;
}
+5 -16
View File
@@ -19,7 +19,6 @@
//! Simple Ed25519 API.
// end::description[]
#[cfg(feature = "full_crypto")]
use sp_std::vec::Vec;
use crate::{
@@ -32,13 +31,11 @@ use scale_info::TypeInfo;
#[cfg(feature = "serde")]
use crate::crypto::Ss58Codec;
use crate::crypto::{
CryptoType, CryptoTypeId, Derive, FromEntropy, Public as TraitPublic, UncheckedFrom,
CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, FromEntropy, Pair as TraitPair,
Public as TraitPublic, SecretStringError, UncheckedFrom,
};
#[cfg(feature = "full_crypto")]
use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError};
#[cfg(feature = "full_crypto")]
use core::convert::TryFrom;
#[cfg(feature = "full_crypto")]
use ed25519_zebra::{SigningKey, VerificationKey};
#[cfg(feature = "serde")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
@@ -53,11 +50,9 @@ pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ed25");
/// 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; 32];
/// A public key.
#[cfg_attr(feature = "full_crypto", derive(Hash))]
#[derive(
PartialEq,
Eq,
@@ -70,11 +65,11 @@ type Seed = [u8; 32];
PassByInner,
MaxEncodedLen,
TypeInfo,
Hash,
)]
pub struct Public(pub [u8; 32]);
/// A key pair.
#[cfg(feature = "full_crypto")]
#[derive(Copy, Clone)]
pub struct Pair {
public: VerificationKey,
@@ -210,8 +205,7 @@ 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)]
#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq, Hash)]
pub struct Signature(pub [u8; 64]);
impl TryFrom<&[u8]> for Signature {
@@ -370,12 +364,10 @@ impl TraitPublic for Public {}
impl Derive for Public {}
/// Derive a single hard junction.
#[cfg(feature = "full_crypto")]
fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed {
("Ed25519HDKD", secret_seed, cc).using_encoded(sp_crypto_hashing::blake2_256)
}
#[cfg(feature = "full_crypto")]
impl TraitPair for Pair {
type Public = Public;
type Seed = Seed;
@@ -414,6 +406,7 @@ impl TraitPair for Pair {
}
/// Sign a message.
#[cfg(feature = "full_crypto")]
fn sign(&self, message: &[u8]) -> Signature {
Signature::from_raw(self.secret.sign(message).into())
}
@@ -433,7 +426,6 @@ impl TraitPair for Pair {
}
}
#[cfg(feature = "full_crypto")]
impl Pair {
/// Get the seed for this key.
pub fn seed(&self) -> Seed {
@@ -454,16 +446,13 @@ impl Pair {
}
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;
}
-3
View File
@@ -46,7 +46,6 @@ pub use sp_debug_derive::RuntimeDebug;
#[cfg(feature = "serde")]
pub use impl_serde::serialize as bytes;
#[cfg(feature = "full_crypto")]
#[deprecated(
since = "27.0.0",
note = "`sp-crypto-hashing` re-exports will be removed after June 2024. Use `sp-crypto-hashing` instead."
@@ -58,7 +57,6 @@ pub mod crypto;
pub mod hexdisplay;
pub use paste;
#[cfg(any(feature = "full_crypto", feature = "std"))]
mod address_uri;
#[cfg(feature = "bandersnatch-experimental")]
pub mod bandersnatch;
@@ -87,7 +85,6 @@ pub use self::{
hash::{convert_hash, H160, H256, H512},
uint::{U256, U512},
};
#[cfg(feature = "full_crypto")]
pub use crypto::{ByteArray, DeriveJunction, Pair, Public};
#[cfg(feature = "std")]
+8 -19
View File
@@ -19,11 +19,11 @@
#[cfg(feature = "serde")]
use crate::crypto::Ss58Codec;
use crate::crypto::{ByteArray, CryptoType, Derive, Public as PublicT, UncheckedFrom};
#[cfg(feature = "full_crypto")]
use crate::crypto::{DeriveError, DeriveJunction, Pair as PairT, SecretStringError};
use crate::crypto::{
ByteArray, CryptoType, Derive, DeriveError, DeriveJunction, Pair as PairT, Public as PublicT,
SecretStringError, UncheckedFrom,
};
#[cfg(feature = "full_crypto")]
use sp_std::vec::Vec;
use codec::{Decode, Encode, MaxEncodedLen};
@@ -39,12 +39,11 @@ use sp_std::convert::TryFrom;
/// ECDSA and BLS12-377 paired crypto scheme
#[cfg(feature = "bls-experimental")]
pub mod ecdsa_bls377 {
use crate::{bls377, crypto::CryptoTypeId, ecdsa};
#[cfg(feature = "full_crypto")]
use crate::Hasher;
use crate::{
bls377,
crypto::{CryptoTypeId, Pair as PairT, UncheckedFrom},
ecdsa,
crypto::{Pair as PairT, UncheckedFrom},
Hasher,
};
/// An identifier used to match public keys against BLS12-377 keys
@@ -56,7 +55,6 @@ pub mod ecdsa_bls377 {
ecdsa::SIGNATURE_SERIALIZED_SIZE + bls377::SIGNATURE_SERIALIZED_SIZE;
/// (ECDSA,BLS12-377) key-pair pair.
#[cfg(feature = "full_crypto")]
pub type Pair = super::Pair<ecdsa::Pair, bls377::Pair, PUBLIC_KEY_LEN, SIGNATURE_LEN>;
/// (ECDSA,BLS12-377) public key pair.
pub type Public = super::Public<PUBLIC_KEY_LEN>;
@@ -64,16 +62,13 @@ pub mod ecdsa_bls377 {
pub type Signature = super::Signature<SIGNATURE_LEN>;
impl super::CryptoType for Public {
#[cfg(feature = "full_crypto")]
type Pair = Pair;
}
impl super::CryptoType for Signature {
#[cfg(feature = "full_crypto")]
type Pair = Pair;
}
#[cfg(feature = "full_crypto")]
impl super::CryptoType for Pair {
type Pair = Pair;
}
@@ -136,7 +131,6 @@ pub mod ecdsa_bls377 {
/// Secure seed length.
///
/// Currently only supporting sub-schemes whose seed is a 32-bytes array.
#[cfg(feature = "full_crypto")]
const SECURE_SEED_LEN: usize = 32;
/// A secret seed.
@@ -144,14 +138,12 @@ const SECURE_SEED_LEN: usize = 32;
/// 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; SECURE_SEED_LEN];
/// A public key.
#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)]
pub struct Public<const LEFT_PLUS_RIGHT_LEN: usize>([u8; LEFT_PLUS_RIGHT_LEN]);
#[cfg(feature = "full_crypto")]
impl<const LEFT_PLUS_RIGHT_LEN: usize> sp_std::hash::Hash for Public<LEFT_PLUS_RIGHT_LEN> {
fn hash<H: sp_std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
@@ -215,7 +207,6 @@ impl<const LEFT_PLUS_RIGHT_LEN: usize> PassBy for Public<LEFT_PLUS_RIGHT_LEN> {
type PassBy = pass_by::Inner<Self, [u8; LEFT_PLUS_RIGHT_LEN]>;
}
#[cfg(feature = "full_crypto")]
impl<
LeftPair: PairT,
RightPair: PairT,
@@ -311,7 +302,6 @@ impl<T: ByteArray> SignatureBound for T {}
#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)]
pub struct Signature<const LEFT_PLUS_RIGHT_LEN: usize>([u8; LEFT_PLUS_RIGHT_LEN]);
#[cfg(feature = "full_crypto")]
impl<const LEFT_PLUS_RIGHT_LEN: usize> sp_std::hash::Hash for Signature<LEFT_PLUS_RIGHT_LEN> {
fn hash<H: sp_std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
@@ -411,7 +401,6 @@ impl<const LEFT_PLUS_RIGHT_LEN: usize> UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]>
}
/// A key pair.
#[cfg(feature = "full_crypto")]
#[derive(Clone)]
pub struct Pair<
LeftPair: PairT,
@@ -423,7 +412,6 @@ pub struct Pair<
right: RightPair,
}
#[cfg(feature = "full_crypto")]
impl<
LeftPair: PairT,
RightPair: PairT,
@@ -483,6 +471,7 @@ where
Self::Public::unchecked_from(raw)
}
#[cfg(feature = "full_crypto")]
fn sign(&self, message: &[u8]) -> Self::Signature {
let mut raw: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN];
raw[..LeftPair::Signature::LEN].copy_from_slice(self.left.sign(message).as_ref());
+7 -23
View File
@@ -19,20 +19,14 @@
//!
//! Note: `CHAIN_CODE_LENGTH` must be equal to `crate::crypto::JUNCTION_ID_LEN`
//! for this to work.
#[cfg(any(feature = "full_crypto", feature = "serde"))]
use crate::crypto::DeriveJunction;
#[cfg(feature = "serde")]
use crate::crypto::Ss58Codec;
use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError};
#[cfg(feature = "full_crypto")]
use crate::crypto::{DeriveError, Pair as TraitPair, SecretStringError};
#[cfg(feature = "full_crypto")]
use schnorrkel::signing_context;
use schnorrkel::{
derive::CHAIN_CODE_LENGTH, signing_context, ExpansionMode, Keypair, MiniSecretKey, SecretKey,
};
#[cfg(any(feature = "full_crypto", feature = "serde"))]
use schnorrkel::{
derive::{ChainCode, Derivation},
PublicKey,
derive::{ChainCode, Derivation, CHAIN_CODE_LENGTH},
ExpansionMode, Keypair, MiniSecretKey, PublicKey, SecretKey,
};
use sp_std::vec::Vec;
@@ -47,7 +41,6 @@ use codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_std::ops::Deref;
#[cfg(feature = "full_crypto")]
use schnorrkel::keys::{MINI_SECRET_KEY_LENGTH, SECRET_KEY_LENGTH};
#[cfg(feature = "serde")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
@@ -56,14 +49,12 @@ use sp_runtime_interface::pass_by::PassByInner;
use sp_std::alloc::{format, string::String};
// signing context
#[cfg(feature = "full_crypto")]
const SIGNING_CTX: &[u8] = b"substrate";
/// An identifier used to match public keys against sr25519 keys
pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"sr25");
/// An Schnorrkel/Ristretto x25519 ("sr25519") public key.
#[cfg_attr(feature = "full_crypto", derive(Hash))]
#[derive(
PartialEq,
Eq,
@@ -76,14 +67,13 @@ pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"sr25");
PassByInner,
MaxEncodedLen,
TypeInfo,
Hash,
)]
pub struct Public(pub [u8; 32]);
/// An Schnorrkel/Ristretto x25519 ("sr25519") key pair.
#[cfg(feature = "full_crypto")]
pub struct Pair(Keypair);
#[cfg(feature = "full_crypto")]
impl Clone for Pair {
fn clone(&self) -> Self {
Pair(schnorrkel::Keypair {
@@ -216,8 +206,7 @@ impl<'de> Deserialize<'de> for Public {
}
/// An Schnorrkel/Ristretto x25519 ("sr25519") signature.
#[cfg_attr(feature = "full_crypto", derive(Hash))]
#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)]
#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq, Hash)]
pub struct Signature(pub [u8; 64]);
impl TryFrom<&[u8]> for Signature {
@@ -435,16 +424,13 @@ impl AsRef<schnorrkel::Keypair> for Pair {
}
/// Derive a single hard junction.
#[cfg(feature = "full_crypto")]
fn derive_hard_junction(secret: &SecretKey, cc: &[u8; CHAIN_CODE_LENGTH]) -> MiniSecretKey {
secret.hard_derive_mini_secret_key(Some(ChainCode(*cc)), b"").0
}
/// The raw secret seed, which can be used to recreate the `Pair`.
#[cfg(feature = "full_crypto")]
type Seed = [u8; MINI_SECRET_KEY_LENGTH];
#[cfg(feature = "full_crypto")]
impl TraitPair for Pair {
type Public = Public;
type Seed = Seed;
@@ -499,6 +485,7 @@ impl TraitPair for Pair {
Ok((Self(result.into()), seed.map(|s| MiniSecretKey::to_bytes(&s))))
}
#[cfg(feature = "full_crypto")]
fn sign(&self, message: &[u8]) -> Signature {
let context = signing_context(SIGNING_CTX);
self.0.sign(context.bytes(message)).into()
@@ -533,16 +520,13 @@ impl Pair {
}
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;
}