Crypto Pair trait refactory (#13657)

* Crypto pair refactory

* Remove unused method

* Apply review suggestions

* Remove leftovers

* Associated type is not really required

* Fix after refactory

* Fix benchmark-ui test

---------

Co-authored-by: Anton <anton.kalyaev@gmail.com>
This commit is contained in:
Davide Galassi
2023-03-22 11:09:10 +01:00
committed by GitHub
parent d62ac2a0a2
commit e92e483c84
6 changed files with 75 additions and 196 deletions
+13 -72
View File
@@ -24,9 +24,7 @@
#[cfg(feature = "std")]
use crate::crypto::Ss58Codec;
#[cfg(feature = "full_crypto")]
use crate::crypto::{DeriveJunction, Infallible, Pair as TraitPair, SecretStringError};
#[cfg(feature = "std")]
use bip39::{Language, Mnemonic, MnemonicType};
use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError};
#[cfg(feature = "full_crypto")]
use schnorrkel::{
derive::{ChainCode, Derivation, CHAIN_CODE_LENGTH},
@@ -34,8 +32,6 @@ use schnorrkel::{
};
#[cfg(feature = "full_crypto")]
use sp_std::vec::Vec;
#[cfg(feature = "std")]
use substrate_bip39::mini_secret_from_entropy;
use crate::{
crypto::{
@@ -458,16 +454,6 @@ impl TraitPair for Pair {
type Public = Public;
type Seed = Seed;
type Signature = Signature;
type DeriveError = Infallible;
/// Make a new key pair from raw secret seed material.
///
/// This is generated using schnorrkel's Mini-Secret-Keys.
///
/// A MiniSecretKey is literally what Ed25519 calls a SecretKey, which is just 32 random bytes.
fn from_seed(seed: &Seed) -> Pair {
Self::from_seed_slice(&seed[..]).expect("32 bytes can always build a key; qed")
}
/// Get the public key.
fn public(&self) -> Public {
@@ -476,10 +462,12 @@ impl TraitPair for Pair {
Public(pk)
}
/// Make a new key pair from secret seed material. The slice must be 32 bytes long or it
/// will return `None`.
/// Make a new key pair from raw secret seed material.
///
/// You should never need to use this; generate(), generate_with_phrase(), from_phrase()
/// This is generated using schnorrkel's Mini-Secret-Keys.
///
/// A `MiniSecretKey` is literally what Ed25519 calls a `SecretKey`, which is just 32 random
/// bytes.
fn from_seed_slice(seed: &[u8]) -> Result<Pair, SecretStringError> {
match seed.len() {
MINI_SECRET_KEY_LENGTH => Ok(Pair(
@@ -495,42 +483,16 @@ impl TraitPair for Pair {
_ => Err(SecretStringError::InvalidSeedLength),
}
}
#[cfg(feature = "std")]
fn generate_with_phrase(password: Option<&str>) -> (Pair, String, Seed) {
let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English);
let phrase = mnemonic.phrase();
let (pair, seed) = Self::from_phrase(phrase, password)
.expect("All phrases generated by Mnemonic are valid; qed");
(pair, phrase.to_owned(), seed)
}
#[cfg(feature = "std")]
fn from_phrase(
phrase: &str,
password: Option<&str>,
) -> Result<(Pair, Seed), SecretStringError> {
Mnemonic::from_phrase(phrase, Language::English)
.map_err(|_| SecretStringError::InvalidPhrase)
.map(|m| Self::from_entropy(m.entropy(), password))
}
fn derive<Iter: Iterator<Item = DeriveJunction>>(
&self,
path: Iter,
seed: Option<Seed>,
) -> Result<(Pair, Option<Seed>), Self::DeriveError> {
let seed = if let Some(s) = seed {
if let Ok(msk) = MiniSecretKey::from_bytes(&s) {
if msk.expand(ExpansionMode::Ed25519) == self.0.secret {
Some(msk)
} else {
None
}
} else {
None
}
} else {
None
};
) -> Result<(Pair, Option<Seed>), DeriveError> {
let seed = seed
.and_then(|s| MiniSecretKey::from_bytes(&s).ok())
.filter(|msk| msk.expand(ExpansionMode::Ed25519) == self.0.secret);
let init = self.0.secret.clone();
let (result, seed) = path.fold((init, seed), |(acc, acc_seed), j| match (j, acc_seed) {
(DeriveJunction::Soft(cc), _) => (acc.derived_key_simple(ChainCode(cc), &[]).0, None),
@@ -572,18 +534,6 @@ impl TraitPair for Pair {
#[cfg(feature = "std")]
impl Pair {
/// Make a new key pair from binary data derived from a valid seed phrase.
///
/// This uses a key derivation function to convert the entropy into a seed, then returns
/// the pair generated from it.
pub fn from_entropy(entropy: &[u8], password: Option<&str>) -> (Pair, Seed) {
let mini_key: MiniSecretKey = mini_secret_from_entropy(entropy, password.unwrap_or(""))
.expect("32 bytes can always build a key; qed");
let kp = mini_key.expand_to_keypair(ExpansionMode::Ed25519);
(Pair(kp), mini_key.to_bytes())
}
/// Verify a signature on a message. Returns `true` if the signature is good.
/// Supports old 0.1.1 deprecated signatures and should be used only for backward
/// compatibility.
@@ -652,10 +602,8 @@ pub fn verify_batch(
#[cfg(test)]
mod compatibility_test {
use super::*;
use crate::crypto::DEV_PHRASE;
// NOTE: tests to ensure addresses that are created with the `0.1.x` version (pre-audit) are
// still functional.
use crate::crypto::{Ss58Codec, DEV_ADDRESS, DEV_PHRASE};
use serde_json;
#[test]
fn derive_soft_known_pair_should_work() {
@@ -690,13 +638,6 @@ mod compatibility_test {
assert!(Pair::verify_deprecated(&signature, &message[..], &public));
assert!(!Pair::verify(&signature, &message[..], &public));
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::crypto::{Ss58Codec, DEV_ADDRESS, DEV_PHRASE};
use serde_json;
#[test]
fn default_phrase_should_be_used() {