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
+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()));
}