use crate::{
crypto::{substrate::Address, RawKeyPair},
errors::Result,
KeyIdentifier, KeyType, Signature,
};
use bip39::{Mnemonic, MnemonicType};
use rand::{CryptoRng, Rng, RngCore};
use secrecy::{ExposeSecret, Secret};
use sp_core::{
crypto::{DeriveJunction, Pair, Ss58Codec},
sr25519,
};
use std::fmt::{Debug, Formatter};
pub(crate) type Public = sp_core::sr25519::Public;
impl Signature for sr25519::Signature {}
#[derive(Clone, Constructor)]
pub struct SubstrateSr25519KeyPair {
pub entropy: Secret<[u8; 16]>,
pub derive_paths: Vec<Secret<String>>,
pub key: sr25519::Pair,
}
impl Debug for SubstrateSr25519KeyPair {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Sr25519({})", self.key.public())
}
}
fn make_sr25519_pair(
entropy: &Secret<[u8; 16]>,
derive_paths: &[Secret<String>],
) -> Result<sr25519::Pair> {
let (kp, _mini_key) = sr25519::Pair::from_entropy(entropy.expose_secret(), None);
let derivations = derive_paths
.iter()
.map(|path| DeriveJunction::from(path.expose_secret()));
let (pair, _seed) = kp.derive(derivations, None)?;
Ok(pair)
}
impl SubstrateSr25519KeyPair {
pub fn to_address(&self) -> Address {
Address {
value: self.key.public().to_ss58check(),
key_type: KeyType::SubstrateSr25519,
}
}
}
impl RawKeyPair for SubstrateSr25519KeyPair {
type PublicKey = Public;
type Signature = sr25519::Signature;
const KEY_TYPE: KeyType = KeyType::SubstrateSr25519;
fn from_strings(secret: Secret<String>) -> Result<Self> {
let (entropy, derive_paths) = super::deconstruct_secret_string(secret)?;
let kp = make_sr25519_pair(&entropy, &derive_paths)?;
Ok(Self::new(entropy, derive_paths, kp))
}
fn from_secret(secret: Secret<String>) -> Result<Self> {
let (entropy, derive_paths) = super::deconstruct_secret_string(secret)?;
let pair = make_sr25519_pair(&entropy, &derive_paths)?;
Ok(Self::new(entropy, derive_paths, pair))
}
fn generate_with<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self> {
let mut entropy = vec![0; MnemonicType::Words12.entropy_bits() / 8];
rng.fill(&mut *entropy);
let mnemonic = Mnemonic::from_entropy(&entropy, bip39::Language::English)
.expect("Mnemonic length is valid by construction");
let phrase = mnemonic.phrase();
let (key, _) = sr25519::Pair::from_phrase(phrase, None)
.expect("All phrases generated by Mnemonic are valid");
let secret_phrase = phrase.to_owned();
let phrase = Secret::new(secret_phrase);
let (entropy, derive_paths) = super::deconstruct_secret_string(phrase)?;
Ok(Self::new(entropy, derive_paths, key))
}
fn sign(&self, message: &[u8]) -> Result<Self::Signature> {
Ok(self.key.sign(message))
}
fn identifier(&self) -> KeyIdentifier {
KeyIdentifier {
value: self.public().to_ss58check(),
key_type: Self::KEY_TYPE,
}
}
fn to_secret(&self) -> Result<Secret<String>> {
super::to_secret_string(&self.entropy, &self.derive_paths)
}
fn public(&self) -> Self::PublicKey {
self.key.public()
}
}