#![cfg(all(feature = "std", feature = "keyring", feature = "serde"))]
use crate::{
error::{Result, SignerError},
keyring::{self, KeyringScheme, KeystoreEntry},
};
use hex::ToHex;
use std::{
fmt,
marker::PhantomData,
path::PathBuf,
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
};
use tempfile::TempDir;
#[derive(Clone)]
pub struct Signer<S: KeyringScheme> {
keyring: Arc<RwLock<keyring::Keyring<S::Keystore>>>,
_tmp_dir: Option<Arc<TempDir>>,
_phantom: PhantomData<S>,
}
impl<S: KeyringScheme> fmt::Debug for Signer<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Signer")
.field("scheme", &S::NAME)
.field("keys", &self.list_keys().ok())
.finish()
}
}
impl<S: KeyringScheme> Signer<S> {
pub fn new(keyring: keyring::Keyring<S::Keystore>) -> Self {
Self {
keyring: Arc::new(RwLock::new(keyring)),
_tmp_dir: None,
_phantom: PhantomData,
}
}
fn with_tempdir(keyring: keyring::Keyring<S::Keystore>, tmp_dir: Option<TempDir>) -> Self {
Self {
keyring: Arc::new(RwLock::new(keyring)),
_tmp_dir: tmp_dir.map(Arc::new),
_phantom: PhantomData,
}
}
pub fn memory() -> Self {
let keyring = keyring::Keyring::try_memory().expect("memory keyring should not fail");
Self::new(keyring)
}
fn namespaced_path(path: PathBuf) -> PathBuf {
keyring::Keyring::<S::Keystore>::namespaced_path(path, S::namespace())
}
pub fn fs(path: PathBuf) -> Result<Self> {
let namespaced = Self::namespaced_path(path);
let keyring = keyring::Keyring::load(namespaced)?;
Ok(Self::new(keyring))
}
pub fn fs_temporary() -> Result<Self> {
let temp_dir = tempfile::tempdir()?;
let namespaced = Self::namespaced_path(temp_dir.path().to_path_buf());
let keyring = keyring::Keyring::load(namespaced)?;
Ok(Self::with_tempdir(keyring, Some(temp_dir)))
}
fn keyring(&self) -> Result<RwLockReadGuard<'_, keyring::Keyring<S::Keystore>>> {
self.keyring
.read()
.map_err(|err| SignerError::Other(format!("Failed to acquire read lock: {err}")))
}
fn keyring_mut(&self) -> Result<RwLockWriteGuard<'_, keyring::Keyring<S::Keystore>>> {
self.keyring
.write()
.map_err(|err| SignerError::Other(format!("Failed to acquire write lock: {err}")))
}
fn key_name(public_key: &S::PublicKey) -> String {
format!(
"key-{}",
S::public_key_to_bytes(public_key).encode_hex::<String>()
)
}
fn store_private_key(
&self,
private_key: S::PrivateKey,
password: Option<&str>,
) -> Result<S::PublicKey> {
let public_key = S::public_key(&private_key);
let name = Self::key_name(&public_key);
let keystore = S::keystore_from_private(&name, &private_key, password)?;
self.keyring_mut()?.store(&name, keystore)?;
Ok(public_key)
}
fn with_keystore<F, R>(&self, public_key: &S::PublicKey, mut f: F) -> Result<R>
where
F: FnMut(&S::Keystore) -> Result<R>,
{
let storage = self.keyring()?;
for keystore in storage.list() {
if S::keystore_public(keystore)? == *public_key {
return f(keystore);
}
}
Err(SignerError::KeyNotFound(format!("{public_key:?}")))
}
pub fn generate(&self) -> Result<S::PublicKey> {
let (private_key, _) = S::generate_keypair();
self.store_private_key(private_key, None)
}
pub fn generate_encrypted(&self, password: &str) -> Result<S::PublicKey> {
let (private_key, _) = S::generate_keypair();
self.store_private_key(private_key, Some(password))
}
pub fn import(&self, private_key: S::PrivateKey) -> Result<S::PublicKey> {
self.store_private_key(private_key, None)
}
pub fn import_encrypted(
&self,
private_key: S::PrivateKey,
password: &str,
) -> Result<S::PublicKey> {
self.store_private_key(private_key, Some(password))
}
pub fn sign(&self, public_key: S::PublicKey, data: &[u8]) -> Result<S::Signature> {
let private_key = self.private_key(public_key)?;
S::sign(&private_key, data)
}
pub fn sign_encrypted(
&self,
public_key: S::PublicKey,
data: &[u8],
password: &str,
) -> Result<S::Signature> {
let private_key = self.private_key_encrypted(public_key, password)?;
S::sign(&private_key, data)
}
pub fn verify(
&self,
public_key: S::PublicKey,
data: &[u8],
signature: &S::Signature,
) -> Result<()> {
S::verify(&public_key, data, signature)
}
pub fn address(&self, public_key: S::PublicKey) -> S::Address {
S::to_address(&public_key)
}
pub fn has_key(&self, public_key: S::PublicKey) -> Result<bool> {
let storage = self.keyring()?;
for keystore in storage.list() {
if S::keystore_public(keystore)? == public_key {
return Ok(true);
}
}
Ok(false)
}
pub fn list_keys(&self) -> Result<Vec<S::PublicKey>> {
let storage = self.keyring()?;
storage.list().iter().map(S::keystore_public).collect()
}
pub fn clear_keys(&self) -> Result<()> {
let mut storage = self.keyring_mut()?;
let names: Vec<String> = storage
.list()
.iter()
.map(|keystore| keystore.name().to_string())
.collect();
for name in names {
storage.remove(&name)?;
}
Ok(())
}
pub fn sub_signer(&self, keys: Vec<S::PublicKey>) -> Result<Self> {
let signer = Signer::memory();
for key in keys {
let private_key = self.private_key(key.clone())?;
signer.import(private_key)?;
}
Ok(signer)
}
pub fn sub_signer_encrypted(&self, keys: Vec<S::PublicKey>, password: &str) -> Result<Self> {
let signer = Signer::memory();
for key in keys {
let private_key = self.private_key_encrypted(key.clone(), password)?;
signer.import_encrypted(private_key, password)?;
}
Ok(signer)
}
pub fn scheme_name(&self) -> &'static str {
S::NAME
}
pub fn private_key(&self, public_key: S::PublicKey) -> Result<S::PrivateKey> {
self.with_keystore(&public_key, |keystore| S::keystore_private(keystore, None))
}
pub fn private_key_encrypted(
&self,
public_key: S::PublicKey,
password: &str,
) -> Result<S::PrivateKey> {
self.with_keystore(&public_key, |keystore| {
S::keystore_private(keystore, Some(password))
})
}
pub fn get_key_by_address(&self, address: S::Address) -> Result<Option<S::PublicKey>> {
let storage = self.keyring()?;
for keystore in storage.list() {
if S::keystore_address(keystore)? == address {
return S::keystore_public(keystore).map(Some);
}
}
Ok(None)
}
}
#[cfg(feature = "peer-id")]
use crate::peer_id::ToPeerId;
#[cfg(feature = "peer-id")]
impl<S: KeyringScheme> Signer<S>
where
S::PublicKey: ToPeerId,
{
pub fn generate_with_peer_id(&self) -> Result<(S::PublicKey, crate::peer_id::PeerId)> {
let public_key = self.generate()?;
let peer_id = public_key.to_peer_id()?;
Ok((public_key, peer_id))
}
pub fn generate_with_peer_id_encrypted(
&self,
password: &str,
) -> Result<(S::PublicKey, crate::peer_id::PeerId)> {
let public_key = self.generate_encrypted(password)?;
let peer_id = public_key.to_peer_id()?;
Ok((public_key, peer_id))
}
pub fn peer_id(&self, public_key: &S::PublicKey) -> Result<crate::peer_id::PeerId> {
public_key.to_peer_id()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "secp256k1")]
#[test]
fn test_signer_secp256k1() {
use crate::schemes::secp256k1::Secp256k1;
let signer = Signer::<Secp256k1>::memory();
let public_key = signer.generate().unwrap();
assert!(signer.has_key(public_key).unwrap());
let message = b"hello world";
let signature = signer.sign(public_key, message).unwrap();
signer.verify(public_key, message, &signature).unwrap();
let keys = signer.list_keys().unwrap();
assert_eq!(keys.len(), 1);
assert!(keys.contains(&public_key));
let address = signer.address(public_key);
assert_eq!(address.as_ref().len(), 20);
}
#[cfg(feature = "sr25519")]
#[test]
fn test_signer_sr25519() {
use crate::schemes::sr25519::Sr25519;
let signer = Signer::<Sr25519>::memory();
let public_key = signer.generate().unwrap();
assert!(signer.has_key(public_key).unwrap());
let message = b"hello world";
let signature = signer.sign(public_key, message).unwrap();
signer.verify(public_key, message, &signature).unwrap();
}
#[cfg(all(feature = "secp256k1", feature = "peer-id"))]
#[test]
fn test_signer_secp256k1_peer_id() {
use crate::schemes::secp256k1::Secp256k1;
let signer = Signer::<Secp256k1>::memory();
let (public_key, peer_id) = signer.generate_with_peer_id().unwrap();
assert!(signer.has_key(public_key).unwrap());
assert!(!peer_id.to_string().is_empty());
let peer_id_again = signer.peer_id(&public_key).unwrap();
assert_eq!(peer_id, peer_id_again);
}
#[cfg(all(feature = "ed25519", feature = "peer-id"))]
#[test]
fn test_signer_ed25519_peer_id() {
use crate::schemes::ed25519::Ed25519;
let signer = Signer::<Ed25519>::memory();
let (public_key, peer_id) = signer.generate_with_peer_id().unwrap();
assert!(signer.has_key(public_key).unwrap());
assert!(!peer_id.to_string().is_empty());
let peer_id_again = signer.peer_id(&public_key).unwrap();
assert_eq!(peer_id, peer_id_again);
}
}