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
@@ -20,12 +20,9 @@
#![warn(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
pub use sp_core::crypto::{key_types, CryptoTypeId, KeyTypeId};
pub use sp_core::crypto::{key_types, CryptoTypeId, DeriveJunction, KeyTypeId, Ss58Codec};
#[doc(hidden)]
#[cfg(feature = "full_crypto")]
pub use sp_core::crypto::{DeriveError, Pair, SecretStringError};
#[cfg(any(feature = "full_crypto", feature = "serde"))]
pub use sp_core::crypto::{DeriveJunction, Ss58Codec};
#[doc(hidden)]
pub use sp_core::{
self,
@@ -85,7 +82,7 @@ macro_rules! app_crypto {
$module::CRYPTO_ID
);
$crate::app_crypto_signature_common!($module::Signature, $key_type);
$crate::app_crypto_pair!($module::Pair, $key_type, $module::CRYPTO_ID);
$crate::app_crypto_pair_common!($module::Pair, $key_type, $module::CRYPTO_ID);
};
}
@@ -116,13 +113,15 @@ macro_rules! app_crypto {
$module::CRYPTO_ID
);
$crate::app_crypto_signature_common!($module::Signature, $key_type);
$crate::app_crypto_pair_common!($module::Pair, $key_type, $module::CRYPTO_ID);
};
}
/// Declares `Pair` type which is functionally equivalent to `$pair`, but is
/// new application-specific type whose identifier is `$key_type`.
/// It is a common part shared between full_crypto and non full_crypto environments.
#[macro_export]
macro_rules! app_crypto_pair {
macro_rules! app_crypto_pair_common {
($pair:ty, $key_type:expr, $crypto_type:expr) => {
$crate::wrap! {
/// A generic `AppPublic` wrapper type over $pair crypto; this has no specific App.
@@ -140,7 +139,14 @@ macro_rules! app_crypto_pair {
type Signature = Signature;
$crate::app_crypto_pair_functions_if_std!($pair);
$crate::app_crypto_pair_functions_if_full_crypto!($pair);
fn from_phrase(
phrase: &str,
password: Option<&str>,
) -> Result<(Self, Self::Seed), $crate::SecretStringError> {
<$pair>::from_phrase(phrase, password).map(|r| (Self(r.0), r.1))
}
fn derive<Iter: Iterator<Item = $crate::DeriveJunction>>(
&self,
path: Iter,
@@ -154,9 +160,6 @@ macro_rules! app_crypto_pair {
fn from_seed_slice(seed: &[u8]) -> Result<Self, $crate::SecretStringError> {
<$pair>::from_seed_slice(seed).map(Self)
}
fn sign(&self, msg: &[u8]) -> Self::Signature {
Signature(self.0.sign(msg))
}
fn verify<M: AsRef<[u8]>>(
sig: &Self::Signature,
message: M,
@@ -203,13 +206,6 @@ macro_rules! app_crypto_pair_functions_if_std {
let r = <$pair>::generate_with_phrase(password);
(Self(r.0), r.1, r.2)
}
fn from_phrase(
phrase: &str,
password: Option<&str>,
) -> Result<(Self, Self::Seed), $crate::SecretStringError> {
<$pair>::from_phrase(phrase, password).map(|r| (Self(r.0), r.1))
}
};
}
@@ -220,6 +216,25 @@ macro_rules! app_crypto_pair_functions_if_std {
($pair:ty) => {};
}
/// Implements functions for the `Pair` trait when `feature = "full_crypto"` is enabled.
#[doc(hidden)]
#[cfg(feature = "full_crypto")]
#[macro_export]
macro_rules! app_crypto_pair_functions_if_full_crypto {
($pair:ty) => {
fn sign(&self, msg: &[u8]) -> Self::Signature {
Signature(self.0.sign(msg))
}
};
}
#[doc(hidden)]
#[cfg(not(feature = "full_crypto"))]
#[macro_export]
macro_rules! app_crypto_pair_functions_if_full_crypto {
($pair:ty) => {};
}
/// Declares `Public` type which is functionally equivalent to `$public` but is
/// new application-specific type whose identifier is `$key_type`.
/// For full functionality, `app_crypto_public_common!` must be called too.
@@ -267,7 +282,7 @@ macro_rules! app_crypto_public_not_full_crypto {
$crate::wrap! {
/// A generic `AppPublic` wrapper type over $public crypto; this has no specific App.
#[derive(
Clone, Eq, PartialEq, Ord, PartialOrd,
Clone, Eq, Hash, PartialEq, Ord, PartialOrd,
$crate::codec::Encode,
$crate::codec::Decode,
$crate::RuntimeDebug,
@@ -277,10 +292,13 @@ macro_rules! app_crypto_public_not_full_crypto {
pub struct Public($public);
}
impl $crate::CryptoType for Public {}
impl $crate::CryptoType for Public {
type Pair = Pair;
}
impl $crate::AppCrypto for Public {
type Public = Public;
type Pair = Pair;
type Signature = Signature;
const ID: $crate::KeyTypeId = $key_type;
const CRYPTO_ID: $crate::CryptoTypeId = $crypto_type;
@@ -452,10 +470,13 @@ macro_rules! app_crypto_signature_not_full_crypto {
pub struct Signature($sig);
}
impl $crate::CryptoType for Signature {}
impl $crate::CryptoType for Signature {
type Pair = Pair;
}
impl $crate::AppCrypto for Signature {
type Public = Public;
type Pair = Pair;
type Signature = Signature;
const ID: $crate::KeyTypeId = $key_type;
const CRYPTO_ID: $crate::CryptoTypeId = $crypto_type;