inspect-key: Adds support for expect-public (#10430)

* Introduce `SecretUri`

* `inspect-key`: Adds support for `expect-public`

`expect-public` can be used to check that a given secret uri corresponds to the given public key.
This is mainly useful when the secret uri is protected by a password and a new derived account
should be generated. With `--expect-public` the user can pass the public key/account-id of the
"base" secret uri aka the one without any derivation to ensure the correct password was inserted.

* Fixes

* 🤦

* Apply suggestions from code review

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>

* Review feedback

* FMT

* Bump the versions

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>
This commit is contained in:
Bastian Köcher
2021-12-11 08:13:18 +01:00
committed by GitHub
parent 91260e8b05
commit f6f58f95e1
152 changed files with 413 additions and 165 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false }
sp-api-proc-macro = { version = "4.0.0-dev", path = "proc-macro" }
sp-core = { version = "4.0.0", default-features = false, path = "../core" }
sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" }
sp-std = { version = "4.0.0", default-features = false, path = "../std" }
sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" }
sp-version = { version = "4.0.0-dev", default-features = false, path = "../version" }
+1 -1
View File
@@ -28,7 +28,7 @@ rustversion = "1.0.5"
criterion = "0.3.0"
futures = "0.3.9"
log = "0.4.14"
sp-core = { version = "4.0.0", path = "../../core" }
sp-core = { version = "4.1.0-dev", path = "../../core" }
[[bench]]
name = "bench"
@@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
sp-core = { version = "4.0.0", default-features = false, path = "../core" }
sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" }
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
scale-info = { version = "1.0", default-features = false, features = ["derive"] }
serde = { version = "1.0.126", optional = true, features = ["derive"] }
@@ -13,7 +13,7 @@ repository = "https://github.com/paritytech/substrate/"
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
sp-core = { version = "4.0.0", default-features = false, path = "../../core" }
sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" }
sp-keystore = { version = "0.10.0-dev", path = "../../keystore", default-features = false }
substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" }
sp-runtime = { version = "4.0.0-dev", path = "../../runtime" }
+1 -1
View File
@@ -13,7 +13,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"]
sp-api = { version = "4.0.0-dev", path = "../api", default-features = false }
sp-application-crypto = { version = "4.0.0-dev", path = "../application-crypto", default-features = false }
sp-core = { version = "4.0.0", path = "../core", default-features = false }
sp-core = { version = "4.1.0-dev", path = "../core", default-features = false }
sp-runtime = { version = "4.0.0-dev", path = "../runtime", default-features = false }
sp-std = { version = "4.0.0", path = "../std", default-features = false }
@@ -22,7 +22,7 @@ sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" }
sp-consensus = { version = "0.10.0-dev", optional = true, path = "../common" }
sp-consensus-slots = { version = "0.10.0-dev", default-features = false, path = "../slots" }
sp-consensus-vrf = { version = "0.10.0-dev", path = "../vrf", default-features = false }
sp-core = { version = "4.0.0", default-features = false, path = "../../core" }
sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" }
sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../inherents" }
sp-keystore = { version = "0.10.0-dev", default-features = false, path = "../../keystore", optional = true }
sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../runtime" }
@@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0", features = [
] }
futures = { version = "0.3.1", features = ["thread-pool"] }
log = "0.4.8"
sp-core = { path = "../../core", version = "4.0.0" }
sp-core = { path = "../../core", version = "4.1.0-dev" }
sp-inherents = { version = "4.0.0-dev", path = "../../inherents" }
sp-state-machine = { version = "0.10.0-dev", path = "../../state-machine" }
futures-timer = "3.0.1"
@@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"]
sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" }
sp-std = { version = "4.0.0", default-features = false, path = "../../std" }
sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../runtime" }
sp-core = { version = "4.0.0", default-features = false, path = "../../core" }
sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" }
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
[features]
@@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"]
codec = { version = "2.0.0", package = "parity-scale-codec", default-features = false }
schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false }
sp-std = { version = "4.0.0", path = "../../std", default-features = false }
sp-core = { version = "4.0.0", path = "../../core", default-features = false }
sp-core = { version = "4.1.0-dev", path = "../../core", default-features = false }
sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../runtime" }
[features]
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "sp-core"
version = "4.0.0"
version = "4.1.0-dev"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2021"
license = "Apache-2.0"
+108 -9
View File
@@ -460,6 +460,7 @@ pub trait Public:
fn as_slice(&self) -> &[u8] {
self.as_ref()
}
/// Return `CryptoTypePublicPair` from public key.
fn to_public_crypto_pair(&self) -> CryptoTypePublicPair;
}
@@ -709,6 +710,104 @@ mod dummy {
}
}
/// A secret uri (`SURI`) that can be used to generate a key pair.
///
/// The `SURI` can be parsed from a string. The string is interpreted in the following way:
///
/// - If `string` is a possibly `0x` prefixed 64-digit hex string, then it will be interpreted
/// directly as a `MiniSecretKey` (aka "seed" in `subkey`).
/// - If `string` is a valid BIP-39 key phrase of 12, 15, 18, 21 or 24 words, then the key will
/// be derived from it. In this case:
/// - the phrase may be followed by one or more items delimited by `/` characters.
/// - the path may be followed by `///`, in which case everything after the `///` is treated
/// as a password.
/// - If `string` begins with a `/` character it is prefixed with the Substrate public `DEV_PHRASE`
/// and interpreted as above.
///
/// In this case they are interpreted as HDKD junctions; purely numeric items are interpreted as
/// integers, non-numeric items as strings. Junctions prefixed with `/` are interpreted as soft
/// junctions, and with `//` as hard junctions.
///
/// There is no correspondence mapping between `SURI` strings and the keys they represent.
/// Two different non-identical strings can actually lead to the same secret being derived.
/// Notably, integer junction indices may be legally prefixed with arbitrary number of zeros.
/// Similarly an empty password (ending the `SURI` with `///`) is perfectly valid and will
/// generally be equivalent to no password at all.
///
/// # Example
///
/// Parse [`DEV_PHRASE`] secret uri with junction:
///
/// ```
/// # use sp_core::crypto::{SecretUri, DeriveJunction, DEV_PHRASE, ExposeSecret};
/// # use std::str::FromStr;
/// let suri = SecretUri::from_str("//Alice").expect("Parse SURI");
///
/// assert_eq!(vec![DeriveJunction::from("Alice").harden()], suri.junctions);
/// assert_eq!(DEV_PHRASE, suri.phrase.expose_secret());
/// assert!(suri.password.is_none());
/// ```
///
/// Parse [`DEV_PHRASE`] secret ui with junction and password:
///
/// ```
/// # use sp_core::crypto::{SecretUri, DeriveJunction, DEV_PHRASE, ExposeSecret};
/// # use std::str::FromStr;
/// let suri = SecretUri::from_str("//Alice///SECRET_PASSWORD").expect("Parse SURI");
///
/// assert_eq!(vec![DeriveJunction::from("Alice").harden()], suri.junctions);
/// assert_eq!(DEV_PHRASE, suri.phrase.expose_secret());
/// assert_eq!("SECRET_PASSWORD", suri.password.unwrap().expose_secret());
/// ```
///
/// Parse [`DEV_PHRASE`] secret ui with hex phrase and junction:
///
/// ```
/// # use sp_core::crypto::{SecretUri, DeriveJunction, DEV_PHRASE, ExposeSecret};
/// # use std::str::FromStr;
/// let suri = SecretUri::from_str("0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a//Alice").expect("Parse SURI");
///
/// assert_eq!(vec![DeriveJunction::from("Alice").harden()], suri.junctions);
/// assert_eq!("0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a", suri.phrase.expose_secret());
/// assert!(suri.password.is_none());
/// ```
#[cfg(feature = "std")]
pub struct SecretUri {
/// The phrase to derive the private key.
///
/// This can either be a 64-bit hex string or a BIP-39 key phrase.
pub phrase: SecretString,
/// Optional password as given as part of the uri.
pub password: Option<SecretString>,
/// The junctions as part of the uri.
pub junctions: Vec<DeriveJunction>,
}
#[cfg(feature = "std")]
impl sp_std::str::FromStr for SecretUri {
type Err = SecretStringError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let cap = SECRET_PHRASE_REGEX.captures(s).ok_or(SecretStringError::InvalidFormat)?;
let junctions = JUNCTION_REGEX
.captures_iter(&cap["path"])
.map(|f| DeriveJunction::from(&f[1]))
.collect::<Vec<_>>();
let phrase = cap.name("phrase").map(|r| r.as_str()).unwrap_or(DEV_PHRASE);
let password = cap.name("password");
Ok(Self {
phrase: SecretString::from_str(phrase).expect("Returns infallible error; qed"),
password: password.map(|v| {
SecretString::from_str(v.as_str()).expect("Returns infallible error; qed")
}),
junctions,
})
}
}
/// Trait suitable for typical cryptographic PKI key pair type.
///
/// For now it just specifies how to create a key from a phrase and derivation path.
@@ -821,14 +920,12 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static {
s: &str,
password_override: Option<&str>,
) -> Result<(Self, Option<Self::Seed>), SecretStringError> {
let cap = SECRET_PHRASE_REGEX.captures(s).ok_or(SecretStringError::InvalidFormat)?;
use sp_std::str::FromStr;
let SecretUri { junctions, phrase, password } = SecretUri::from_str(s)?;
let password =
password_override.or_else(|| password.as_ref().map(|p| p.expose_secret().as_str()));
let path = JUNCTION_REGEX.captures_iter(&cap["path"]).map(|f| DeriveJunction::from(&f[1]));
let phrase = cap.name("phrase").map(|r| r.as_str()).unwrap_or(DEV_PHRASE);
let password = password_override.or_else(|| cap.name("password").map(|m| m.as_str()));
let (root, seed) = if let Some(stripped) = phrase.strip_prefix("0x") {
let (root, seed) = if let Some(stripped) = phrase.expose_secret().strip_prefix("0x") {
hex::decode(stripped)
.ok()
.and_then(|seed_vec| {
@@ -842,9 +939,11 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static {
})
.ok_or(SecretStringError::InvalidSeed)?
} else {
Self::from_phrase(phrase, password).map_err(|_| SecretStringError::InvalidPhrase)?
Self::from_phrase(phrase.expose_secret().as_str(), password)
.map_err(|_| SecretStringError::InvalidPhrase)?
};
root.derive(path, Some(seed)).map_err(|_| SecretStringError::InvalidPath)
root.derive(junctions.into_iter(), Some(seed))
.map_err(|_| SecretStringError::InvalidPath)
}
/// Interprets the string `s` in order to generate a key pair.
@@ -22,7 +22,7 @@ log = { version = "0.4.8", optional = true }
serde = { version = "1.0.126", optional = true, features = ["derive"] }
sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" }
sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../application-crypto" }
sp-core = { version = "4.0.0", default-features = false, path = "../core" }
sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" }
sp-keystore = { version = "0.10.0-dev", default-features = false, path = "../keystore", optional = true }
sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" }
sp-std = { version = "4.0.0", default-features = false, path = "../std" }
+1 -1
View File
@@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
sp-std = { version = "4.0.0", default-features = false, path = "../std" }
sp-core = { version = "4.0.0", default-features = false, path = "../core" }
sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" }
sp-runtime = { version = "4.0.0-dev", path = "../runtime", optional = true }
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
thiserror = { version = "1.0.30", optional = true }
+1 -1
View File
@@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false }
hash-db = { version = "0.15.2", default-features = false }
sp-core = { version = "4.0.0", default-features = false, path = "../core" }
sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" }
sp-keystore = { version = "0.10.0-dev", default-features = false, optional = true, path = "../keystore" }
sp-std = { version = "4.0.0", default-features = false, path = "../std" }
libsecp256k1 = { version = "0.7", optional = true }
+1 -1
View File
@@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
sp-core = { version = "4.0.0", path = "../core" }
sp-core = { version = "4.1.0-dev", path = "../core" }
sp-runtime = { version = "4.0.0-dev", path = "../runtime" }
lazy_static = "1.4.0"
strum = { version = "0.22.0", features = ["derive"] }
+1 -1
View File
@@ -21,7 +21,7 @@ schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backen
merlin = { version = "2.0", default-features = false }
parking_lot = { version = "0.11.1", default-features = false }
serde = { version = "1.0", optional = true}
sp-core = { version = "4.0.0", path = "../core" }
sp-core = { version = "4.1.0-dev", path = "../core" }
sp-externalities = { version = "0.10.0", path = "../externalities", default-features = false }
[dev-dependencies]
@@ -19,7 +19,7 @@ serde = { version = "1.0.126", optional = true, features = ["derive"] }
sp-std = { version = "4.0.0", default-features = false, path = "../std" }
sp-npos-elections-solution-type = { version = "4.0.0-dev", path = "./solution-type" }
sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../arithmetic" }
sp-core = { version = "4.0.0", default-features = false, path = "../core" }
sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" }
sp-runtime = { version = "4.0.0-dev", path = "../runtime", default-features = false }
[dev-dependencies]
+1 -1
View File
@@ -13,7 +13,7 @@ readme = "README.md"
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
sp-core = { version = "4.0.0", default-features = false, path = "../core" }
sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" }
sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" }
sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" }
+1 -1
View File
@@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
serde = { version = "1.0.126", features = ["derive"] }
sp-core = { version = "4.0.0", path = "../core" }
sp-core = { version = "4.1.0-dev", path = "../core" }
rustc-hash = "1.1.0"
[dev-dependencies]
@@ -28,7 +28,7 @@ impl-trait-for-tuples = "0.2.1"
[dev-dependencies]
sp-runtime-interface-test-wasm = { version = "2.0.0", path = "test-wasm" }
sp-state-machine = { version = "0.10.0-dev", path = "../state-machine" }
sp-core = { version = "4.0.0", path = "../core" }
sp-core = { version = "4.1.0-dev", path = "../core" }
sp-io = { version = "4.0.0-dev", path = "../io" }
rustversion = "1.0.5"
trybuild = "1.0.52"
@@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"]
sp-runtime-interface = { version = "4.0.0", default-features = false, path = "../" }
sp-std = { version = "4.0.0", default-features = false, path = "../../std" }
sp-io = { version = "4.0.0-dev", default-features = false, path = "../../io" }
sp-core = { version = "4.0.0", default-features = false, path = "../../core" }
sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" }
[build-dependencies]
substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" }
@@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"]
sp-runtime-interface = { version = "4.0.0", default-features = false, path = "../" }
sp-std = { version = "4.0.0", default-features = false, path = "../../std" }
sp-io = { version = "4.0.0-dev", default-features = false, path = "../../io" }
sp-core = { version = "4.0.0", default-features = false, path = "../../core" }
sp-core = { version = "4.1.0-dev", default-features = false, path = "../../core" }
[build-dependencies]
substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder" }
+1 -1
View File
@@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"]
serde = { version = "1.0.126", optional = true, features = ["derive"] }
codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] }
scale-info = { version = "1.0", default-features = false, features = ["derive"] }
sp-core = { version = "4.0.0", default-features = false, path = "../core" }
sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" }
sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../application-crypto" }
sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../arithmetic" }
sp-std = { version = "4.0.0", default-features = false, path = "../std" }
+1 -1
View File
@@ -20,7 +20,7 @@ wasmi = "0.9.0"
[dependencies]
wasmi = { version = "0.9.0", optional = true }
sp-core = { version = "4.0.0", default-features = false, path = "../core" }
sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" }
sp-std = { version = "4.0.0", default-features = false, path = "../std" }
sp-io = { version = "4.0.0-dev", default-features = false, path = "../io" }
sp-wasm-interface = { version = "4.0.0", default-features = false, path = "../wasm-interface" }
+1 -1
View File
@@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"]
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
scale-info = { version = "1.0", default-features = false, features = ["derive"] }
sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" }
sp-core = { version = "4.0.0", default-features = false, path = "../core" }
sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" }
sp-std = { version = "4.0.0", default-features = false, path = "../std" }
sp-staking = { version = "4.0.0-dev", default-features = false, path = "../staking" }
sp-runtime = { version = "4.0.0-dev", optional = true, path = "../runtime" }
@@ -21,7 +21,7 @@ hash-db = { version = "0.15.2", default-features = false }
trie-db = { version = "0.22.6", default-features = false }
trie-root = { version = "0.16.0", default-features = false }
sp-trie = { version = "4.0.0-dev", path = "../trie", default-features = false }
sp-core = { version = "4.0.0", path = "../core", default-features = false }
sp-core = { version = "4.1.0-dev", path = "../core", default-features = false }
sp-panic-handler = { version = "4.0.0-dev", path = "../panic-handler", optional = true }
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false }
num-traits = { version = "0.2.8", default-features = false }
+1 -1
View File
@@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
log = { version = "0.4.8", optional = true }
sp-core = { version = "4.0.0", default-features = false, path = "../core" }
sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" }
sp-externalities = { version = "0.10.0", optional = true, path = "../externalities" }
sp-io = { version = "4.0.0-dev", default-features = false, path = "../io" }
sp-runtime-interface = { version = "4.0.0", default-features = false, path = "../runtime-interface" }
@@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
sp-application-crypto = { version = "4.0.0-dev", default-features = false, path = "../application-crypto" }
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
sp-core = { version = "4.0.0", default-features = false, path = "../core" }
sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" }
serde = { version = "1.0.126", optional = true, features = ["derive"] }
sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" }
parity-util-mem = { version = "0.10.2", default-features = false, features = ["primitive-types"] }
@@ -17,7 +17,7 @@ sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inh
sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../runtime" }
sp-std = { version = "4.0.0", default-features = false, path = "../std" }
sp-trie = { version = "4.0.0-dev", optional = true, path = "../trie" }
sp-core = { version = "4.0.0", path = "../core", optional = true }
sp-core = { version = "4.1.0-dev", path = "../core", optional = true }
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
scale-info = { version = "1.0", default-features = false, features = ["derive"] }
log = { version = "0.4.8", optional = true }
+1 -1
View File
@@ -25,7 +25,7 @@ hash-db = { version = "0.15.2", default-features = false }
trie-db = { version = "0.22.6", default-features = false }
trie-root = { version = "0.16.0", default-features = false }
memory-db = { version = "0.27.0", default-features = false }
sp-core = { version = "4.0.0", default-features = false, path = "../core" }
sp-core = { version = "4.1.0-dev", default-features = false, path = "../core" }
[dev-dependencies]
trie-bench = "0.28.0"