mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 13:21:10 +00:00
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:
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user