Keystore overhaul (final) (#13683)

* Introduce keystore specialized sign methods

* Get rid of 'AppKey::UntypedGeneric' associated type.

Untyped generics are accessible using associated types 'Generic' associated type.
I.e. <T as AppKey>::Public::Generic

* Get rid of 'CryptoTypePublicPair'

* Trivial fix

* Small refactory of local keystore implementations

* Remove 'crypto_id' method from 'Public'

* Trivial rename of 'AppKey' to 'AppCrypto'

* Remove unused import

* Improve docs

* Better signature related errors for authority-discovery

* Apply review suggestion

* Apply review suggestions

Co-authored-by: Koute <koute@users.noreply.github.com>

* Authority discoverty signing error revisited

* Signing error revisited for babe and aura as well

* Further cleanup

---------

Co-authored-by: Koute <koute@users.noreply.github.com>
This commit is contained in:
Davide Galassi
2023-03-24 14:46:02 +01:00
committed by GitHub
parent 370e71cb20
commit 40e1704e1c
27 changed files with 552 additions and 616 deletions
+3 -9
View File
@@ -592,7 +592,7 @@ mod tests {
use sc_service_test::TestNetNode;
use sc_transaction_pool_api::{ChainEvent, MaintainedTransactionPool};
use sp_consensus::{BlockOrigin, Environment, Proposer};
use sp_core::{crypto::Pair as CryptoPair, Public};
use sp_core::crypto::Pair;
use sp_inherents::InherentDataProvider;
use sp_keyring::AccountKeyring;
use sp_keystore::KeystorePtr;
@@ -737,16 +737,10 @@ mod tests {
// add it to a digest item.
let to_sign = pre_hash.encode();
let signature = keystore
.sign_with(
sp_consensus_babe::AuthorityId::ID,
&alice.to_public_crypto_pair(),
&to_sign,
)
.sr25519_sign(sp_consensus_babe::AuthorityId::ID, alice.as_ref(), &to_sign)
.unwrap()
.unwrap()
.try_into()
.unwrap();
let item = <DigestItem as CompatibleDigestItem>::babe_seal(signature);
let item = <DigestItem as CompatibleDigestItem>::babe_seal(signature.into());
slot += 1;
let mut params = BlockImportParams::new(BlockOrigin::File, new_header);
@@ -18,7 +18,7 @@
use codec::Decode;
use frame_system::offchain::{SendSignedTransaction, Signer, SubmitTransaction};
use kitchensink_runtime::{Executive, Indices, Runtime, UncheckedExtrinsic};
use sp_application_crypto::AppKey;
use sp_application_crypto::AppCrypto;
use sp_core::offchain::{testing::TestTransactionPoolExt, TransactionPoolExt};
use sp_keyring::sr25519::Keyring::Alice;
use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt};
@@ -18,8 +18,6 @@
//! Authority discovery errors.
use sp_core::crypto::CryptoTypePublicPair;
/// AuthorityDiscovery Result.
pub type Result<T> = std::result::Result<T, Error>;
@@ -59,11 +57,8 @@ pub enum Error {
#[error("Failed to parse a libp2p key.")]
ParsingLibp2pIdentity(#[from] libp2p::identity::error::DecodingError),
#[error("Failed to sign using a specific public key.")]
MissingSignature(CryptoTypePublicPair),
#[error("Failed to sign using all public keys.")]
Signing,
#[error("Failed to sign: {0}.")]
CannotSign(String),
#[error("Failed to register Prometheus metric.")]
Prometheus(#[from] prometheus_endpoint::PrometheusError),
@@ -32,7 +32,7 @@ use std::{
use futures::{channel::mpsc, future, stream::Fuse, FutureExt, Stream, StreamExt};
use addr_cache::AddrCache;
use codec::Decode;
use codec::{Decode, Encode};
use ip_network::IpNetwork;
use libp2p::{
core::multiaddr,
@@ -43,6 +43,7 @@ use log::{debug, error, log_enabled};
use prometheus_endpoint::{register, Counter, CounterVec, Gauge, Opts, U64};
use prost::Message;
use rand::{seq::SliceRandom, thread_rng};
use sc_network::{
event::DhtEvent, KademliaKey, NetworkDHTProvider, NetworkSigner, NetworkStateInfo, Signature,
};
@@ -51,8 +52,7 @@ use sp_authority_discovery::{
AuthorityDiscoveryApi, AuthorityId, AuthorityPair, AuthoritySignature,
};
use sp_blockchain::HeaderBackend;
use sp_core::crypto::{key_types, CryptoTypePublicPair, Pair};
use sp_core::crypto::{key_types, ByteArray, Pair};
use sp_keystore::{Keystore, KeystorePtr};
use sp_runtime::traits::Block as BlockT;
@@ -127,7 +127,7 @@ pub struct Worker<Client, Network, Block, DhtEventStream> {
publish_if_changed_interval: ExpIncInterval,
/// List of keys onto which addresses have been published at the latest publication.
/// Used to check whether they have changed.
latest_published_keys: HashSet<CryptoTypePublicPair>,
latest_published_keys: HashSet<AuthorityId>,
/// Same value as in the configuration.
publish_non_global_ips: bool,
/// Same value as in the configuration.
@@ -339,7 +339,7 @@ where
let keys = Worker::<Client, Network, Block, DhtEventStream>::get_own_public_keys_within_authority_set(
key_store.clone(),
self.client.as_ref(),
).await?.into_iter().map(Into::into).collect::<HashSet<_>>();
).await?.into_iter().collect::<HashSet<_>>();
if only_if_changed && keys == self.latest_published_keys {
return Ok(())
@@ -654,7 +654,7 @@ fn sign_record_with_peer_id(
) -> Result<schema::PeerSignature> {
let signature = network
.sign_with_local_identity(serialized_record)
.map_err(|_| Error::Signing)?;
.map_err(|e| Error::CannotSign(format!("{} (network packet)", e)))?;
let public_key = signature.public_key.to_protobuf_encoding();
let signature = signature.bytes;
Ok(schema::PeerSignature { signature, public_key })
@@ -664,15 +664,20 @@ fn sign_record_with_authority_ids(
serialized_record: Vec<u8>,
peer_signature: Option<schema::PeerSignature>,
key_store: &dyn Keystore,
keys: Vec<CryptoTypePublicPair>,
keys: Vec<AuthorityId>,
) -> Result<Vec<(KademliaKey, Vec<u8>)>> {
let mut result = Vec::with_capacity(keys.len());
for key in keys.iter() {
let auth_signature = key_store
.sign_with(key_types::AUTHORITY_DISCOVERY, key, &serialized_record)
.map_err(|_| Error::Signing)?
.ok_or_else(|| Error::MissingSignature(key.clone()))?;
.sr25519_sign(key_types::AUTHORITY_DISCOVERY, key.as_ref(), &serialized_record)
.map_err(|e| Error::CannotSign(format!("{}. Key: {:?}", e, key)))?
.ok_or_else(|| {
Error::CannotSign(format!("Could not find key in keystore. Key: {:?}", key))
})?;
// Scale encode
let auth_signature = auth_signature.encode();
let signed_record = schema::SignedAuthorityRecord {
record: serialized_record.clone(),
@@ -681,7 +686,7 @@ fn sign_record_with_authority_ids(
}
.encode_to_vec();
result.push((hash_authority_id(&key.1), signed_record));
result.push((hash_authority_id(key.as_slice()), signed_record));
}
Ok(result)
+28 -31
View File
@@ -45,7 +45,7 @@ use sc_consensus_slots::{
};
use sc_telemetry::TelemetryHandle;
use sp_api::{Core, ProvideRuntimeApi};
use sp_application_crypto::{AppKey, AppPublic};
use sp_application_crypto::{AppCrypto, AppPublic};
use sp_blockchain::{HeaderBackend, Result as CResult};
use sp_consensus::{BlockOrigin, Environment, Error as ConsensusError, Proposer, SelectChain};
use sp_consensus_slots::Slot;
@@ -205,7 +205,7 @@ pub fn start_aura<P, B, C, SC, I, PF, SO, L, CIDP, BS, Error>(
telemetry,
compatibility_mode,
}: StartAuraParams<C, SC, I, PF, SO, L, CIDP, BS, NumberFor<B>>,
) -> Result<impl Future<Output = ()>, sp_consensus::Error>
) -> Result<impl Future<Output = ()>, ConsensusError>
where
P: Pair + Send + Sync,
P::Public: AppPublic + Hash + Member + Encode + Decode,
@@ -222,7 +222,7 @@ where
CIDP: CreateInherentDataProviders<B, ()> + Send + 'static,
CIDP::InherentDataProviders: InherentDataProviderExt + Send,
BS: BackoffAuthoringBlocksStrategy<NumberFor<B>> + Send + Sync + 'static,
Error: std::error::Error + Send + From<sp_consensus::Error> + 'static,
Error: std::error::Error + Send + From<ConsensusError> + 'static,
{
let worker = build_aura_worker::<P, _, _, _, _, _, _, _, _>(BuildAuraWorkerParams {
client,
@@ -320,7 +320,7 @@ where
P::Public: AppPublic + Hash + Member + Encode + Decode,
P::Signature: TryFrom<Vec<u8>> + Hash + Member + Encode + Decode,
I: BlockImport<B, Transaction = sp_api::TransactionFor<C, B>> + Send + Sync + 'static,
Error: std::error::Error + Send + From<sp_consensus::Error> + 'static,
Error: std::error::Error + Send + From<ConsensusError> + 'static,
SO: SyncOracle + Send + Sync + Clone,
L: sc_consensus::JustificationSyncLink<B>,
BS: BackoffAuthoringBlocksStrategy<NumberFor<B>> + Send + Sync + 'static,
@@ -374,13 +374,13 @@ where
SO: SyncOracle + Send + Clone + Sync,
L: sc_consensus::JustificationSyncLink<B>,
BS: BackoffAuthoringBlocksStrategy<NumberFor<B>> + Send + Sync + 'static,
Error: std::error::Error + Send + From<sp_consensus::Error> + 'static,
Error: std::error::Error + Send + From<ConsensusError> + 'static,
{
type BlockImport = I;
type SyncOracle = SO;
type JustificationSyncLink = L;
type CreateProposer =
Pin<Box<dyn Future<Output = Result<E::Proposer, sp_consensus::Error>> + Send + 'static>>;
Pin<Box<dyn Future<Output = Result<E::Proposer, ConsensusError>> + Send + 'static>>;
type Proposer = E::Proposer;
type Claim = P::Public;
type AuxData = Vec<AuthorityId<P>>;
@@ -393,11 +393,7 @@ where
&mut self.block_import
}
fn aux_data(
&self,
header: &B::Header,
_slot: Slot,
) -> Result<Self::AuxData, sp_consensus::Error> {
fn aux_data(&self, header: &B::Header, _slot: Slot) -> Result<Self::AuxData, ConsensusError> {
authorities(
self.client.as_ref(),
header.hash(),
@@ -406,17 +402,17 @@ where
)
}
fn authorities_len(&self, epoch_data: &Self::AuxData) -> Option<usize> {
Some(epoch_data.len())
fn authorities_len(&self, authorities: &Self::AuxData) -> Option<usize> {
Some(authorities.len())
}
async fn claim_slot(
&self,
_header: &B::Header,
slot: Slot,
epoch_data: &Self::AuxData,
authorities: &Self::AuxData,
) -> Option<Self::Claim> {
let expected_author = slot_author::<P>(slot, epoch_data);
let expected_author = slot_author::<P>(slot, authorities);
expected_author.and_then(|p| {
if self
.keystore
@@ -440,29 +436,30 @@ where
body: Vec<B::Extrinsic>,
storage_changes: StorageChanges<<Self::BlockImport as BlockImport<B>>::Transaction, B>,
public: Self::Claim,
_epoch: Self::AuxData,
_authorities: Self::AuxData,
) -> Result<
sc_consensus::BlockImportParams<B, <Self::BlockImport as BlockImport<B>>::Transaction>,
sp_consensus::Error,
ConsensusError,
> {
// sign the pre-sealed hash of the block and then
// add it to a digest item.
let public_type_pair = public.to_public_crypto_pair();
let public = public.to_raw_vec();
let signature = self
.keystore
.sign_with(<AuthorityId<P> as AppKey>::ID, &public_type_pair, header_hash.as_ref())
.map_err(|e| sp_consensus::Error::CannotSign(public.clone(), e.to_string()))?
.sign_with(
<AuthorityId<P> as AppCrypto>::ID,
<AuthorityId<P> as AppCrypto>::CRYPTO_ID,
public.as_slice(),
header_hash.as_ref(),
)
.map_err(|e| ConsensusError::CannotSign(format!("{}. Key: {:?}", e, public)))?
.ok_or_else(|| {
sp_consensus::Error::CannotSign(
public.clone(),
"Could not find key in keystore.".into(),
)
ConsensusError::CannotSign(format!(
"Could not find key in keystore. Key: {:?}",
public
))
})?;
let signature = signature
.clone()
.try_into()
.map_err(|_| sp_consensus::Error::InvalidSignature(signature, public))?;
.map_err(|_| ConsensusError::InvalidSignature(signature, public.to_raw_vec()))?;
let signature_digest_item =
<DigestItem as CompatibleDigestItem<P::Signature>>::aura_seal(signature);
@@ -507,7 +504,7 @@ where
fn proposer(&mut self, block: &B::Header) -> Self::CreateProposer {
self.env
.init(block)
.map_err(|e| sp_consensus::Error::ClientImport(format!("{:?}", e)))
.map_err(|e| ConsensusError::ClientImport(format!("{:?}", e)))
.boxed()
}
@@ -620,14 +617,14 @@ where
Default::default(),
),
)
.map_err(|_| sp_consensus::Error::InvalidAuthoritiesSet)?;
.map_err(|_| ConsensusError::InvalidAuthoritiesSet)?;
},
}
runtime_api
.authorities(parent_hash)
.ok()
.ok_or(sp_consensus::Error::InvalidAuthoritiesSet)
.ok_or(ConsensusError::InvalidAuthoritiesSet)
}
#[cfg(test)]
@@ -30,7 +30,7 @@ use sc_consensus_epochs::{descendent_query, Epoch as EpochT, SharedEpochChanges}
use sc_rpc_api::DenyUnsafe;
use serde::{Deserialize, Serialize};
use sp_api::ProvideRuntimeApi;
use sp_application_crypto::AppKey;
use sp_application_crypto::AppCrypto;
use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata};
use sp_consensus::{Error as ConsensusError, SelectChain};
use sp_consensus_babe::{
@@ -22,7 +22,7 @@ use super::Epoch;
use codec::Encode;
use sc_consensus_epochs::Epoch as EpochT;
use schnorrkel::{keys::PublicKey, vrf::VRFInOut};
use sp_application_crypto::AppKey;
use sp_application_crypto::AppCrypto;
use sp_consensus_babe::{
digests::{PreDigest, PrimaryPreDigest, SecondaryPlainPreDigest, SecondaryVRFPreDigest},
make_transcript, make_transcript_data, AuthorityId, BabeAuthorityWeight, Slot, BABE_VRF_PREFIX,
+18 -29
View File
@@ -108,7 +108,7 @@ use sc_consensus_slots::{
};
use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_TRACE};
use sp_api::{ApiExt, ProvideRuntimeApi};
use sp_application_crypto::AppKey;
use sp_application_crypto::AppCrypto;
use sp_block_builder::BlockBuilder as BlockBuilderApi;
use sp_blockchain::{
Backend as _, BlockStatus, Error as ClientError, ForkBackend, HeaderBackend, HeaderMetadata,
@@ -117,7 +117,7 @@ use sp_blockchain::{
use sp_consensus::{BlockOrigin, Environment, Error as ConsensusError, Proposer, SelectChain};
use sp_consensus_babe::inherents::BabeInherentData;
use sp_consensus_slots::Slot;
use sp_core::{crypto::ByteArray, ExecutionContext};
use sp_core::ExecutionContext;
use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvider};
use sp_keystore::KeystorePtr;
use sp_runtime::{
@@ -274,7 +274,7 @@ pub enum Error<B: BlockT> {
MultipleConfigChangeDigests,
/// Could not extract timestamp and slot
#[error("Could not extract timestamp and slot: {0}")]
Extraction(sp_consensus::Error),
Extraction(ConsensusError),
/// Could not fetch epoch
#[error("Could not fetch epoch at {0:?}")]
FetchEpoch(B::Hash),
@@ -471,7 +471,7 @@ pub fn start_babe<B, C, SC, E, I, SO, CIDP, BS, L, Error>(
max_block_proposal_slot_portion,
telemetry,
}: BabeParams<B, C, SC, E, I, SO, L, CIDP, BS>,
) -> Result<BabeWorker<B>, sp_consensus::Error>
) -> Result<BabeWorker<B>, ConsensusError>
where
B: BlockT,
C: ProvideRuntimeApi<B>
@@ -739,7 +739,7 @@ where
type SyncOracle = SO;
type JustificationSyncLink = L;
type CreateProposer =
Pin<Box<dyn Future<Output = Result<E::Proposer, sp_consensus::Error>> + Send + 'static>>;
Pin<Box<dyn Future<Output = Result<E::Proposer, ConsensusError>> + Send + 'static>>;
type Proposer = E::Proposer;
type BlockImport = I;
type AuxData = ViableEpochDescriptor<B::Hash, NumberFor<B>, Epoch>;
@@ -762,7 +762,7 @@ where
slot,
)
.map_err(|e| ConsensusError::ChainLookup(e.to_string()))?
.ok_or(sp_consensus::Error::InvalidAuthoritiesSet)
.ok_or(ConsensusError::InvalidAuthoritiesSet)
}
fn authorities_len(&self, epoch_descriptor: &Self::AuxData) -> Option<usize> {
@@ -827,28 +827,21 @@ where
(_, public): Self::Claim,
epoch_descriptor: Self::AuxData,
) -> Result<
sc_consensus::BlockImportParams<B, <Self::BlockImport as BlockImport<B>>::Transaction>,
sp_consensus::Error,
BlockImportParams<B, <Self::BlockImport as BlockImport<B>>::Transaction>,
ConsensusError,
> {
// sign the pre-sealed hash of the block and then
// add it to a digest item.
let public_type_pair = public.clone().into();
let public = public.to_raw_vec();
let signature = self
.keystore
.sign_with(<AuthorityId as AppKey>::ID, &public_type_pair, header_hash.as_ref())
.map_err(|e| sp_consensus::Error::CannotSign(public.clone(), e.to_string()))?
.sr25519_sign(<AuthorityId as AppCrypto>::ID, public.as_ref(), header_hash.as_ref())
.map_err(|e| ConsensusError::CannotSign(format!("{}. Key: {:?}", e, public)))?
.ok_or_else(|| {
sp_consensus::Error::CannotSign(
public.clone(),
"Could not find key in keystore.".into(),
)
ConsensusError::CannotSign(format!(
"Could not find key in keystore. Key: {:?}",
public
))
})?;
let signature: AuthoritySignature = signature
.clone()
.try_into()
.map_err(|_| sp_consensus::Error::InvalidSignature(signature, public))?;
let digest_item = <DigestItem as CompatibleDigestItem>::babe_seal(signature);
let digest_item = <DigestItem as CompatibleDigestItem>::babe_seal(signature.into());
let mut import_block = BlockImportParams::new(BlockOrigin::Own, header);
import_block.post_digests.push(digest_item);
@@ -891,11 +884,7 @@ where
}
fn proposer(&mut self, block: &B::Header) -> Self::CreateProposer {
Box::pin(
self.env
.init(block)
.map_err(|e| sp_consensus::Error::ClientImport(format!("{:?}", e))),
)
Box::pin(self.env.init(block).map_err(|e| ConsensusError::ClientImport(e.to_string())))
}
fn telemetry(&self) -> Option<TelemetryHandle> {
@@ -1182,7 +1171,7 @@ where
.create_inherent_data_providers
.create_inherent_data_providers(parent_hash, ())
.await
.map_err(|e| Error::<Block>::Client(sp_consensus::Error::from(e).into()))?;
.map_err(|e| Error::<Block>::Client(ConsensusError::from(e).into()))?;
let slot_now = create_inherent_data_providers.slot();
@@ -72,7 +72,7 @@ use sc_network::types::ProtocolName;
use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO};
use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver};
use sp_api::ProvideRuntimeApi;
use sp_application_crypto::AppKey;
use sp_application_crypto::AppCrypto;
use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata, Result as ClientResult};
use sp_consensus::SelectChain;
use sp_consensus_grandpa::{
+1 -1
View File
@@ -150,7 +150,7 @@ pub trait SimpleSlotWorker<B: BlockT> {
body: Vec<B::Extrinsic>,
storage_changes: StorageChanges<<Self::BlockImport as BlockImport<B>>::Transaction, B>,
public: Self::Claim,
epoch: Self::AuxData,
aux_data: Self::AuxData,
) -> Result<
sc_consensus::BlockImportParams<B, <Self::BlockImport as BlockImport<B>>::Transaction>,
sp_consensus::Error,
+106 -108
View File
@@ -18,13 +18,10 @@
//! Local keystore implementation
use parking_lot::RwLock;
use sp_application_crypto::{ecdsa, ed25519, sr25519, AppKey, AppPair, IsWrappedBy};
use sp_application_crypto::{AppCrypto, AppPair, IsWrappedBy};
use sp_core::{
crypto::{
ByteArray, CryptoTypePublicPair, ExposeSecret, KeyTypeId, Pair as PairT, SecretString,
},
sr25519::{Pair as Sr25519Pair, Public as Sr25519Public},
Encode,
crypto::{ByteArray, ExposeSecret, KeyTypeId, Pair as CorePair, SecretString},
ecdsa, ed25519, sr25519,
};
use sp_keystore::{
vrf::{make_transcript, VRFSignature, VRFTranscriptData},
@@ -62,67 +59,13 @@ impl LocalKeystore {
/// `Err(_)` when something failed.
pub fn key_pair<Pair: AppPair>(
&self,
public: &<Pair as AppKey>::Public,
public: &<Pair as AppCrypto>::Public,
) -> Result<Option<Pair>> {
self.0.read().key_pair::<Pair>(public)
}
}
impl Keystore for LocalKeystore {
fn keys(&self, id: KeyTypeId) -> std::result::Result<Vec<CryptoTypePublicPair>, TraitError> {
let raw_keys = self.0.read().raw_public_keys(id)?;
Ok(raw_keys.into_iter().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));
v
}))
}
fn sign_with(
&self,
id: KeyTypeId,
key: &CryptoTypePublicPair,
msg: &[u8],
) -> std::result::Result<Option<Vec<u8>>, TraitError> {
match key.0 {
ed25519::CRYPTO_ID => {
let pub_key = ed25519::Public::from_slice(key.1.as_slice()).map_err(|()| {
TraitError::Other("Corrupted public key - Invalid size".into())
})?;
let key_pair = self
.0
.read()
.key_pair_by_type::<ed25519::Pair>(&pub_key, id)
.map_err(TraitError::from)?;
key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose()
},
sr25519::CRYPTO_ID => {
let pub_key = sr25519::Public::from_slice(key.1.as_slice()).map_err(|()| {
TraitError::Other("Corrupted public key - Invalid size".into())
})?;
let key_pair = self
.0
.read()
.key_pair_by_type::<sr25519::Pair>(&pub_key, id)
.map_err(TraitError::from)?;
key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose()
},
ecdsa::CRYPTO_ID => {
let pub_key = ecdsa::Public::from_slice(key.1.as_slice()).map_err(|()| {
TraitError::Other("Corrupted public key - Invalid size".into())
})?;
let key_pair = self
.0
.read()
.key_pair_by_type::<ecdsa::Pair>(&pub_key, id)
.map_err(TraitError::from)?;
key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose()
},
_ => Err(TraitError::KeyNotSupported(id)),
}
}
fn sr25519_public_keys(&self, key_type: KeyTypeId) -> Vec<sr25519::Public> {
self.0
.read()
@@ -140,19 +83,49 @@ impl Keystore for LocalKeystore {
/// If the `[seed]` is `Some` then the key will be ephemeral and stored in memory.
fn sr25519_generate_new(
&self,
id: KeyTypeId,
key_type: KeyTypeId,
seed: Option<&str>,
) -> std::result::Result<sr25519::Public, TraitError> {
let pair = match seed {
Some(seed) =>
self.0.write().insert_ephemeral_from_seed_by_type::<sr25519::Pair>(seed, id),
None => self.0.write().generate_by_type::<sr25519::Pair>(id),
Some(seed) => self
.0
.write()
.insert_ephemeral_from_seed_by_type::<sr25519::Pair>(seed, key_type),
None => self.0.write().generate_by_type::<sr25519::Pair>(key_type),
}
.map_err(|e| -> TraitError { e.into() })?;
Ok(pair.public())
}
fn sr25519_sign(
&self,
key_type: KeyTypeId,
public: &sr25519::Public,
msg: &[u8],
) -> std::result::Result<Option<sr25519::Signature>, TraitError> {
let res = self
.0
.read()
.key_pair_by_type::<sr25519::Pair>(public, key_type)?
.map(|pair| pair.sign(msg));
Ok(res)
}
fn sr25519_vrf_sign(
&self,
key_type: KeyTypeId,
public: &sr25519::Public,
transcript_data: VRFTranscriptData,
) -> std::result::Result<Option<VRFSignature>, TraitError> {
let res = self.0.read().key_pair_by_type::<sr25519::Pair>(public, key_type)?.map(|pair| {
let transcript = make_transcript(transcript_data);
let (inout, proof, _) = pair.as_ref().vrf_sign(transcript);
VRFSignature { output: inout.to_output(), proof }
});
Ok(res)
}
fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec<ed25519::Public> {
self.0
.read()
@@ -170,19 +143,35 @@ impl Keystore for LocalKeystore {
/// If the `[seed]` is `Some` then the key will be ephemeral and stored in memory.
fn ed25519_generate_new(
&self,
id: KeyTypeId,
key_type: KeyTypeId,
seed: Option<&str>,
) -> std::result::Result<ed25519::Public, TraitError> {
let pair = match seed {
Some(seed) =>
self.0.write().insert_ephemeral_from_seed_by_type::<ed25519::Pair>(seed, id),
None => self.0.write().generate_by_type::<ed25519::Pair>(id),
Some(seed) => self
.0
.write()
.insert_ephemeral_from_seed_by_type::<ed25519::Pair>(seed, key_type),
None => self.0.write().generate_by_type::<ed25519::Pair>(key_type),
}
.map_err(|e| -> TraitError { e.into() })?;
Ok(pair.public())
}
fn ed25519_sign(
&self,
key_type: KeyTypeId,
public: &ed25519::Public,
msg: &[u8],
) -> std::result::Result<Option<ed25519::Signature>, TraitError> {
let res = self
.0
.read()
.key_pair_by_type::<ed25519::Pair>(public, key_type)?
.map(|pair| pair.sign(msg));
Ok(res)
}
fn ecdsa_public_keys(&self, key_type: KeyTypeId) -> Vec<ecdsa::Public> {
self.0
.read()
@@ -200,19 +189,47 @@ impl Keystore for LocalKeystore {
/// If the `[seed]` is `Some` then the key will be ephemeral and stored in memory.
fn ecdsa_generate_new(
&self,
id: KeyTypeId,
key_type: KeyTypeId,
seed: Option<&str>,
) -> std::result::Result<ecdsa::Public, TraitError> {
let pair = match seed {
Some(seed) =>
self.0.write().insert_ephemeral_from_seed_by_type::<ecdsa::Pair>(seed, id),
None => self.0.write().generate_by_type::<ecdsa::Pair>(id),
self.0.write().insert_ephemeral_from_seed_by_type::<ecdsa::Pair>(seed, key_type),
None => self.0.write().generate_by_type::<ecdsa::Pair>(key_type),
}
.map_err(|e| -> TraitError { e.into() })?;
Ok(pair.public())
}
fn ecdsa_sign(
&self,
key_type: KeyTypeId,
public: &ecdsa::Public,
msg: &[u8],
) -> std::result::Result<Option<ecdsa::Signature>, TraitError> {
let res = self
.0
.read()
.key_pair_by_type::<ecdsa::Pair>(public, key_type)?
.map(|pair| pair.sign(msg));
Ok(res)
}
fn ecdsa_sign_prehashed(
&self,
key_type: KeyTypeId,
public: &ecdsa::Public,
msg: &[u8; 32],
) -> std::result::Result<Option<ecdsa::Signature>, TraitError> {
let res = self
.0
.read()
.key_pair_by_type::<ecdsa::Pair>(public, key_type)?
.map(|pair| pair.sign_prehashed(msg));
Ok(res)
}
fn insert(
&self,
key_type: KeyTypeId,
@@ -222,39 +239,15 @@ impl Keystore for LocalKeystore {
self.0.write().insert(key_type, suri, public).map_err(|_| ())
}
fn keys(&self, key_type: KeyTypeId) -> std::result::Result<Vec<Vec<u8>>, TraitError> {
self.0.read().raw_public_keys(key_type).map_err(|e| e.into())
}
fn has_keys(&self, public_keys: &[(Vec<u8>, KeyTypeId)]) -> bool {
public_keys
.iter()
.all(|(p, t)| self.0.read().key_phrase_by_type(p, *t).ok().flatten().is_some())
}
fn sr25519_vrf_sign(
&self,
key_type: KeyTypeId,
public: &Sr25519Public,
transcript_data: VRFTranscriptData,
) -> std::result::Result<Option<VRFSignature>, TraitError> {
let transcript = make_transcript(transcript_data);
let pair = self.0.read().key_pair_by_type::<Sr25519Pair>(public, key_type)?;
if let Some(pair) = pair {
let (inout, proof, _) = pair.as_ref().vrf_sign(transcript);
Ok(Some(VRFSignature { output: inout.to_output(), proof }))
} else {
Ok(None)
}
}
fn ecdsa_sign_prehashed(
&self,
id: KeyTypeId,
public: &ecdsa::Public,
msg: &[u8; 32],
) -> std::result::Result<Option<ecdsa::Signature>, TraitError> {
let pair = self.0.read().key_pair_by_type::<ecdsa::Pair>(public, id)?;
pair.map(|k| k.sign_prehashed(msg)).map(Ok).transpose()
}
}
impl Into<KeystorePtr> for LocalKeystore {
@@ -305,7 +298,12 @@ impl KeystoreInner {
/// Insert the given public/private key pair with the given key type.
///
/// Does not place it into the file system store.
fn insert_ephemeral_pair<Pair: PairT>(&mut self, pair: &Pair, seed: &str, key_type: KeyTypeId) {
fn insert_ephemeral_pair<Pair: CorePair>(
&mut self,
pair: &Pair,
seed: &str,
key_type: KeyTypeId,
) {
let key = (key_type, pair.public().to_raw_vec());
self.additional.insert(key, seed.into());
}
@@ -325,7 +323,7 @@ impl KeystoreInner {
///
/// Places it into the file system store, if a path is configured. Otherwise insert
/// it into the memory cache only.
fn generate_by_type<Pair: PairT>(&mut self, key_type: KeyTypeId) -> Result<Pair> {
fn generate_by_type<Pair: CorePair>(&mut self, key_type: KeyTypeId) -> Result<Pair> {
let (pair, phrase, _) = Pair::generate_with_phrase(self.password());
if let Some(path) = self.key_file_path(pair.public().as_slice(), key_type) {
Self::write_to_file(path, &phrase)?;
@@ -354,7 +352,7 @@ impl KeystoreInner {
/// Create a new key from seed.
///
/// Does not place it into the file system store.
fn insert_ephemeral_from_seed_by_type<Pair: PairT>(
fn insert_ephemeral_from_seed_by_type<Pair: CorePair>(
&mut self,
seed: &str,
key_type: KeyTypeId,
@@ -386,7 +384,7 @@ impl KeystoreInner {
}
/// Get a key pair for the given public key and key type.
fn key_pair_by_type<Pair: PairT>(
fn key_pair_by_type<Pair: CorePair>(
&self,
public: &Pair::Public,
key_type: KeyTypeId,
@@ -418,12 +416,12 @@ impl KeystoreInner {
}
/// Returns a list of raw public keys filtered by `KeyTypeId`
fn raw_public_keys(&self, id: KeyTypeId) -> Result<Vec<Vec<u8>>> {
fn raw_public_keys(&self, key_type: KeyTypeId) -> Result<Vec<Vec<u8>>> {
let mut public_keys: Vec<Vec<u8>> = self
.additional
.keys()
.into_iter()
.filter_map(|k| if k.0 == id { Some(k.1.clone()) } else { None })
.filter_map(|k| if k.0 == key_type { Some(k.1.clone()) } else { None })
.collect();
if let Some(path) = &self.path {
@@ -435,7 +433,7 @@ impl KeystoreInner {
if let Some(name) = path.file_name().and_then(|n| n.to_str()) {
match array_bytes::hex2bytes(name) {
Ok(ref hex) if hex.len() > 4 => {
if hex[0..4] != id.0 {
if hex[0..4] != key_type.0 {
continue
}
let public = hex[4..].to_vec();
@@ -456,7 +454,7 @@ impl KeystoreInner {
/// when something failed.
pub fn key_pair<Pair: AppPair>(
&self,
public: &<Pair as AppKey>::Public,
public: &<Pair as AppCrypto>::Public,
) -> Result<Option<Pair>> {
self.key_pair_by_type::<Pair::Generic>(IsWrappedBy::from_ref(public), Pair::ID)
.map(|v| v.map(Into::into))
+5 -9
View File
@@ -31,8 +31,8 @@ use sc_transaction_pool_api::TransactionStatus;
use sp_core::{
blake2_256,
bytes::to_hex,
crypto::{ByteArray, CryptoTypePublicPair, Pair},
ed25519, sr25519,
crypto::{ByteArray, Pair},
ed25519,
testing::{ED25519, SR25519},
H256,
};
@@ -227,9 +227,7 @@ async fn author_should_insert_key() {
api.call::<_, ()>("author_insertKey", params).await.unwrap();
let pubkeys = setup.keystore.keys(ED25519).unwrap();
assert!(
pubkeys.contains(&CryptoTypePublicPair(ed25519::CRYPTO_ID, keypair.public().to_raw_vec()))
);
assert!(pubkeys.contains(&keypair.public().to_raw_vec()));
}
#[tokio::test]
@@ -242,10 +240,8 @@ async fn author_should_rotate_keys() {
SessionKeys::decode(&mut &new_pubkeys[..]).expect("SessionKeys decode successfully");
let ed25519_pubkeys = setup.keystore.keys(ED25519).unwrap();
let sr25519_pubkeys = setup.keystore.keys(SR25519).unwrap();
assert!(ed25519_pubkeys
.contains(&CryptoTypePublicPair(ed25519::CRYPTO_ID, session_keys.ed25519.to_raw_vec())));
assert!(sr25519_pubkeys
.contains(&CryptoTypePublicPair(sr25519::CRYPTO_ID, session_keys.sr25519.to_raw_vec())));
assert!(ed25519_pubkeys.contains(&session_keys.ed25519.to_raw_vec()));
assert!(sr25519_pubkeys.contains(&session_keys.sr25519.to_raw_vec()));
}
#[tokio::test]
@@ -27,10 +27,7 @@ pub use sp_core::crypto::{DeriveError, DeriveJunction, Pair, SecretStringError,
#[doc(hidden)]
pub use sp_core::{
self,
crypto::{
ByteArray, CryptoType, CryptoTypePublicPair, Derive, IsWrappedBy, Public, UncheckedFrom,
Wraps,
},
crypto::{ByteArray, CryptoType, Derive, IsWrappedBy, Public, UncheckedFrom, Wraps},
RuntimeDebug,
};
@@ -170,8 +167,7 @@ macro_rules! app_crypto_pair {
}
}
impl $crate::AppKey for Pair {
type UntypedGeneric = $pair;
impl $crate::AppCrypto for Pair {
type Public = Public;
type Pair = Pair;
type Signature = Signature;
@@ -238,8 +234,7 @@ macro_rules! app_crypto_public_full_crypto {
type Pair = Pair;
}
impl $crate::AppKey for Public {
type UntypedGeneric = $public;
impl $crate::AppCrypto for Public {
type Public = Public;
type Pair = Pair;
type Signature = Signature;
@@ -272,8 +267,7 @@ macro_rules! app_crypto_public_not_full_crypto {
impl $crate::CryptoType for Public {}
impl $crate::AppKey for Public {
type UntypedGeneric = $public;
impl $crate::AppCrypto for Public {
type Public = Public;
type Signature = Signature;
const ID: $crate::KeyTypeId = $key_type;
@@ -306,11 +300,8 @@ macro_rules! app_crypto_public_common {
impl $crate::ByteArray for Public {
const LEN: usize = <$public>::LEN;
}
impl $crate::Public for Public {
fn to_public_crypto_pair(&self) -> $crate::CryptoTypePublicPair {
$crate::CryptoTypePublicPair($crypto_type, $crate::ByteArray::to_raw_vec(self))
}
}
impl $crate::Public for Public {}
impl $crate::AppPublic for Public {
type Generic = $public;
@@ -350,18 +341,6 @@ macro_rules! app_crypto_public_common {
}
}
impl From<Public> for $crate::CryptoTypePublicPair {
fn from(key: Public) -> Self {
(&key).into()
}
}
impl From<&Public> for $crate::CryptoTypePublicPair {
fn from(key: &Public) -> Self {
$crate::CryptoTypePublicPair($crypto_type, $crate::ByteArray::to_raw_vec(key))
}
}
impl<'a> TryFrom<&'a [u8]> for Public {
type Error = ();
@@ -450,8 +429,7 @@ macro_rules! app_crypto_signature_full_crypto {
type Pair = Pair;
}
impl $crate::AppKey for Signature {
type UntypedGeneric = $sig;
impl $crate::AppCrypto for Signature {
type Public = Public;
type Pair = Pair;
type Signature = Signature;
@@ -482,8 +460,7 @@ macro_rules! app_crypto_signature_not_full_crypto {
impl $crate::CryptoType for Signature {}
impl $crate::AppKey for Signature {
type UntypedGeneric = $sig;
impl $crate::AppCrypto for Signature {
type Public = Public;
type Signature = Signature;
const ID: $crate::KeyTypeId = $key_type;
@@ -23,24 +23,22 @@ use sp_core::crypto::{CryptoType, CryptoTypeId, IsWrappedBy, KeyTypeId, Public};
use sp_std::{fmt::Debug, vec::Vec};
/// An application-specific key.
pub trait AppKey: 'static + Send + Sync + Sized + CryptoType + Clone {
/// The corresponding type as a generic crypto type.
type UntypedGeneric: IsWrappedBy<Self>;
pub trait AppCrypto: 'static + Send + Sync + Sized + CryptoType + Clone {
/// Identifier for application-specific key type.
const ID: KeyTypeId;
/// Identifier of the crypto type of this application-specific key type.
const CRYPTO_ID: CryptoTypeId;
/// The corresponding public key type in this application scheme.
type Public: AppPublic;
/// The corresponding key pair type in this application scheme.
#[cfg(feature = "full_crypto")]
type Pair: AppPair;
/// The corresponding signature type in this application scheme.
type Signature: AppSignature;
/// An identifier for this application-specific key type.
const ID: KeyTypeId;
/// The identifier of the crypto type of this application-specific key type.
const CRYPTO_ID: CryptoTypeId;
/// The corresponding key pair type in this application scheme.
#[cfg(feature = "full_crypto")]
type Pair: AppPair;
}
/// Type which implements Hash in std, not when no-std (std variant).
@@ -63,7 +61,7 @@ impl<T: sp_std::hash::Hash> MaybeDebugHash for T {}
/// A application's public key.
pub trait AppPublic:
AppKey + Public + Ord + PartialOrd + Eq + PartialEq + Debug + MaybeHash + codec::Codec
AppCrypto + Public + Ord + PartialOrd + Eq + PartialEq + Debug + MaybeHash + codec::Codec
{
/// The wrapped type which is just a plain instance of `Public`.
type Generic: IsWrappedBy<Self>
@@ -79,14 +77,15 @@ pub trait AppPublic:
/// A application's key pair.
#[cfg(feature = "full_crypto")]
pub trait AppPair: AppKey + Pair<Public = <Self as AppKey>::Public> {
pub trait AppPair: AppCrypto + Pair<Public = <Self as AppCrypto>::Public> {
/// The wrapped type which is just a plain instance of `Pair`.
type Generic: IsWrappedBy<Self>
+ Pair<Public = <<Self as AppKey>::Public as AppPublic>::Generic>;
+ Pair<Public = <<Self as AppCrypto>::Public as AppPublic>::Generic>
+ Pair<Signature = <<Self as AppCrypto>::Signature as AppSignature>::Generic>;
}
/// A application's signature.
pub trait AppSignature: AppKey + Eq + PartialEq + Debug + MaybeHash {
pub trait AppSignature: AppCrypto + Eq + PartialEq + Debug + MaybeHash {
/// The wrapped type which is just a plain instance of `Signature`.
type Generic: IsWrappedBy<Self> + Eq + PartialEq + Debug + MaybeHash;
}
@@ -17,8 +17,11 @@
//! Integration tests for ecdsa
use sp_api::ProvideRuntimeApi;
use sp_application_crypto::ecdsa::{AppPair, AppPublic};
use sp_core::{crypto::Pair, testing::ECDSA};
use sp_application_crypto::ecdsa::AppPair;
use sp_core::{
crypto::{ByteArray, Pair},
testing::ECDSA,
};
use sp_keystore::{testing::MemoryKeystore, Keystore};
use std::sync::Arc;
use substrate_test_runtime_client::{
@@ -35,6 +38,6 @@ fn ecdsa_works_in_runtime() {
.expect("Tests `ecdsa` crypto.");
let supported_keys = keystore.keys(ECDSA).unwrap();
assert!(supported_keys.contains(&public.clone().into()));
assert!(AppPair::verify(&signature, "ecdsa", &AppPublic::from(public)));
assert!(supported_keys.contains(&public.to_raw_vec()));
assert!(AppPair::verify(&signature, "ecdsa", &public));
}
@@ -18,8 +18,11 @@
//! Integration tests for ed25519
use sp_api::ProvideRuntimeApi;
use sp_application_crypto::ed25519::{AppPair, AppPublic};
use sp_core::{crypto::Pair, testing::ED25519};
use sp_application_crypto::ed25519::AppPair;
use sp_core::{
crypto::{ByteArray, Pair},
testing::ED25519,
};
use sp_keystore::{testing::MemoryKeystore, Keystore};
use std::sync::Arc;
use substrate_test_runtime_client::{
@@ -36,6 +39,6 @@ fn ed25519_works_in_runtime() {
.expect("Tests `ed25519` crypto.");
let supported_keys = keystore.keys(ED25519).unwrap();
assert!(supported_keys.contains(&public.clone().into()));
assert!(AppPair::verify(&signature, "ed25519", &AppPublic::from(public)));
assert!(supported_keys.contains(&public.to_raw_vec()));
assert!(AppPair::verify(&signature, "ed25519", &public));
}
@@ -18,8 +18,11 @@
//! Integration tests for sr25519
use sp_api::ProvideRuntimeApi;
use sp_application_crypto::sr25519::{AppPair, AppPublic};
use sp_core::{crypto::Pair, testing::SR25519};
use sp_application_crypto::sr25519::AppPair;
use sp_core::{
crypto::{ByteArray, Pair},
testing::SR25519,
};
use sp_keystore::{testing::MemoryKeystore, Keystore};
use std::sync::Arc;
use substrate_test_runtime_client::{
@@ -36,6 +39,6 @@ fn sr25519_works_in_runtime() {
.expect("Tests `sr25519` crypto.");
let supported_keys = keystore.keys(SR25519).unwrap();
assert!(supported_keys.contains(&public.clone().into()));
assert!(AppPair::verify(&signature, "sr25519", &AppPublic::from(public)));
assert!(supported_keys.contains(&public.to_raw_vec()));
assert!(AppPair::verify(&signature, "sr25519", &public));
}
@@ -48,8 +48,8 @@ pub enum Error {
#[error("Chain lookup failed: {0}")]
ChainLookup(String),
/// Signing failed.
#[error("Failed to sign using key: {0:?}. Reason: {1}")]
CannotSign(Vec<u8>, String),
#[error("Failed to sign: {0}")]
CannotSign(String),
/// Some other error.
#[error(transparent)]
Other(#[from] Box<dyn std::error::Error + Sync + Send + 'static>),
@@ -451,12 +451,11 @@ where
H: Encode,
N: Encode,
{
use sp_application_crypto::AppKey;
use sp_core::crypto::Public;
use sp_application_crypto::AppCrypto;
let encoded = localized_payload(round, set_id, &message);
let signature = keystore
.sign_with(AuthorityId::ID, &public.to_public_crypto_pair(), &encoded[..])
.ed25519_sign(AuthorityId::ID, public.as_ref(), &encoded[..])
.ok()
.flatten()?
.try_into()
+3 -34
View File
@@ -19,8 +19,6 @@
//! Cryptographic utilities.
// end::description[]
#[cfg(feature = "std")]
use crate::hexdisplay::HexDisplay;
use crate::{ed25519, sr25519};
#[cfg(feature = "std")]
use base58::{FromBase58, ToBase58};
@@ -487,10 +485,7 @@ pub trait ByteArray: AsRef<[u8]> + AsMut<[u8]> + for<'a> TryFrom<&'a [u8], Error
}
/// Trait suitable for typical cryptographic PKI key public type.
pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {
/// Return `CryptoTypePublicPair` from public key.
fn to_public_crypto_pair(&self) -> CryptoTypePublicPair;
}
pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {}
/// An opaque 32-byte cryptographic identifier.
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, TypeInfo)]
@@ -689,11 +684,7 @@ mod dummy {
b""
}
}
impl Public for Dummy {
fn to_public_crypto_pair(&self) -> CryptoTypePublicPair {
CryptoTypePublicPair(CryptoTypeId(*b"dumm"), <Self as ByteArray>::to_raw_vec(self))
}
}
impl Public for Dummy {}
impl Pair for Dummy {
type Public = Dummy;
@@ -1118,24 +1109,6 @@ impl<'a> TryFrom<&'a str> for KeyTypeId {
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub struct CryptoTypeId(pub [u8; 4]);
/// A type alias of CryptoTypeId & a public key
#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub struct CryptoTypePublicPair(pub CryptoTypeId, pub Vec<u8>);
#[cfg(feature = "std")]
impl sp_std::fmt::Display for CryptoTypePublicPair {
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
let id = match str::from_utf8(&(self.0).0[..]) {
Ok(id) => id.to_string(),
Err(_) => {
format!("{:#?}", self.0)
},
};
write!(f, "{}-{}", id, HexDisplay::from(&self.1))
}
}
/// Known key types; this also functions as a global registry of key types for projects wishing to
/// avoid collisions with each other.
///
@@ -1223,11 +1196,7 @@ mod tests {
vec![]
}
}
impl Public for TestPublic {
fn to_public_crypto_pair(&self) -> CryptoTypePublicPair {
CryptoTypePublicPair(CryptoTypeId(*b"dumm"), self.to_raw_vec())
}
}
impl Public for TestPublic {}
impl Pair for TestPair {
type Public = TestPublic;
type Seed = [u8; 8];
+2 -19
View File
@@ -24,8 +24,7 @@ use sp_runtime_interface::pass_by::PassByInner;
#[cfg(feature = "std")]
use crate::crypto::Ss58Codec;
use crate::crypto::{
ByteArray, CryptoType, CryptoTypeId, CryptoTypePublicPair, Derive, Public as TraitPublic,
UncheckedFrom,
ByteArray, CryptoType, CryptoTypeId, Derive, Public as TraitPublic, UncheckedFrom,
};
#[cfg(feature = "full_crypto")]
use crate::{
@@ -103,23 +102,7 @@ impl ByteArray for Public {
const LEN: usize = 33;
}
impl TraitPublic for Public {
fn to_public_crypto_pair(&self) -> CryptoTypePublicPair {
CryptoTypePublicPair(CRYPTO_ID, self.to_raw_vec())
}
}
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 TraitPublic for Public {}
impl Derive for Public {}
+2 -20
View File
@@ -31,9 +31,7 @@ use scale_info::TypeInfo;
#[cfg(feature = "std")]
use crate::crypto::Ss58Codec;
use crate::crypto::{
CryptoType, CryptoTypeId, CryptoTypePublicPair, Derive, Public as TraitPublic, UncheckedFrom,
};
use crate::crypto::{CryptoType, CryptoTypeId, Derive, Public as TraitPublic, UncheckedFrom};
#[cfg(feature = "full_crypto")]
use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError};
#[cfg(feature = "full_crypto")]
@@ -355,26 +353,10 @@ impl ByteArray for Public {
const LEN: usize = 32;
}
impl TraitPublic for Public {
fn to_public_crypto_pair(&self) -> CryptoTypePublicPair {
CryptoTypePublicPair(CRYPTO_ID, self.to_raw_vec())
}
}
impl TraitPublic for Public {}
impl Derive 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())
}
}
/// Derive a single hard junction.
#[cfg(feature = "full_crypto")]
fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed {
+2 -21
View File
@@ -34,10 +34,7 @@ use schnorrkel::{
use sp_std::vec::Vec;
use crate::{
crypto::{
ByteArray, CryptoType, CryptoTypeId, CryptoTypePublicPair, Derive, Public as TraitPublic,
UncheckedFrom,
},
crypto::{ByteArray, CryptoType, CryptoTypeId, Derive, Public as TraitPublic, UncheckedFrom},
hash::{H256, H512},
};
use codec::{Decode, Encode, MaxEncodedLen};
@@ -386,23 +383,7 @@ impl ByteArray for Public {
const LEN: usize = 32;
}
impl TraitPublic for Public {
fn to_public_crypto_pair(&self) -> CryptoTypePublicPair {
CryptoTypePublicPair(CRYPTO_ID, self.to_raw_vec())
}
}
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 TraitPublic for Public {}
#[cfg(feature = "std")]
impl From<MiniSecretKey> for Pair {
+3 -6
View File
@@ -762,10 +762,9 @@ pub trait Crypto {
) -> Option<ed25519::Signature> {
self.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!")
.sign_with(id, &pub_key.into(), msg)
.ed25519_sign(id, pub_key, msg)
.ok()
.flatten()
.and_then(|sig| ed25519::Signature::from_slice(&sig))
}
/// Verify `ed25519` signature.
@@ -902,10 +901,9 @@ pub trait Crypto {
) -> Option<sr25519::Signature> {
self.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!")
.sign_with(id, &pub_key.into(), msg)
.sr25519_sign(id, pub_key, msg)
.ok()
.flatten()
.and_then(|sig| sr25519::Signature::from_slice(&sig))
}
/// Verify an `sr25519` signature.
@@ -949,10 +947,9 @@ pub trait Crypto {
) -> Option<ecdsa::Signature> {
self.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!")
.sign_with(id, &pub_key.into(), msg)
.ecdsa_sign(id, pub_key, msg)
.ok()
.flatten()
.and_then(|sig| ecdsa::Signature::from_slice(&sig))
}
/// Sign the given a pre-hashed `msg` with the `ecdsa` key that corresponds to the given public
+137 -72
View File
@@ -21,7 +21,7 @@ pub mod vrf;
use crate::vrf::{VRFSignature, VRFTranscriptData};
use sp_core::{
crypto::{CryptoTypePublicPair, KeyTypeId},
crypto::{ByteArray, CryptoTypeId, KeyTypeId},
ecdsa, ed25519, sr25519,
};
use std::sync::Arc;
@@ -45,84 +45,44 @@ pub enum Error {
/// Something that generates, stores and provides access to secret keys.
pub trait Keystore: Send + Sync {
/// Returns all sr25519 public keys for the given key type.
fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec<sr25519::Public>;
/// Returns all the sr25519 public keys for the given key type.
fn sr25519_public_keys(&self, key_type: 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.
/// Returns an `sr25519::Public` key of the generated key pair or an `Err` if
/// something failed during key generation.
fn sr25519_generate_new(
&self,
id: KeyTypeId,
key_type: KeyTypeId,
seed: Option<&str>,
) -> Result<sr25519::Public, Error>;
/// 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.
/// Generate an sr25519 signature for a given message.
///
/// If the given seed is `Some(_)`, the key pair will only be stored in memory.
/// Receives [`KeyTypeId`] and an [`sr25519::Public`] key to be able to map
/// them to a private key that exists in the keystore.
///
/// Returns the public key of the generated key pair.
fn ed25519_generate_new(
/// Returns an [`sr25519::Signature`] or `None` in case the given `key_type`
/// and `public` combination doesn't exist in the keystore.
/// An `Err` will be returned if generating the signature itself failed.
fn sr25519_sign(
&self,
id: KeyTypeId,
seed: Option<&str>,
) -> Result<ed25519::Public, Error>;
/// 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(&self, id: KeyTypeId, seed: Option<&str>)
-> Result<ecdsa::Public, Error>;
/// Insert a new secret key.
fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()>;
/// List all supported keys
///
/// Returns a set of public keys the signer supports.
fn keys(&self, id: KeyTypeId) -> Result<Vec<CryptoTypePublicPair>, Error>;
/// Checks if the private keys for the given public key and key type combinations exist.
///
/// Returns `true` iff all private keys could be found.
fn has_keys(&self, public_keys: &[(Vec<u8>, KeyTypeId)]) -> bool;
/// Sign with key
///
/// Signs a message with the private key that matches
/// the public key passed.
///
/// Returns the SCALE encoded signature if key is found and supported, `None` if the key doesn't
/// exist or an error when something failed.
fn sign_with(
&self,
id: KeyTypeId,
key: &CryptoTypePublicPair,
key_type: KeyTypeId,
public: &sr25519::Public,
msg: &[u8],
) -> Result<Option<Vec<u8>>, Error>;
) -> Result<Option<sr25519::Signature>, Error>;
/// Generate VRF signature for given transcript data.
/// Generate an sr25519 VRF signature for a given transcript data.
///
/// Receives KeyTypeId and Public key to be able to map
/// them to a private key that exists in the keystore which
/// is, in turn, used for signing the provided transcript.
/// Receives [`KeyTypeId`] and an [`sr25519::Public`] key to be able to map
/// them to a private key that exists in the keystore.
///
/// Returns a result containing the signature data.
/// Namely, VRFOutput and VRFProof which are returned
/// inside the `VRFSignature` container struct.
///
/// This function will return `None` if the given `key_type` and `public` combination
/// doesn't exist in the keystore or an `Err` when something failed.
/// Namely, VRFOutput and VRFProof which are returned inside the `VRFSignature`
/// container struct.
/// Returns `None` if the given `key_type` and `public` combination doesn't
/// exist in the keystore or an `Err` when something failed.
fn sr25519_vrf_sign(
&self,
key_type: KeyTypeId,
@@ -130,24 +90,129 @@ pub trait Keystore: Send + Sync {
transcript_data: VRFTranscriptData,
) -> Result<Option<VRFSignature>, Error>;
/// Generate an ECDSA signature for a given pre-hashed message.
/// Returns all ed25519 public keys for the given key type.
fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec<ed25519::Public>;
/// Generate a new ed25519 key pair for the given key type and an optional seed.
///
/// Returns an `ed25519::Public` key of the generated key pair or an `Err` if
/// something failed during key generation.
fn ed25519_generate_new(
&self,
key_type: KeyTypeId,
seed: Option<&str>,
) -> Result<ed25519::Public, Error>;
/// Generate an ed25519 signature for a given message.
///
/// Receives [`KeyTypeId`] and an [`ed25519::Public`] key to be able to map
/// them to a private key that exists in the keystore.
///
/// Returns an [`ed25519::Signature`] or `None` in case the given `key_type`
/// and `public` combination doesn't exist in the keystore.
/// An `Err` will be returned if generating the signature itself failed.
fn ed25519_sign(
&self,
key_type: KeyTypeId,
public: &ed25519::Public,
msg: &[u8],
) -> Result<Option<ed25519::Signature>, Error>;
/// Returns all ecdsa public keys for the given key type.
fn ecdsa_public_keys(&self, key_type: KeyTypeId) -> Vec<ecdsa::Public>;
/// Generate a new ecdsa key pair for the given key type and an optional seed.
///
/// Returns an `ecdsa::Public` key of the generated key pair or an `Err` if
/// something failed during key generation.
fn ecdsa_generate_new(
&self,
key_type: KeyTypeId,
seed: Option<&str>,
) -> Result<ecdsa::Public, Error>;
/// Generate an ecdsa signature for a given message.
///
/// Receives [`KeyTypeId`] and an [`ecdsa::Public`] key to be able to map
/// them to a private key that exists in the keystore. This private key is,
/// in turn, used for signing the provided pre-hashed message.
/// them to a private key that exists in the keystore.
///
/// The `msg` argument provided should be a hashed message for which an
/// ECDSA signature should be generated.
/// Returns an [`ecdsa::Signature`] or `None` in case the given `key_type`
/// and `public` combination doesn't exist in the keystore.
/// An `Err` will be returned if generating the signature itself failed.
fn ecdsa_sign(
&self,
key_type: KeyTypeId,
public: &ecdsa::Public,
msg: &[u8],
) -> Result<Option<ecdsa::Signature>, Error>;
/// Generate an ecdsa signature for a given pre-hashed message.
///
/// Returns an [`ecdsa::Signature`] or `None` in case the given `id` and
/// `public` combination doesn't exist in the keystore. An `Err` will be
/// returned if generating the signature itself failed.
/// Receives [`KeyTypeId`] and an [`ecdsa::Public`] key to be able to map
/// them to a private key that exists in the keystore.
///
/// Returns an [`ecdsa::Signature`] or `None` in case the given `key_type`
/// and `public` combination doesn't exist in the keystore.
/// An `Err` will be returned if generating the signature itself failed.
fn ecdsa_sign_prehashed(
&self,
id: KeyTypeId,
key_type: KeyTypeId,
public: &ecdsa::Public,
msg: &[u8; 32],
) -> Result<Option<ecdsa::Signature>, Error>;
/// Insert a new secret key.
fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()>;
/// List all supported keys of a given type.
///
/// Returns a set of public keys the signer supports in raw format.
fn keys(&self, key_type: KeyTypeId) -> Result<Vec<Vec<u8>>, Error>;
/// Checks if the private keys for the given public key and key type combinations exist.
///
/// Returns `true` iff all private keys could be found.
fn has_keys(&self, public_keys: &[(Vec<u8>, KeyTypeId)]) -> bool;
/// Convenience method to sign a message using the given key type and a raw public key
/// for secret lookup.
///
/// The message is signed using the cryptographic primitive specified by `crypto_id`.
///
/// Schemes supported by the default trait implementation: sr25519, ed25519 and ecdsa.
/// To support more schemes you can overwrite this method.
///
/// Returns the SCALE encoded signature if key is found and supported, `None` if the key doesn't
/// exist or an error when something failed.
fn sign_with(
&self,
id: KeyTypeId,
crypto_id: CryptoTypeId,
public: &[u8],
msg: &[u8],
) -> Result<Option<Vec<u8>>, Error> {
use codec::Encode;
let signature = match crypto_id {
sr25519::CRYPTO_ID => {
let public = sr25519::Public::from_slice(public)
.map_err(|_| Error::ValidationError("Invalid public key format".into()))?;
self.sr25519_sign(id, &public, msg)?.map(|s| s.encode())
},
ed25519::CRYPTO_ID => {
let public = ed25519::Public::from_slice(public)
.map_err(|_| Error::ValidationError("Invalid public key format".into()))?;
self.ed25519_sign(id, &public, msg)?.map(|s| s.encode())
},
ecdsa::CRYPTO_ID => {
let public = ecdsa::Public::from_slice(public)
.map_err(|_| Error::ValidationError("Invalid public key format".into()))?;
self.ecdsa_sign(id, &public, msg)?.map(|s| s.encode())
},
_ => return Err(Error::KeyNotSupported(id)),
};
Ok(signature)
}
}
/// A shared pointer to a keystore implementation.
+163 -164
View File
@@ -18,7 +18,7 @@
//! Types that should only be used for testing!
use sp_core::{
crypto::{ByteArray, CryptoTypePublicPair, KeyTypeId, Pair},
crypto::{ByteArray, KeyTypeId, Pair},
ecdsa, ed25519, sr25519,
};
@@ -42,51 +42,44 @@ impl MemoryKeystore {
Self::default()
}
fn sr25519_key_pair(&self, id: KeyTypeId, pub_key: &sr25519::Public) -> Option<sr25519::Pair> {
self.keys.read().get(&id).and_then(|inner| {
inner.get(pub_key.as_slice()).map(|s| {
fn sr25519_key_pair(
&self,
key_type: KeyTypeId,
public: &sr25519::Public,
) -> Option<sr25519::Pair> {
self.keys.read().get(&key_type).and_then(|inner| {
inner.get(public.as_slice()).map(|s| {
sr25519::Pair::from_string(s, None).expect("`sr25519` seed slice is valid")
})
})
}
fn ed25519_key_pair(&self, id: KeyTypeId, pub_key: &ed25519::Public) -> Option<ed25519::Pair> {
self.keys.read().get(&id).and_then(|inner| {
inner.get(pub_key.as_slice()).map(|s| {
fn ed25519_key_pair(
&self,
key_type: KeyTypeId,
public: &ed25519::Public,
) -> Option<ed25519::Pair> {
self.keys.read().get(&key_type).and_then(|inner| {
inner.get(public.as_slice()).map(|s| {
ed25519::Pair::from_string(s, None).expect("`ed25519` seed slice is valid")
})
})
}
fn ecdsa_key_pair(&self, id: KeyTypeId, pub_key: &ecdsa::Public) -> Option<ecdsa::Pair> {
self.keys.read().get(&id).and_then(|inner| {
fn ecdsa_key_pair(&self, key_type: KeyTypeId, public: &ecdsa::Public) -> Option<ecdsa::Pair> {
self.keys.read().get(&key_type).and_then(|inner| {
inner
.get(pub_key.as_slice())
.get(public.as_slice())
.map(|s| ecdsa::Pair::from_string(s, None).expect("`ecdsa` seed slice is valid"))
})
}
}
impl Keystore for MemoryKeystore {
fn keys(&self, id: KeyTypeId) -> Result<Vec<CryptoTypePublicPair>, Error> {
fn sr25519_public_keys(&self, key_type: KeyTypeId) -> Vec<sr25519::Public> {
self.keys
.read()
.get(&id)
.map(|map| {
Ok(map.keys().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
}))
})
.unwrap_or_else(|| Ok(vec![]))
}
fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec<sr25519::Public> {
self.keys
.read()
.get(&id)
.get(&key_type)
.map(|keys| {
keys.values()
.map(|s| {
@@ -100,7 +93,7 @@ impl Keystore for MemoryKeystore {
fn sr25519_generate_new(
&self,
id: KeyTypeId,
key_type: KeyTypeId,
seed: Option<&str>,
) -> Result<sr25519::Public, Error> {
match seed {
@@ -110,7 +103,7 @@ impl Keystore for MemoryKeystore {
})?;
self.keys
.write()
.entry(id)
.entry(key_type)
.or_default()
.insert(pair.public().to_raw_vec(), seed.into());
Ok(pair.public())
@@ -119,7 +112,7 @@ impl Keystore for MemoryKeystore {
let (pair, phrase, _) = sr25519::Pair::generate_with_phrase(None);
self.keys
.write()
.entry(id)
.entry(key_type)
.or_default()
.insert(pair.public().to_raw_vec(), phrase);
Ok(pair.public())
@@ -127,137 +120,13 @@ impl Keystore for MemoryKeystore {
}
}
fn ed25519_public_keys(&self, id: KeyTypeId) -> Vec<ed25519::Public> {
self.keys
.read()
.get(&id)
.map(|keys| {
keys.values()
.map(|s| {
ed25519::Pair::from_string(s, None).expect("`ed25519` seed slice is valid")
})
.map(|p| p.public())
.collect()
})
.unwrap_or_default()
}
fn ed25519_generate_new(
fn sr25519_sign(
&self,
id: KeyTypeId,
seed: Option<&str>,
) -> Result<ed25519::Public, Error> {
match seed {
Some(seed) => {
let pair = ed25519::Pair::from_string(seed, None).map_err(|_| {
Error::ValidationError("Generates an `ed25519` pair.".to_owned())
})?;
self.keys
.write()
.entry(id)
.or_default()
.insert(pair.public().to_raw_vec(), seed.into());
Ok(pair.public())
},
None => {
let (pair, phrase, _) = ed25519::Pair::generate_with_phrase(None);
self.keys
.write()
.entry(id)
.or_default()
.insert(pair.public().to_raw_vec(), phrase);
Ok(pair.public())
},
}
}
fn ecdsa_public_keys(&self, id: KeyTypeId) -> Vec<ecdsa::Public> {
self.keys
.read()
.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(
&self,
id: KeyTypeId,
seed: Option<&str>,
) -> Result<ecdsa::Public, Error> {
match seed {
Some(seed) => {
let pair = ecdsa::Pair::from_string(seed, None)
.map_err(|_| Error::ValidationError("Generates an `ecdsa` pair.".to_owned()))?;
self.keys
.write()
.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
.write()
.entry(id)
.or_default()
.insert(pair.public().to_raw_vec(), phrase);
Ok(pair.public())
},
}
}
fn insert(&self, id: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> {
self.keys
.write()
.entry(id)
.or_default()
.insert(public.to_owned(), suri.to_string());
Ok(())
}
fn has_keys(&self, public_keys: &[(Vec<u8>, KeyTypeId)]) -> bool {
public_keys
.iter()
.all(|(k, t)| self.keys.read().get(t).and_then(|s| s.get(k)).is_some())
}
fn sign_with(
&self,
id: KeyTypeId,
key: &CryptoTypePublicPair,
key_type: KeyTypeId,
public: &sr25519::Public,
msg: &[u8],
) -> Result<Option<Vec<u8>>, Error> {
use codec::Encode;
match key.0 {
ed25519::CRYPTO_ID => {
let key_pair = self
.ed25519_key_pair(id, &ed25519::Public::from_slice(key.1.as_slice()).unwrap());
key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose()
},
sr25519::CRYPTO_ID => {
let key_pair = self
.sr25519_key_pair(id, &sr25519::Public::from_slice(key.1.as_slice()).unwrap());
key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose()
},
ecdsa::CRYPTO_ID => {
let key_pair =
self.ecdsa_key_pair(id, &ecdsa::Public::from_slice(key.1.as_slice()).unwrap());
key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose()
},
_ => Err(Error::KeyNotSupported(id)),
}
) -> Result<Option<sr25519::Signature>, Error> {
Ok(self.sr25519_key_pair(key_type, public).map(|pair| pair.sign(msg)))
}
fn sr25519_vrf_sign(
@@ -274,14 +143,144 @@ impl Keystore for MemoryKeystore {
Ok(Some(VRFSignature { output: inout.to_output(), proof }))
}
fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec<ed25519::Public> {
self.keys
.read()
.get(&key_type)
.map(|keys| {
keys.values()
.map(|s| {
ed25519::Pair::from_string(s, None).expect("`ed25519` seed slice is valid")
})
.map(|p| p.public())
.collect()
})
.unwrap_or_default()
}
fn ed25519_generate_new(
&self,
key_type: KeyTypeId,
seed: Option<&str>,
) -> Result<ed25519::Public, Error> {
match seed {
Some(seed) => {
let pair = ed25519::Pair::from_string(seed, None).map_err(|_| {
Error::ValidationError("Generates an `ed25519` pair.".to_owned())
})?;
self.keys
.write()
.entry(key_type)
.or_default()
.insert(pair.public().to_raw_vec(), seed.into());
Ok(pair.public())
},
None => {
let (pair, phrase, _) = ed25519::Pair::generate_with_phrase(None);
self.keys
.write()
.entry(key_type)
.or_default()
.insert(pair.public().to_raw_vec(), phrase);
Ok(pair.public())
},
}
}
fn ed25519_sign(
&self,
key_type: KeyTypeId,
public: &ed25519::Public,
msg: &[u8],
) -> Result<Option<ed25519::Signature>, Error> {
Ok(self.ed25519_key_pair(key_type, public).map(|pair| pair.sign(msg)))
}
fn ecdsa_public_keys(&self, key_type: KeyTypeId) -> Vec<ecdsa::Public> {
self.keys
.read()
.get(&key_type)
.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(
&self,
key_type: KeyTypeId,
seed: Option<&str>,
) -> Result<ecdsa::Public, Error> {
match seed {
Some(seed) => {
let pair = ecdsa::Pair::from_string(seed, None)
.map_err(|_| Error::ValidationError("Generates an `ecdsa` pair.".to_owned()))?;
self.keys
.write()
.entry(key_type)
.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
.write()
.entry(key_type)
.or_default()
.insert(pair.public().to_raw_vec(), phrase);
Ok(pair.public())
},
}
}
fn ecdsa_sign(
&self,
key_type: KeyTypeId,
public: &ecdsa::Public,
msg: &[u8],
) -> Result<Option<ecdsa::Signature>, Error> {
Ok(self.ecdsa_key_pair(key_type, public).map(|pair| pair.sign(msg)))
}
fn ecdsa_sign_prehashed(
&self,
id: KeyTypeId,
key_type: KeyTypeId,
public: &ecdsa::Public,
msg: &[u8; 32],
) -> Result<Option<ecdsa::Signature>, Error> {
let pair = self.ecdsa_key_pair(id, public);
pair.map(|k| k.sign_prehashed(msg)).map(Ok).transpose()
let pair = self.ecdsa_key_pair(key_type, public);
pair.map(|pair| pair.sign_prehashed(msg)).map(Ok).transpose()
}
fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> {
self.keys
.write()
.entry(key_type)
.or_default()
.insert(public.to_owned(), suri.to_string());
Ok(())
}
fn keys(&self, key_type: KeyTypeId) -> Result<Vec<Vec<u8>>, Error> {
let keys = self
.keys
.read()
.get(&key_type)
.map(|map| map.keys().cloned().collect())
.unwrap_or_default();
Ok(keys)
}
fn has_keys(&self, public_keys: &[(Vec<u8>, KeyTypeId)]) -> bool {
public_keys
.iter()
.all(|(k, t)| self.keys.read().get(t).and_then(|s| s.get(k)).is_some())
}
}
@@ -306,7 +305,7 @@ mod tests {
let public = store.ed25519_generate_new(ED25519, None).expect("Generates key");
let public_keys = store.keys(ED25519).unwrap();
let public_keys = store.ed25519_public_keys(ED25519);
assert!(public_keys.contains(&public.into()));
}
@@ -322,7 +321,7 @@ mod tests {
.insert(SR25519, secret_uri, key_pair.public().as_ref())
.expect("Inserts unknown key");
let public_keys = store.keys(SR25519).unwrap();
let public_keys = store.sr25519_public_keys(SR25519);
assert!(public_keys.contains(&key_pair.public().into()));
}
+10 -8
View File
@@ -30,7 +30,7 @@ use crate::{
use impl_trait_for_tuples::impl_for_tuples;
#[cfg(feature = "std")]
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use sp_application_crypto::AppKey;
use sp_application_crypto::AppCrypto;
pub use sp_arithmetic::traits::{
checked_pow, ensure_pow, AtLeast32Bit, AtLeast32BitUnsigned, Bounded, CheckedAdd, CheckedDiv,
CheckedMul, CheckedShl, CheckedShr, CheckedSub, Ensure, EnsureAdd, EnsureAddAssign, EnsureDiv,
@@ -148,10 +148,10 @@ pub trait AppVerify {
}
impl<
S: Verify<Signer = <<T as AppKey>::Public as sp_application_crypto::AppPublic>::Generic>
S: Verify<Signer = <<T as AppCrypto>::Public as sp_application_crypto::AppPublic>::Generic>
+ From<T>,
T: sp_application_crypto::Wraps<Inner = S>
+ sp_application_crypto::AppKey
+ sp_application_crypto::AppCrypto
+ sp_application_crypto::AppSignature
+ AsRef<S>
+ AsMut<S>
@@ -159,16 +159,18 @@ impl<
> AppVerify for T
where
<S as Verify>::Signer: IdentifyAccount<AccountId = <S as Verify>::Signer>,
<<T as AppKey>::Public as sp_application_crypto::AppPublic>::Generic: IdentifyAccount<
AccountId = <<T as AppKey>::Public as sp_application_crypto::AppPublic>::Generic,
<<T as AppCrypto>::Public as sp_application_crypto::AppPublic>::Generic: IdentifyAccount<
AccountId = <<T as AppCrypto>::Public as sp_application_crypto::AppPublic>::Generic,
>,
{
type AccountId = <T as AppKey>::Public;
fn verify<L: Lazy<[u8]>>(&self, msg: L, signer: &<T as AppKey>::Public) -> bool {
type AccountId = <T as AppCrypto>::Public;
fn verify<L: Lazy<[u8]>>(&self, msg: L, signer: &<T as AppCrypto>::Public) -> bool {
use sp_application_crypto::IsWrappedBy;
let inner: &S = self.as_ref();
let inner_pubkey =
<<T as AppKey>::Public as sp_application_crypto::AppPublic>::Generic::from_ref(signer);
<<T as AppCrypto>::Public as sp_application_crypto::AppPublic>::Generic::from_ref(
signer,
);
Verify::verify(inner, msg, inner_pubkey)
}
}