diff --git a/examples/generate_keys.rs b/examples/generate_keys.rs index ae1ec2b84..f605b58a7 100644 --- a/examples/generate_keys.rs +++ b/examples/generate_keys.rs @@ -4,7 +4,7 @@ use secp256k1::rand::rngs::OsRng; use secp256k1::{PublicKey, Secp256k1, SecretKey}; fn main() { - let secp = Secp256k1::new(); + let secp = Secp256k1::new_randomize(); let mut rng = OsRng::new().unwrap(); // First option: let (seckey, pubkey) = secp.generate_keypair(&mut rng); diff --git a/examples/sign_verify.rs b/examples/sign_verify.rs index 20dfde303..ff186f1df 100644 --- a/examples/sign_verify.rs +++ b/examples/sign_verify.rs @@ -21,7 +21,7 @@ fn sign(secp: &Secp256k1, msg: &[u8], seckey: [u8; 32]) -> Result } fn main() { - let secp = Secp256k1::new(); + let secp = Secp256k1::new_no_randomize(); let seckey = [59, 148, 11, 85, 134, 130, 61, 253, 2, 174, 59, 70, 27, 180, 51, 107, 94, 203, 174, 253, 102, 39, 170, 146, 46, 252, 4, 143, 236, 12, 136, 28]; let pubkey = [2, 29, 21, 35, 7, 198, 183, 43, 14, 208, 65, 139, 14, 112, 205, 128, 231, 245, 41, 91, 141, 134, 245, 114, 45, 63, 82, 19, 251, 210, 57, 79, 54]; diff --git a/examples/sign_verify_recovery.rs b/examples/sign_verify_recovery.rs index 627bbdc13..5afca7845 100644 --- a/examples/sign_verify_recovery.rs +++ b/examples/sign_verify_recovery.rs @@ -22,7 +22,7 @@ fn sign_recovery(secp: &Secp256k1, msg: &[u8], seckey: [u8; 32]) } fn main() { - let secp = Secp256k1::new(); + let secp = Secp256k1::new_no_randomize(); let seckey = [ 59, 148, 11, 85, 134, 130, 61, 253, 2, 174, 59, 70, 27, 180, 51, 107, diff --git a/no_std_test/src/main.rs b/no_std_test/src/main.rs index d245ce9dd..0a7e3aa04 100644 --- a/no_std_test/src/main.rs +++ b/no_std_test/src/main.rs @@ -135,7 +135,7 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize { #[cfg(feature = "alloc")] { - let secp_alloc = Secp256k1::new(); + let secp_alloc = Secp256k1::new_no_randomize(); let public_key = PublicKey::from_secret_key(&secp_alloc, &secret_key); let message = Message::from_slice(&[0xab; 32]).expect("32 bytes"); diff --git a/src/context.rs b/src/context.rs index 755ba8a48..e00ffb861 100644 --- a/src/context.rs +++ b/src/context.rs @@ -29,7 +29,7 @@ pub mod global { /// A global, static context to avoid repeatedly creating contexts where one can't be passed /// /// If the global-context feature is enabled (and not just the global-context-less-secure), - /// this will have been randomized. + /// this will have been randomized for additional defense-in-depth side channel protection. pub static SECP256K1: &GlobalContext = &GlobalContext { __private: () }; impl Deref for GlobalContext { @@ -40,7 +40,7 @@ pub mod global { static ONCE: Once = Once::new(); static mut CONTEXT: Option> = None; ONCE.call_once(|| unsafe { - let mut ctx = Secp256k1::new(); + let mut ctx = Secp256k1::new_no_randomize(); #[cfg(feature = "global-context")] { ctx.randomize(&mut rand::thread_rng()); @@ -167,8 +167,8 @@ mod alloc_only { } impl Secp256k1 { - /// Lets you create a context in a generic manner(sign/verify/all) - pub fn gen_new() -> Secp256k1 { + /// Helper function only intended to be called by other gen_new_* functions. + fn _gen_new() -> Secp256k1 { #[cfg(target_arch = "wasm32")] ffi::types::sanity_checks_for_wasm(); @@ -181,32 +181,118 @@ mod alloc_only { size, } } + + /// Lets you create a context in a generic manner(sign/verify/all). + /// + /// Context is randomized using `thread_rng` for additional defense-in-depth side channel + /// protection. + #[cfg(feature = "rand-std")] + #[cfg_attr(docsrs, doc(cfg(feature = "rand-std")))] + pub fn gen_new_randomize() -> Secp256k1 { + let mut secp = Secp256k1::_gen_new(); + secp.randomize(&mut rand::thread_rng()); + secp + } + + /// Lets you create a context in a generic manner(sign/verify/all). + /// + /// No randomization is done, this context is perfectly safe but for additional + /// defense-in-depth side channel protection consider using `gen_new_seeded_randomize`. + pub fn gen_new_no_randomize() -> Secp256k1 { + Secp256k1::_gen_new() + } + + /// Lets you create a context in a generic manner(sign/verify/all). + /// + /// Context is randomized using `seed` for additional defense-in-depth side channel + /// protection. + pub fn gen_new_seeded_randomize(seed: &[u8; 32]) -> Secp256k1 { + let mut secp = Secp256k1::_gen_new(); + secp.seeded_randomize(seed); + secp + } } impl Secp256k1 { - /// Creates a new Secp256k1 context with all capabilities - pub fn new() -> Secp256k1 { - Secp256k1::gen_new() + /// Creates a new Secp256k1 context with all capabilities. + /// + /// Context is randomized using `thread_rng` for additional defense-in-depth side channel + /// protection. + #[cfg(feature = "rand-std")] + #[cfg_attr(docsrs, doc(cfg(feature = "rand-std")))] + pub fn new_randomize() -> Secp256k1 { + Secp256k1::gen_new_randomize() + } + /// Creates a new Secp256k1 context with all capabilities. + /// + /// No randomization is done, this context is perfectly safe but for additional + /// defense-in-depth side channel protection consider using `new_seeded_randomize`. + pub fn new_no_randomize() -> Secp256k1 { + Secp256k1::gen_new_no_randomize() + } + + /// Creates a new Secp256k1 context with all capabilities. + /// + /// Context is randomized using `seed` for additional defense-in-depth side channel + /// protection. + pub fn new_seeded_randomize(seed: &[u8; 32]) -> Secp256k1 { + Secp256k1::gen_new_seeded_randomize(seed) } } impl Secp256k1 { - /// Creates a new Secp256k1 context that can only be used for signing - pub fn signing_only() -> Secp256k1 { - Secp256k1::gen_new() + /// Creates a new Secp256k1 context that can only be used for signing. + /// + /// Context is randomized using `thread_rng` for additional defense-in-depth side channel + /// protection. + #[cfg(feature = "rand-std")] + #[cfg_attr(docsrs, doc(cfg(feature = "rand-std")))] + pub fn signing_only_randomize() -> Secp256k1 { + Secp256k1::gen_new_randomize() + } + + /// Creates a new Secp256k1 context that can only be used for signing. + /// + /// No randomization is done, this context is perfectly safe but for additional + /// defense-in-depth side channel protection consider using `signing_only_seeded_randomize`. + pub fn signing_only_no_randomize() -> Secp256k1 { + Secp256k1::gen_new_no_randomize() + } + + /// Creates a new Secp256k1 context that can only be used for signing. + /// + /// Context is randomized using `seed` for additional defense-in-depth side channel + /// protection. + pub fn signing_only_seeded_randomize(seed: &[u8; 32]) -> Secp256k1 { + Secp256k1::gen_new_seeded_randomize(seed) } } impl Secp256k1 { - /// Creates a new Secp256k1 context that can only be used for verification - pub fn verification_only() -> Secp256k1 { - Secp256k1::gen_new() + /// Creates a new Secp256k1 context that can only be used for verifying. + /// + /// Context is randomized using `thread_rng` for additional defense-in-depth side channel + /// protection. + #[cfg(feature = "rand-std")] + #[cfg_attr(docsrs, doc(cfg(feature = "rand-std")))] + pub fn verification_only_randomize() -> Secp256k1 { + Secp256k1::gen_new_randomize() + } + + /// Creates a new Secp256k1 context that can only be used for verifying. + /// + /// No randomization is done, this context is perfectly safe but for additional + /// defense-in-depth side channel protection consider using `verification_only_seeded_randomize`. + pub fn verification_only_no_randomize() -> Secp256k1 { + Secp256k1::gen_new_no_randomize() } - } - impl Default for Secp256k1 { - fn default() -> Self { - Self::new() + /// Creates a new Secp256k1 context that can only be used for verifying. + /// + /// Context is randomized using `seed` for additional defense-in-depth side channel + /// protection. + pub fn verification_only_seeded_randomize(seed: &[u8; 32]) -> Secp256k1 { + Secp256k1::gen_new_seeded_randomize(seed) } } diff --git a/src/ecdh.rs b/src/ecdh.rs index e1dea695a..190069200 100644 --- a/src/ecdh.rs +++ b/src/ecdh.rs @@ -127,10 +127,11 @@ impl SharedSecret { /// `SharedSecret` can be easily created via the `From` impl from arrays. /// # Examples /// ``` + /// # #[cfg(any(features = "alloc", feature = "std"))] { /// # use secp256k1::ecdh::SharedSecret; /// # use secp256k1::{Secp256k1, PublicKey, SecretKey}; /// # fn sha2(_a: &[u8], _b: &[u8]) -> [u8; 32] {[0u8; 32]} - /// # let secp = Secp256k1::signing_only(); + /// # let secp = Secp256k1::signing_only_no_randomize(); /// # let secret_key = SecretKey::from_slice(&[3u8; 32]).unwrap(); /// # let secret_key2 = SecretKey::from_slice(&[7u8; 32]).unwrap(); /// # let public_key = PublicKey::from_secret_key(&secp, &secret_key2); @@ -139,7 +140,7 @@ impl SharedSecret { /// let hash: [u8; 32] = sha2(&x,&y); /// hash.into() /// }); - /// + /// # } /// ``` pub fn new_with_hash(point: &PublicKey, scalar: &SecretKey, mut hash_function: F) -> SharedSecret where F: FnMut([u8; 32], [u8; 32]) -> SharedSecret { @@ -170,15 +171,20 @@ impl SharedSecret { #[cfg(test)] mod tests { use super::*; - use rand::thread_rng; - use super::super::Secp256k1; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::wasm_bindgen_test as test; + #[cfg(feature = "rand-std")] + use rand::thread_rng; + + #[cfg(all(feature = "rand-std", any(features = "alloc", feature = "std")))] + use super::super::Secp256k1; + #[test] + #[cfg(all(feature = "rand-std", any(features = "alloc", feature = "std")))] fn ecdh() { - let s = Secp256k1::signing_only(); + let s = Secp256k1::signing_only_randomize(); let (sk1, pk1) = s.generate_keypair(&mut thread_rng()); let (sk2, pk2) = s.generate_keypair(&mut thread_rng()); @@ -190,8 +196,9 @@ mod tests { } #[test] + #[cfg(all(feature = "rand-std", any(features = "alloc", feature = "std")))] fn ecdh_with_hash() { - let s = Secp256k1::signing_only(); + let s = Secp256k1::signing_only_randomize(); let (sk1, pk1) = s.generate_keypair(&mut thread_rng()); let (sk2, pk2) = s.generate_keypair(&mut thread_rng()); @@ -203,8 +210,9 @@ mod tests { } #[test] + #[cfg(all(feature = "rand-std", any(features = "alloc", feature = "std")))] fn ecdh_with_hash_callback() { - let s = Secp256k1::signing_only(); + let s = Secp256k1::signing_only_randomize(); let (sk1, pk1) = s.generate_keypair(&mut thread_rng()); let expect_result: [u8; 64] = [123; 64]; let mut x_out = [0u8; 32]; @@ -235,7 +243,7 @@ mod tests { } } -#[cfg(all(test, feature = "unstable", feature = "rand", any(features = "alloc", feature = "std")))] +#[cfg(all(test, feature = "unstable", feature = "rand-std", any(features = "alloc", feature = "std")))] mod benches { use rand::thread_rng; use test::{Bencher, black_box}; @@ -245,7 +253,7 @@ mod benches { #[bench] pub fn bench_ecdh(bh: &mut Bencher) { - let s = Secp256k1::signing_only(); + let s = Secp256k1::signing_only_randomize(); let (sk, pk) = s.generate_keypair(&mut thread_rng()); bh.iter( || { diff --git a/src/ecdsa/mod.rs b/src/ecdsa/mod.rs index 7098ab49c..565f89af5 100644 --- a/src/ecdsa/mod.rs +++ b/src/ecdsa/mod.rs @@ -431,11 +431,11 @@ impl Secp256k1 { /// verify-capable context. /// /// ```rust - /// # #[cfg(feature="rand")] { + /// # #[cfg(all(feature="rand", any(feature = "alloc", feature = "std")))] { /// # use secp256k1::rand::rngs::OsRng; /// # use secp256k1::{Secp256k1, Message, Error}; /// # - /// # let secp = Secp256k1::new(); + /// # let secp = Secp256k1::new_randomize(); /// # let mut rng = OsRng::new().expect("OsRng"); /// # let (secret_key, public_key) = secp.generate_keypair(&mut rng); /// # @@ -460,11 +460,11 @@ impl Secp256k1 { /// verify-capable context. /// /// ```rust - /// # #[cfg(feature="rand")] { + /// # #[cfg(all(feature="rand", any(feature = "alloc", feature = "std")))] { /// # use secp256k1::rand::rngs::OsRng; /// # use secp256k1::{Secp256k1, Message, Error}; /// # - /// # let secp = Secp256k1::new(); + /// # let secp = Secp256k1::new_randomize(); /// # let mut rng = OsRng::new().expect("OsRng"); /// # let (secret_key, public_key) = secp.generate_keypair(&mut rng); /// # diff --git a/src/ecdsa/recovery.rs b/src/ecdsa/recovery.rs index 3e754639d..84b98b9dd 100644 --- a/src/ecdsa/recovery.rs +++ b/src/ecdsa/recovery.rs @@ -210,10 +210,11 @@ mod tests { use wasm_bindgen_test::wasm_bindgen_test as test; #[test] + #[cfg(all(feature = "rand-std", any(features = "alloc", feature = "std")))] fn capabilities() { - let sign = Secp256k1::signing_only(); - let vrfy = Secp256k1::verification_only(); - let full = Secp256k1::new(); + let sign = Secp256k1::signing_only_randomize(); + let vrfy = Secp256k1::verification_only_randomize(); + let full = Secp256k1::new_randomize(); let mut msg = [0u8; 32]; thread_rng().fill_bytes(&mut msg); @@ -243,9 +244,9 @@ mod tests { #[test] #[cfg(not(fuzzing))] // fixed sig vectors can't work with fuzz-sigs + #[cfg(all(feature = "rand-std", any(features = "alloc", feature = "std")))] fn sign() { - let mut s = Secp256k1::new(); - s.randomize(&mut thread_rng()); + let s = Secp256k1::new_randomize(); let one: [u8; 32] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; @@ -266,9 +267,9 @@ mod tests { } #[test] + #[cfg(all(feature = "rand-std", any(features = "alloc", feature = "std")))] fn sign_and_verify_fail() { - let mut s = Secp256k1::new(); - s.randomize(&mut thread_rng()); + let s = Secp256k1::new_randomize(); let mut msg = [0u8; 32]; thread_rng().fill_bytes(&mut msg); @@ -289,9 +290,9 @@ mod tests { } #[test] + #[cfg(all(feature = "rand-std", any(features = "alloc", feature = "std")))] fn sign_with_recovery() { - let mut s = Secp256k1::new(); - s.randomize(&mut thread_rng()); + let s = Secp256k1::new_randomize(); let mut msg = [0u8; 32]; thread_rng().fill_bytes(&mut msg); @@ -305,9 +306,9 @@ mod tests { } #[test] + #[cfg(all(feature = "rand-std", any(features = "alloc", feature = "std")))] fn bad_recovery() { - let mut s = Secp256k1::new(); - s.randomize(&mut thread_rng()); + let s = Secp256k1::new_randomize(); let msg = Message::from_slice(&[0x55; 32]).unwrap(); @@ -379,7 +380,7 @@ mod benches { #[bench] pub fn bench_recover(bh: &mut Bencher) { - let s = Secp256k1::new(); + let s = Secp256k1::new_randomize(); let mut msg = [0u8; 32]; thread_rng().fill_bytes(&mut msg); let msg = Message::from_slice(&msg).unwrap(); diff --git a/src/key.rs b/src/key.rs index 358eb4698..045201425 100644 --- a/src/key.rs +++ b/src/key.rs @@ -35,10 +35,10 @@ use ffi::{self, CPtr}; /// Basic usage: /// /// ``` -/// # #[cfg(feature="rand")] { +/// # #[cfg(all(feature="rand", any(feature = "alloc", feature = "std")))] { /// use secp256k1::{rand, Secp256k1, SecretKey}; /// -/// let secp = Secp256k1::new(); +/// let secp = Secp256k1::new_randomize(); /// let secret_key = SecretKey::new(&mut rand::thread_rng()); /// # } /// ``` @@ -70,11 +70,13 @@ pub const ONE_KEY: SecretKey = SecretKey([0, 0, 0, 0, 0, 0, 0, 0, /// Basic usage: /// /// ``` +/// # #[cfg(any(feature = "alloc", feature = "std"))] { /// use secp256k1::{SecretKey, Secp256k1, PublicKey}; /// -/// let secp = Secp256k1::new(); +/// let secp = Secp256k1::new_no_randomize(); /// let secret_key = SecretKey::from_slice(&[0xcd; 32]).expect("32 bytes, within curve order"); /// let public_key = PublicKey::from_secret_key(&secp, &secret_key); +/// # } /// ``` #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] #[repr(transparent)] @@ -183,10 +185,10 @@ impl SecretKey { /// # Examples /// /// ``` - /// # #[cfg(feature="rand")] { + /// # #[cfg(all(feature="rand", any(feature = "alloc", feature = "std")))] { /// use secp256k1::{rand, Secp256k1, SecretKey, KeyPair}; /// - /// let secp = Secp256k1::new(); + /// let secp = Secp256k1::new_randomize(); /// let key_pair = KeyPair::new(&secp, &mut rand::thread_rng()); /// let secret_key = SecretKey::from_keypair(&key_pair); /// # } @@ -327,10 +329,10 @@ impl PublicKey { /// # Examples /// /// ``` - /// # #[cfg(feature="rand")] { + /// # #[cfg(all(feature="rand", any(feature = "alloc", feature = "std")))] { /// use secp256k1::{rand, Secp256k1, SecretKey, PublicKey}; /// - /// let secp = Secp256k1::new(); + /// let secp = Secp256k1::new_randomize(); /// let secret_key = SecretKey::new(&mut rand::thread_rng()); /// let public_key = PublicKey::from_secret_key(&secp, &secret_key); /// # } @@ -375,10 +377,10 @@ impl PublicKey { /// # Examples /// /// ``` - /// # #[cfg(feature="rand")] { + /// # #[cfg(all(feature="rand", any(feature = "alloc", feature = "std")))] { /// use secp256k1::{rand, Secp256k1, PublicKey, KeyPair}; /// - /// let secp = Secp256k1::new(); + /// let secp = Secp256k1::new_randomize(); /// let key_pair = KeyPair::new(&secp, &mut rand::thread_rng()); /// let public_key = PublicKey::from_keypair(&key_pair); /// # } @@ -506,10 +508,10 @@ impl PublicKey { /// # Examples /// /// ``` - /// # #[cfg(feature="rand")] { + /// # #[cfg(all(feature="rand", any(feature = "alloc", feature = "std")))] { /// use secp256k1::{rand, Secp256k1}; /// - /// let secp = Secp256k1::new(); + /// let secp = Secp256k1::new_randomize(); /// let mut rng = rand::thread_rng(); /// let (_, pk1) = secp.generate_keypair(&mut rng); /// let (_, pk2) = secp.generate_keypair(&mut rng); @@ -532,10 +534,10 @@ impl PublicKey { /// # Examples /// /// ``` - /// # #[cfg(feature="rand")] { + /// # #[cfg(all(feature="rand", any(feature = "alloc", feature = "std")))] { /// use secp256k1::{rand, Secp256k1, PublicKey}; /// - /// let secp = Secp256k1::new(); + /// let secp = Secp256k1::new_randomize(); /// let mut rng = rand::thread_rng(); /// let (_, pk1) = secp.generate_keypair(&mut rng); /// let (_, pk2) = secp.generate_keypair(&mut rng); @@ -648,10 +650,10 @@ impl Ord for PublicKey { /// Basic usage: /// /// ``` -/// # #[cfg(feature="rand")] { +/// # #[cfg(all(feature="rand", any(feature = "alloc", feature = "std")))] { /// use secp256k1::{rand, KeyPair, Secp256k1}; /// -/// let secp = Secp256k1::new(); +/// let secp = Secp256k1::new_randomize(); /// let (secret_key, public_key) = secp.generate_keypair(&mut rand::thread_rng()); /// let key_pair = KeyPair::from_secret_key(&secp, secret_key); /// # } @@ -742,10 +744,10 @@ impl KeyPair { /// # Examples /// /// ``` - /// # #[cfg(feature="rand")] { + /// # #[cfg(all(feature="rand", any(feature = "alloc", feature = "std")))] { /// use secp256k1::{rand, Secp256k1, SecretKey, KeyPair}; /// - /// let secp = Secp256k1::new(); + /// let secp = Secp256k1::new_randomize(); /// let key_pair = KeyPair::new(&secp, &mut rand::thread_rng()); /// # } /// ``` @@ -788,11 +790,11 @@ impl KeyPair { /// # Examples /// /// ``` - /// # #[cfg(feature="rand")] { + /// # #[cfg(all(feature="rand", any(feature = "alloc", feature = "std")))] { /// use secp256k1::{Secp256k1, KeyPair}; /// use secp256k1::rand::{RngCore, thread_rng}; /// - /// let secp = Secp256k1::new(); + /// let secp = Secp256k1::new_randomize(); /// let mut tweak = [0u8; 32]; /// thread_rng().fill_bytes(&mut tweak); /// @@ -912,10 +914,10 @@ impl<'de> ::serde::Deserialize<'de> for KeyPair { /// Basic usage: /// /// ``` -/// # #[cfg(feature="rand")] { +/// # #[cfg(all(feature="rand", any(feature = "alloc", feature = "std")))] { /// use secp256k1::{rand, Secp256k1, KeyPair, XOnlyPublicKey}; /// -/// let secp = Secp256k1::new(); +/// let secp = Secp256k1::new_randomize(); /// let key_pair = KeyPair::new(&secp, &mut rand::thread_rng()); /// let xonly = XOnlyPublicKey::from_keypair(&key_pair); /// # } @@ -1040,11 +1042,11 @@ impl XOnlyPublicKey { /// # Examples /// /// ``` - /// # #[cfg(feature="rand")] { + /// # #[cfg(all(feature="rand", any(feature = "alloc", feature = "std")))] { /// use secp256k1::{Secp256k1, KeyPair}; /// use secp256k1::rand::{RngCore, thread_rng}; /// - /// let secp = Secp256k1::new(); + /// let secp = Secp256k1::new_randomize(); /// let mut tweak = [0u8; 32]; /// thread_rng().fill_bytes(&mut tweak); /// @@ -1105,11 +1107,11 @@ impl XOnlyPublicKey { /// # Examples /// /// ``` - /// # #[cfg(feature="rand")] { + /// # #[cfg(all(feature="rand", any(feature = "alloc", feature = "std")))] { /// use secp256k1::{Secp256k1, KeyPair}; /// use secp256k1::rand::{thread_rng, RngCore}; /// - /// let secp = Secp256k1::new(); + /// let secp = Secp256k1::new_randomize(); /// let mut tweak = [0u8; 32]; /// thread_rng().fill_bytes(&mut tweak); /// @@ -1392,8 +1394,9 @@ mod test { } #[test] + #[cfg(all(feature = "rand", any(features = "alloc", feature = "std")))] fn keypair_slice_round_trip() { - let s = Secp256k1::new(); + let s = Secp256k1::new_randomize(); let (sk1, pk1) = s.generate_keypair(&mut thread_rng()); assert_eq!(SecretKey::from_slice(&sk1[..]), Ok(sk1)); @@ -1428,6 +1431,7 @@ mod test { } #[test] + #[cfg(any(features = "alloc", feature = "std"))] fn test_out_of_range() { struct BadRng(u8); @@ -1454,7 +1458,7 @@ mod test { } } - let s = Secp256k1::new(); + let s = Secp256k1::new_no_randomize(); s.generate_keypair(&mut BadRng(0xff)); } @@ -1539,7 +1543,7 @@ mod test { } } - let s = Secp256k1::new(); + let s = Secp256k1::new_no_randomize(); let (sk, _) = s.generate_keypair(&mut DumbRng(0)); assert_eq!(&format!("{:?}", sk), @@ -1559,7 +1563,7 @@ mod test { 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, ]; - let s = Secp256k1::signing_only(); + let s = Secp256k1::signing_only_no_randomize(); let sk = SecretKey::from_slice(&SK_BYTES).expect("sk"); // In fuzzing mode secret->public key derivation is different, so @@ -1632,7 +1636,7 @@ mod test { } } - let s = Secp256k1::new(); + let s = Secp256k1::new_no_randomize(); let (_, pk1) = s.generate_keypair(&mut DumbRng(0)); assert_eq!(&pk1.serialize_uncompressed()[..], &[4, 124, 121, 49, 14, 253, 63, 197, 50, 39, 194, 107, 17, 193, 219, 108, 154, 126, 9, 181, 248, 2, 12, 149, 233, 198, 71, 149, 134, 250, 184, 154, 229, 185, 28, 165, 110, 27, 3, 162, 126, 238, 167, 157, 242, 221, 76, 251, 237, 34, 231, 72, 39, 245, 3, 191, 64, 111, 170, 117, 103, 82, 28, 102, 163][..]); @@ -1642,7 +1646,7 @@ mod test { #[test] fn test_addition() { - let s = Secp256k1::new(); + let s = Secp256k1::new_no_randomize(); let (mut sk1, mut pk1) = s.generate_keypair(&mut thread_rng()); let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng()); @@ -1660,7 +1664,7 @@ mod test { #[test] fn test_multiplication() { - let s = Secp256k1::new(); + let s = Secp256k1::new_no_randomize(); let (mut sk1, mut pk1) = s.generate_keypair(&mut thread_rng()); let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng()); @@ -1678,7 +1682,7 @@ mod test { #[test] fn test_negation() { - let s = Secp256k1::new(); + let s = Secp256k1::new_no_randomize(); let (mut sk, mut pk) = s.generate_keypair(&mut thread_rng()); @@ -1709,7 +1713,7 @@ mod test { s.finish() } - let s = Secp256k1::new(); + let s = Secp256k1::new_no_randomize(); let mut set = HashSet::new(); const COUNT : usize = 1024; for _ in 0..COUNT { @@ -1771,7 +1775,7 @@ mod test { #[test] fn create_pubkey_combine() { - let s = Secp256k1::new(); + let s = Secp256k1::new_no_randomize(); let (mut sk1, pk1) = s.generate_keypair(&mut thread_rng()); let (sk2, pk2) = s.generate_keypair(&mut thread_rng()); @@ -1833,7 +1837,7 @@ mod test { 0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166\ "; - let s = Secp256k1::new(); + let s = Secp256k1::new_no_randomize(); let sk = SecretKey::from_slice(&SK_BYTES).unwrap(); // In fuzzing mode secret->public key derivation is different, so @@ -1863,7 +1867,7 @@ mod test { #[test] fn test_tweak_add_assign_then_tweak_add_check() { - let s = Secp256k1::new(); + let s = Secp256k1::new_no_randomize(); for _ in 0..10 { let mut tweak = [0u8; 32]; diff --git a/src/lib.rs b/src/lib.rs index e342d447b..c8c5cb5a3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,9 +20,12 @@ //! and its derivatives. //! //! To minimize dependencies, some functions are feature-gated. To generate -//! random keys or to re-randomize a context object, compile with the "rand" -//! feature. To de/serialize objects with serde, compile with "serde". -//! **Important**: `serde` encoding is **not** the same as consensus encoding! +//! random keys or to re-randomize a context object, compile with the `rand` +//! feature. If you are willing to use the `rand` dependency, we have enabled an +//! additional defense-in-depth side channel protection for our context objects, +//! which re-blinds certain operations on secret key data. To de/serialize +//! objects with serde, compile with "serde". **Important**: `serde` encoding is +//! **not** the same as consensus encoding! //! //! Where possible, the bindings use the Rust type system to ensure that //! API usage errors are impossible. For example, the library uses context @@ -43,7 +46,7 @@ //! use secp256k1::{Secp256k1, Message}; //! use secp256k1::hashes::sha256; //! -//! let secp = Secp256k1::new(); +//! let secp = Secp256k1::new_randomize(); //! let mut rng = OsRng::new().expect("OsRng"); //! let (secret_key, public_key) = secp.generate_keypair(&mut rng); //! let message = Message::from_hashed_data::("Hello World!".as_bytes()); @@ -60,7 +63,7 @@ //! ```rust //! use secp256k1::{Secp256k1, Message, SecretKey, PublicKey}; //! -//! let secp = Secp256k1::new(); +//! let secp = Secp256k1::new_no_randomize(); //! let secret_key = SecretKey::from_slice(&[0xcd; 32]).expect("32 bytes, within curve order"); //! let public_key = PublicKey::from_secret_key(&secp, &secret_key); //! // This is unsafe unless the supplied byte slice is the output of a cryptographic hash function. @@ -74,9 +77,10 @@ //! Users who only want to verify signatures can use a cheaper context, like so: //! //! ```rust +//! # #[cfg(any(features = "alloc", feature = "std"))] //! use secp256k1::{Secp256k1, Message, ecdsa, PublicKey}; //! -//! let secp = Secp256k1::verification_only(); +//! let secp = Secp256k1::verification_only_no_randomize(); //! //! let public_key = PublicKey::from_slice(&[ //! 0x02, @@ -117,7 +121,7 @@ //! //! * `std` - use standard Rust library, enabled by default. //! * `alloc` - use the `alloc` standard Rust library to provide heap allocations. -//! * `rand` - use `rand` library to provide random generator (e.g. to generate keys). +//! * `rand` - use `rand` library to provide randomness (e.g. to randomize contexts). //! * `rand-std` - use `rand` library with its `std` feature enabled. (Implies `rand`.) //! * `recovery` - enable functions that can compute the public key from signature. //! * `lowmemory` - optimize the library for low-memory environments. @@ -551,12 +555,13 @@ mod tests { } #[test] + #[cfg(any(features = "alloc", feature = "std"))] fn test_raw_ctx() { use std::mem::ManuallyDrop; - let ctx_full = Secp256k1::new(); - let ctx_sign = Secp256k1::signing_only(); - let ctx_vrfy = Secp256k1::verification_only(); + let ctx_full = Secp256k1::new_no_randomize(); + let ctx_sign = Secp256k1::signing_only_no_randomize(); + let ctx_vrfy = Secp256k1::verification_only_no_randomize(); let mut full = unsafe {Secp256k1::from_raw_all(ctx_full.ctx)}; let mut sign = unsafe {Secp256k1::from_raw_signining_only(ctx_sign.ctx)}; @@ -586,8 +591,9 @@ mod tests { #[cfg(not(target_arch = "wasm32"))] #[test] #[ignore] // Panicking from C may trap (SIGILL) intentionally, so we test this manually. + #[cfg(any(features = "alloc", feature = "std"))] fn test_panic_raw_ctx_should_terminate_abnormally() { - let ctx_vrfy = Secp256k1::verification_only(); + let ctx_vrfy = Secp256k1::verification_only_no_randomize(); let raw_ctx_verify_as_full = unsafe {Secp256k1::from_raw_all(ctx_vrfy.ctx)}; // Generating a key pair in verify context will panic (ARG_CHECK). raw_ctx_verify_as_full.generate_keypair(&mut thread_rng()); @@ -618,10 +624,11 @@ mod tests { } #[test] + #[cfg(any(features = "alloc", feature = "std"))] fn capabilities() { - let sign = Secp256k1::signing_only(); - let vrfy = Secp256k1::verification_only(); - let full = Secp256k1::new(); + let sign = Secp256k1::signing_only_no_randomize(); + let vrfy = Secp256k1::verification_only_no_randomize(); + let full = Secp256k1::new_no_randomize(); let mut msg = [0u8; 32]; thread_rng().fill_bytes(&mut msg); @@ -647,9 +654,9 @@ mod tests { } #[test] + #[cfg(all(feature = "rand", any(features = "alloc", feature = "std")))] fn signature_serialize_roundtrip() { - let mut s = Secp256k1::new(); - s.randomize(&mut thread_rng()); + let s = Secp256k1::new_randomize(); let mut msg = [0u8; 32]; for _ in 0..100 { @@ -733,9 +740,9 @@ mod tests { } #[test] + #[cfg(all(feature = "rand", any(features = "alloc", feature = "std")))] fn sign_and_verify_ecdsa() { - let mut s = Secp256k1::new(); - s.randomize(&mut thread_rng()); + let s = Secp256k1::new_randomize(); let mut msg = [0u8; 32]; for _ in 0..100 { @@ -764,9 +771,9 @@ mod tests { } #[test] + #[cfg(any(features = "alloc", feature = "std"))] fn sign_and_verify_extreme() { - let mut s = Secp256k1::new(); - s.randomize(&mut thread_rng()); + let s = Secp256k1::new_no_randomize(); // Wild keys: 1, CURVE_ORDER - 1 // Wild msgs: 1, CURVE_ORDER - 1 @@ -797,9 +804,9 @@ mod tests { } #[test] + #[cfg(all(feature = "rand", any(features = "alloc", feature = "std")))] fn sign_and_verify_fail() { - let mut s = Secp256k1::new(); - s.randomize(&mut thread_rng()); + let s = Secp256k1::new_randomize(); let mut msg = [0u8; 32]; thread_rng().fill_bytes(&mut msg); @@ -866,7 +873,7 @@ mod tests { let pk = hex!("031ee99d2b786ab3b0991325f2de8489246a6a3fdb700f6d0511b1d80cf5f4cd43"); let msg = hex!("a4965ca63b7d8562736ceec36dfa5a11bf426eb65be8ea3f7a49ae363032da0d"); - let secp = Secp256k1::new(); + let secp = Secp256k1::new_no_randomize(); let mut sig = ecdsa::Signature::from_der(&sig[..]).unwrap(); let pk = PublicKey::from_slice(&pk[..]).unwrap(); let msg = Message::from_slice(&msg[..]).unwrap(); @@ -881,7 +888,7 @@ mod tests { #[test] #[cfg(not(fuzzing))] // fuzz-sigs have fixed size/format fn test_low_r() { - let secp = Secp256k1::new(); + let secp = Secp256k1::new_no_randomize(); let msg = hex!("887d04bb1cf1b1554f1b268dfe62d13064ca67ae45348d50d1392ce2d13418ac"); let msg = Message::from_slice(&msg).unwrap(); let sk = SecretKey::from_str("57f0148f94d13095cfda539d0da0d1541304b678d8b36e243980aab4e1b7cead").unwrap(); @@ -896,7 +903,7 @@ mod tests { #[test] #[cfg(not(fuzzing))] // fuzz-sigs have fixed size/format fn test_grind_r() { - let secp = Secp256k1::new(); + let secp = Secp256k1::new_no_randomize(); let msg = hex!("ef2d5b9a7c61865a95941d0f04285420560df7e9d76890ac1b8867b12ce43167"); let msg = Message::from_slice(&msg).unwrap(); let sk = SecretKey::from_str("848355d75fe1c354cf05539bb29b2015f1863065bcb6766b44d399ab95c3fa0b").unwrap(); @@ -913,7 +920,7 @@ mod tests { fn test_serde() { use serde_test::{Configure, Token, assert_tokens}; - let s = Secp256k1::new(); + let s = Secp256k1::new_no_randomize(); let msg = Message::from_slice(&[1; 32]).unwrap(); let sk = SecretKey::from_slice(&[2; 32]).unwrap(); @@ -1017,7 +1024,7 @@ mod benches { } - let s = Secp256k1::new(); + let s = Secp256k1::new_no_randomize(); let mut r = CounterRng(0); bh.iter( || { let (sk, pk) = s.generate_keypair(&mut r); @@ -1028,7 +1035,7 @@ mod benches { #[bench] pub fn bench_sign_ecdsa(bh: &mut Bencher) { - let s = Secp256k1::new(); + let s = Secp256k1::new_randomize(); let mut msg = [0u8; 32]; thread_rng().fill_bytes(&mut msg); let msg = Message::from_slice(&msg).unwrap(); @@ -1042,7 +1049,7 @@ mod benches { #[bench] pub fn bench_verify_ecdsa(bh: &mut Bencher) { - let s = Secp256k1::new(); + let s = Secp256k1::new_randomize(); let mut msg = [0u8; 32]; thread_rng().fill_bytes(&mut msg); let msg = Message::from_slice(&msg).unwrap(); diff --git a/src/schnorr.rs b/src/schnorr.rs index e71391365..d61380127 100644 --- a/src/schnorr.rs +++ b/src/schnorr.rs @@ -269,13 +269,20 @@ impl Secp256k1 { #[cfg(test)] mod tests { use super::super::Error::InvalidPublicKey; - use super::super::{constants, from_hex, All, Message, Secp256k1}; + use super::super::{constants, from_hex, Message, Secp256k1}; use super::{KeyPair, XOnlyPublicKey, Signature}; - use rand::{rngs::ThreadRng, thread_rng, Error, ErrorKind, RngCore}; - use rand_core::impls; + use std::iter; use std::str::FromStr; + #[cfg(feature = "rand")] + use rand_core::impls; + #[cfg(feature = "rand")] + use rand::{rngs::ThreadRng, thread_rng, Error, ErrorKind, RngCore}; + + #[cfg(all(feature = "rand", any(feature = "alloc", feature = "std")))] + use super::super::All; + #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::wasm_bindgen_test as test; use SecretKey; @@ -289,6 +296,7 @@ mod tests { } #[test] + #[cfg(all(feature = "rand", any(feature = "alloc", feature = "std")))] fn test_schnorrsig_sign_with_aux_rand_verify() { test_schnorrsig_sign_helper(|secp, msg, seckey, rng| { let mut aux_rand = [0u8; 32]; @@ -298,6 +306,7 @@ mod tests { } #[test] + #[cfg(all(feature = "rand", any(feature = "alloc", feature = "std")))] fn test_schnorrsig_sign_with_rng_verify() { test_schnorrsig_sign_helper(|secp, msg, seckey, mut rng| { secp.sign_schnorr_with_rng(msg, seckey, &mut rng) @@ -305,23 +314,26 @@ mod tests { } #[test] - fn test_schnorrsig_sign_verify() { + #[cfg(all(feature = "rand", any(feature = "alloc", feature = "std")))] + fn test_schnorrsig_sign_verifya() { test_schnorrsig_sign_helper(|secp, msg, seckey, _| { secp.sign_schnorr(msg, seckey) }) } #[test] + #[cfg(all(feature = "rand", any(feature = "alloc", feature = "std")))] fn test_schnorrsig_sign_no_aux_rand_verify() { test_schnorrsig_sign_helper(|secp, msg, seckey, _| { secp.sign_schnorr_no_aux_rand(msg, seckey) }) } + #[cfg(all(feature = "rand", any(feature = "alloc", feature = "std")))] fn test_schnorrsig_sign_helper( sign: fn(&Secp256k1, &Message, &KeyPair, &mut ThreadRng) -> Signature, ) { - let secp = Secp256k1::new(); + let secp = Secp256k1::new_randomize(); let mut rng = thread_rng(); let kp = KeyPair::new(&secp, &mut rng); @@ -341,8 +353,9 @@ mod tests { #[test] #[cfg(not(fuzzing))] // fixed sig vectors can't work with fuzz-sigs + #[cfg(any(feature = "alloc", feature = "std"))] fn test_schnorrsig_sign() { - let secp = Secp256k1::new(); + let secp = Secp256k1::new_no_randomize(); let hex_msg = hex_32!("E48441762FB75010B2AA31A512B62B4148AA3FB08EB0765D76B252559064A614"); let msg = Message::from_slice(&hex_msg).unwrap(); @@ -363,8 +376,9 @@ mod tests { #[test] #[cfg(not(fuzzing))] // fixed sig vectors can't work with fuzz-sigs + #[cfg(any(feature = "alloc", feature = "std"))] fn test_schnorrsig_verify() { - let secp = Secp256k1::new(); + let secp = Secp256k1::new_no_randomize(); let hex_msg = hex_32!("E48441762FB75010B2AA31A512B62B4148AA3FB08EB0765D76B252559064A614"); let msg = Message::from_slice(&hex_msg).unwrap(); @@ -389,8 +403,9 @@ mod tests { } #[test] + #[cfg(all(feature = "rand", any(feature = "alloc", feature = "std")))] fn test_pubkey_serialize_roundtrip() { - let secp = Secp256k1::new(); + let secp = Secp256k1::new_randomize(); let kp = KeyPair::new(&secp, &mut thread_rng()); let pk = kp.public_key(); @@ -400,8 +415,9 @@ mod tests { } #[test] + #[cfg(any(feature = "alloc", feature = "std"))] fn test_xonly_key_extraction() { - let secp = Secp256k1::new(); + let secp = Secp256k1::new_no_randomize(); let sk_str = "688C77BC2D5AAFF5491CF309D4753B732135470D05B7B2CD21ADD0744FE97BEF"; let keypair = KeyPair::from_seckey_str(&secp, sk_str).unwrap(); let sk = SecretKey::from_keypair(&keypair); @@ -441,7 +457,7 @@ mod tests { #[test] fn test_pubkey_display_output() { - let secp = Secp256k1::new(); + let secp = Secp256k1::new_no_randomize(); static SK_BYTES: [u8; 32] = [ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, @@ -496,6 +512,7 @@ mod tests { // In fuzzing mode secret->public key derivation is different, so // this test will never correctly derive the static pubkey. #[cfg(not(fuzzing))] + #[cfg(all(feature = "rand", any(feature = "alloc", feature = "std")))] fn test_pubkey_serialize() { struct DumbRng(u32); impl RngCore for DumbRng { @@ -515,7 +532,7 @@ mod tests { } } - let secp = Secp256k1::new(); + let secp = Secp256k1::new_no_randomize(); let kp = KeyPair::new(&secp, &mut DumbRng(0)); let pk = kp.public_key(); assert_eq!( @@ -533,7 +550,7 @@ mod tests { fn test_serde() { use serde_test::{assert_tokens, Configure, Token}; - let s = Secp256k1::new(); + let s = Secp256k1::new_no_randomize(); let msg = Message::from_slice(&[1; 32]).unwrap(); let keypair = KeyPair::from_seckey_slice(&s, &[2; 32]).unwrap(); diff --git a/src/secret.rs b/src/secret.rs index 28bd80d36..9e4168307 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -129,7 +129,7 @@ impl KeyPair { /// use secp256k1::KeyPair; /// use secp256k1::Secp256k1; /// - /// let secp = Secp256k1::new(); + /// let secp = Secp256k1::new_no_randomize(); /// let key = ONE_KEY; /// let key = KeyPair::from_secret_key(&secp, key); ///