From a69da4a85f73e54a21b9cc80526d8222e234311c Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Mon, 30 Oct 2023 17:03:30 +0100 Subject: [PATCH] Switch from `tiny-bip39` to `bip39` crate (#2084) Switch from: https://crates.io/crates/tiny-bip39 to: https://crates.io/crates/bip39 Required for: https://github.com/paritytech/polkadot-sdk/pull/2044 --- Cargo.lock | 38 ++++--------------- substrate/client/cli/Cargo.toml | 3 +- substrate/client/cli/src/commands/generate.rs | 23 ++++++----- substrate/primitives/core/Cargo.toml | 7 +++- substrate/primitives/core/src/crypto.rs | 16 +++++--- 5 files changed, 38 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1183f9204a2d..c95cc70b0da4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1377,6 +1377,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" dependencies = [ "bitcoin_hashes", + "rand 0.7.3", + "rand_core 0.5.1", + "serde", + "unicode-normalization", ] [[package]] @@ -11407,15 +11411,6 @@ dependencies = [ "crypto-mac 0.11.1", ] -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest 0.10.7", -] - [[package]] name = "pbkdf2" version = "0.12.2" @@ -14732,11 +14727,13 @@ name = "sc-cli" version = "0.10.0-dev" dependencies = [ "array-bytes 6.1.0", + "bip39", "chrono", "clap 4.4.6", "fdlimit", "futures", "futures-timer", + "itertools 0.10.5", "libp2p-identity", "log", "names 0.13.0", @@ -14765,7 +14762,6 @@ dependencies = [ "sp-version", "tempfile", "thiserror", - "tiny-bip39", "tokio", ] @@ -17076,6 +17072,7 @@ version = "21.0.0" dependencies = [ "array-bytes 6.1.0", "bandersnatch_vrfs", + "bip39", "bitflags 1.3.2", "blake2 0.10.6", "bounded-collections", @@ -17087,6 +17084,7 @@ dependencies = [ "hash-db", "hash256-std-hasher", "impl-serde", + "itertools 0.10.5", "lazy_static", "libsecp256k1", "log", @@ -17113,7 +17111,6 @@ dependencies = [ "ss58-registry", "substrate-bip39", "thiserror", - "tiny-bip39", "tracing", "w3f-bls", "zeroize", @@ -18707,25 +18704,6 @@ dependencies = [ "time-core", ] -[[package]] -name = "tiny-bip39" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62cc94d358b5a1e84a5cb9109f559aa3c4d634d2b1b4de3d0fa4adc7c78e2861" -dependencies = [ - "anyhow", - "hmac 0.12.1", - "once_cell", - "pbkdf2 0.11.0", - "rand 0.8.5", - "rustc-hash", - "sha2 0.10.7", - "thiserror", - "unicode-normalization", - "wasm-bindgen", - "zeroize", -] - [[package]] name = "tiny-keccak" version = "2.0.2" diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index dc53ed54d967..5a98b43f43c2 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -18,6 +18,7 @@ chrono = "0.4.27" clap = { version = "4.4.6", features = ["derive", "string", "wrap_help"] } fdlimit = "0.2.1" futures = "0.3.21" +itertools = "0.10.3" libp2p-identity = { version = "0.1.3", features = ["peerid", "ed25519"]} log = "0.4.17" names = { version = "0.13.0", default-features = false } @@ -28,7 +29,7 @@ rpassword = "7.0.0" serde = "1.0.188" serde_json = "1.0.107" thiserror = "1.0.48" -tiny-bip39 = "1.0.0" +bip39 = "2.0.0" tokio = { version = "1.22.0", features = ["signal", "rt-multi-thread", "parking_lot"] } sc-client-api = { path = "../api" } sc-client-db = { path = "../db", default-features = false} diff --git a/substrate/client/cli/src/commands/generate.rs b/substrate/client/cli/src/commands/generate.rs index 93b83fcbef51..c465bcc85a47 100644 --- a/substrate/client/cli/src/commands/generate.rs +++ b/substrate/client/cli/src/commands/generate.rs @@ -20,8 +20,9 @@ use crate::{ utils::print_from_uri, with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams, NetworkSchemeFlag, OutputTypeFlag, }; -use bip39::{Language, Mnemonic, MnemonicType}; +use bip39::Mnemonic; use clap::Parser; +use itertools::Itertools; /// The `generate` command #[derive(Debug, Clone, Parser)] @@ -52,20 +53,22 @@ impl GenerateCmd { /// Run the command pub fn run(&self) -> Result<(), Error> { let words = match self.words { - Some(words) => MnemonicType::for_word_count(words).map_err(|_| { - Error::Input( - "Invalid number of words given for phrase: must be 12/15/18/21/24".into(), - ) - })?, - None => MnemonicType::Words12, - }; - let mnemonic = Mnemonic::new(words, Language::English); + Some(words_count) if [12, 15, 18, 21, 24].contains(&words_count) => Ok(words_count), + Some(_) => Err(Error::Input( + "Invalid number of words given for phrase: must be 12/15/18/21/24".into(), + )), + None => Ok(12), + }?; + let mnemonic = Mnemonic::generate(words) + .map_err(|e| Error::Input(format!("Mnemonic generation failed: {e}").into()))?; let password = self.keystore_params.read_password()?; let output = self.output_scheme.output_type; + let phrase = mnemonic.word_iter().join(" "); + with_crypto_scheme!( self.crypto_scheme.scheme, - print_from_uri(mnemonic.phrase(), password, self.network_scheme.network, output) + print_from_uri(&phrase, password, self.network_scheme.network, output) ); Ok(()) } diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 1b6b10eeeedf..1e8a353f419b 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -25,7 +25,7 @@ hash256-std-hasher = { version = "0.15.2", default-features = false } bs58 = { version = "0.5.0", default-features = false, optional = true } rand = { version = "0.8.5", features = ["small_rng"], optional = true } substrate-bip39 = { version = "0.4.4", optional = true } -tiny-bip39 = { version = "1.0.0", optional = true } +bip39 = { version = "2.0.0", default-features = false } regex = { version = "1.6.0", optional = true } zeroize = { version = "1.4.3", default-features = false } secrecy = { version = "0.8.0", default-features = false } @@ -42,6 +42,7 @@ thiserror = { version = "1.0.48", optional = true } tracing = { version = "0.1.29", optional = true } bitflags = "1.3" paste = "1.0.7" +itertools = { version = "0.10.3", optional = true } # full crypto array-bytes = { version = "6.1", optional = true } @@ -76,6 +77,8 @@ default = [ "std" ] std = [ "array-bytes", "bandersnatch_vrfs/getrandom", + "bip39/rand", + "bip39/std", "blake2/std", "bounded-collections/std", "bs58/std", @@ -88,6 +91,7 @@ std = [ "hash-db/std", "hash256-std-hasher/std", "impl-serde/std", + "itertools", "lazy_static", "libsecp256k1/std", "log/std", @@ -114,7 +118,6 @@ std = [ "ss58-registry/std", "substrate-bip39", "thiserror", - "tiny-bip39", "tracing", "w3f-bls?/std", "zeroize/alloc", diff --git a/substrate/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index f7e2c56ca9a4..d369de5a1c01 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -19,9 +19,11 @@ use crate::{ed25519, sr25519}; #[cfg(feature = "std")] -use bip39::{Language, Mnemonic, MnemonicType}; +use bip39::{Language, Mnemonic}; use codec::{Decode, Encode, MaxEncodedLen}; #[cfg(feature = "std")] +use itertools::Itertools; +#[cfg(feature = "std")] use rand::{rngs::OsRng, RngCore}; #[cfg(feature = "std")] use regex::Regex; @@ -870,9 +872,9 @@ pub trait Pair: CryptoType + Sized { /// the key from the current session. #[cfg(feature = "std")] fn generate_with_phrase(password: Option<&str>) -> (Self, String, Self::Seed) { - let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English); - let phrase = mnemonic.phrase(); - let (pair, seed) = Self::from_phrase(phrase, password) + let mnemonic = Mnemonic::generate(12).expect("Mnemonic generation always works; qed"); + let phrase = mnemonic.word_iter().join(" "); + let (pair, seed) = Self::from_phrase(&phrase, password) .expect("All phrases generated by Mnemonic are valid; qed"); (pair, phrase.to_owned(), seed) } @@ -883,10 +885,12 @@ pub trait Pair: CryptoType + Sized { phrase: &str, password: Option<&str>, ) -> Result<(Self, Self::Seed), SecretStringError> { - let mnemonic = Mnemonic::from_phrase(phrase, Language::English) + let mnemonic = Mnemonic::parse_in(Language::English, phrase) .map_err(|_| SecretStringError::InvalidPhrase)?; + + let (entropy, entropy_len) = mnemonic.to_entropy_array(); let big_seed = - substrate_bip39::seed_from_entropy(mnemonic.entropy(), password.unwrap_or("")) + substrate_bip39::seed_from_entropy(&entropy[0..entropy_len], password.unwrap_or("")) .map_err(|_| SecretStringError::InvalidSeed)?; let mut seed = Self::Seed::default(); let seed_slice = seed.as_mut();