Keystore overhaul (#13615)

* Remove 'supported_keys' 'sign_with_any' and 'sign_with_all' from keystore trait

* Remove the aync keystore

* Renaming:
- SyncCryptoStore -> Keystore
- SyncCryptoStorePtr -> KeystorePtr
- KeyStore -> MemoryKeystore

* Fix authority discovery worker and tests

* Rename 'insert_unknown' to 'insert'

* Remove leftover
This commit is contained in:
Davide Galassi
2023-03-17 12:24:14 +01:00
committed by GitHub
parent 91bb2d29ca
commit f110941b7f
49 changed files with 317 additions and 820 deletions
@@ -19,7 +19,7 @@
use sp_api::ProvideRuntimeApi;
use sp_application_crypto::ecdsa::{AppPair, AppPublic};
use sp_core::{crypto::Pair, testing::ECDSA};
use sp_keystore::{testing::KeyStore, SyncCryptoStore};
use sp_keystore::{testing::MemoryKeystore, Keystore};
use std::sync::Arc;
use substrate_test_runtime_client::{
runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt,
@@ -27,14 +27,14 @@ use substrate_test_runtime_client::{
#[test]
fn ecdsa_works_in_runtime() {
let keystore = Arc::new(KeyStore::new());
let keystore = Arc::new(MemoryKeystore::new());
let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build();
let (signature, public) = test_client
.runtime_api()
.test_ecdsa_crypto(test_client.chain_info().genesis_hash)
.expect("Tests `ecdsa` crypto.");
let supported_keys = SyncCryptoStore::keys(&*keystore, ECDSA).unwrap();
let supported_keys = Keystore::keys(&*keystore, ECDSA).unwrap();
assert!(supported_keys.contains(&public.clone().into()));
assert!(AppPair::verify(&signature, "ecdsa", &AppPublic::from(public)));
}
@@ -20,7 +20,7 @@
use sp_api::ProvideRuntimeApi;
use sp_application_crypto::ed25519::{AppPair, AppPublic};
use sp_core::{crypto::Pair, testing::ED25519};
use sp_keystore::{testing::KeyStore, SyncCryptoStore};
use sp_keystore::{testing::MemoryKeystore, Keystore};
use std::sync::Arc;
use substrate_test_runtime_client::{
runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt,
@@ -28,14 +28,14 @@ use substrate_test_runtime_client::{
#[test]
fn ed25519_works_in_runtime() {
let keystore = Arc::new(KeyStore::new());
let keystore = Arc::new(MemoryKeystore::new());
let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build();
let (signature, public) = test_client
.runtime_api()
.test_ed25519_crypto(test_client.chain_info().genesis_hash)
.expect("Tests `ed25519` crypto.");
let supported_keys = SyncCryptoStore::keys(&*keystore, ED25519).unwrap();
let supported_keys = Keystore::keys(&*keystore, ED25519).unwrap();
assert!(supported_keys.contains(&public.clone().into()));
assert!(AppPair::verify(&signature, "ed25519", &AppPublic::from(public)));
}
@@ -20,7 +20,7 @@
use sp_api::ProvideRuntimeApi;
use sp_application_crypto::sr25519::{AppPair, AppPublic};
use sp_core::{crypto::Pair, testing::SR25519};
use sp_keystore::{testing::KeyStore, SyncCryptoStore};
use sp_keystore::{testing::MemoryKeystore, Keystore};
use std::sync::Arc;
use substrate_test_runtime_client::{
runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt,
@@ -28,14 +28,14 @@ use substrate_test_runtime_client::{
#[test]
fn sr25519_works_in_runtime() {
let keystore = Arc::new(KeyStore::new());
let keystore = Arc::new(MemoryKeystore::new());
let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build();
let (signature, public) = test_client
.runtime_api()
.test_sr25519_crypto(test_client.chain_info().genesis_hash)
.expect("Tests `sr25519` crypto.");
let supported_keys = SyncCryptoStore::keys(&*keystore, SR25519).unwrap();
let supported_keys = Keystore::keys(&*keystore, SR25519).unwrap();
assert!(supported_keys.contains(&public.clone().into()));
assert!(AppPair::verify(&signature, "sr25519", &AppPublic::from(public)));
}
@@ -253,7 +253,7 @@ mod tests {
use crate::{crypto, known_payloads, KEY_TYPE};
use codec::Decode;
use sp_core::{keccak_256, Pair};
use sp_keystore::{testing::KeyStore, SyncCryptoStore, SyncCryptoStorePtr};
use sp_keystore::{testing::MemoryKeystore, Keystore, KeystorePtr};
type TestCommitment = Commitment<u128>;
type TestSignedCommitment = SignedCommitment<u128, crypto::Signature>;
@@ -263,20 +263,18 @@ mod tests {
// The mock signatures are equivalent to the ones produced by the BEEFY keystore
fn mock_signatures() -> (crypto::Signature, crypto::Signature) {
let store: SyncCryptoStorePtr = KeyStore::new().into();
let store: KeystorePtr = MemoryKeystore::new().into();
let alice = sp_core::ecdsa::Pair::from_string("//Alice", None).unwrap();
let _ =
SyncCryptoStore::insert_unknown(&*store, KEY_TYPE, "//Alice", alice.public().as_ref())
.unwrap();
let _ = Keystore::insert(&*store, KEY_TYPE, "//Alice", alice.public().as_ref()).unwrap();
let msg = keccak_256(b"This is the first message");
let sig1 = SyncCryptoStore::ecdsa_sign_prehashed(&*store, KEY_TYPE, &alice.public(), &msg)
let sig1 = Keystore::ecdsa_sign_prehashed(&*store, KEY_TYPE, &alice.public(), &msg)
.unwrap()
.unwrap();
let msg = keccak_256(b"This is the second message");
let sig2 = SyncCryptoStore::ecdsa_sign_prehashed(&*store, KEY_TYPE, &alice.public(), &msg)
let sig2 = Keystore::ecdsa_sign_prehashed(&*store, KEY_TYPE, &alice.public(), &msg)
.unwrap()
.unwrap();
@@ -76,7 +76,7 @@ impl<TBlockNumber, TMerkleRoot> SignedCommitmentWitness<TBlockNumber, TMerkleRoo
mod tests {
use sp_core::{keccak_256, Pair};
use sp_keystore::{testing::KeyStore, SyncCryptoStore, SyncCryptoStorePtr};
use sp_keystore::{testing::MemoryKeystore, Keystore, KeystorePtr};
use super::*;
use codec::Decode;
@@ -90,20 +90,18 @@ mod tests {
// The mock signatures are equivalent to the ones produced by the BEEFY keystore
fn mock_signatures() -> (crypto::Signature, crypto::Signature) {
let store: SyncCryptoStorePtr = KeyStore::new().into();
let store: KeystorePtr = MemoryKeystore::new().into();
let alice = sp_core::ecdsa::Pair::from_string("//Alice", None).unwrap();
let _ =
SyncCryptoStore::insert_unknown(&*store, KEY_TYPE, "//Alice", alice.public().as_ref())
.unwrap();
let _ = Keystore::insert(&*store, KEY_TYPE, "//Alice", alice.public().as_ref()).unwrap();
let msg = keccak_256(b"This is the first message");
let sig1 = SyncCryptoStore::ecdsa_sign_prehashed(&*store, KEY_TYPE, &alice.public(), &msg)
let sig1 = Keystore::ecdsa_sign_prehashed(&*store, KEY_TYPE, &alice.public(), &msg)
.unwrap()
.unwrap();
let msg = keccak_256(b"This is the second message");
let sig2 = SyncCryptoStore::ecdsa_sign_prehashed(&*store, KEY_TYPE, &alice.public(), &msg)
let sig2 = Keystore::ecdsa_sign_prehashed(&*store, KEY_TYPE, &alice.public(), &msg)
.unwrap()
.unwrap();
@@ -28,7 +28,7 @@ use serde::Serialize;
use codec::{Codec, Decode, Encode, Input};
use scale_info::TypeInfo;
#[cfg(feature = "std")]
use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr};
use sp_keystore::{Keystore, KeystorePtr};
use sp_runtime::{
traits::{Header as HeaderT, NumberFor},
ConsensusEngineId, RuntimeDebug,
@@ -444,7 +444,7 @@ where
/// Localizes the message to the given set and round and signs the payload.
#[cfg(feature = "std")]
pub fn sign_message<H, N>(
keystore: SyncCryptoStorePtr,
keystore: KeystorePtr,
message: grandpa::Message<H, N>,
public: AuthorityId,
round: RoundNumber,
@@ -458,7 +458,7 @@ where
use sp_core::crypto::Public;
let encoded = localized_payload(round, set_id, &message);
let signature = SyncCryptoStore::sign_with(
let signature = Keystore::sign_with(
&*keystore,
AuthorityId::ID,
&public.to_public_crypto_pair(),
+11 -13
View File
@@ -43,7 +43,7 @@ use sp_core::{
traits::TaskExecutorExt,
};
#[cfg(feature = "std")]
use sp_keystore::{KeystoreExt, SyncCryptoStore};
use sp_keystore::{Keystore, KeystoreExt};
use sp_core::{
crypto::KeyTypeId,
@@ -734,7 +734,7 @@ pub trait Crypto {
let keystore = &***self
.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!");
SyncCryptoStore::ed25519_public_keys(keystore, id)
Keystore::ed25519_public_keys(keystore, id)
}
/// Generate an `ed22519` key for the given key type using an optional `seed` and
@@ -748,8 +748,7 @@ pub trait Crypto {
let keystore = &***self
.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!");
SyncCryptoStore::ed25519_generate_new(keystore, id, seed)
.expect("`ed25519_generate` failed")
Keystore::ed25519_generate_new(keystore, id, seed).expect("`ed25519_generate` failed")
}
/// Sign the given `msg` with the `ed25519` key that corresponds to the given public key and
@@ -765,7 +764,7 @@ pub trait Crypto {
let keystore = &***self
.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!");
SyncCryptoStore::sign_with(keystore, id, &pub_key.into(), msg)
Keystore::sign_with(keystore, id, &pub_key.into(), msg)
.ok()
.flatten()
.and_then(|sig| ed25519::Signature::from_slice(&sig))
@@ -877,7 +876,7 @@ pub trait Crypto {
let keystore = &***self
.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!");
SyncCryptoStore::sr25519_public_keys(keystore, id)
Keystore::sr25519_public_keys(keystore, id)
}
/// Generate an `sr22519` key for the given key type using an optional seed and
@@ -891,8 +890,7 @@ pub trait Crypto {
let keystore = &***self
.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!");
SyncCryptoStore::sr25519_generate_new(keystore, id, seed)
.expect("`sr25519_generate` failed")
Keystore::sr25519_generate_new(keystore, id, seed).expect("`sr25519_generate` failed")
}
/// Sign the given `msg` with the `sr25519` key that corresponds to the given public key and
@@ -908,7 +906,7 @@ pub trait Crypto {
let keystore = &***self
.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!");
SyncCryptoStore::sign_with(keystore, id, &pub_key.into(), msg)
Keystore::sign_with(keystore, id, &pub_key.into(), msg)
.ok()
.flatten()
.and_then(|sig| sr25519::Signature::from_slice(&sig))
@@ -927,7 +925,7 @@ pub trait Crypto {
let keystore = &***self
.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!");
SyncCryptoStore::ecdsa_public_keys(keystore, id)
Keystore::ecdsa_public_keys(keystore, id)
}
/// Generate an `ecdsa` key for the given key type using an optional `seed` and
@@ -941,7 +939,7 @@ pub trait Crypto {
let keystore = &***self
.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!");
SyncCryptoStore::ecdsa_generate_new(keystore, id, seed).expect("`ecdsa_generate` failed")
Keystore::ecdsa_generate_new(keystore, id, seed).expect("`ecdsa_generate` failed")
}
/// Sign the given `msg` with the `ecdsa` key that corresponds to the given public key and
@@ -957,7 +955,7 @@ pub trait Crypto {
let keystore = &***self
.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!");
SyncCryptoStore::sign_with(keystore, id, &pub_key.into(), msg)
Keystore::sign_with(keystore, id, &pub_key.into(), msg)
.ok()
.flatten()
.and_then(|sig| ecdsa::Signature::from_slice(&sig))
@@ -976,7 +974,7 @@ pub trait Crypto {
let keystore = &***self
.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!");
SyncCryptoStore::ecdsa_sign_prehashed(keystore, id, pub_key, msg).ok().flatten()
Keystore::ecdsa_sign_prehashed(keystore, id, pub_key, msg).ok().flatten()
}
/// Verify `ecdsa` signature.
-1
View File
@@ -13,7 +13,6 @@ documentation = "https://docs.rs/sp-core"
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
async-trait = "0.1.57"
codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] }
futures = "0.3.21"
merlin = { version = "2.0", default-features = false }
+8 -242
View File
@@ -20,15 +20,13 @@ pub mod testing;
pub mod vrf;
use crate::vrf::{VRFSignature, VRFTranscriptData};
use async_trait::async_trait;
use futures::{executor::block_on, future::join_all};
use sp_core::{
crypto::{CryptoTypePublicPair, KeyTypeId},
ecdsa, ed25519, sr25519,
};
use std::sync::Arc;
/// CryptoStore error
/// Keystore error
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Public key type is not supported
@@ -45,179 +43,8 @@ pub enum Error {
Other(String),
}
/// Something that generates, stores and provides access to keys.
#[async_trait]
pub trait CryptoStore: Send + Sync {
/// Returns all sr25519 public keys for the given key type.
async 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.
async fn sr25519_generate_new(
&self,
id: KeyTypeId,
seed: Option<&str>,
) -> Result<sr25519::Public, Error>;
/// Returns all ed25519 public keys for the given key type.
async 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.
async fn ed25519_generate_new(
&self,
id: KeyTypeId,
seed: Option<&str>,
) -> Result<ed25519::Public, Error>;
/// Returns all ecdsa public keys for the given key type.
async 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.
async fn ecdsa_generate_new(
&self,
id: KeyTypeId,
seed: Option<&str>,
) -> Result<ecdsa::Public, Error>;
/// 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`.
async fn insert_unknown(&self, id: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()>;
/// Find intersection between provided keys and supported keys
///
/// Provided a list of (CryptoTypeId,[u8]) pairs, this would return
/// a filtered set of public keys which are supported by the keystore.
async fn supported_keys(
&self,
id: KeyTypeId,
keys: Vec<CryptoTypePublicPair>,
) -> Result<Vec<CryptoTypePublicPair>, Error>;
/// List all supported keys
///
/// Returns a set of public keys the signer supports.
async 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.
async 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.
async fn sign_with(
&self,
id: KeyTypeId,
key: &CryptoTypePublicPair,
msg: &[u8],
) -> Result<Option<Vec<u8>>, Error>;
/// Sign with any key
///
/// Given a list of public keys, find the first supported key and
/// sign the provided message with that key.
///
/// Returns a tuple of the used key and the SCALE encoded signature or `None` if no key could
/// be found to sign.
async fn sign_with_any(
&self,
id: KeyTypeId,
keys: Vec<CryptoTypePublicPair>,
msg: &[u8],
) -> Result<Option<(CryptoTypePublicPair, Vec<u8>)>, Error> {
if keys.len() == 1 {
return Ok(self.sign_with(id, &keys[0], msg).await?.map(|s| (keys[0].clone(), s)))
} else {
for k in self.supported_keys(id, keys).await? {
if let Ok(Some(sign)) = self.sign_with(id, &k, msg).await {
return Ok(Some((k, sign)))
}
}
}
Ok(None)
}
/// Sign with all keys
///
/// Provided a list of public keys, sign a message with
/// each key given that the key is supported.
///
/// Returns a list of `Result`s each representing the SCALE encoded
/// signature of each key, `None` if the key doesn't exist or a error when something failed.
async fn sign_with_all(
&self,
id: KeyTypeId,
keys: Vec<CryptoTypePublicPair>,
msg: &[u8],
) -> Result<Vec<Result<Option<Vec<u8>>, Error>>, ()> {
let futs = keys.iter().map(|k| self.sign_with(id, k, msg));
Ok(join_all(futs).await)
}
/// Generate VRF signature for 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.
///
/// 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.
async fn sr25519_vrf_sign(
&self,
key_type: KeyTypeId,
public: &sr25519::Public,
transcript_data: VRFTranscriptData,
) -> Result<Option<VRFSignature>, Error>;
/// Generate an ECDSA signature for a given pre-hashed 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.
///
/// 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 `id` and
/// `public` combination doesn't exist in the keystore. An `Err` will be
/// returned if generating the signature itself failed.
async fn ecdsa_sign_prehashed(
&self,
id: KeyTypeId,
public: &ecdsa::Public,
msg: &[u8; 32],
) -> Result<Option<ecdsa::Signature>, Error>;
}
/// Sync version of the CryptoStore
///
/// Some parts of Substrate still rely on a sync version of the `CryptoStore`.
/// To make the transition easier this auto trait wraps any async `CryptoStore` and
/// exposes a `sync` interface using `block_on`. Usage of this is deprecated and it
/// will be removed as soon as the internal usage has transitioned successfully.
/// If you are starting out building something new **do not use this**,
/// instead, use [`CryptoStore`].
pub trait SyncCryptoStore: CryptoStore + Send + Sync {
/// 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>;
@@ -257,30 +84,13 @@ pub trait SyncCryptoStore: CryptoStore + Send + Sync {
fn ecdsa_generate_new(&self, id: KeyTypeId, seed: Option<&str>)
-> Result<ecdsa::Public, Error>;
/// 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(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()>;
/// Find intersection between provided keys and supported keys
///
/// Provided a list of (CryptoTypeId,[u8]) pairs, this would return
/// a filtered set of public keys which are supported by the keystore.
fn supported_keys(
&self,
id: KeyTypeId,
keys: Vec<CryptoTypePublicPair>,
) -> Result<Vec<CryptoTypePublicPair>, 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> {
block_on(CryptoStore::keys(self, id))
}
fn keys(&self, id: KeyTypeId) -> Result<Vec<CryptoTypePublicPair>, Error>;
/// Checks if the private keys for the given public key and key type combinations exist.
///
@@ -301,50 +111,6 @@ pub trait SyncCryptoStore: CryptoStore + Send + Sync {
msg: &[u8],
) -> Result<Option<Vec<u8>>, Error>;
/// Sign with any key
///
/// Given a list of public keys, find the first supported key and
/// sign the provided message with that key.
///
/// Returns a tuple of the used key and the SCALE encoded signature or `None` if no key could
/// be found to sign.
fn sign_with_any(
&self,
id: KeyTypeId,
keys: Vec<CryptoTypePublicPair>,
msg: &[u8],
) -> Result<Option<(CryptoTypePublicPair, Vec<u8>)>, Error> {
if keys.len() == 1 {
return Ok(
SyncCryptoStore::sign_with(self, id, &keys[0], msg)?.map(|s| (keys[0].clone(), s))
)
} else {
for k in SyncCryptoStore::supported_keys(self, id, keys)? {
if let Ok(Some(sign)) = SyncCryptoStore::sign_with(self, id, &k, msg) {
return Ok(Some((k, sign)))
}
}
}
Ok(None)
}
/// Sign with all keys
///
/// Provided a list of public keys, sign a message with
/// each key given that the key is supported.
///
/// Returns a list of `Result`s each representing the SCALE encoded
/// signature of each key, `None` if the key doesn't exist or an error when something failed.
fn sign_with_all(
&self,
id: KeyTypeId,
keys: Vec<CryptoTypePublicPair>,
msg: &[u8],
) -> Result<Vec<Result<Option<Vec<u8>>, Error>>, ()> {
Ok(keys.iter().map(|k| SyncCryptoStore::sign_with(self, id, k, msg)).collect())
}
/// Generate VRF signature for given transcript data.
///
/// Receives KeyTypeId and Public key to be able to map
@@ -385,9 +151,9 @@ pub trait SyncCryptoStore: CryptoStore + Send + Sync {
}
/// A pointer to a keystore.
pub type SyncCryptoStorePtr = Arc<dyn SyncCryptoStore>;
pub type KeystorePtr = Arc<dyn Keystore>;
sp_externalities::decl_extension! {
/// The keystore extension to register/retrieve from the externalities.
pub struct KeystoreExt(SyncCryptoStorePtr);
pub struct KeystoreExt(KeystorePtr);
}
+23 -133
View File
@@ -24,23 +24,19 @@ use sp_core::{
use crate::{
vrf::{make_transcript, VRFSignature, VRFTranscriptData},
CryptoStore, Error, SyncCryptoStore, SyncCryptoStorePtr,
Error, Keystore, KeystorePtr,
};
use async_trait::async_trait;
use parking_lot::RwLock;
use std::{
collections::{HashMap, HashSet},
sync::Arc,
};
use std::{collections::HashMap, sync::Arc};
/// A keystore implementation usable in tests.
#[derive(Default)]
pub struct KeyStore {
pub struct MemoryKeystore {
/// `KeyTypeId` maps to public keys and public keys map to private keys.
keys: Arc<RwLock<HashMap<KeyTypeId, HashMap<Vec<u8>, String>>>>,
}
impl KeyStore {
impl MemoryKeystore {
/// Creates a new instance of `Self`.
pub fn new() -> Self {
Self::default()
@@ -71,93 +67,7 @@ impl KeyStore {
}
}
#[async_trait]
impl CryptoStore for KeyStore {
async fn keys(&self, id: KeyTypeId) -> Result<Vec<CryptoTypePublicPair>, Error> {
SyncCryptoStore::keys(self, id)
}
async fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec<sr25519::Public> {
SyncCryptoStore::sr25519_public_keys(self, id)
}
async fn sr25519_generate_new(
&self,
id: KeyTypeId,
seed: Option<&str>,
) -> Result<sr25519::Public, Error> {
SyncCryptoStore::sr25519_generate_new(self, id, seed)
}
async fn ed25519_public_keys(&self, id: KeyTypeId) -> Vec<ed25519::Public> {
SyncCryptoStore::ed25519_public_keys(self, id)
}
async fn ed25519_generate_new(
&self,
id: KeyTypeId,
seed: Option<&str>,
) -> Result<ed25519::Public, Error> {
SyncCryptoStore::ed25519_generate_new(self, id, seed)
}
async fn ecdsa_public_keys(&self, id: KeyTypeId) -> Vec<ecdsa::Public> {
SyncCryptoStore::ecdsa_public_keys(self, id)
}
async fn ecdsa_generate_new(
&self,
id: KeyTypeId,
seed: Option<&str>,
) -> Result<ecdsa::Public, Error> {
SyncCryptoStore::ecdsa_generate_new(self, id, seed)
}
async fn insert_unknown(&self, id: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> {
SyncCryptoStore::insert_unknown(self, id, suri, public)
}
async fn has_keys(&self, public_keys: &[(Vec<u8>, KeyTypeId)]) -> bool {
SyncCryptoStore::has_keys(self, public_keys)
}
async fn supported_keys(
&self,
id: KeyTypeId,
keys: Vec<CryptoTypePublicPair>,
) -> std::result::Result<Vec<CryptoTypePublicPair>, Error> {
SyncCryptoStore::supported_keys(self, id, keys)
}
async fn sign_with(
&self,
id: KeyTypeId,
key: &CryptoTypePublicPair,
msg: &[u8],
) -> Result<Option<Vec<u8>>, Error> {
SyncCryptoStore::sign_with(self, id, key, msg)
}
async fn sr25519_vrf_sign(
&self,
key_type: KeyTypeId,
public: &sr25519::Public,
transcript_data: VRFTranscriptData,
) -> Result<Option<VRFSignature>, Error> {
SyncCryptoStore::sr25519_vrf_sign(self, key_type, public, transcript_data)
}
async fn ecdsa_sign_prehashed(
&self,
id: KeyTypeId,
public: &ecdsa::Public,
msg: &[u8; 32],
) -> Result<Option<ecdsa::Signature>, Error> {
SyncCryptoStore::ecdsa_sign_prehashed(self, id, public, msg)
}
}
impl SyncCryptoStore for KeyStore {
impl Keystore for MemoryKeystore {
fn keys(&self, id: KeyTypeId) -> Result<Vec<CryptoTypePublicPair>, Error> {
self.keys
.read()
@@ -304,7 +214,7 @@ impl SyncCryptoStore for KeyStore {
}
}
fn insert_unknown(&self, id: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> {
fn insert(&self, id: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> {
self.keys
.write()
.entry(id)
@@ -319,17 +229,6 @@ impl SyncCryptoStore for KeyStore {
.all(|(k, t)| self.keys.read().get(t).and_then(|s| s.get(k)).is_some())
}
fn supported_keys(
&self,
id: KeyTypeId,
keys: Vec<CryptoTypePublicPair>,
) -> std::result::Result<Vec<CryptoTypePublicPair>, Error> {
let provided_keys = keys.into_iter().collect::<HashSet<_>>();
let all_keys = SyncCryptoStore::keys(self, id)?.into_iter().collect::<HashSet<_>>();
Ok(provided_keys.intersection(&all_keys).cloned().collect())
}
fn sign_with(
&self,
id: KeyTypeId,
@@ -386,14 +285,8 @@ impl SyncCryptoStore for KeyStore {
}
}
impl Into<SyncCryptoStorePtr> for KeyStore {
fn into(self) -> SyncCryptoStorePtr {
Arc::new(self)
}
}
impl Into<Arc<dyn CryptoStore>> for KeyStore {
fn into(self) -> Arc<dyn CryptoStore> {
impl Into<KeystorePtr> for MemoryKeystore {
fn into(self) -> KeystorePtr {
Arc::new(self)
}
}
@@ -401,7 +294,7 @@ impl Into<Arc<dyn CryptoStore>> for KeyStore {
#[cfg(test)]
mod tests {
use super::*;
use crate::{vrf::VRFTranscriptValue, SyncCryptoStore};
use crate::vrf::VRFTranscriptValue;
use sp_core::{
sr25519,
testing::{ECDSA, ED25519, SR25519},
@@ -409,34 +302,33 @@ mod tests {
#[test]
fn store_key_and_extract() {
let store = KeyStore::new();
let store = MemoryKeystore::new();
let public =
SyncCryptoStore::ed25519_generate_new(&store, ED25519, None).expect("Generates key");
let public = Keystore::ed25519_generate_new(&store, ED25519, None).expect("Generates key");
let public_keys = SyncCryptoStore::keys(&store, ED25519).unwrap();
let public_keys = Keystore::keys(&store, ED25519).unwrap();
assert!(public_keys.contains(&public.into()));
}
#[test]
fn store_unknown_and_extract_it() {
let store = KeyStore::new();
let store = MemoryKeystore::new();
let secret_uri = "//Alice";
let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair");
SyncCryptoStore::insert_unknown(&store, SR25519, secret_uri, key_pair.public().as_ref())
Keystore::insert(&store, SR25519, secret_uri, key_pair.public().as_ref())
.expect("Inserts unknown key");
let public_keys = SyncCryptoStore::keys(&store, SR25519).unwrap();
let public_keys = Keystore::keys(&store, SR25519).unwrap();
assert!(public_keys.contains(&key_pair.public().into()));
}
#[test]
fn vrf_sign() {
let store = KeyStore::new();
let store = MemoryKeystore::new();
let secret_uri = "//Alice";
let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair");
@@ -450,7 +342,7 @@ mod tests {
],
};
let result = SyncCryptoStore::sr25519_vrf_sign(
let result = Keystore::sr25519_vrf_sign(
&store,
SR25519,
&key_pair.public(),
@@ -458,18 +350,18 @@ mod tests {
);
assert!(result.unwrap().is_none());
SyncCryptoStore::insert_unknown(&store, SR25519, secret_uri, key_pair.public().as_ref())
Keystore::insert(&store, SR25519, secret_uri, key_pair.public().as_ref())
.expect("Inserts unknown key");
let result =
SyncCryptoStore::sr25519_vrf_sign(&store, SR25519, &key_pair.public(), transcript_data);
Keystore::sr25519_vrf_sign(&store, SR25519, &key_pair.public(), transcript_data);
assert!(result.unwrap().is_some());
}
#[test]
fn ecdsa_sign_prehashed_works() {
let store = KeyStore::new();
let store = MemoryKeystore::new();
let suri = "//Alice";
let pair = ecdsa::Pair::from_string(suri, None).unwrap();
@@ -477,15 +369,13 @@ mod tests {
let msg = sp_core::keccak_256(b"this should be a hashed message");
// no key in key store
let res =
SyncCryptoStore::ecdsa_sign_prehashed(&store, ECDSA, &pair.public(), &msg).unwrap();
let res = Keystore::ecdsa_sign_prehashed(&store, ECDSA, &pair.public(), &msg).unwrap();
assert!(res.is_none());
// insert key, sign again
SyncCryptoStore::insert_unknown(&store, ECDSA, suri, pair.public().as_ref()).unwrap();
Keystore::insert(&store, ECDSA, suri, pair.public().as_ref()).unwrap();
let res =
SyncCryptoStore::ecdsa_sign_prehashed(&store, ECDSA, &pair.public(), &msg).unwrap();
let res = Keystore::ecdsa_sign_prehashed(&store, ECDSA, &pair.public(), &msg).unwrap();
assert!(res.is_some());
}
}