mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 00:01:09 +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() {
|
||||
|
||||
@@ -29,10 +29,10 @@ use substrate_bip39::seed_from_entropy;
|
||||
#[cfg(feature = "std")]
|
||||
use bip39::{Mnemonic, Language, MnemonicType};
|
||||
#[cfg(feature = "std")]
|
||||
use crate::crypto::{Pair as TraitPair, DeriveJunction, SecretStringError, Derive, Ss58Codec};
|
||||
use crate::crypto::{Pair as TraitPair, DeriveJunction, SecretStringError, Ss58Codec};
|
||||
#[cfg(feature = "std")]
|
||||
use serde::{de, Serializer, Serialize, Deserializer, Deserialize};
|
||||
use crate::crypto::{key_types, KeyTypeId, Public as TraitPublic, TypedKey, UncheckedFrom};
|
||||
use crate::{crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Derive}};
|
||||
|
||||
/// 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
|
||||
@@ -77,6 +77,20 @@ impl AsMut<[u8]> for Public {
|
||||
}
|
||||
}
|
||||
|
||||
impl rstd::convert::TryFrom<&[u8]> for Public {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
|
||||
if data.len() == 32 {
|
||||
let mut inner = [0u8; 32];
|
||||
inner.copy_from_slice(data);
|
||||
Ok(Public(inner))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Public> for [u8; 32] {
|
||||
fn from(x: Public) -> Self {
|
||||
x.0
|
||||
@@ -90,12 +104,6 @@ impl From<Pair> for Public {
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Public> for Public {
|
||||
fn as_ref(&self) -> &Public {
|
||||
&self
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Public> for H256 {
|
||||
fn from(x: Public) -> Self {
|
||||
x.0.into()
|
||||
@@ -115,15 +123,15 @@ impl UncheckedFrom<H256> for Public {
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::fmt::Display for Public {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
impl std::fmt::Display for Public {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", self.to_ss58check())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::fmt::Debug for Public {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
impl std::fmt::Debug for Public {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let s = self.to_ss58check();
|
||||
write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8])
|
||||
}
|
||||
@@ -145,8 +153,8 @@ impl<'de> Deserialize<'de> for Public {
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::hash::Hash for Public {
|
||||
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
|
||||
impl std::hash::Hash for Public {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.0.hash(state);
|
||||
}
|
||||
}
|
||||
@@ -155,6 +163,20 @@ impl ::std::hash::Hash for Public {
|
||||
#[derive(Encode, Decode)]
|
||||
pub struct Signature(pub [u8; 64]);
|
||||
|
||||
impl rstd::convert::TryFrom<&[u8]> for Signature {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
|
||||
if data.len() == 64 {
|
||||
let mut inner = [0u8; 64];
|
||||
inner.copy_from_slice(data);
|
||||
Ok(Signature(inner))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Signature {
|
||||
fn clone(&self) -> Self {
|
||||
let mut r = [0u8; 64];
|
||||
@@ -171,7 +193,7 @@ impl Default for Signature {
|
||||
|
||||
impl PartialEq for Signature {
|
||||
fn eq(&self, b: &Self) -> bool {
|
||||
&self.0[..] == &b.0[..]
|
||||
self.0[..] == b.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,16 +230,16 @@ impl AsMut<[u8]> for Signature {
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::fmt::Debug for Signature {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
impl std::fmt::Debug for Signature {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::hash::Hash for Signature {
|
||||
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
|
||||
::std::hash::Hash::hash(&self.0[..], state);
|
||||
impl std::hash::Hash for Signature {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
std::hash::Hash::hash(&self.0[..], state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,31 +328,10 @@ impl TraitPublic for Public {
|
||||
r.copy_from_slice(data);
|
||||
Public(r)
|
||||
}
|
||||
|
||||
/// Return a `Vec<u8>` filled with raw data.
|
||||
#[cfg(feature = "std")]
|
||||
fn to_raw_vec(&self) -> Vec<u8> {
|
||||
let r: &[u8; 32] = self.as_ref();
|
||||
r.to_vec()
|
||||
}
|
||||
|
||||
/// Return a slice filled with raw data.
|
||||
fn as_slice(&self) -> &[u8] {
|
||||
let r: &[u8; 32] = self.as_ref();
|
||||
&r[..]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Derive for Public {}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl AsRef<Pair> for Pair {
|
||||
fn as_ref(&self) -> &Pair {
|
||||
&self
|
||||
}
|
||||
}
|
||||
|
||||
/// Derive a single hard junction.
|
||||
#[cfg(feature = "std")]
|
||||
fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed {
|
||||
@@ -438,8 +439,8 @@ impl TraitPair for Pair {
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
Self::verify_weak(&sig.0[..], message.as_ref(), &pubkey.as_ref().0[..])
|
||||
fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool {
|
||||
Self::verify_weak(&sig.0[..], message.as_ref(), pubkey)
|
||||
}
|
||||
|
||||
/// Verify a signature on a message. Returns true if the signature is good.
|
||||
@@ -488,17 +489,19 @@ impl Pair {
|
||||
}
|
||||
}
|
||||
|
||||
impl TypedKey for Public {
|
||||
const KEY_TYPE: KeyTypeId = key_types::ED25519;
|
||||
impl CryptoType for Public {
|
||||
#[cfg(feature="std")]
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
impl TypedKey for Signature {
|
||||
const KEY_TYPE: KeyTypeId = key_types::ED25519;
|
||||
impl CryptoType for Signature {
|
||||
#[cfg(feature="std")]
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl TypedKey for Pair {
|
||||
const KEY_TYPE: KeyTypeId = key_types::ED25519;
|
||||
impl CryptoType for Pair {
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -33,11 +33,13 @@ macro_rules! map {
|
||||
|
||||
use rstd::prelude::*;
|
||||
use rstd::ops::Deref;
|
||||
use codec::{Encode, Decode};
|
||||
#[cfg(feature = "std")]
|
||||
use std::borrow::Cow;
|
||||
#[cfg(feature = "std")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
#[cfg(feature = "std")]
|
||||
pub use serde;// << for macro
|
||||
pub use codec::{Encode, Decode};// << for macro
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use impl_serde::serialize as bytes;
|
||||
@@ -61,6 +63,8 @@ pub mod sandbox;
|
||||
pub mod storage;
|
||||
pub mod uint;
|
||||
mod changes_trie;
|
||||
pub mod traits;
|
||||
pub mod testing;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
@@ -77,7 +81,6 @@ pub use hash_db::Hasher;
|
||||
pub use self::hasher::blake2::Blake2Hasher;
|
||||
|
||||
/// Context for executing a call into the runtime.
|
||||
#[repr(u8)]
|
||||
pub enum ExecutionContext {
|
||||
/// Context for general importing (including own blocks).
|
||||
Importing,
|
||||
@@ -91,6 +94,17 @@ pub enum ExecutionContext {
|
||||
Other,
|
||||
}
|
||||
|
||||
impl ExecutionContext {
|
||||
/// Returns if the keystore should be enabled for the current context.
|
||||
pub fn enable_keystore(&self) -> bool {
|
||||
use ExecutionContext::*;
|
||||
match self {
|
||||
Importing | Syncing | BlockConstruction => false,
|
||||
OffchainWorker(_) | Other => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Hex-serialized shim for `Vec<u8>`.
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, Hash, PartialOrd, Ord))]
|
||||
@@ -147,7 +161,7 @@ impl<R: codec::Encode> ::std::fmt::Debug for NativeOrEncoded<R> {
|
||||
#[cfg(feature = "std")]
|
||||
impl<R: codec::Encode> NativeOrEncoded<R> {
|
||||
/// Return the value as the encoded format.
|
||||
pub fn as_encoded<'a>(&'a self) -> Cow<'a, [u8]> {
|
||||
pub fn as_encoded(&self) -> Cow<'_, [u8]> {
|
||||
match self {
|
||||
NativeOrEncoded::Encoded(e) => Cow::Borrowed(e.as_slice()),
|
||||
NativeOrEncoded::Native(n) => Cow::Owned(n.encode()),
|
||||
@@ -199,3 +213,4 @@ impl codec::Decode for NeverNativeValue {
|
||||
Err("`NeverNativeValue` should never be decoded".into())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,11 +16,12 @@
|
||||
|
||||
//! Offchain workers types
|
||||
|
||||
use crate::crypto;
|
||||
use codec::{Encode, Decode};
|
||||
use rstd::prelude::{Vec, Box};
|
||||
use rstd::convert::TryFrom;
|
||||
|
||||
pub use crate::crypto::KeyTypeId;
|
||||
|
||||
/// A type of supported crypto.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
@@ -58,81 +59,6 @@ impl From<StorageKind> for u32 {
|
||||
}
|
||||
}
|
||||
|
||||
/// A type of supported crypto.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
#[repr(C)]
|
||||
pub enum CryptoKind {
|
||||
/// SR25519 crypto (Schnorrkel)
|
||||
Sr25519 = crypto::key_types::SR25519 as isize,
|
||||
/// ED25519 crypto (Edwards)
|
||||
Ed25519 = crypto::key_types::ED25519 as isize,
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for CryptoKind {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(kind: u32) -> Result<Self, Self::Error> {
|
||||
match kind {
|
||||
e if e == CryptoKind::Sr25519 as isize as u32 => Ok(CryptoKind::Sr25519),
|
||||
e if e == CryptoKind::Ed25519 as isize as u32 => Ok(CryptoKind::Ed25519),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CryptoKind> for u32 {
|
||||
fn from(c: CryptoKind) -> Self {
|
||||
c as isize as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// Key to use in the offchain worker crypto api.
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
pub enum CryptoKey {
|
||||
/// Use a key from the offchain workers local storage.
|
||||
LocalKey {
|
||||
/// The id of the key.
|
||||
id: u16,
|
||||
/// The kind of the key.
|
||||
kind: CryptoKind,
|
||||
},
|
||||
/// Use the key the block authoring algorithm uses.
|
||||
AuthorityKey,
|
||||
/// Use the key the finality gadget uses.
|
||||
FgAuthorityKey,
|
||||
}
|
||||
|
||||
impl TryFrom<u64> for CryptoKey {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(key: u64) -> Result<Self, Self::Error> {
|
||||
match key & 0xFF {
|
||||
0 => {
|
||||
let id = (key >> 8 & 0xFFFF) as u16;
|
||||
let kind = CryptoKind::try_from((key >> 32) as u32)?;
|
||||
Ok(CryptoKey::LocalKey { id, kind })
|
||||
}
|
||||
1 => Ok(CryptoKey::AuthorityKey),
|
||||
2 => Ok(CryptoKey::FgAuthorityKey),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CryptoKey> for u64 {
|
||||
fn from(key: CryptoKey) -> u64 {
|
||||
match key {
|
||||
CryptoKey::LocalKey { id, kind } => {
|
||||
((kind as u64) << 32) | ((id as u64) << 8)
|
||||
}
|
||||
CryptoKey::AuthorityKey => 1,
|
||||
CryptoKey::FgAuthorityKey => 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Opaque type for offchain http requests.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
@@ -314,45 +240,6 @@ pub trait Externalities {
|
||||
/// Returns information about the local node's network state.
|
||||
fn network_state(&self) -> Result<OpaqueNetworkState, ()>;
|
||||
|
||||
/// Create new key(pair) for signing/encryption/decryption.
|
||||
///
|
||||
/// Returns an error if given crypto kind is not supported.
|
||||
fn new_crypto_key(&mut self, crypto: CryptoKind) -> Result<CryptoKey, ()>;
|
||||
|
||||
/// Returns the locally configured authority public key, if available.
|
||||
fn pubkey(&self, key: CryptoKey) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Encrypt a piece of data using given crypto key.
|
||||
///
|
||||
/// If `key` is `None`, it will attempt to use current authority key of `CryptoKind`.
|
||||
///
|
||||
/// Returns an error if `key` is not available or does not exist,
|
||||
/// or the expected `CryptoKind` does not match.
|
||||
fn encrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Decrypt a piece of data using given crypto key.
|
||||
///
|
||||
/// If `key` is `None`, it will attempt to use current authority key of `CryptoKind`.
|
||||
///
|
||||
/// Returns an error if data cannot be decrypted or the `key` is not available or does not exist,
|
||||
/// or the expected `CryptoKind` does not match.
|
||||
fn decrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Sign a piece of data using given crypto key.
|
||||
///
|
||||
/// If `key` is `None`, it will attempt to use current authority key of `CryptoKind`.
|
||||
///
|
||||
/// Returns an error if `key` is not available or does not exist,
|
||||
/// or the expected `CryptoKind` does not match.
|
||||
fn sign(&mut self, key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Verifies that `signature` for `msg` matches given `key`.
|
||||
///
|
||||
/// Returns an `Ok` with `true` in case it does, `false` in case it doesn't.
|
||||
/// Returns an error in case the key is not available or does not exist or the parameters
|
||||
/// lengths are incorrect or `CryptoKind` does not match.
|
||||
fn verify(&mut self, key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result<bool, ()>;
|
||||
|
||||
/// Returns current UNIX timestamp (in millis)
|
||||
fn timestamp(&mut self) -> Timestamp;
|
||||
|
||||
@@ -466,34 +353,10 @@ impl<T: Externalities + ?Sized> Externalities for Box<T> {
|
||||
(&mut **self).submit_transaction(ex)
|
||||
}
|
||||
|
||||
fn new_crypto_key(&mut self, crypto: CryptoKind) -> Result<CryptoKey, ()> {
|
||||
(&mut **self).new_crypto_key(crypto)
|
||||
}
|
||||
|
||||
fn encrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
(&mut **self).encrypt(key, data)
|
||||
}
|
||||
|
||||
fn network_state(&self) -> Result<OpaqueNetworkState, ()> {
|
||||
(& **self).network_state()
|
||||
}
|
||||
|
||||
fn pubkey(&self, key: CryptoKey) -> Result<Vec<u8>, ()> {
|
||||
(&**self).pubkey(key)
|
||||
}
|
||||
|
||||
fn decrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
(&mut **self).decrypt(key, data)
|
||||
}
|
||||
|
||||
fn sign(&mut self, key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
(&mut **self).sign(key, data)
|
||||
}
|
||||
|
||||
fn verify(&mut self, key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result<bool, ()> {
|
||||
(&mut **self).verify(key, msg, signature)
|
||||
}
|
||||
|
||||
fn timestamp(&mut self) -> Timestamp {
|
||||
(&mut **self).timestamp()
|
||||
}
|
||||
@@ -571,27 +434,4 @@ mod tests {
|
||||
assert_eq!(t.sub(Duration::from_millis(10)), Timestamp(0));
|
||||
assert_eq!(t.diff(&Timestamp(3)), Duration(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn crypto_key_to_from_u64() {
|
||||
let key = CryptoKey::AuthorityKey;
|
||||
let uint: u64 = key.clone().into();
|
||||
let key2 = CryptoKey::try_from(uint).unwrap();
|
||||
assert_eq!(key, key2);
|
||||
|
||||
let key = CryptoKey::FgAuthorityKey;
|
||||
let uint: u64 = key.clone().into();
|
||||
let key2 = CryptoKey::try_from(uint).unwrap();
|
||||
assert_eq!(key, key2);
|
||||
|
||||
let key = CryptoKey::LocalKey { id: 0, kind: CryptoKind::Ed25519 };
|
||||
let uint: u64 = key.clone().into();
|
||||
let key2 = CryptoKey::try_from(uint).unwrap();
|
||||
assert_eq!(key, key2);
|
||||
|
||||
let key = CryptoKey::LocalKey { id: 10, kind: CryptoKind::Sr25519 };
|
||||
let uint: u64 = key.clone().into();
|
||||
let key2 = CryptoKey::try_from(uint).unwrap();
|
||||
assert_eq!(key, key2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,10 @@ use substrate_bip39::mini_secret_from_entropy;
|
||||
#[cfg(feature = "std")]
|
||||
use bip39::{Mnemonic, Language, MnemonicType};
|
||||
#[cfg(feature = "std")]
|
||||
use crate::crypto::{Pair as TraitPair, DeriveJunction, Infallible, SecretStringError, Derive, Ss58Codec};
|
||||
use crate::crypto::{key_types, KeyTypeId, Public as TraitPublic, TypedKey, UncheckedFrom};
|
||||
use crate::crypto::{
|
||||
Pair as TraitPair, DeriveJunction, Infallible, SecretStringError, Ss58Codec
|
||||
};
|
||||
use crate::{crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Derive}};
|
||||
use crate::hash::{H256, H512};
|
||||
use codec::{Encode, Decode};
|
||||
|
||||
@@ -56,19 +58,13 @@ pub struct Pair(Keypair);
|
||||
impl Clone for Pair {
|
||||
fn clone(&self) -> Self {
|
||||
Pair(schnorrkel::Keypair {
|
||||
public: self.0.public.clone(),
|
||||
public: self.0.public,
|
||||
secret: schnorrkel::SecretKey::from_bytes(&self.0.secret.to_bytes()[..])
|
||||
.expect("key is always the correct size; qed")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Public> for Public {
|
||||
fn as_ref(&self) -> &Public {
|
||||
&self
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8; 32]> for Public {
|
||||
fn as_ref(&self) -> &[u8; 32] {
|
||||
&self.0
|
||||
@@ -99,6 +95,20 @@ impl From<Public> for H256 {
|
||||
}
|
||||
}
|
||||
|
||||
impl rstd::convert::TryFrom<&[u8]> for Public {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
|
||||
if data.len() == 32 {
|
||||
let mut inner = [0u8; 32];
|
||||
inner.copy_from_slice(data);
|
||||
Ok(Public(inner))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UncheckedFrom<[u8; 32]> for Public {
|
||||
fn unchecked_from(x: [u8; 32]) -> Self {
|
||||
Public::from_raw(x)
|
||||
@@ -112,15 +122,15 @@ impl UncheckedFrom<H256> for Public {
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::fmt::Display for Public {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
impl std::fmt::Display for Public {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", self.to_ss58check())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::fmt::Debug for Public {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
impl std::fmt::Debug for Public {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
let s = self.to_ss58check();
|
||||
write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8])
|
||||
}
|
||||
@@ -142,8 +152,8 @@ impl<'de> Deserialize<'de> for Public {
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::hash::Hash for Public {
|
||||
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
|
||||
impl std::hash::Hash for Public {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.0.hash(state);
|
||||
}
|
||||
}
|
||||
@@ -154,6 +164,20 @@ impl ::std::hash::Hash for Public {
|
||||
#[derive(Encode, Decode)]
|
||||
pub struct Signature(pub [u8; 64]);
|
||||
|
||||
impl rstd::convert::TryFrom<&[u8]> for Signature {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
|
||||
if data.len() == 64 {
|
||||
let mut inner = [0u8; 64];
|
||||
inner.copy_from_slice(data);
|
||||
Ok(Signature(inner))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Signature {
|
||||
fn clone(&self) -> Self {
|
||||
let mut r = [0u8; 64];
|
||||
@@ -170,7 +194,7 @@ impl Default for Signature {
|
||||
|
||||
impl PartialEq for Signature {
|
||||
fn eq(&self, b: &Self) -> bool {
|
||||
&self.0[..] == &b.0[..]
|
||||
self.0[..] == b.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,11 +292,11 @@ impl Signature {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Derive for Public {
|
||||
/// Derive a child key from a series of given junctions.
|
||||
///
|
||||
/// `None` if there are any hard junctions in there.
|
||||
#[cfg(feature = "std")]
|
||||
fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, path: Iter) -> Option<Public> {
|
||||
let mut acc = PublicKey::from_bytes(self.as_ref()).ok()?;
|
||||
for j in path {
|
||||
@@ -318,24 +342,6 @@ impl TraitPublic for Public {
|
||||
r.copy_from_slice(data);
|
||||
Public(r)
|
||||
}
|
||||
|
||||
/// Return a `Vec<u8>` filled with raw data.
|
||||
#[cfg(feature = "std")]
|
||||
fn to_raw_vec(&self) -> Vec<u8> {
|
||||
self.0.to_vec()
|
||||
}
|
||||
|
||||
/// Return a slice filled with raw data.
|
||||
fn as_slice(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl AsRef<Pair> for Pair {
|
||||
fn as_ref(&self) -> &Pair {
|
||||
&self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
@@ -475,20 +481,15 @@ impl TraitPair for Pair {
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
// Match both schnorrkel 0.1.1 and 0.8.0+ signatures, supporting both wallets
|
||||
// that have not been upgraded and those that have. To swap to 0.8.0 only,
|
||||
// create `schnorrkel::Signature` and pass that into `verify_simple`
|
||||
match PublicKey::from_bytes(pubkey.as_ref().as_slice()) {
|
||||
Ok(pk) => pk.verify_simple_preaudit_deprecated(
|
||||
SIGNING_CTX, message.as_ref(), &sig.as_ref(),
|
||||
).is_ok(),
|
||||
Err(_) => false,
|
||||
}
|
||||
fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool {
|
||||
Self::verify_weak(&sig.0[..], message, pubkey)
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
// Match both schnorrkel 0.1.1 and 0.8.0+ signatures, supporting both wallets
|
||||
// that have not been upgraded and those that have. To swap to 0.8.0 only,
|
||||
// create `schnorrkel::Signature` and pass that into `verify_simple`
|
||||
match PublicKey::from_bytes(pubkey.as_ref()) {
|
||||
Ok(pk) => pk.verify_simple_preaudit_deprecated(
|
||||
SIGNING_CTX, message.as_ref(), &sig,
|
||||
@@ -518,17 +519,19 @@ impl Pair {
|
||||
}
|
||||
}
|
||||
|
||||
impl TypedKey for Public {
|
||||
const KEY_TYPE: KeyTypeId = key_types::SR25519;
|
||||
impl CryptoType for Public {
|
||||
#[cfg(feature="std")]
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
impl TypedKey for Signature {
|
||||
const KEY_TYPE: KeyTypeId = key_types::SR25519;
|
||||
impl CryptoType for Signature {
|
||||
#[cfg(feature="std")]
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl TypedKey for Pair {
|
||||
const KEY_TYPE: KeyTypeId = key_types::SR25519;
|
||||
impl CryptoType for Pair {
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -713,6 +716,6 @@ mod test {
|
||||
let js_signature = Signature::from_raw(hex!(
|
||||
"28a854d54903e056f89581c691c1f7d2ff39f8f896c9e9c22475e60902cc2b3547199e0e91fa32902028f2ca2355e8cdd16cfe19ba5e8b658c94aa80f3b81a00"
|
||||
));
|
||||
assert!(Pair::verify(&js_signature, b"SUBSTRATE", public));
|
||||
assert!(Pair::verify(&js_signature, b"SUBSTRATE", &public));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate 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.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Types that should only be used for testing!
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use crate::{ed25519, sr25519, crypto::{Public, Pair, KeyTypeId}};
|
||||
|
||||
/// A keystore implementation usable in tests.
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(Default)]
|
||||
pub struct KeyStore {
|
||||
/// `KeyTypeId` maps to public keys and public keys map to private keys.
|
||||
keys: std::collections::HashMap<KeyTypeId, std::collections::HashMap<Vec<u8>, Vec<u8>>>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl KeyStore {
|
||||
/// Creates a new instance of `Self`.
|
||||
pub fn new() -> std::sync::Arc<parking_lot::RwLock<Self>> {
|
||||
std::sync::Arc::new(parking_lot::RwLock::new(Self::default()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl crate::traits::BareCryptoStore for KeyStore {
|
||||
fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec<sr25519::Public> {
|
||||
self.keys.get(&id)
|
||||
.map(|keys|
|
||||
keys.values()
|
||||
.map(|s| sr25519::Pair::from_seed_slice(s).expect("`sr25519` seed slice is valid"))
|
||||
.map(|p| p.public())
|
||||
.collect()
|
||||
)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn sr25519_generate_new(
|
||||
&mut self,
|
||||
id: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<sr25519::Public, String> {
|
||||
match seed {
|
||||
Some(seed) => {
|
||||
let pair = sr25519::Pair::from_string(seed, None).expect("Generates an `sr25519` pair.");
|
||||
self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), pair.to_raw_vec());
|
||||
Ok(pair.public())
|
||||
},
|
||||
None => {
|
||||
let (pair, _) = sr25519::Pair::generate();
|
||||
self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), pair.to_raw_vec());
|
||||
Ok(pair.public())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sr25519_key_pair(&self, id: KeyTypeId, pub_key: &sr25519::Public) -> Option<sr25519::Pair> {
|
||||
self.keys.get(&id)
|
||||
.and_then(|inner|
|
||||
inner.get(pub_key.as_slice())
|
||||
.map(|s| sr25519::Pair::from_seed_slice(s).expect("`sr25519` seed slice is valid"))
|
||||
)
|
||||
}
|
||||
|
||||
fn ed25519_public_keys(&self, id: KeyTypeId) -> Vec<ed25519::Public> {
|
||||
self.keys.get(&id)
|
||||
.map(|keys|
|
||||
keys.values()
|
||||
.map(|s| ed25519::Pair::from_seed_slice(s).expect("`ed25519` seed slice is valid"))
|
||||
.map(|p| p.public())
|
||||
.collect()
|
||||
)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn ed25519_generate_new(
|
||||
&mut self,
|
||||
id: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<ed25519::Public, String> {
|
||||
match seed {
|
||||
Some(seed) => {
|
||||
let pair = ed25519::Pair::from_string(seed, None).expect("Generates an `ed25519` pair.");
|
||||
self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), pair.to_raw_vec());
|
||||
Ok(pair.public())
|
||||
},
|
||||
None => {
|
||||
let (pair, _) = ed25519::Pair::generate();
|
||||
self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), pair.to_raw_vec());
|
||||
Ok(pair.public())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ed25519_key_pair(&self, id: KeyTypeId, pub_key: &ed25519::Public) -> Option<ed25519::Pair> {
|
||||
self.keys.get(&id)
|
||||
.and_then(|inner|
|
||||
inner.get(pub_key.as_slice())
|
||||
.map(|s| ed25519::Pair::from_seed_slice(s).expect("`ed25519` seed slice is valid"))
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate 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.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Shareable Substrate traits.
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use crate::{crypto::KeyTypeId, ed25519, sr25519};
|
||||
|
||||
/// Something that generates, stores and provides access to keys.
|
||||
#[cfg(feature = "std")]
|
||||
pub trait BareCryptoStore: Send + Sync {
|
||||
/// Returns all sr25519 public keys for the given key type.
|
||||
fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec<sr25519::Public>;
|
||||
/// Generate a new sr25519 key pair for the given key type and an optional seed.
|
||||
///
|
||||
/// If the given seed is `Some(_)`, the key pair will only be stored in memory.
|
||||
///
|
||||
/// Returns the public key of the generated key pair.
|
||||
fn sr25519_generate_new(
|
||||
&mut self,
|
||||
id: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<sr25519::Public, String>;
|
||||
/// Returns the sr25519 key pair for the given key type and public key combination.
|
||||
fn sr25519_key_pair(&self, id: KeyTypeId, pub_key: &sr25519::Public) -> Option<sr25519::Pair>;
|
||||
|
||||
/// Returns all ed25519 public keys for the given key type.
|
||||
fn ed25519_public_keys(&self, id: KeyTypeId) -> Vec<ed25519::Public>;
|
||||
/// Generate a new ed25519 key pair for the given key type and an optional seed.
|
||||
///
|
||||
/// If the given seed is `Some(_)`, the key pair will only be stored in memory.
|
||||
///
|
||||
/// Returns the public key of the generated key pair.
|
||||
fn ed25519_generate_new(
|
||||
&mut self,
|
||||
id: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<ed25519::Public, String>;
|
||||
|
||||
/// Returns the ed25519 key pair for the given key type and public key combination.
|
||||
fn ed25519_key_pair(&self, id: KeyTypeId, pub_key: &ed25519::Public) -> Option<ed25519::Pair>;
|
||||
|
||||
/// Insert a new key. This doesn't require any known of the crypto; but a public key must be
|
||||
/// manually provided.
|
||||
///
|
||||
/// Places it into the file system store.
|
||||
///
|
||||
/// `Err` if there's some sort of weird filesystem error, but should generally be `Ok`.
|
||||
fn insert_unknown(&mut self, _key_type: KeyTypeId, _suri: &str, _public: &[u8]) -> Result<(), ()> {
|
||||
Err(())
|
||||
}
|
||||
|
||||
/// Get the password for this store.
|
||||
fn password(&self) -> Option<&str> { None }
|
||||
}
|
||||
|
||||
/// A pointer to the key store.
|
||||
#[cfg(feature = "std")]
|
||||
pub type BareCryptoStorePtr = std::sync::Arc<parking_lot::RwLock<dyn BareCryptoStore>>;
|
||||
Reference in New Issue
Block a user