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:
Gavin Wood
2019-08-07 20:47:48 +02:00
committed by GitHub
parent a6a6779f01
commit 1a524b8207
160 changed files with 4467 additions and 2769 deletions
+202 -36
View File
@@ -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() {