From 14b21ab0dfd290bb3cb2611e468ea8617d4e51aa Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Fri, 2 Feb 2024 14:39:03 +0100 Subject: [PATCH] port subxt-signer to no-std (such a pain) --- Cargo.lock | 19 +- Cargo.toml | 15 +- core/src/lib.rs | 2 + signer/Cargo.toml | 26 +-- signer/src/crypto/secret_uri.rs | 8 +- signer/src/crypto/seed_from_entropy.rs | 1 + signer/src/ecdsa.rs | 56 ++++-- signer/src/lib.rs | 9 +- signer/src/sr25519.rs | 30 +-- signer/src/utils.rs | 4 +- testing/no-std-tests/Cargo.lock | 261 +++++++++++++++++++++++++ testing/no-std-tests/Cargo.toml | 1 + testing/no-std-tests/src/main.rs | 8 + 13 files changed, 378 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7dc9b6274b..2b28f2d1fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1076,6 +1076,12 @@ dependencies = [ "itertools 0.10.5", ] +[[package]] +name = "critical-section" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" + [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -2732,6 +2738,10 @@ name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +dependencies = [ + "critical-section", + "portable-atomic", +] [[package]] name = "oorandom" @@ -2979,6 +2989,12 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "portable-atomic" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -4622,9 +4638,11 @@ name = "subxt-signer" version = "0.34.0" dependencies = [ "bip39", + "derive_more", "getrandom", "hex", "hmac 0.12.1", + "once_cell", "parity-scale-codec", "pbkdf2 0.12.2", "regex", @@ -4636,7 +4654,6 @@ dependencies = [ "sp-core-hashing", "sp-keyring", "subxt-core", - "thiserror", "zeroize", ] diff --git a/Cargo.toml b/Cargo.toml index 1ecc821c31..86fced57fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,12 +76,13 @@ heck = "0.4.1" impl-serde = { version = "0.4.0", default-features = false } indoc = "2" jsonrpsee = { version = "0.21" } +once_cell = { version = "1.19.0", default-features = false } pretty_assertions = "1.4.0" primitive-types = { version = "0.12.2", default-features = false } proc-macro-error = "1.0.4" proc-macro2 = "1.0.78" quote = "1.0.35" -regex = "1.10.3" +regex = { version = "1.10.3", default-features = false } scale-info = { version = "2.10.0", default-features = false } scale-value = { version = "0.13.0", default-features = false } scale-bits = { version = "0.4.0", default-features = false } @@ -134,19 +135,19 @@ subxt-macro = { version = "0.34.0", path = "macro" } subxt-core = { version = "0.34.0", path = "core", default-features = false } subxt-metadata = { version = "0.34.0", path = "metadata", default-features = false } subxt-codegen = { version = "0.34.0", path = "codegen" } -subxt-signer = { version = "0.34.0", path = "signer" } +subxt-signer = { version = "0.34.0", path = "signer", default-features = false } subxt-lightclient = { version = "0.34.0", path = "lightclient", default-features = false } test-runtime = { path = "testing/test-runtime" } substrate-runner = { path = "testing/substrate-runner" } # subxt-signer deps that I expect aren't useful anywhere else: -bip39 = "2.0.0" -hmac = "0.12.1" +bip39 = { version = "2.0.0", default-features = false } +hmac = { version = "0.12.1", default-features = false } pbkdf2 = { version = "0.12.2", default-features = false } -schnorrkel = "0.11.4" -secp256k1 = "0.28.1" +schnorrkel = { version = "0.11.4", default-features = false } +secp256k1 = { version = "0.28.1", default-features = false } secrecy = "0.8.0" -sha2 = "0.10.8" +sha2 = { version = "0.10.8", default-features = false } zeroize = { version = "1", default-features = false } [profile.dev.package.smoldot-light] diff --git a/core/src/lib.rs b/core/src/lib.rs index fa2df7b65a..72720ece28 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -30,6 +30,8 @@ pub use config::{ PolkadotExtrinsicParams, SubstrateConfig, SubstrateExtrinsicParams, }; +pub use utils::{AccountId32, MultiAddress, MultiSignature, H160, H256, H512}; + pub use signer::Signer; pub use metadata::Metadata; diff --git a/signer/Cargo.toml b/signer/Cargo.toml index 4192e27a09..f60ad4e942 100644 --- a/signer/Cargo.toml +++ b/signer/Cargo.toml @@ -15,7 +15,8 @@ description = "Sign extrinsics to be submitted by Subxt" keywords = ["parity", "subxt", "extrinsic", "signer"] [features] -default = ["sr25519", "ecdsa", "subxt"] +default = ["sr25519", "ecdsa", "subxt", "std"] +std = [] # Pick the signer implementation(s) you need by enabling the # corresponding features. Note: I had more difficulties getting @@ -34,25 +35,28 @@ web = ["getrandom/js"] [dependencies] subxt-core = { workspace = true, optional = true, default-features = false } -regex = { workspace = true } +regex = { workspace = true, default-features = false } hex = { workspace = true } codec = { package = "parity-scale-codec", workspace = true, features = ["derive"] } -sp-core-hashing = { workspace = true } -thiserror = { workspace = true } -pbkdf2 = { workspace = true } -sha2 = { workspace = true } -hmac = { workspace = true } +sp-core-hashing = { workspace = true, default-features = false } +derive_more = { workspace = true } +pbkdf2 = { workspace = true, default-features = false } +sha2 = { workspace = true, default-features = false } +hmac = { workspace = true, default-features = false } zeroize = { workspace = true } -bip39 = { workspace = true } -schnorrkel = { workspace = true, optional = true } -secp256k1 = { workspace = true, features = ["recovery", "global-context"], optional = true } +bip39 = { workspace = true, default-features = false, features = ["unicode-normalization"] } +schnorrkel = { workspace = true, optional = true, default-features = false } +secp256k1 = { workspace = true, optional = true, default-features = false, features = ["alloc", "recovery"] } # features = ["recovery", "global-context"], secrecy = { workspace = true } +# We only pull this in because `std::sync::OnceLock` is not available in no-std contexts. +once_cell = { workspace = true, default-features = false, features = ["alloc", "critical-section"] } + # We only pull this in to enable the JS flag for schnorrkel to use. getrandom = { workspace = true, optional = true } [dev-dependencies] -sp-core = { workspace = true, features = ["std"] } +sp-core = { workspace = true, default-features = false } sp-keyring = { workspace = true } [package.metadata.cargo-machete] diff --git a/signer/src/crypto/secret_uri.rs b/signer/src/crypto/secret_uri.rs index 7be43b8286..027d938b7e 100644 --- a/signer/src/crypto/secret_uri.rs +++ b/signer/src/crypto/secret_uri.rs @@ -3,6 +3,8 @@ // see LICENSE for license details. use super::DeriveJunction; +use alloc::vec::Vec; +use derive_more::Display; use regex::Regex; use secrecy::SecretString; @@ -88,7 +90,7 @@ pub struct SecretUri { pub junctions: Vec, } -impl std::str::FromStr for SecretUri { +impl core::str::FromStr for SecretUri { type Err = SecretUriError; fn from_str(s: &str) -> Result { @@ -115,10 +117,10 @@ impl std::str::FromStr for SecretUri { } /// This is returned if `FromStr` cannot parse a string into a `SecretUri`. -#[derive(Debug, Copy, Clone, PartialEq, thiserror::Error)] +#[derive(Debug, Copy, Clone, PartialEq, Display)] pub enum SecretUriError { /// Parsing the secret URI from a string failed; wrong format. - #[error("Invalid secret phrase format")] + #[display(fmt = "Invalid secret phrase format")] InvalidFormat, } diff --git a/signer/src/crypto/seed_from_entropy.rs b/signer/src/crypto/seed_from_entropy.rs index 7643ff7835..e665c132ab 100644 --- a/signer/src/crypto/seed_from_entropy.rs +++ b/signer/src/crypto/seed_from_entropy.rs @@ -2,6 +2,7 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. +use alloc::string::String; use hmac::Hmac; use pbkdf2::pbkdf2; use sha2::Sha512; diff --git a/signer/src/ecdsa.rs b/signer/src/ecdsa.rs index a76054abf1..6946446f60 100644 --- a/signer/src/ecdsa.rs +++ b/signer/src/ecdsa.rs @@ -6,10 +6,22 @@ use codec::Encode; use crate::crypto::{seed_from_entropy, DeriveJunction, SecretUri}; +use core::str::FromStr; +use derive_more::{Display, From}; use hex::FromHex; -use secp256k1::{ecdsa::RecoverableSignature, Message, SecretKey, SECP256K1}; +use secp256k1::{ecdsa::RecoverableSignature, All, Message, Secp256k1, SecretKey}; use secrecy::ExposeSecret; +struct GlobalSecp256K1Context; +impl core::ops::Deref for GlobalSecp256K1Context { + type Target = Secp256k1; + + fn deref(&self) -> &Self::Target { + static ONCE: once_cell::sync::OnceCell> = once_cell::sync::OnceCell::new(); + ONCE.get_or_init(|| Secp256k1::new()) + } +} + const SEED_LENGTH: usize = 32; /// Seed bytes used to generate a key pair. @@ -68,7 +80,7 @@ impl Keypair { let seed = Seed::from_hex(hex_str)?; Self::from_seed(seed)? } else { - let phrase = bip39::Mnemonic::parse(phrase.expose_secret().as_str())?; + let phrase = bip39::Mnemonic::from_str(phrase.expose_secret().as_str())?; let pass_str = password.as_ref().map(|p| p.expose_secret().as_str()); Self::from_phrase(&phrase, pass_str)? }; @@ -91,8 +103,9 @@ impl Keypair { /// keypair.sign(b"Hello world!"); /// ``` pub fn from_phrase(mnemonic: &bip39::Mnemonic, password: Option<&str>) -> Result { - let big_seed = seed_from_entropy(&mnemonic.to_entropy(), password.unwrap_or("")) - .ok_or(Error::InvalidSeed)?; + let (arr, len) = mnemonic.to_entropy_array(); + let big_seed = + seed_from_entropy(&arr[0..len], password.unwrap_or("")).ok_or(Error::InvalidSeed)?; let seed: Seed = big_seed[..SEED_LENGTH] .try_into() @@ -109,7 +122,8 @@ impl Keypair { pub fn from_seed(seed: Seed) -> Result { let secret = SecretKey::from_slice(&seed).map_err(|_| Error::InvalidSeed)?; Ok(Self(secp256k1::Keypair::from_secret_key( - SECP256K1, &secret, + &GlobalSecp256K1Context, + &secret, ))) } @@ -161,9 +175,9 @@ impl Keypair { // From sp_core::ecdsa::sign_prehashed: let wrapped = Message::from_digest_slice(&message_hash).expect("Message is 32 bytes; qed"); let recsig: RecoverableSignature = - SECP256K1.sign_ecdsa_recoverable(&wrapped, &self.0.secret_key()); + GlobalSecp256K1Context.sign_ecdsa_recoverable(&wrapped, &self.0.secret_key()); // From sp_core::ecdsa's `impl From for Signature`: - let (recid, sig) = recsig.serialize_compact(); + let (recid, sig): (_, [u8; 64]) = recsig.serialize_compact(); let mut signature_bytes: [u8; 65] = [0; 65]; signature_bytes[..64].copy_from_slice(&sig); signature_bytes[64] = (recid.to_i32() & 0xFF) as u8; @@ -192,31 +206,35 @@ pub fn verify>(sig: &Signature, message: M, pubkey: &PublicKey) - }; let message_hash = sp_core_hashing::blake2_256(message.as_ref()); let wrapped = Message::from_digest_slice(&message_hash).expect("Message is 32 bytes; qed"); - signature.verify(&wrapped, &public).is_ok() + GlobalSecp256K1Context + .verify_ecdsa(&wrapped, &signature, &public) + .is_ok() } /// An error handed back if creating a keypair fails. -#[derive(Debug, PartialEq, thiserror::Error)] +#[derive(Debug, PartialEq, Display, From)] pub enum Error { /// Invalid seed. - #[error("Invalid seed (was it the wrong length?)")] + #[display(fmt = "Invalid seed (was it the wrong length?)")] + #[from(ignore)] InvalidSeed, /// Invalid seed. - #[error("Invalid seed for ECDSA, contained soft junction")] + #[display(fmt = "Invalid seed for ECDSA, contained soft junction")] + #[from(ignore)] SoftJunction, /// Invalid phrase. - #[error("Cannot parse phrase: {0}")] - Phrase(#[from] bip39::Error), + #[display(fmt = "Cannot parse phrase: {_0}")] + Phrase(bip39::Error), /// Invalid hex. - #[error("Cannot parse hex string: {0}")] - Hex(#[from] hex::FromHexError), + #[display(fmt = "Cannot parse hex string: {_0}")] + Hex(hex::FromHexError), } /// Dev accounts, helpful for testing but not to be used in production, /// since the secret keys are known. pub mod dev { use super::*; - use std::str::FromStr; + use core::str::FromStr; once_static_cloned! { /// Equivalent to `{DEV_PHRASE}//Alice`. @@ -260,9 +278,9 @@ pub mod dev { mod subxt_compat { use super::*; - use subxt::config::Config; - use subxt::tx::Signer as SignerT; - use subxt::utils::{AccountId32, MultiAddress, MultiSignature}; + use subxt_core::config::Config; + use subxt_core::utils::{AccountId32, MultiAddress, MultiSignature}; + use subxt_core::Signer as SignerT; impl From for MultiSignature { fn from(value: Signature) -> Self { diff --git a/signer/src/lib.rs b/signer/src/lib.rs index 2c79d6a1ec..db13732327 100644 --- a/signer/src/lib.rs +++ b/signer/src/lib.rs @@ -14,6 +14,9 @@ //! subxt transactions for chains supporting sr25519 signatures. #![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; #[macro_use] mod utils; @@ -40,9 +43,3 @@ pub use secrecy::{ExposeSecret, SecretString}; // SecretUri's can be parsed from strings and used to generate key pairs. // DeriveJunctions are the "path" part of these SecretUris. pub use crypto::{DeriveJunction, SecretUri, SecretUriError, DEV_PHRASE}; - -#[cfg(any( - all(feature = "web", feature = "native"), - not(any(feature = "web", feature = "native")) -))] -compile_error!("subxt-signer: exactly one of the 'web' and 'native' features should be used."); diff --git a/signer/src/sr25519.rs b/signer/src/sr25519.rs index 01e6cc84b1..fcf48f8555 100644 --- a/signer/src/sr25519.rs +++ b/signer/src/sr25519.rs @@ -4,7 +4,11 @@ //! An sr25519 keypair implementation. +use core::str::FromStr; + use crate::crypto::{seed_from_entropy, DeriveJunction, SecretUri}; + +use derive_more::{Display, From}; use hex::FromHex; use schnorrkel::{ derive::{ChainCode, Derivation}, @@ -72,7 +76,7 @@ impl Keypair { let seed = Seed::from_hex(hex_str)?; Self::from_seed(seed)? } else { - let phrase = bip39::Mnemonic::parse(phrase.expose_secret().as_str())?; + let phrase = bip39::Mnemonic::from_str(phrase.expose_secret().as_str())?; let pass_str = password.as_ref().map(|p| p.expose_secret().as_str()); Self::from_phrase(&phrase, pass_str)? }; @@ -95,8 +99,9 @@ impl Keypair { /// keypair.sign(b"Hello world!"); /// ``` pub fn from_phrase(mnemonic: &bip39::Mnemonic, password: Option<&str>) -> Result { - let big_seed = seed_from_entropy(&mnemonic.to_entropy(), password.unwrap_or("")) - .ok_or(Error::InvalidSeed)?; + let (arr, len) = mnemonic.to_entropy_array(); + let big_seed = + seed_from_entropy(&arr[0..len], password.unwrap_or("")).ok_or(Error::InvalidSeed)?; let seed: Seed = big_seed[..SEED_LENGTH] .try_into() @@ -187,24 +192,25 @@ pub fn verify>(sig: &Signature, message: M, pubkey: &PublicKey) - } /// An error handed back if creating a keypair fails. -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Display, From)] pub enum Error { /// Invalid seed. - #[error("Invalid seed (was it the wrong length?)")] + #[display(fmt = "Invalid seed (was it the wrong length?)")] + #[from(ignore)] InvalidSeed, /// Invalid phrase. - #[error("Cannot parse phrase: {0}")] - Phrase(#[from] bip39::Error), + #[display(fmt = "Cannot parse phrase: {_0}")] + Phrase(bip39::Error), /// Invalid hex. - #[error("Cannot parse hex string: {0}")] - Hex(#[from] hex::FromHexError), + #[display(fmt = "Cannot parse hex string: {_0}")] + Hex(hex::FromHexError), } /// Dev accounts, helpful for testing but not to be used in production, /// since the secret keys are known. pub mod dev { use super::*; - use std::str::FromStr; + use core::str::FromStr; once_static_cloned! { /// Equivalent to `{DEV_PHRASE}//Alice`. @@ -249,9 +255,7 @@ pub mod dev { mod subxt_compat { use super::*; - use subxt::config::Config; - use subxt::tx::Signer as SignerT; - use subxt::utils::{AccountId32, MultiAddress, MultiSignature}; + use subxt_core::{AccountId32, Config, MultiAddress, MultiSignature, Signer as SignerT}; impl From for MultiSignature { fn from(value: Signature) -> Self { diff --git a/signer/src/utils.rs b/signer/src/utils.rs index 2e12665419..52a935a1fd 100644 --- a/signer/src/utils.rs +++ b/signer/src/utils.rs @@ -19,7 +19,7 @@ macro_rules! once_static { $( $(#[$attr])* $vis fn $name() -> &'static $ty { - static VAR: std::sync::OnceLock<$ty> = std::sync::OnceLock::new(); + static VAR: once_cell::sync::OnceCell<$ty> = once_cell::sync::OnceCell::new(); VAR.get_or_init(|| { $expr }) } )+ @@ -33,7 +33,7 @@ macro_rules! once_static_cloned { $( $(#[$attr])* $vis fn $name() -> $ty { - static VAR: std::sync::OnceLock<$ty> = std::sync::OnceLock::new(); + static VAR: once_cell::sync::OnceCell<$ty> = once_cell::sync::OnceCell::new(); VAR.get_or_init(|| { $expr }).clone() } )+ diff --git a/testing/no-std-tests/Cargo.lock b/testing/no-std-tests/Cargo.lock index 184ac58900..b13c83f097 100644 --- a/testing/no-std-tests/Cargo.lock +++ b/testing/no-std-tests/Cargo.lock @@ -38,6 +38,22 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" +[[package]] +name = "bip39" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" +dependencies = [ + "bitcoin_hashes", + "unicode-normalization", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" + [[package]] name = "bitvec" version = "1.0.1" @@ -91,6 +107,15 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -118,6 +143,12 @@ dependencies = [ "libc", ] +[[package]] +name = "critical-section" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" + [[package]] name = "crunchy" version = "0.2.2" @@ -134,6 +165,34 @@ dependencies = [ "typenum", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "platforms", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "darling" version = "0.14.4" @@ -216,6 +275,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "fiat-crypto" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" + [[package]] name = "fixed-hash" version = "0.8.0" @@ -269,6 +334,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom_or_panic" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea1015b5a70616b688dc230cfe50c8af89d972cb132d5a622814d29773b10b9" +dependencies = [ + "rand_core", +] + [[package]] name = "hashbrown" version = "0.14.3" @@ -285,6 +359,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -363,11 +446,27 @@ version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core", + "zeroize", +] + [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +dependencies = [ + "critical-section", + "portable-atomic", +] [[package]] name = "parity-scale-codec" @@ -393,6 +492,27 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", +] + +[[package]] +name = "platforms" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626dec3cac7cc0e1577a2ec3fc496277ec2baa084bebad95bb6fdbfae235f84c" + +[[package]] +name = "portable-atomic" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + [[package]] name = "primitive-types" version = "0.12.2" @@ -450,6 +570,37 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "rustc_version" version = "0.4.0" @@ -573,6 +724,50 @@ dependencies = [ "scale-info", ] +[[package]] +name = "schnorrkel" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de18f6d8ba0aad7045f5feae07ec29899c1112584a38509a84ad7b04451eaa0" +dependencies = [ + "arrayref", + "arrayvec", + "curve25519-dalek", + "getrandom_or_panic", + "merlin", + "rand_core", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" +dependencies = [ + "cc", +] + +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "zeroize", +] + [[package]] name = "semver" version = "1.0.21" @@ -703,6 +898,7 @@ dependencies = [ "parity-scale-codec", "subxt-core", "subxt-metadata", + "subxt-signer", ] [[package]] @@ -717,6 +913,27 @@ dependencies = [ "sp-core-hashing", ] +[[package]] +name = "subxt-signer" +version = "0.34.0" +dependencies = [ + "bip39", + "derive_more", + "hex", + "hmac", + "once_cell", + "parity-scale-codec", + "pbkdf2", + "regex", + "schnorrkel", + "secp256k1", + "secrecy", + "sha2", + "sp-core-hashing", + "subxt-core", + "zeroize", +] + [[package]] name = "syn" version = "1.0.109" @@ -745,6 +962,21 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "toml_datetime" version = "0.6.3" @@ -808,6 +1040,15 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + [[package]] name = "version_check" version = "0.9.4" @@ -851,3 +1092,23 @@ dependencies = [ "quote", "syn 2.0.48", ] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] diff --git a/testing/no-std-tests/Cargo.toml b/testing/no-std-tests/Cargo.toml index 5e6f14c074..2d6da33488 100644 --- a/testing/no-std-tests/Cargo.toml +++ b/testing/no-std-tests/Cargo.toml @@ -8,6 +8,7 @@ resolver = "2" [dependencies] subxt-metadata = { path = "../../metadata", default-features = false } subxt-core = { path = "../../core", default-features = false } +subxt-signer = { path = "../../signer", default-features = false, features = ["sr25519", "ecdsa", "subxt"] } codec = { package = "parity-scale-codec", version = "3.6.9", default-features = false, features = ["derive"] } libc = { version = "0.2", default-features = false } libc_alloc = { version = "1.0.6" } diff --git a/testing/no-std-tests/src/main.rs b/testing/no-std-tests/src/main.rs index 2812cae098..9b1dd79e60 100644 --- a/testing/no-std-tests/src/main.rs +++ b/testing/no-std-tests/src/main.rs @@ -49,6 +49,14 @@ fn subxt_metadata_test() { subxt_metadata::Metadata::decode(&mut &METADATA[..]).expect("should be valid metadata"); } +fn subxt_signer_test() { + use subxt_signer::{ SecretUri, ecdsa::Keypair }; + use core::str::FromStr; + let uri = SecretUri::from_str("//Alice").unwrap(); + let keypair = Keypair::from_uri(&uri).unwrap(); +} + fn subxt_core_test() { let _ = subxt_core::utils::Era::Immortal; } +