mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-11 21:11:07 +00:00
Added RuntimePublic for ecdsa public key. (#6029)
* add generate ecdsa, etc to keystore * impl ecdsa needed traits * add ecdsa to sr_io * add ecdsa to application-crypto * add ecdsa to test-utils * add ecdsa debug derive * fix ecdsa public
This commit is contained in:
@@ -23,7 +23,7 @@ use sp_core::{
|
||||
traits::{BareCryptoStore, BareCryptoStoreError as TraitError},
|
||||
Encode,
|
||||
};
|
||||
use sp_application_crypto::{AppKey, AppPublic, AppPair, ed25519, sr25519};
|
||||
use sp_application_crypto::{AppKey, AppPublic, AppPair, ed25519, sr25519, ecdsa};
|
||||
use parking_lot::RwLock;
|
||||
|
||||
/// Keystore pointer
|
||||
@@ -308,6 +308,7 @@ impl BareCryptoStore for Store {
|
||||
.fold(Vec::new(), |mut v, k| {
|
||||
v.push(CryptoTypePublicPair(sr25519::CRYPTO_ID, k.clone()));
|
||||
v.push(CryptoTypePublicPair(ed25519::CRYPTO_ID, k.clone()));
|
||||
v.push(CryptoTypePublicPair(ecdsa::CRYPTO_ID, k.clone()));
|
||||
v
|
||||
}))
|
||||
}
|
||||
@@ -343,6 +344,13 @@ impl BareCryptoStore for Store {
|
||||
.key_pair_by_type::<sr25519::Pair>(&pub_key, id)
|
||||
.map_err(|e| TraitError::from(e))?;
|
||||
Ok(key_pair.sign(msg).encode())
|
||||
},
|
||||
ecdsa::CRYPTO_ID => {
|
||||
let pub_key = ecdsa::Public::from_slice(key.1.as_slice());
|
||||
let key_pair: ecdsa::Pair = self
|
||||
.key_pair_by_type::<ecdsa::Pair>(&pub_key, id)
|
||||
.map_err(|e| TraitError::from(e))?;
|
||||
Ok(key_pair.sign(msg).encode())
|
||||
}
|
||||
_ => Err(TraitError::KeyNotSupported(id))
|
||||
}
|
||||
@@ -394,6 +402,29 @@ impl BareCryptoStore for Store {
|
||||
Ok(pair.public())
|
||||
}
|
||||
|
||||
fn ecdsa_public_keys(&self, key_type: KeyTypeId) -> Vec<ecdsa::Public> {
|
||||
self.raw_public_keys(key_type)
|
||||
.map(|v| {
|
||||
v.into_iter()
|
||||
.map(|k| ecdsa::Public::from_slice(k.as_slice()))
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn ecdsa_generate_new(
|
||||
&mut self,
|
||||
id: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> std::result::Result<ecdsa::Public, TraitError> {
|
||||
let pair = match seed {
|
||||
Some(seed) => self.insert_ephemeral_from_seed_by_type::<ecdsa::Pair>(seed, id),
|
||||
None => self.generate_by_type::<ecdsa::Pair>(id),
|
||||
}.map_err(|e| -> TraitError { e.into() })?;
|
||||
|
||||
Ok(pair.public())
|
||||
}
|
||||
|
||||
fn insert_unknown(&mut self, key_type: KeyTypeId, suri: &str, public: &[u8])
|
||||
-> std::result::Result<(), ()>
|
||||
{
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright 2019-2020 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/>.
|
||||
|
||||
//! Ecdsa crypto types.
|
||||
|
||||
use crate::{RuntimePublic, KeyTypeId};
|
||||
|
||||
use sp_std::vec::Vec;
|
||||
|
||||
pub use sp_core::ecdsa::*;
|
||||
|
||||
mod app {
|
||||
use sp_core::testing::ECDSA;
|
||||
|
||||
crate::app_crypto!(super, ECDSA);
|
||||
|
||||
impl crate::traits::BoundToRuntimeAppPublic for Public {
|
||||
type Public = Self;
|
||||
}
|
||||
}
|
||||
|
||||
pub use app::{Public as AppPublic, Signature as AppSignature};
|
||||
#[cfg(feature = "full_crypto")]
|
||||
pub use app::Pair as AppPair;
|
||||
|
||||
impl RuntimePublic for Public {
|
||||
type Signature = Signature;
|
||||
|
||||
fn all(key_type: KeyTypeId) -> crate::Vec<Self> {
|
||||
sp_io::crypto::ecdsa_public_keys(key_type)
|
||||
}
|
||||
|
||||
fn generate_pair(key_type: KeyTypeId, seed: Option<Vec<u8>>) -> Self {
|
||||
sp_io::crypto::ecdsa_generate(key_type, seed)
|
||||
}
|
||||
|
||||
fn sign<M: AsRef<[u8]>>(&self, key_type: KeyTypeId, msg: &M) -> Option<Self::Signature> {
|
||||
sp_io::crypto::ecdsa_sign(key_type, self, msg.as_ref())
|
||||
}
|
||||
|
||||
fn verify<M: AsRef<[u8]>>(&self, msg: &M, signature: &Self::Signature) -> bool {
|
||||
sp_io::crypto::ecdsa_verify(&signature, msg.as_ref(), self)
|
||||
}
|
||||
|
||||
fn to_raw_vec(&self) -> Vec<u8> {
|
||||
sp_core::crypto::Public::to_raw_vec(self)
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,7 @@ pub use sp_std::{
|
||||
|
||||
pub mod ed25519;
|
||||
pub mod sr25519;
|
||||
pub mod ecdsa;
|
||||
mod traits;
|
||||
|
||||
pub use traits::*;
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright 2019-2020 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/>.
|
||||
|
||||
//! Integration tests for ecdsa
|
||||
|
||||
use sp_runtime::generic::BlockId;
|
||||
use sp_core::{
|
||||
crypto::Pair,
|
||||
testing::{KeyStore, ECDSA},
|
||||
};
|
||||
use substrate_test_runtime_client::{
|
||||
TestClientBuilder, DefaultTestClientBuilderExt, TestClientBuilderExt,
|
||||
runtime::TestAPI,
|
||||
};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_application_crypto::ecdsa::{AppPair, AppPublic};
|
||||
|
||||
#[test]
|
||||
fn ecdsa_works_in_runtime() {
|
||||
let keystore = KeyStore::new();
|
||||
let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build();
|
||||
let (signature, public) = test_client.runtime_api()
|
||||
.test_ecdsa_crypto(&BlockId::Number(0))
|
||||
.expect("Tests `ecdsa` crypto.");
|
||||
|
||||
let supported_keys = keystore.read().keys(ECDSA).unwrap();
|
||||
assert!(supported_keys.contains(&public.clone().into()));
|
||||
assert!(AppPair::verify(&signature, "ecdsa", &AppPublic::from(public)));
|
||||
}
|
||||
@@ -20,4 +20,6 @@
|
||||
#[cfg(test)]
|
||||
mod ed25519;
|
||||
#[cfg(test)]
|
||||
mod sr25519;
|
||||
mod sr25519;
|
||||
#[cfg(test)]
|
||||
mod ecdsa;
|
||||
|
||||
@@ -38,6 +38,7 @@ use crate::crypto::Ss58Codec;
|
||||
#[cfg(feature = "std")]
|
||||
use serde::{de, Serializer, Serialize, Deserializer, Deserialize};
|
||||
use crate::crypto::{Public as TraitPublic, CryptoTypePublicPair, UncheckedFrom, CryptoType, Derive, CryptoTypeId};
|
||||
use sp_runtime_interface::pass_by::PassByInner;
|
||||
#[cfg(feature = "full_crypto")]
|
||||
use secp256k1::{PublicKey, SecretKey};
|
||||
|
||||
@@ -51,7 +52,7 @@ pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecds");
|
||||
type Seed = [u8; 32];
|
||||
|
||||
/// The ECDSA compressed public key.
|
||||
#[derive(Clone, Encode, Decode)]
|
||||
#[derive(Clone, Encode, Decode, PassByInner)]
|
||||
pub struct Public([u8; 33]);
|
||||
|
||||
impl PartialOrd for Public {
|
||||
@@ -125,6 +126,18 @@ impl TraitPublic for Public {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Public> for CryptoTypePublicPair {
|
||||
fn from(key: Public) -> Self {
|
||||
(&key).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Public> for CryptoTypePublicPair {
|
||||
fn from(key: &Public) -> Self {
|
||||
CryptoTypePublicPair(CRYPTO_ID, key.to_raw_vec())
|
||||
}
|
||||
}
|
||||
|
||||
impl Derive for Public {}
|
||||
|
||||
impl Default for Public {
|
||||
@@ -178,12 +191,17 @@ impl std::fmt::Display for Public {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::fmt::Debug for Public {
|
||||
impl sp_std::fmt::Debug for Public {
|
||||
#[cfg(feature = "std")]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let s = self.to_ss58check();
|
||||
write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.as_ref()), &s[0..8])
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
@@ -209,7 +227,7 @@ impl sp_std::hash::Hash for Public {
|
||||
}
|
||||
|
||||
/// A signature (a 512-bit value, plus 8 bits for recovery ID).
|
||||
#[derive(Encode, Decode)]
|
||||
#[derive(Encode, Decode, PassByInner)]
|
||||
pub struct Signature([u8; 65]);
|
||||
|
||||
impl sp_std::convert::TryFrom<&[u8]> for Signature {
|
||||
@@ -289,11 +307,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 sp_std::fmt::Debug for Signature {
|
||||
#[cfg(feature = "std")]
|
||||
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
|
||||
write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
|
||||
@@ -21,7 +21,7 @@ use crate::crypto::KeyTypeId;
|
||||
#[cfg(feature = "std")]
|
||||
use crate::{
|
||||
crypto::{Pair, Public, CryptoTypePublicPair},
|
||||
ed25519, sr25519,
|
||||
ed25519, sr25519, ecdsa,
|
||||
traits::BareCryptoStoreError
|
||||
};
|
||||
#[cfg(feature = "std")]
|
||||
@@ -30,6 +30,8 @@ use std::collections::HashSet;
|
||||
pub const ED25519: KeyTypeId = KeyTypeId(*b"ed25");
|
||||
/// Key type for generic Sr 25519 key.
|
||||
pub const SR25519: KeyTypeId = KeyTypeId(*b"sr25");
|
||||
/// Key type for generic Sr 25519 key.
|
||||
pub const ECDSA: KeyTypeId = KeyTypeId(*b"ecds");
|
||||
|
||||
/// A keystore implementation usable in tests.
|
||||
#[cfg(feature = "std")]
|
||||
@@ -62,6 +64,14 @@ impl KeyStore {
|
||||
)
|
||||
}
|
||||
|
||||
fn ecdsa_key_pair(&self, id: KeyTypeId, pub_key: &ecdsa::Public) -> Option<ecdsa::Pair> {
|
||||
self.keys.get(&id)
|
||||
.and_then(|inner|
|
||||
inner.get(pub_key.as_slice())
|
||||
.map(|s| ecdsa::Pair::from_string(s, None).expect("`ecdsa` seed slice is valid"))
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
@@ -74,6 +84,7 @@ impl crate::traits::BareCryptoStore for KeyStore {
|
||||
.fold(Vec::new(), |mut v, k| {
|
||||
v.push(CryptoTypePublicPair(sr25519::CRYPTO_ID, k.clone()));
|
||||
v.push(CryptoTypePublicPair(ed25519::CRYPTO_ID, k.clone()));
|
||||
v.push(CryptoTypePublicPair(ecdsa::CRYPTO_ID, k.clone()));
|
||||
v
|
||||
}))
|
||||
})
|
||||
@@ -142,6 +153,37 @@ impl crate::traits::BareCryptoStore for KeyStore {
|
||||
}
|
||||
}
|
||||
|
||||
fn ecdsa_public_keys(&self, id: KeyTypeId) -> Vec<ecdsa::Public> {
|
||||
self.keys.get(&id)
|
||||
.map(|keys|
|
||||
keys.values()
|
||||
.map(|s| ecdsa::Pair::from_string(s, None).expect("`ecdsa` seed slice is valid"))
|
||||
.map(|p| p.public())
|
||||
.collect()
|
||||
)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn ecdsa_generate_new(
|
||||
&mut self,
|
||||
id: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<ecdsa::Public, BareCryptoStoreError> {
|
||||
match seed {
|
||||
Some(seed) => {
|
||||
let pair = ecdsa::Pair::from_string(seed, None)
|
||||
.map_err(|_| BareCryptoStoreError::ValidationError("Generates an `ecdsa` pair.".to_owned()))?;
|
||||
self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), seed.into());
|
||||
Ok(pair.public())
|
||||
},
|
||||
None => {
|
||||
let (pair, phrase, _) = ecdsa::Pair::generate_with_phrase(None);
|
||||
self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), phrase);
|
||||
Ok(pair.public())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_unknown(&mut self, id: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> {
|
||||
self.keys.entry(id).or_default().insert(public.to_owned(), suri.to_string());
|
||||
Ok(())
|
||||
@@ -187,6 +229,12 @@ impl crate::traits::BareCryptoStore for KeyStore {
|
||||
.ok_or(BareCryptoStoreError::PairNotFound("sr25519".to_owned()))?;
|
||||
return Ok(key_pair.sign(msg).encode());
|
||||
}
|
||||
ecdsa::CRYPTO_ID => {
|
||||
let key_pair: ecdsa::Pair = self
|
||||
.ecdsa_key_pair(id, &ecdsa::Public::from_slice(key.1.as_slice()))
|
||||
.ok_or(BareCryptoStoreError::PairNotFound("ecdsa".to_owned()))?;
|
||||
return Ok(key_pair.sign(msg).encode());
|
||||
}
|
||||
_ => Err(BareCryptoStoreError::KeyNotSupported(id))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
use crate::{
|
||||
crypto::{KeyTypeId, CryptoTypePublicPair},
|
||||
ed25519, sr25519,
|
||||
ed25519, sr25519, ecdsa,
|
||||
};
|
||||
|
||||
use std::{
|
||||
@@ -77,6 +77,18 @@ pub trait BareCryptoStore: Send + Sync {
|
||||
id: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<ed25519::Public, BareCryptoStoreError>;
|
||||
/// Returns all ecdsa public keys for the given key type.
|
||||
fn ecdsa_public_keys(&self, id: KeyTypeId) -> Vec<ecdsa::Public>;
|
||||
/// Generate a new ecdsa 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 ecdsa_generate_new(
|
||||
&mut self,
|
||||
id: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<ecdsa::Public, BareCryptoStoreError>;
|
||||
|
||||
/// Insert a new key. This doesn't require any known of the crypto; but a public key must be
|
||||
/// manually provided.
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
//! Batch/parallel verification.
|
||||
|
||||
use sp_core::{ed25519, sr25519, crypto::Pair, traits::CloneableSpawn};
|
||||
use sp_core::{ed25519, sr25519, ecdsa, crypto::Pair, traits::CloneableSpawn};
|
||||
use std::sync::{Arc, atomic::{AtomicBool, Ordering as AtomicOrdering}};
|
||||
use futures::{future::FutureExt, task::FutureObj, channel::oneshot};
|
||||
|
||||
@@ -124,6 +124,29 @@ impl BatchVerifier {
|
||||
true
|
||||
}
|
||||
|
||||
/// Push ecdsa signature to verify.
|
||||
///
|
||||
/// Returns false if some of the pushed signatures before already failed the check
|
||||
/// (in this case it won't verify anything else)
|
||||
pub fn push_ecdsa(
|
||||
&mut self,
|
||||
signature: ecdsa::Signature,
|
||||
pub_key: ecdsa::Public,
|
||||
message: Vec<u8>,
|
||||
) -> bool {
|
||||
if self.invalid.load(AtomicOrdering::Relaxed) { return false; }
|
||||
|
||||
if self.spawn_verification_task(move || ecdsa::Pair::verify(&signature, &message, &pub_key)).is_err() {
|
||||
log::debug!(
|
||||
target: "runtime",
|
||||
"Batch-verification returns false because failed to spawn background task.",
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn verify_sr25519_batch(items: Vec<Sr25519BatchItem>) -> bool {
|
||||
let messages = items.iter().map(|item| &item.message[..]).collect();
|
||||
let signatures = items.iter().map(|item| &item.signature).collect();
|
||||
|
||||
@@ -42,7 +42,7 @@ use sp_core::{
|
||||
};
|
||||
|
||||
use sp_core::{
|
||||
crypto::KeyTypeId, ed25519, sr25519, H256, LogLevel,
|
||||
crypto::KeyTypeId, ed25519, sr25519, ecdsa, H256, LogLevel,
|
||||
offchain::{
|
||||
Timestamp, HttpRequestId, HttpRequestStatus, HttpError, StorageKind, OpaqueNetworkState,
|
||||
},
|
||||
@@ -545,6 +545,80 @@ pub trait Crypto {
|
||||
sr25519::Pair::verify_deprecated(sig, msg, pubkey)
|
||||
}
|
||||
|
||||
/// Returns all `ecdsa` public keys for the given key id from the keystore.
|
||||
fn ecdsa_public_keys(&mut self, id: KeyTypeId) -> Vec<ecdsa::Public> {
|
||||
self.extension::<KeystoreExt>()
|
||||
.expect("No `keystore` associated for the current context!")
|
||||
.read()
|
||||
.ecdsa_public_keys(id)
|
||||
}
|
||||
|
||||
/// Generate an `ecdsa` key for the given key type using an optional `seed` and
|
||||
/// store it in the keystore.
|
||||
///
|
||||
/// The `seed` needs to be a valid utf8.
|
||||
///
|
||||
/// Returns the public key.
|
||||
fn ecdsa_generate(&mut self, id: KeyTypeId, seed: Option<Vec<u8>>) -> ecdsa::Public {
|
||||
let seed = seed.as_ref().map(|s| std::str::from_utf8(&s).expect("Seed is valid utf8!"));
|
||||
self.extension::<KeystoreExt>()
|
||||
.expect("No `keystore` associated for the current context!")
|
||||
.write()
|
||||
.ecdsa_generate_new(id, seed)
|
||||
.expect("`ecdsa_generate` failed")
|
||||
}
|
||||
|
||||
/// Sign the given `msg` with the `ecdsa` key that corresponds to the given public key and
|
||||
/// key type in the keystore.
|
||||
///
|
||||
/// Returns the signature.
|
||||
fn ecdsa_sign(
|
||||
&mut self,
|
||||
id: KeyTypeId,
|
||||
pub_key: &ecdsa::Public,
|
||||
msg: &[u8],
|
||||
) -> Option<ecdsa::Signature> {
|
||||
self.extension::<KeystoreExt>()
|
||||
.expect("No `keystore` associated for the current context!")
|
||||
.read()
|
||||
.sign_with(id, &pub_key.into(), msg)
|
||||
.map(|sig| ecdsa::Signature::from_slice(sig.as_slice()))
|
||||
.ok()
|
||||
}
|
||||
|
||||
/// Verify `ecdsa` signature.
|
||||
///
|
||||
/// Returns `true` when the verification is either successful or batched.
|
||||
/// If no batching verification extension registered, this will return the result
|
||||
/// of verification immediately. If batching verification extension is registered
|
||||
/// caller should call `crypto::finish_batch_verify` to actualy check all submitted
|
||||
/// signatures.
|
||||
fn ecdsa_verify(
|
||||
sig: &ecdsa::Signature,
|
||||
msg: &[u8],
|
||||
pub_key: &ecdsa::Public,
|
||||
) -> bool {
|
||||
// TODO: see #5554, this is used outside of externalities context/runtime, thus this manual
|
||||
// `with_externalities`.
|
||||
//
|
||||
// This `with_externalities(..)` block returns Some(Some(result)) if signature verification was successfully
|
||||
// batched, everything else (Some(None)/None) means it was not batched and needs to be verified.
|
||||
let evaluated = sp_externalities::with_externalities(|mut instance|
|
||||
instance.extension::<VerificationExt>().map(
|
||||
|extension| extension.push_ecdsa(
|
||||
sig.clone(),
|
||||
pub_key.clone(),
|
||||
msg.to_vec(),
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
match evaluated {
|
||||
Some(Some(val)) => val,
|
||||
_ => ecdsa::Pair::verify(sig, msg, pub_key),
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify and recover a SECP256k1 ECDSA signature.
|
||||
///
|
||||
/// - `sig` is passed in RSV format. V should be either `0/1` or `27/28`.
|
||||
|
||||
@@ -27,7 +27,7 @@ use sp_std::{prelude::*, marker::PhantomData};
|
||||
use codec::{Encode, Decode, Input, Error};
|
||||
|
||||
use sp_core::{OpaqueMetadata, RuntimeDebug, ChangesTrieConfiguration};
|
||||
use sp_application_crypto::{ed25519, sr25519, RuntimeAppPublic};
|
||||
use sp_application_crypto::{ed25519, sr25519, ecdsa, RuntimeAppPublic};
|
||||
use trie_db::{TrieMut, Trie};
|
||||
use sp_trie::PrefixedMemoryDB;
|
||||
use sp_trie::trie_types::{TrieDB, TrieDBMut};
|
||||
@@ -305,6 +305,10 @@ cfg_if! {
|
||||
///
|
||||
/// Returns the signature generated for the message `sr25519`.
|
||||
fn test_sr25519_crypto() -> (sr25519::AppSignature, sr25519::AppPublic);
|
||||
/// Test that `ecdsa` crypto works in the runtime.
|
||||
///
|
||||
/// Returns the signature generated for the message `ecdsa`.
|
||||
fn test_ecdsa_crypto() -> (ecdsa::AppSignature, ecdsa::AppPublic);
|
||||
/// Run various tests against storage.
|
||||
fn test_storage();
|
||||
}
|
||||
@@ -347,6 +351,10 @@ cfg_if! {
|
||||
///
|
||||
/// Returns the signature generated for the message `sr25519`.
|
||||
fn test_sr25519_crypto() -> (sr25519::AppSignature, sr25519::AppPublic);
|
||||
/// Test that `ecdsa` crypto works in the runtime.
|
||||
///
|
||||
/// Returns the signature generated for the message `ecdsa`.
|
||||
fn test_ecdsa_crypto() -> (ecdsa::AppSignature, ecdsa::AppPublic);
|
||||
/// Run various tests against storage.
|
||||
fn test_storage();
|
||||
}
|
||||
@@ -485,6 +493,7 @@ impl_opaque_keys! {
|
||||
pub struct SessionKeys {
|
||||
pub ed25519: ed25519::AppPublic,
|
||||
pub sr25519: sr25519::AppPublic,
|
||||
pub ecdsa: ecdsa::AppPublic,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -620,6 +629,10 @@ cfg_if! {
|
||||
test_sr25519_crypto()
|
||||
}
|
||||
|
||||
fn test_ecdsa_crypto() -> (ecdsa::AppSignature, ecdsa::AppPublic) {
|
||||
test_ecdsa_crypto()
|
||||
}
|
||||
|
||||
fn test_storage() {
|
||||
test_read_storage();
|
||||
test_read_child_storage();
|
||||
@@ -837,6 +850,10 @@ cfg_if! {
|
||||
test_sr25519_crypto()
|
||||
}
|
||||
|
||||
fn test_ecdsa_crypto() -> (ecdsa::AppSignature, ecdsa::AppPublic) {
|
||||
test_ecdsa_crypto()
|
||||
}
|
||||
|
||||
fn test_storage() {
|
||||
test_read_storage();
|
||||
test_read_child_storage();
|
||||
@@ -929,6 +946,22 @@ fn test_sr25519_crypto() -> (sr25519::AppSignature, sr25519::AppPublic) {
|
||||
(signature, public0)
|
||||
}
|
||||
|
||||
fn test_ecdsa_crypto() -> (ecdsa::AppSignature, ecdsa::AppPublic) {
|
||||
let public0 = ecdsa::AppPublic::generate_pair(None);
|
||||
let public1 = ecdsa::AppPublic::generate_pair(None);
|
||||
let public2 = ecdsa::AppPublic::generate_pair(None);
|
||||
|
||||
let all = ecdsa::AppPublic::all();
|
||||
assert!(all.contains(&public0));
|
||||
assert!(all.contains(&public1));
|
||||
assert!(all.contains(&public2));
|
||||
|
||||
let signature = public0.sign(&"ecdsa").expect("Generates a valid `ecdsa` signature.");
|
||||
|
||||
assert!(public0.verify(&"ecdsa", &signature));
|
||||
(signature, public0)
|
||||
}
|
||||
|
||||
fn test_read_storage() {
|
||||
const KEY: &[u8] = b":read_storage";
|
||||
sp_io::storage::set(KEY, b"test");
|
||||
|
||||
Reference in New Issue
Block a user