Every gadget would definitely need access to some sort of key management, like signing transactions and signing messages over network.
A Keystore should be exposed as a trait with default implementations that could be utilized as required, so we split the keystore into a frontend and a backend, with a trait that sits in between.
Possible Backends:
in Memory Keystore (useful for testing)
File-based Keystore
AWS KMS based Keystore
GCP CKM based Keystore
…etc.
Keystore backend trait design
pub trait KeystoreBackend {
/// Generate a new sr25519 key pair with an optional seed.
///
/// Returns an `sr25519::Public` key of the generated key pair or an `Err` if
/// something failed during key generation.
fn sr25519_generate_new(
&self,
seed: Option<&str>,
) -> Result<sr25519::Public, Error>;
/// Generate an sr25519 signature for a given message.
///
/// Receives an [`sr25519::Public`] key to be able to map
/// them to a private key that exists in the keystore.
///
/// Returns an [`sr25519::Signature`] or `None` in case the given
/// `public` doesn't exist in the keystore.
/// An `Err` will be returned if generating the signature itself failed.
fn sr25519_sign(
&self,
public: &sr25519::Public,
msg: &[u8],
) -> Result<Option<sr25519::Signature>, Error>;
/// Generate a new ed25519 key pair with 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,
seed: Option<&str>,
) -> Result<ed25519::Public, Error>;
/// Generate an ed25519 signature for a given message.
///
/// Receives an [`ed25519::Public`] key to be able to map
/// it to a private key that exists in the keystore.
///
/// Returns an [`ed25519::Signature`] or `None` in case the given
/// `public` doesn't exist in the keystore.
/// An `Err` will be returned if generating the signature itself failed.
fn ed25519_sign(
&self,
public: &ed25519::Public,
msg: &[u8],
) -> Result<Option<ed25519::Signature>, Error>;
/// Generate a new ecdsa key pair with 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,
seed: Option<&str>,
) -> Result<ecdsa::Public, Error>;
/// Generate an ecdsa signature for a given message.
///
/// Receives an [`ecdsa::Public`] key to be able to map
/// it to a private key that exists in the keystore.
///
/// Returns an [`ecdsa::Signature`] or `None` in case the given
/// `public` doesn't exist in the keystore.
/// An `Err` will be returned if generating the signature itself failed.
fn ecdsa_sign(
&self,
public: &ecdsa::Public,
msg: &[u8],
) -> Result<Option<ecdsa::Signature>, Error>;
/// Generate a new bls381 key pair with an optional seed.
///
/// Returns an `bls381::Public` key of the generated key pair or an `Err` if
/// something failed during key generation.
fn bls381_generate_new(
&self,
seed: Option<&str>,
) -> Result<bls381::Public, Error>;
/// Generate an bls381 signature for a given message.
///
/// Receives an [`bls381::Public`] key to be able to map
/// it to a private key that exists in the keystore.
///
/// Returns an [`bls381::Signature`] or `None` in case the given
/// `public` doesn't exist in the keystore.
/// An `Err` will be returned if generating the signature itself failed.
fn bls381_sign(
&self,
public: &bls381::Public,
msg: &[u8],
) -> Result<Option<bls381::Signature>, Error>;
/// Checks if the private key for the given public key exist.
///
/// Returns `true` if the private key could be found.
fn has_key(&self, public: &[u8]) -> bool;
/// Returns the Keypair for the given [`sr25519::Public`] if it does exist, otherwise returns `None`.
/// An `Err` will be returned if finding the key operation itself failed.
fn expose_sr25519_pair(&self, public: &sr25519::Public) -> Result<Option<sr25519::Pair>, Error>;
/// Returns the Keypair for the given [`ecdsa::Public`] if it does exist, otherwise returns `None`.
/// An `Err` will be returned if finding the key operation itself failed.
fn expose_ecdsa_pair(&self, public: &ecdsa::Public) -> Result<Option<ecdsa::Pair>, Error>;
/// Returns the Keypair for the given [`ed25519::Public`] if it does exist, otherwise returns `None`.
/// An `Err` will be returned if finding the key operation itself failed.
fn expose_ed25519_pair(&self, public: &ed25519::Public) -> Result<Option<ed25519::Pair>, Error>;
/// Returns the Keypair for the given [`bls381::Public`] if it does exist, otherwise returns `None`.
/// An `Err` will be returned if finding the key operation itself failed.
fn expose_bls381_pair(&self, public: &bls381::Public) -> Result<Option<bls381::Pair>, Error>;
}
Constraints
This new Keystore should not directly depend on sp- or sc- crates, instead we could have a Substrate Keystore backend behind a feature flag.
For each backend implemented, we should keep it behind a feature flag (the mem backend is enabled by default).
Overview
Every gadget would definitely need access to some sort of key management, like signing transactions and signing messages over network.
A Keystore should be exposed as a trait with default implementations that could be utilized as required, so we split the keystore into a frontend and a backend, with a trait that sits in between.
Possible Backends:
Keystore backend trait design
Constraints