diff --git a/Cargo.lock b/Cargo.lock index 5326152b43..a4e699dcef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -542,16 +542,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.34" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.52.0", + "windows-link", ] [[package]] @@ -1206,8 +1206,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if 1.0.0", + "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -3169,13 +3171,13 @@ dependencies = [ "chrono", "curve25519-dalek", "ed25519-dalek", + "getrandom 0.2.12", "hashbrown 0.15.2", "lazy_static", "libsecp256k1", "nix", "proptest", "rand 0.8.5", - "rand_core 0.6.4", "ripemd", "rusqlite", "secp256k1", @@ -4178,6 +4180,12 @@ dependencies = [ "windows-targets 0.52.0", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index 74f59ccb84..cabb5abb99 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,24 +14,29 @@ members = [ # Dependencies we want to keep the same between workspace members [workspace.dependencies] -ed25519-dalek = { version = "2.1.1", features = ["serde", "rand_core"] } +ed25519-dalek = { version = "2.1.1", default-features = false } hashbrown = { version = "0.15.2", features = ["serde"] } +lazy_static = "1.4.0" rand_core = "0.6.4" rand = "0.8" rand_chacha = "0.3.1" -tikv-jemallocator = "0.5.4" +serde = "1" +serde_derive = "1" +serde_json = { version = "1.0", features = ["arbitrary_precision", "unbounded_depth"] } +slog = { version = "2.5.2", features = [ "max_level_trace" ] } rusqlite = { version = "0.31.0", features = ["blob", "serde_json", "i128_blob", "bundled", "trace"] } +tikv-jemallocator = "0.5.4" thiserror = "1.0.65" toml = "0.5.6" # Use a bit more than default optimization for -# dev builds to speed up test execution +# dev builds to speed up test execution [profile.dev] opt-level = 1 # Use release-level optimization for dependencies # This slows down "first" builds on development environments, -# but won't impact subsequent builds. +# but won't impact subsequent builds. [profile.dev.package."*"] opt-level = 3 diff --git a/stacks-common/Cargo.toml b/stacks-common/Cargo.toml index 45afb08452..4b2c96d3bb 100644 --- a/stacks-common/Cargo.toml +++ b/stacks-common/Cargo.toml @@ -30,21 +30,26 @@ name = "stacks_common" path = "./src/libcommon.rs" [dependencies] -rand = { workspace = true } -serde = { version = "1.0", features = ["derive"] } -serde_derive = "1" -sha3 = "0.10.1" -ripemd = "0.1.1" -lazy_static = "1.4.0" -slog = { version = "2.5.2", features = ["max_level_trace"] } -slog-term = "2.6.0" -slog-json = { version = "2.3.0", optional = true } -chrono = "0.4.19" +chrono = { version = "0.4.41", default-features = false, features = ["clock"] } +curve25519-dalek = { version = "4.1.3", default-features = false, features = ["serde"] } +ed25519-dalek = { workspace = true } hashbrown = { workspace = true } -rusqlite = { workspace = true, optional = true } +lazy_static = { workspace = true } +ripemd = { version = "0.1.1", default-features = false } +serde = { workspace = true , features = ["derive"] } +serde_derive = { workspace = true } +serde_json = { workspace = true } +sha3 = { version = "0.10.1", default-features = false } +slog = { workspace = true } +slog-term = { version = "2.6.0", default-features = false } + +# Optional dependencies +getrandom = { version = "0.2", default-features = false, optional = true } +rand = { workspace = true, optional = true } +slog-json = { version = "2.3.0", default-features = false, optional = true } [target.'cfg(unix)'.dependencies] -nix = "0.23" +nix = {version = "0.23", default-features = false, optional = true} [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = [ @@ -52,47 +57,46 @@ winapi = { version = "0.3", features = [ "handleapi", "synchapi", "winbase", -] } - -[target.'cfg(windows)'.dev-dependencies] -winapi = { version = "0.3", features = ["fileapi", "processenv", "winnt"] } - -[dependencies.serde_json] -version = "1.0" -features = ["arbitrary_precision", "unbounded_depth"] - -[dependencies.ed25519-dalek] -workspace = true - -[dependencies.curve25519-dalek] -version = "4.1.3" -features = ["serde"] +], optional = true } [target.'cfg(not(target_family = "wasm"))'.dependencies] -secp256k1 = { version = "0.24.3", features = ["serde", "recovery"] } +secp256k1 = { version = "0.24.3", default-features = false, features = ["std","serde", "recovery"] } +rusqlite = { workspace = true, optional = true } [target.'cfg(target_family = "wasm")'.dependencies] -libsecp256k1 = { version = "0.7.0" } +libsecp256k1 = { version = "0.7.0", default-features = false, features = ["hmac"] } + +[target.'cfg(all(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"), not(any(target_os="windows"))))'.dependencies] +sha2 = { version = "0.10", features = ["asm"] } + +[target.'cfg(any(not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64")), any(target_os="windows")))'.dependencies] +sha2 = { version = "0.10" } [dev-dependencies] -rand_core = { workspace = true } proptest = "1.6.0" +[target.'cfg(windows)'.dev-dependencies] +winapi = { version = "0.3", features = ["fileapi", "processenv", "winnt"] } + +[build-dependencies] +toml = { workspace = true } + [features] -default = ["developer-mode"] +default = ["developer-mode", "ctrlc-handler", "rand"] developer-mode = [] +# Enables graceful shutdown handling for Ctrl+C (SIGINT) signals. +# This pulls in the `nix` or `winapi` dependency. +ctrlc-handler = ["dep:nix", "dep:winapi"] slog_json = ["slog-json"] -rusqlite = ["dep:rusqlite"] -testing = [] +rusqlite = ["dep:rusqlite", "rand"] +# Enables the rand module. This flag must be off on deterministic +# platforms such as CosmWasm +rand = ["dep:rand"] serde = [] +testing = ["rand"] bech32_std = [] bech32_strict = [] -[build-dependencies] -toml = "0.5.6" - -[target.'cfg(all(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"), not(any(target_os="windows"))))'.dependencies] -sha2 = { version = "0.10", features = ["asm"] } - -[target.'cfg(any(not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64")), any(target_os="windows")))'.dependencies] -sha2 = { version = "0.10" } +# Wasm-specific features for easier configuration +wasm-web = ["rand", "getrandom/js", "libsecp256k1/static-context"] +wasm-deterministic = ["getrandom/custom"] diff --git a/stacks-common/src/deps_common/bitcoin/mod.rs b/stacks-common/src/deps_common/bitcoin/mod.rs index 097bfa2b65..2585d164a8 100644 --- a/stacks-common/src/deps_common/bitcoin/mod.rs +++ b/stacks-common/src/deps_common/bitcoin/mod.rs @@ -25,9 +25,6 @@ //! software. //! -// Clippy flags -#![allow(clippy::needless_range_loop)] // suggests making a big mess of array newtypes - // Coding conventions #![deny(non_upper_case_globals)] #![deny(non_camel_case_types)] diff --git a/stacks-common/src/deps_common/bitcoin/util/mod.rs b/stacks-common/src/deps_common/bitcoin/util/mod.rs index 7032ba41cd..a4740ffe06 100644 --- a/stacks-common/src/deps_common/bitcoin/util/mod.rs +++ b/stacks-common/src/deps_common/bitcoin/util/mod.rs @@ -20,8 +20,6 @@ pub mod hash; use std::{error, fmt}; -use secp256k1; - use crate::deps_common::bitcoin::network; use crate::deps_common::bitcoin::network::serialize; @@ -50,8 +48,6 @@ pub trait BitArray { /// if appropriate. #[derive(Debug)] pub enum Error { - /// secp-related error - Secp256k1(secp256k1::Error), /// Serialization error Serialize(serialize::Error), /// Network error @@ -65,7 +61,6 @@ pub enum Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Error::Secp256k1(ref e) => fmt::Display::fmt(e, f), Error::Serialize(ref e) => fmt::Display::fmt(e, f), Error::Network(ref e) => fmt::Display::fmt(e, f), Error::SpvBadProofOfWork => f.write_str("target correct but not attained"), @@ -77,7 +72,6 @@ impl fmt::Display for Error { impl error::Error for Error { fn cause(&self) -> Option<&dyn error::Error> { match *self { - Error::Secp256k1(ref e) => Some(e), Error::Serialize(ref e) => Some(e), Error::Network(ref e) => Some(e), Error::SpvBadProofOfWork | Error::SpvBadTarget => None, @@ -85,20 +79,6 @@ impl error::Error for Error { } } -#[doc(hidden)] -impl From for Error { - fn from(e: secp256k1::Error) -> Error { - Error::Secp256k1(e) - } -} - -#[doc(hidden)] -impl From for Error { - fn from(e: serialize::Error) -> Error { - Error::Serialize(e) - } -} - #[doc(hidden)] impl From for Error { fn from(e: network::Error) -> Error { diff --git a/stacks-common/src/libcommon.rs b/stacks-common/src/libcommon.rs index 48f8cd5970..2a83bd4270 100644 --- a/stacks-common/src/libcommon.rs +++ b/stacks-common/src/libcommon.rs @@ -4,7 +4,6 @@ #![allow(non_snake_case)] #![allow(non_upper_case_globals)] #![cfg_attr(test, allow(unused_variables, unused_assignments))] -#![allow(clippy::assertions_on_constants)] #[allow(unused_imports)] #[macro_use(o, slog_log, slog_trace, slog_debug, slog_info, slog_warn, slog_error)] @@ -13,10 +12,10 @@ extern crate slog; #[macro_use] extern crate serde_derive; -#[cfg(unix)] +#[cfg(all(unix, feature = "ctrlc-handler"))] extern crate nix; -#[cfg(windows)] +#[cfg(all(windows, feature = "ctrlc-handler"))] extern crate winapi; #[macro_use] @@ -29,7 +28,14 @@ pub mod types; pub mod address; -pub mod deps_common; +pub mod deps_common { + pub mod bech32; + pub mod bitcoin; + pub mod httparse; + + #[cfg(all(not(target_family = "wasm"), feature = "ctrlc-handler"))] + pub mod ctrlc; +} pub mod bitvec; diff --git a/stacks-common/src/types/chainstate.rs b/stacks-common/src/types/chainstate.rs index 7026eacffd..58f247a88f 100644 --- a/stacks-common/src/types/chainstate.rs +++ b/stacks-common/src/types/chainstate.rs @@ -168,8 +168,12 @@ impl SortitionId { write!(hasher, "{pox}").expect("Failed to deserialize PoX ID into the hasher"); let h = Sha512Trunc256Sum::from_hasher(hasher); let s = SortitionId(h.0); - test_debug!("SortitionId({}) = {} + {}", &s, bhh, pox); - s + // The `test_debug!` macro will expand to nothing on release builds. + #[allow(clippy::let_and_return)] + { + test_debug!("SortitionId({}) = {} + {}", &s, bhh, pox); + s + } } } } diff --git a/stacks-common/src/util/chunked_encoding.rs b/stacks-common/src/util/chunked_encoding.rs index ef6ce6fa79..81ee94ae99 100644 --- a/stacks-common/src/util/chunked_encoding.rs +++ b/stacks-common/src/util/chunked_encoding.rs @@ -447,7 +447,7 @@ mod test { use std::io; use std::io::Read; - use rand::RngCore; + use rand::RngCore as _; use super::*; diff --git a/stacks-common/src/util/mod.rs b/stacks-common/src/util/mod.rs index 1765817f29..69e14a4473 100644 --- a/stacks-common/src/util/mod.rs +++ b/stacks-common/src/util/mod.rs @@ -147,3 +147,5 @@ where let reader = BufReader::new(file); serde_json::from_reader::<_, J>(reader).map_err(std::io::Error::from) } +#[cfg(all(feature = "rusqlite", target_family = "wasm"))] +compile_error!("The `rusqlite` feature is not supported for wasm targets"); diff --git a/stacks-common/src/util/pipe.rs b/stacks-common/src/util/pipe.rs index c851c04ae5..e7bfca27fb 100644 --- a/stacks-common/src/util/pipe.rs +++ b/stacks-common/src/util/pipe.rs @@ -317,8 +317,7 @@ mod test { use std::io::{Read, Write}; use std::{io, thread}; - use rand; - use rand::RngCore; + use rand::RngCore as _; use super::*; diff --git a/stacks-common/src/util/secp256k1/native.rs b/stacks-common/src/util/secp256k1/native.rs index d47bcb597b..74c57ad837 100644 --- a/stacks-common/src/util/secp256k1/native.rs +++ b/stacks-common/src/util/secp256k1/native.rs @@ -24,7 +24,6 @@ use ::secp256k1::{ constants as LibSecp256k1Constants, Error as LibSecp256k1Error, Message as LibSecp256k1Message, PublicKey as LibSecp256k1PublicKey, Secp256k1, SecretKey as LibSecp256k1PrivateKey, }; -use rand::RngCore; use serde::de::{Deserialize, Error as de_Error}; use serde::Serialize; @@ -240,7 +239,10 @@ impl PublicKey for Secp256k1PublicKey { } impl Secp256k1PrivateKey { + #[cfg(feature = "rand")] pub fn random() -> Secp256k1PrivateKey { + use rand::RngCore as _; + let mut rng = rand::thread_rng(); loop { // keep trying to generate valid bytes @@ -422,6 +424,7 @@ pub fn secp256k1_verify( #[cfg(test)] mod tests { + use rand::RngCore as _; use secp256k1; use secp256k1::{PublicKey as LibSecp256k1PublicKey, Secp256k1}; @@ -612,15 +615,13 @@ mod tests { (Err(e1), Err(e2)) => assert_eq!(e1, e2), (Err(e1), _) => { test_debug!("Failed to verify signature: {}", e1); - assert!( - false, + panic!( "failed fixture (verification: {:?}): {:#?}", &ver_res, &fixture ); } (_, _) => { - assert!( - false, + panic!( "failed fixture (verification: {:?}): {:#?}", &ver_res, &fixture ); diff --git a/stacks-common/src/util/secp256k1/wasm.rs b/stacks-common/src/util/secp256k1/wasm.rs index bea3c5e2d5..c9c79a352e 100644 --- a/stacks-common/src/util/secp256k1/wasm.rs +++ b/stacks-common/src/util/secp256k1/wasm.rs @@ -16,12 +16,12 @@ use ::libsecp256k1; pub use ::libsecp256k1::Error; +#[cfg(not(feature = "wasm-deterministic"))] +use ::libsecp256k1::{Error as LibSecp256k1Error, Message as LibSecp256k1Message}; use ::libsecp256k1::{ - Error as LibSecp256k1Error, Message as LibSecp256k1Message, PublicKey as LibSecp256k1PublicKey, - RecoveryId as LibSecp256k1RecoveryId, SecretKey as LibSecp256k1PrivateKey, - Signature as LibSecp256k1Signature, + PublicKey as LibSecp256k1PublicKey, RecoveryId as LibSecp256k1RecoveryId, + SecretKey as LibSecp256k1PrivateKey, Signature as LibSecp256k1Signature, }; -use rand::RngCore; use serde::de::{Deserialize, Error as de_Error}; use serde::Serialize; @@ -102,6 +102,7 @@ impl Secp256k1PublicKey { Secp256k1PublicKey::from_slice(&data[..]).map_err(|_e| "Invalid public key hex string") } + #[cfg(not(feature = "wasm-deterministic"))] pub fn from_private(privk: &Secp256k1PrivateKey) -> Secp256k1PublicKey { let key = LibSecp256k1PublicKey::from_secret_key(&privk.key); Secp256k1PublicKey { @@ -110,6 +111,7 @@ impl Secp256k1PublicKey { } } + #[cfg(not(feature = "wasm-deterministic"))] /// recover message and signature to public key (will be compressed) pub fn recover_to_pubkey( msg: &[u8], @@ -123,7 +125,10 @@ impl Secp256k1PublicKey { } impl Secp256k1PrivateKey { + #[cfg(feature = "rand")] pub fn new() -> Secp256k1PrivateKey { + use rand::RngCore as _; + let mut rng = rand::thread_rng(); loop { // keep trying to generate valid bytes @@ -184,6 +189,7 @@ impl Secp256k1PrivateKey { } } +#[cfg(not(feature = "wasm-deterministic"))] pub fn secp256k1_recover( message_arr: &[u8], serialized_signature: &[u8], @@ -195,6 +201,7 @@ pub fn secp256k1_recover( Ok(recovered_pub_key.serialize_compressed()) } +#[cfg(not(feature = "wasm-deterministic"))] pub fn secp256k1_verify( message_arr: &[u8], serialized_signature: &[u8], @@ -298,6 +305,12 @@ impl PublicKey for Secp256k1PublicKey { self.to_bytes() } + #[cfg(feature = "wasm-deterministic")] + fn verify(&self, _data_hash: &[u8], _sig: &MessageSignature) -> Result { + Err("Not implemented for wasm-deterministic") + } + + #[cfg(not(feature = "wasm-deterministic"))] fn verify(&self, data_hash: &[u8], sig: &MessageSignature) -> Result { let pub_key = Secp256k1PublicKey::recover_to_pubkey(data_hash, sig)?; Ok(self.eq(&pub_key)) @@ -313,6 +326,12 @@ impl PrivateKey for Secp256k1PrivateKey { bits } + #[cfg(feature = "wasm-deterministic")] + fn sign(&self, _data_hash: &[u8]) -> Result { + Err("Not implemented for wasm-deterministic") + } + + #[cfg(not(feature = "wasm-deterministic"))] fn sign(&self, data_hash: &[u8]) -> Result { let message = LibSecp256k1Message::parse_slice(data_hash) .map_err(|_e| "Invalid message: failed to decode data hash: must be a 32-byte hash")?; diff --git a/stacks-common/src/util/vrf.rs b/stacks-common/src/util/vrf.rs index bd124a5da0..a0cbee3373 100644 --- a/stacks-common/src/util/vrf.rs +++ b/stacks-common/src/util/vrf.rs @@ -27,7 +27,6 @@ use std::{error, fmt}; use curve25519_dalek::constants::ED25519_BASEPOINT_POINT; use curve25519_dalek::edwards::{CompressedEdwardsY, EdwardsPoint}; use curve25519_dalek::scalar::{clamp_integer, Scalar as ed25519_Scalar}; -use rand; use sha2::{Digest, Sha512}; use crate::util::hash::{hex_bytes, to_hex}; @@ -99,6 +98,7 @@ impl PartialEq for VRFPrivateKey { } } +#[cfg(any(test, feature = "testing"))] impl Default for VRFPrivateKey { fn default() -> Self { Self::new() @@ -106,9 +106,13 @@ impl Default for VRFPrivateKey { } impl VRFPrivateKey { + #[cfg(any(test, feature = "testing"))] pub fn new() -> VRFPrivateKey { + use rand::RngCore as _; let mut rng = rand::thread_rng(); - let signing_key = ed25519_dalek::SigningKey::generate(&mut rng); + let mut sk_bytes = [0u8; 32]; + rng.fill_bytes(&mut sk_bytes); + let signing_key = ed25519_dalek::SigningKey::from_bytes(&sk_bytes); VRFPrivateKey(signing_key) } @@ -182,7 +186,6 @@ pub enum Error { InvalidPublicKey, InvalidDataError, InvalidHashPoints, - OSRNGError(rand::Error), } impl fmt::Display for Error { @@ -191,7 +194,6 @@ impl fmt::Display for Error { Error::InvalidPublicKey => write!(f, "Invalid public key"), Error::InvalidDataError => write!(f, "No data could be found"), Error::InvalidHashPoints => write!(f, "VRF hash points did not yield a valid scalar"), - Error::OSRNGError(ref e) => fmt::Display::fmt(e, f), } } } @@ -202,7 +204,6 @@ impl error::Error for Error { Error::InvalidPublicKey => None, Error::InvalidDataError => None, Error::InvalidHashPoints => None, - Error::OSRNGError(ref e) => Some(e), } } } @@ -540,8 +541,7 @@ impl VRF { #[cfg(test)] mod tests { - use rand; - use rand::RngCore; + use rand::RngCore as _; use super::*; use crate::util::hash::hex_bytes; diff --git a/stackslib/src/burnchains/tests/burnchain.rs b/stackslib/src/burnchains/tests/burnchain.rs index 9d170ab6f2..c4d6cb0ed9 100644 --- a/stackslib/src/burnchains/tests/burnchain.rs +++ b/stackslib/src/burnchains/tests/burnchain.rs @@ -15,7 +15,7 @@ // along with this program. If not, see . use rand::rngs::ThreadRng; -use rand::thread_rng; +use rand::{thread_rng, RngCore as _}; use stacks_common::address::AddressHashMode; use stacks_common::types::chainstate::{ BlockHeaderHash, BurnchainHeaderHash, PoxId, SortitionId, TrieHash, VRFSeed, @@ -690,7 +690,9 @@ fn test_burn_snapshot_sequence() { for i in 0..32 { let mut csprng: ThreadRng = thread_rng(); - let vrf_privkey = VRFPrivateKey(ed25519_dalek::SigningKey::generate(&mut csprng)); + let mut sk_bytes = [0u8; 32]; + csprng.fill_bytes(&mut sk_bytes); + let vrf_privkey = VRFPrivateKey(ed25519_dalek::SigningKey::from_bytes(&sk_bytes)); let vrf_pubkey = VRFPublicKey::from_private(&vrf_privkey); let pubkey_hex = vrf_pubkey.to_hex();