mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 02:51:08 +00:00
Refactor key management (#3296)
* Add Call type to extensible transactions. Cleanup some naming * Merge Resource and BlockExhausted into just Exhausted * Fix * Another fix * Call * Some fixes * Fix srml tests. * Fix all tests. * Refactor crypto so each application of it has its own type. * Introduce new AuthorityProvider API into Aura This will eventually allow for dynamic determination of authority keys and avoid having to set them directly on CLI. * Introduce authority determinator for Babe. Experiment with modular consensus API. * Work in progress to introduce KeyTypeId and avoid polluting API with validator IDs * Finish up drafting imonline * Rework offchain workers API. * Rework API implementation. * Make it compile for wasm, simplify app_crypto. * Fix compilation of im-online. * Fix compilation of im-online. * Fix more compilation errors. * Make it compile. * Fixing tests. * Rewrite `keystore` * Fix session tests * Bring back `TryFrom`'s' * Fix `srml-grandpa` * Fix `srml-aura` * Fix consensus babe * More fixes * Make service generate keys from dev_seed * Build fixes * Remove offchain tests * More fixes and cleanups * Fixes finality grandpa * Fix `consensus-aura` * Fix cli * Fix `node-cli` * Fix chain_spec builder * Fix doc tests * Add authority getter for grandpa. * Test fix * Fixes * Make keystore accessible from the runtime * Move app crypto to its own crate * Update `Cargo.lock` * Make the crypto stuff usable from the runtime * Adds some runtime crypto tests * Use last finalized block for grandpa authority * Fix warning * Adds `SessionKeys` runtime api * Remove `FinalityPair` and `ConsensusPair` * Minor governance tweaks to get it inline with docs. * Make the governance be up to date with the docs. * Build fixes. * Generate the inital session keys * Failing keystore is a hard error * Make babe work again * Fix grandpa * Fix tests * Disable `keystore` in consensus critical stuff * Build fix. * ImOnline supports multiple authorities at once. * Update core/application-crypto/src/ed25519.rs * Merge branch 'master' into gav-in-progress * Remove unneeded code for now. * Some `session` testing * Support querying the public keys * Cleanup offchain * Remove warnings * More cleanup * Apply suggestions from code review Co-Authored-By: Benjamin Kampmann <ben.kampmann@googlemail.com> * More cleanups * JSONRPC API for setting keys. Also, rename traits::KeyStore* -> traits::BareCryptoStore* * Bad merge * Fix integration tests * Fix test build * Test fix * Fixes * Warnings * Another warning * Bump version.
This commit is contained in:
@@ -18,13 +18,11 @@
|
||||
//! Cryptographic utilities.
|
||||
// end::description[]
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use rstd::convert::{TryFrom, TryInto};
|
||||
#[cfg(feature = "std")]
|
||||
use parking_lot::Mutex;
|
||||
#[cfg(feature = "std")]
|
||||
use rand::{RngCore, rngs::OsRng};
|
||||
#[cfg(feature = "std")]
|
||||
use codec::{Encode, Decode};
|
||||
#[cfg(feature = "std")]
|
||||
use regex::Regex;
|
||||
@@ -33,6 +31,8 @@ use base58::{FromBase58, ToBase58};
|
||||
#[cfg(feature = "std")]
|
||||
use std::hash::Hash;
|
||||
use zeroize::Zeroize;
|
||||
#[doc(hidden)]
|
||||
pub use rstd::ops::Deref;
|
||||
|
||||
/// The root phrase for our publicly known keys.
|
||||
pub const DEV_PHRASE: &str = "bottom drive obey lake curtain smoke basket hold race lonely fit walk";
|
||||
@@ -83,6 +83,14 @@ impl<T: Zeroize> AsRef<T> for Protected<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Zeroize> rstd::ops::Deref for Protected<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: Zeroize> std::fmt::Debug for Protected<T> {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
@@ -279,12 +287,12 @@ pub trait Ss58Codec: Sized {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
/// Derivable key trait.
|
||||
pub trait Derive: Sized {
|
||||
/// Derive a child key from a series of given junctions.
|
||||
///
|
||||
/// Will be `None` for public keys if there are any hard junctions in there.
|
||||
#[cfg(feature = "std")]
|
||||
fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, _path: Iter) -> Option<Self> {
|
||||
None
|
||||
}
|
||||
@@ -457,8 +465,8 @@ impl<T: AsMut<[u8]> + AsRef<[u8]> + Default + Derive> Ss58Codec for T {
|
||||
}
|
||||
|
||||
/// Trait suitable for typical cryptographic PKI key public type.
|
||||
pub trait Public: AsRef<[u8]> + TypedKey + PartialEq + Eq + Clone + Send + Sync {
|
||||
/// A new instance from the given slice that should be 32 bytes long.
|
||||
pub trait Public: AsRef<[u8]> + AsMut<[u8]> + Default + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {
|
||||
/// A new instance from the given slice.
|
||||
///
|
||||
/// 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!
|
||||
@@ -466,17 +474,85 @@ pub trait Public: AsRef<[u8]> + TypedKey + PartialEq + Eq + Clone + Send + Sync
|
||||
|
||||
/// Return a `Vec<u8>` filled with raw data.
|
||||
#[cfg(feature = "std")]
|
||||
fn to_raw_vec(&self) -> Vec<u8>;
|
||||
fn to_raw_vec(&self) -> Vec<u8> { self.as_slice().to_owned() }
|
||||
|
||||
/// Return a slice filled with raw data.
|
||||
fn as_slice(&self) -> &[u8];
|
||||
fn as_slice(&self) -> &[u8] { self.as_ref() }
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::dummy::*;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod dummy {
|
||||
use super::*;
|
||||
|
||||
/// Dummy cryptography. Doesn't do anything.
|
||||
#[derive(Clone, Hash, Default, Eq, PartialEq)]
|
||||
pub struct Dummy;
|
||||
|
||||
impl AsRef<[u8]> for Dummy {
|
||||
fn as_ref(&self) -> &[u8] { &b""[..] }
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for Dummy {
|
||||
fn as_mut(&mut self) -> &mut[u8] {
|
||||
unsafe {
|
||||
#[allow(mutable_transmutes)]
|
||||
rstd::mem::transmute::<_, &'static mut [u8]>(&b""[..])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CryptoType for Dummy {
|
||||
type Pair = Dummy;
|
||||
}
|
||||
|
||||
impl Derive for Dummy {}
|
||||
|
||||
impl Public for Dummy {
|
||||
fn from_slice(_: &[u8]) -> Self { Self }
|
||||
#[cfg(feature = "std")]
|
||||
fn to_raw_vec(&self) -> Vec<u8> { vec![] }
|
||||
fn as_slice(&self) -> &[u8] { b"" }
|
||||
}
|
||||
|
||||
impl Pair for Dummy {
|
||||
type Public = Dummy;
|
||||
type Seed = Dummy;
|
||||
type Signature = Dummy;
|
||||
type DeriveError = ();
|
||||
fn generate_with_phrase(_: Option<&str>) -> (Self, String, Self::Seed) { Default::default() }
|
||||
fn from_phrase(_: &str, _: Option<&str>)
|
||||
-> Result<(Self, Self::Seed), SecretStringError>
|
||||
{
|
||||
Ok(Default::default())
|
||||
}
|
||||
fn derive<
|
||||
Iter: Iterator<Item=DeriveJunction>
|
||||
>(&self, _: Iter) -> Result<Self, Self::DeriveError> { Ok(Self) }
|
||||
fn from_seed(_: &Self::Seed) -> Self { Self }
|
||||
fn from_seed_slice(_: &[u8]) -> Result<Self, SecretStringError> { Ok(Self) }
|
||||
fn from_standard_components<
|
||||
I: Iterator<Item=DeriveJunction>
|
||||
>(
|
||||
_: &str,
|
||||
_: Option<&str>,
|
||||
_: I
|
||||
) -> Result<Self, SecretStringError> { Ok(Self) }
|
||||
fn sign(&self, _: &[u8]) -> Self::Signature { Self }
|
||||
fn verify<M: AsRef<[u8]>>(_: &Self::Signature, _: M, _: &Self::Public) -> bool { true }
|
||||
fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(_: &[u8], _: M, _: P) -> bool { true }
|
||||
fn public(&self) -> Self::Public { Self }
|
||||
fn to_raw_vec(&self) -> Vec<u8> { vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 = "std")]
|
||||
pub trait Pair: TypedKey + Sized + Clone + Send + Sync + 'static {
|
||||
pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static {
|
||||
/// The type which is used to encode a public key.
|
||||
type Public: Public + Hash;
|
||||
|
||||
@@ -538,7 +614,7 @@ pub trait Pair: TypedKey + Sized + Clone + Send + Sync + 'static {
|
||||
fn sign(&self, message: &[u8]) -> Self::Signature;
|
||||
|
||||
/// Verify a signature on a message. Returns true if the signature is good.
|
||||
fn verify<P: AsRef<Self::Public>, M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: P) -> bool;
|
||||
fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool;
|
||||
|
||||
/// Verify a signature on a message. Returns true if the signature is good.
|
||||
fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool;
|
||||
@@ -603,26 +679,109 @@ pub trait Pair: TypedKey + Sized + Clone + Send + Sync + 'static {
|
||||
fn to_raw_vec(&self) -> Vec<u8>;
|
||||
}
|
||||
|
||||
/// One type is wrapped by another.
|
||||
pub trait IsWrappedBy<Outer>: From<Outer> + Into<Outer> {
|
||||
/// Get a reference to the inner from the outer.
|
||||
fn from_ref(outer: &Outer) -> &Self;
|
||||
/// Get a mutable reference to the inner from the outer.
|
||||
fn from_mut(outer: &mut Outer) -> &mut Self;
|
||||
}
|
||||
|
||||
/// Opposite of `IsWrappedBy` - denotes a type which is a simple wrapper around another type.
|
||||
pub trait Wraps: Sized {
|
||||
/// The inner type it is wrapping.
|
||||
type Inner: IsWrappedBy<Self>;
|
||||
}
|
||||
|
||||
impl<T, Outer> IsWrappedBy<Outer> for T where
|
||||
Outer: AsRef<Self> + AsMut<Self> + From<Self>,
|
||||
T: From<Outer>,
|
||||
{
|
||||
/// Get a reference to the inner from the outer.
|
||||
fn from_ref(outer: &Outer) -> &Self { outer.as_ref() }
|
||||
|
||||
/// Get a mutable reference to the inner from the outer.
|
||||
fn from_mut(outer: &mut Outer) -> &mut Self { outer.as_mut() }
|
||||
}
|
||||
|
||||
impl<Inner, Outer, T> UncheckedFrom<T> for Outer where
|
||||
Outer: Wraps<Inner=Inner>,
|
||||
Inner: IsWrappedBy<Outer> + UncheckedFrom<T>,
|
||||
{
|
||||
fn unchecked_from(t: T) -> Self {
|
||||
let inner: Inner = t.unchecked_into();
|
||||
inner.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Type which has a particular kind of crypto associated with it.
|
||||
pub trait CryptoType {
|
||||
/// The pair key type of this crypto.
|
||||
#[cfg(feature="std")]
|
||||
type Pair: Pair;
|
||||
}
|
||||
|
||||
/// An identifier for a type of cryptographic key.
|
||||
///
|
||||
/// 0-1024 are reserved.
|
||||
pub type KeyTypeId = u32;
|
||||
/// To avoid clashes with other modules when distributing your module publically, register your
|
||||
/// `KeyTypeId` on the list here by making a PR.
|
||||
///
|
||||
/// Values whose first character is `_` are reserved for private use and won't conflict with any
|
||||
/// public modules.
|
||||
#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
pub struct KeyTypeId(pub [u8; 4]);
|
||||
|
||||
/// Constant key types.
|
||||
impl From<u32> for KeyTypeId {
|
||||
fn from(x: u32) -> Self {
|
||||
Self(x.to_le_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KeyTypeId> for u32 {
|
||||
fn from(x: KeyTypeId) -> Self {
|
||||
u32::from_le_bytes(x.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a str> for KeyTypeId {
|
||||
type Error = ();
|
||||
fn try_from(x: &'a str) -> Result<Self, ()> {
|
||||
let b = x.as_bytes();
|
||||
if b.len() != 4 {
|
||||
return Err(());
|
||||
}
|
||||
let mut res = KeyTypeId::default();
|
||||
res.0.copy_from_slice(&b[0..4]);
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
/// Known key types; this also functions as a global registry of key types for projects wishing to
|
||||
/// avoid collisions with each other.
|
||||
///
|
||||
/// It's not universal in the sense that *all* key types need to be mentioned here, it's just a
|
||||
/// handy place to put common key types.
|
||||
pub mod key_types {
|
||||
use super::KeyTypeId;
|
||||
|
||||
/// ED25519 public key.
|
||||
pub const ED25519: KeyTypeId = 10;
|
||||
|
||||
/// SR25519 public key.
|
||||
pub const SR25519: KeyTypeId = 20;
|
||||
}
|
||||
|
||||
/// A trait for something that has a key type ID.
|
||||
pub trait TypedKey {
|
||||
/// The type ID of this key.
|
||||
const KEY_TYPE: KeyTypeId;
|
||||
/// Key type for generic S/R 25519 key.
|
||||
pub const SR25519: KeyTypeId = KeyTypeId(*b"sr25");
|
||||
/// Key type for generic Ed25519 key.
|
||||
pub const ED25519: KeyTypeId = KeyTypeId(*b"ed25");
|
||||
/// Key type for Babe module, build-in.
|
||||
pub const BABE: KeyTypeId = KeyTypeId(*b"babe");
|
||||
/// Key type for Grandpa module, build-in.
|
||||
pub const GRANDPA: KeyTypeId = KeyTypeId(*b"gran");
|
||||
/// Key type for controlling an account in a Substrate runtime, built-in.
|
||||
pub const ACCOUNT: KeyTypeId = KeyTypeId(*b"acco");
|
||||
/// Key type for Aura module, built-in.
|
||||
pub const AURA: KeyTypeId = KeyTypeId(*b"aura");
|
||||
/// Key type for ImOnline module, built-in.
|
||||
pub const IM_ONLINE: KeyTypeId = KeyTypeId(*b"imon");
|
||||
/// A key type ID useful for tests.
|
||||
#[cfg(feature = "std")]
|
||||
pub const DUMMY: KeyTypeId = KeyTypeId(*b"dumy");
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -639,14 +798,31 @@ mod tests {
|
||||
Standard{phrase: String, password: Option<String>, path: Vec<DeriveJunction>},
|
||||
Seed(Vec<u8>),
|
||||
}
|
||||
impl Default for TestPair {
|
||||
fn default() -> Self {
|
||||
TestPair::Generated
|
||||
}
|
||||
}
|
||||
impl CryptoType for TestPair {
|
||||
type Pair = Self;
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Default)]
|
||||
struct TestPublic;
|
||||
impl AsRef<[u8]> for TestPublic {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&[]
|
||||
}
|
||||
}
|
||||
impl AsMut<[u8]> for TestPublic {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut []
|
||||
}
|
||||
}
|
||||
impl CryptoType for TestPublic {
|
||||
type Pair = TestPair;
|
||||
}
|
||||
impl Derive for TestPublic {}
|
||||
impl Public for TestPublic {
|
||||
fn from_slice(_bytes: &[u8]) -> Self {
|
||||
Self
|
||||
@@ -658,9 +834,6 @@ mod tests {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
impl TypedKey for TestPublic {
|
||||
const KEY_TYPE: u32 = 4242;
|
||||
}
|
||||
impl Pair for TestPair {
|
||||
type Public = TestPublic;
|
||||
type Seed = [u8; 0];
|
||||
@@ -686,11 +859,7 @@ mod tests {
|
||||
}
|
||||
fn from_seed(_seed: &<TestPair as Pair>::Seed) -> Self { TestPair::Seed(vec![]) }
|
||||
fn sign(&self, _message: &[u8]) -> Self::Signature { [] }
|
||||
fn verify<P: AsRef<Self::Public>, M: AsRef<[u8]>>(
|
||||
_sig: &Self::Signature,
|
||||
_message: M,
|
||||
_pubkey: P
|
||||
) -> bool { true }
|
||||
fn verify<M: AsRef<[u8]>>(_: &Self::Signature, _: M, _: &Self::Public) -> bool { true }
|
||||
fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(
|
||||
_sig: &[u8],
|
||||
_message: M,
|
||||
@@ -717,9 +886,6 @@ mod tests {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
impl TypedKey for TestPair {
|
||||
const KEY_TYPE: u32 = 4242;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interpret_std_seed_should_work() {
|
||||
|
||||
Reference in New Issue
Block a user