diff --git a/examples/generate_keys.rs b/examples/generate_keys.rs index ae45bb010..e938dd0f2 100644 --- a/examples/generate_keys.rs +++ b/examples/generate_keys.rs @@ -1,16 +1,15 @@ extern crate secp256k1; -use secp256k1::{PublicKey, Secp256k1, SecretKey}; +use secp256k1::{PublicKey, SecretKey}; fn main() { - let secp = Secp256k1::new(); let mut rng = rand::rng(); // First option: - let (seckey, pubkey) = secp.generate_keypair(&mut rng); + let (seckey, pubkey) = secp256k1::generate_keypair(&mut rng); - assert_eq!(pubkey, PublicKey::from_secret_key(&secp, &seckey)); + assert_eq!(pubkey, PublicKey::from_secret_key(&seckey)); // Second option: let seckey = SecretKey::new(&mut rng); - let _pubkey = PublicKey::from_secret_key(&secp, &seckey); + let _pubkey = PublicKey::from_secret_key(&seckey); } diff --git a/examples/musig.rs b/examples/musig.rs index 3fac51149..6231c0b1c 100644 --- a/examples/musig.rs +++ b/examples/musig.rs @@ -4,33 +4,32 @@ use secp256k1::musig::{ new_nonce_pair, AggregatedNonce, KeyAggCache, PartialSignature, PublicNonce, Session, SessionSecretRand, }; -use secp256k1::{Keypair, PublicKey, Scalar, Secp256k1, SecretKey}; +use secp256k1::{Keypair, PublicKey, Scalar, SecretKey}; fn main() { - let secp = Secp256k1::new(); let mut rng = rand::rng(); - let (seckey1, pubkey1) = secp.generate_keypair(&mut rng); + let (seckey1, pubkey1) = secp256k1::generate_keypair(&mut rng); let seckey2 = SecretKey::new(&mut rng); - let pubkey2 = PublicKey::from_secret_key(&secp, &seckey2); + let pubkey2 = PublicKey::from_secret_key(&seckey2); let pubkeys = [pubkey1, pubkey2]; let mut pubkeys_ref: Vec<&PublicKey> = pubkeys.iter().collect(); let pubkeys_ref = pubkeys_ref.as_mut_slice(); - secp.sort_pubkeys(pubkeys_ref); + secp256k1::sort_pubkeys(pubkeys_ref); - let mut musig_key_agg_cache = KeyAggCache::new(&secp, pubkeys_ref); + let mut musig_key_agg_cache = KeyAggCache::new(pubkeys_ref); let plain_tweak: [u8; 32] = *b"this could be a BIP32 tweak....\0"; let xonly_tweak: [u8; 32] = *b"this could be a Taproot tweak..\0"; let plain_tweak = Scalar::from_be_bytes(plain_tweak).unwrap(); - musig_key_agg_cache.pubkey_ec_tweak_add(&secp, &plain_tweak).unwrap(); + musig_key_agg_cache.pubkey_ec_tweak_add(&plain_tweak).unwrap(); let xonly_tweak = Scalar::from_be_bytes(xonly_tweak).unwrap(); - let tweaked_agg_pk = musig_key_agg_cache.pubkey_xonly_tweak_add(&secp, &xonly_tweak).unwrap(); + let tweaked_agg_pk = musig_key_agg_cache.pubkey_xonly_tweak_add(&xonly_tweak).unwrap(); let agg_pk = musig_key_agg_cache.agg_pk(); @@ -41,7 +40,6 @@ fn main() { let musig_session_sec_rand1 = SessionSecretRand::from_rng(&mut rng); let nonce_pair1 = new_nonce_pair( - &secp, musig_session_sec_rand1, Some(&musig_key_agg_cache), Some(seckey1), @@ -53,7 +51,6 @@ fn main() { let musig_session_sec_rand2 = SessionSecretRand::from_rng(&mut rng); let nonce_pair2 = new_nonce_pair( - &secp, musig_session_sec_rand2, Some(&musig_key_agg_cache), Some(seckey2), @@ -72,22 +69,22 @@ fn main() { let nonces_ref: Vec<&PublicNonce> = nonces.iter().collect(); let nonces_ref = nonces_ref.as_slice(); - let agg_nonce = AggregatedNonce::new(&secp, nonces_ref); + let agg_nonce = AggregatedNonce::new(nonces_ref); - let session = Session::new(&secp, &musig_key_agg_cache, agg_nonce, msg); + let session = Session::new(&musig_key_agg_cache, agg_nonce, msg); - let keypair1 = Keypair::from_secret_key(&secp, &seckey1); - let partial_sign1 = session.partial_sign(&secp, sec_nonce1, &keypair1, &musig_key_agg_cache); + let keypair1 = Keypair::from_secret_key(&seckey1); + let partial_sign1 = session.partial_sign(sec_nonce1, &keypair1, &musig_key_agg_cache); - let keypair2 = Keypair::from_secret_key(&secp, &seckey2); - let partial_sign2 = session.partial_sign(&secp, sec_nonce2, &keypair2, &musig_key_agg_cache); + let keypair2 = Keypair::from_secret_key(&seckey2); + let partial_sign2 = session.partial_sign(sec_nonce2, &keypair2, &musig_key_agg_cache); let is_partial_signature_valid = - session.partial_verify(&secp, &musig_key_agg_cache, &partial_sign1, &pub_nonce1, pubkey1); + session.partial_verify(&musig_key_agg_cache, &partial_sign1, &pub_nonce1, pubkey1); assert!(is_partial_signature_valid); let is_partial_signature_valid = - session.partial_verify(&secp, &musig_key_agg_cache, &partial_sign2, &pub_nonce2, pubkey2); + session.partial_verify(&musig_key_agg_cache, &partial_sign2, &pub_nonce2, pubkey2); assert!(is_partial_signature_valid); let partial_sigs = [partial_sign1, partial_sign2]; @@ -96,5 +93,5 @@ fn main() { let aggregated_signature = session.partial_sig_agg(partial_sigs_ref); - assert!(aggregated_signature.verify(&secp, &agg_pk, msg).is_ok()); + assert!(aggregated_signature.verify(&agg_pk, msg).is_ok()); } diff --git a/examples/sign_verify.rs b/examples/sign_verify.rs index 7879baff4..9ab3a5920 100644 --- a/examples/sign_verify.rs +++ b/examples/sign_verify.rs @@ -15,34 +15,23 @@ extern crate secp256k1; -use secp256k1::{ecdsa, Error, Message, PublicKey, Secp256k1, SecretKey, Signing, Verification}; - -fn verify( - secp: &Secp256k1, - msg_digest: [u8; 32], - sig: [u8; 64], - pubkey: [u8; 33], -) -> Result { +use secp256k1::{ecdsa, Error, Message, PublicKey, SecretKey}; + +fn verify(sig: [u8; 64], msg_digest: [u8; 32], pubkey: [u8; 33]) -> Result { let msg = Message::from_digest(msg_digest); let sig = ecdsa::Signature::from_compact(&sig)?; let pubkey = PublicKey::from_slice(&pubkey)?; - Ok(secp.verify_ecdsa(&sig, msg, &pubkey).is_ok()) + Ok(ecdsa::verify(&sig, msg, &pubkey).is_ok()) } -fn sign( - secp: &Secp256k1, - msg_digest: [u8; 32], - seckey: [u8; 32], -) -> Result { +fn sign(msg_digest: [u8; 32], seckey: [u8; 32]) -> Result { let msg = Message::from_digest(msg_digest); let seckey = SecretKey::from_secret_bytes(seckey)?; - Ok(secp.sign_ecdsa(msg, &seckey)) + Ok(ecdsa::sign(msg, &seckey)) } fn main() { - let secp = Secp256k1::new(); - 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, @@ -53,9 +42,9 @@ fn main() { ]; let msg_digest = *b"this must be secure hash output."; - let signature = sign(&secp, msg_digest, seckey).unwrap(); + let signature = sign(msg_digest, seckey).unwrap(); let serialize_sig = signature.serialize_compact(); - assert!(verify(&secp, msg_digest, serialize_sig, pubkey).unwrap()); + assert!(verify(serialize_sig, msg_digest, pubkey).unwrap()); } diff --git a/no_std_test/src/main.rs b/no_std_test/src/main.rs index 16d6c5ef8..02b10685f 100644 --- a/no_std_test/src/main.rs +++ b/no_std_test/src/main.rs @@ -79,14 +79,14 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize { let mut secp = Secp256k1::preallocated_new(&mut buf).unwrap(); secp.randomize(&mut FakeRng); let secret_key = SecretKey::new(&mut FakeRng); - let public_key = PublicKey::from_secret_key(&secp, &secret_key); + let public_key = PublicKey::from_secret_key(&secret_key); let message = Message::from_digest_slice(&[0xab; 32]).expect("32 bytes"); - let sig = secp.sign_ecdsa(message, &secret_key); - assert!(secp.verify_ecdsa(&sig, message, &public_key).is_ok()); + let sig = ecdsa::sign(message, &secret_key); + assert!(ecdsa::verify(&sig, message, &public_key).is_ok()); let rec_sig = ecdsa::RecoverableSignature::sign_ecdsa_recoverable(message, &secret_key); - assert!(secp.verify_ecdsa(&rec_sig.to_standard(), message, &public_key).is_ok()); + assert!(ecdsa::verify(&rec_sig.to_standard(), message, &public_key).is_ok()); assert_eq!(public_key, rec_sig.recover_ecdsa(message).unwrap()); let (rec_id, data) = rec_sig.serialize_compact(); let new_rec_sig = ecdsa::RecoverableSignature::from_compact(&data, rec_id).unwrap(); @@ -106,11 +106,11 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize { #[cfg(feature = "alloc")] { let secp_alloc = Secp256k1::new(); - let public_key = PublicKey::from_secret_key(&secp_alloc, &secret_key); + let public_key = PublicKey::from_secret_key(&secret_key); let message = Message::from_digest_slice(&[0xab; 32]).expect("32 bytes"); - let sig = secp_alloc.sign_ecdsa(message, &secret_key); - assert!(secp_alloc.verify_ecdsa(&sig, message, &public_key).is_ok()); + let sig = ecdsa::sign(message, &secret_key); + assert!(ecdsa::verify(&sig, message, &public_key).is_ok()); unsafe { libc::printf("Verified alloc Successfully!\n\0".as_ptr() as _) }; } diff --git a/src/context/mod.rs b/src/context/mod.rs index e31611e7b..ea57cc58e 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -38,13 +38,6 @@ pub mod global { /// /// If `rand` and `std` feature is enabled, context will have been randomized using /// `rng`. - /// - /// ``` - /// # #[cfg(all(feature = "global-context", feature = "rand", feature = "std"))] { - /// use secp256k1::{PublicKey, SECP256K1}; - /// let _ = SECP256K1.generate_keypair(&mut rand::rng()); - /// # } - /// ``` pub static SECP256K1: &GlobalContext = &GlobalContext { __private: () }; impl Deref for GlobalContext { diff --git a/src/ecdh.rs b/src/ecdh.rs index dc88ce155..58b0f745a 100644 --- a/src/ecdh.rs +++ b/src/ecdh.rs @@ -21,11 +21,9 @@ const SHARED_SECRET_SIZE: usize = constants::SECRET_KEY_SIZE; /// /// ``` /// # #[cfg(all(feature = "rand", feature = "std"))] { -/// # use secp256k1::{rand, Secp256k1}; -/// # use secp256k1::ecdh::SharedSecret; -/// let s = Secp256k1::new(); -/// let (sk1, pk1) = s.generate_keypair(&mut rand::rng()); -/// let (sk2, pk2) = s.generate_keypair(&mut rand::rng()); +/// # use secp256k1::{rand, ecdh::SharedSecret}; +/// let (sk1, pk1) = secp256k1::generate_keypair(&mut rand::rng()); +/// let (sk2, pk2) = secp256k1::generate_keypair(&mut rand::rng()); /// let sec1 = SharedSecret::new(&pk2, &sk1); /// let sec2 = SharedSecret::new(&pk1, &sk2); /// assert_eq!(sec1, sec2); @@ -112,11 +110,10 @@ impl AsRef<[u8]> for SharedSecret { /// # Examples /// ```ignore /// use bitcoin_hashes::{Hash, sha512}; -/// use secp256k1::{ecdh, rand, Secp256k1, PublicKey, SecretKey}; +/// use secp256k1::{ecdh, rand, PublicKey, SecretKey}; /// -/// let s = Secp256k1::new(); -/// let (sk1, pk1) = s.generate_keypair(&mut rand::rng()); -/// let (sk2, pk2) = s.generate_keypair(&mut rand::rng()); +/// let (sk1, pk1) = crate::generate_keypair(&mut rand::rng()); +/// let (sk2, pk2) = crate::generate_keypair(&mut rand::rng()); /// /// let point1 = ecdh::shared_secret_point(&pk2, &sk1); /// let secret1 = sha512::Hash::hash(&point1); @@ -189,7 +186,6 @@ mod tests { use wasm_bindgen_test::wasm_bindgen_test as test; use super::SharedSecret; - use crate::Secp256k1; #[test] fn ecdh() { @@ -251,11 +247,9 @@ mod benches { use test::{black_box, Bencher}; use super::SharedSecret; - use crate::Secp256k1; #[bench] pub fn bench_ecdh(bh: &mut Bencher) { - let s = Secp256k1::signing_only(); let (sk, pk) = s.generate_keypair(&mut rand::rng()); bh.iter(|| { diff --git a/src/ecdsa/mod.rs b/src/ecdsa/mod.rs index 12072f8ac..5eabc97bd 100644 --- a/src/ecdsa/mod.rs +++ b/src/ecdsa/mod.rs @@ -13,11 +13,7 @@ use core::{fmt, ptr, str}; pub use self::recovery::{RecoverableSignature, RecoveryId}; pub use self::serialized_signature::SerializedSignature; use crate::ffi::CPtr; -#[cfg(feature = "global-context")] -use crate::SECP256K1; -use crate::{ - ffi, from_hex, Error, Message, PublicKey, Secp256k1, SecretKey, Signing, Verification, -}; +use crate::{ecdsa, ffi, from_hex, Error, Message, PublicKey, Secp256k1, SecretKey}; /// An ECDSA signature #[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] @@ -190,12 +186,12 @@ impl Signature { ret } - /// Verifies an ECDSA signature for `msg` using `pk` and the global [`SECP256K1`] context. + /// Verifies an ECDSA signature for `msg` using `pk`. + /// /// The signature must be normalized or verification will fail (see [`Signature::normalize_s`]). #[inline] - #[cfg(feature = "global-context")] pub fn verify(&self, msg: impl Into, pk: &PublicKey) -> Result<(), Error> { - SECP256K1.verify_ecdsa(self, msg, pk) + ecdsa::verify(self, msg, pk) } } @@ -240,167 +236,165 @@ impl<'de> serde::Deserialize<'de> for Signature { } } -impl Secp256k1 { - fn sign_ecdsa_with_noncedata_pointer( - &self, - msg: impl Into, - sk: &SecretKey, - noncedata: Option<&[u8; 32]>, - ) -> Signature { - let msg = msg.into(); - unsafe { - let mut ret = ffi::Signature::new(); - let noncedata_ptr = match noncedata { - Some(arr) => arr.as_c_ptr() as *const _, - None => ptr::null(), - }; - // We can assume the return value because it's not possible to construct - // an invalid signature from a valid `Message` and `SecretKey` - assert_eq!( +fn sign_ecdsa_with_noncedata_pointer( + msg: impl Into, + sk: &SecretKey, + noncedata: Option<&[u8; 32]>, +) -> Signature { + let msg = msg.into(); + unsafe { + let mut ret = ffi::Signature::new(); + let noncedata_ptr = match noncedata { + Some(arr) => arr.as_c_ptr() as *const _, + None => ptr::null(), + }; + // We can assume the return value because it's not possible to construct + // an invalid signature from a valid `Message` and `SecretKey` + let res = crate::with_global_context( + |secp: &Secp256k1| { ffi::secp256k1_ecdsa_sign( - self.ctx.as_ptr(), + secp.ctx.as_ptr(), &mut ret, msg.as_c_ptr(), sk.as_c_ptr(), ffi::secp256k1_nonce_function_rfc6979, - noncedata_ptr - ), - 1 - ); - Signature::from(ret) - } - } + noncedata_ptr, + ) + }, + Some(&sk.to_secret_bytes()), + ); - /// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce - /// Requires a signing-capable context. - pub fn sign_ecdsa(&self, msg: impl Into, sk: &SecretKey) -> Signature { - self.sign_ecdsa_with_noncedata_pointer(msg, sk, None) - } + assert_eq!(res, 1); - /// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce - /// and includes 32 bytes of noncedata in the nonce generation via inclusion in - /// one of the hash operations during nonce generation. This is useful when multiple - /// signatures are needed for the same Message and SecretKey while still using RFC6979. - /// Requires a signing-capable context. - pub fn sign_ecdsa_with_noncedata( - &self, - msg: impl Into, - sk: &SecretKey, - noncedata: &[u8; 32], - ) -> Signature { - self.sign_ecdsa_with_noncedata_pointer(msg, sk, Some(noncedata)) + Signature::from(ret) } +} + +/// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce +/// Requires a signing-capable context. +pub fn sign(msg: impl Into, sk: &SecretKey) -> Signature { + sign_ecdsa_with_noncedata_pointer(msg, sk, None) +} + +/// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce +/// and includes 32 bytes of noncedata in the nonce generation via inclusion in +/// one of the hash operations during nonce generation. This is useful when multiple +/// signatures are needed for the same Message and SecretKey while still using RFC6979. +/// Requires a signing-capable context. +pub fn sign_with_noncedata( + msg: impl Into, + sk: &SecretKey, + noncedata: &[u8; 32], +) -> Signature { + sign_ecdsa_with_noncedata_pointer(msg, sk, Some(noncedata)) +} - fn sign_grind_with_check( - &self, - msg: impl Into, - sk: &SecretKey, - check: impl Fn(&ffi::Signature) -> bool, - ) -> Signature { - let mut entropy_p: *const ffi::types::c_void = ptr::null(); - let mut counter: u32 = 0; - let mut extra_entropy = [0u8; 32]; - let msg = msg.into(); - loop { - unsafe { - let mut ret = ffi::Signature::new(); - // We can assume the return value because it's not possible to construct - // an invalid signature from a valid `Message` and `SecretKey` - assert_eq!( +fn sign_grind_with_check( + msg: impl Into, + sk: &SecretKey, + check: impl Fn(&ffi::Signature) -> bool, +) -> Signature { + let mut entropy_p: *const ffi::types::c_void = ptr::null(); + let mut counter: u32 = 0; + let mut extra_entropy = [0u8; 32]; + let msg = msg.into(); + loop { + unsafe { + let mut ret = ffi::Signature::new(); + // We can assume the return value because it's not possible to construct + // an invalid signature from a valid `Message` and `SecretKey` + let res = crate::with_global_context( + |secp: &Secp256k1| { ffi::secp256k1_ecdsa_sign( - self.ctx.as_ptr(), + secp.ctx.as_ptr(), &mut ret, msg.as_c_ptr(), sk.as_c_ptr(), ffi::secp256k1_nonce_function_rfc6979, - entropy_p - ), - 1 - ); - if check(&ret) { - return Signature::from(ret); - } - - counter += 1; - extra_entropy[..4].copy_from_slice(&counter.to_le_bytes()); - entropy_p = extra_entropy.as_c_ptr().cast::(); - - // When fuzzing, these checks will usually spinloop forever, so just short-circuit them. - #[cfg(secp256k1_fuzz)] + entropy_p, + ) + }, + Some(&sk.to_secret_bytes()), + ); + assert_eq!(res, 1); + + if check(&ret) { return Signature::from(ret); } + + counter += 1; + extra_entropy[..4].copy_from_slice(&counter.to_le_bytes()); + entropy_p = extra_entropy.as_c_ptr().cast::(); + + // When fuzzing, these checks will usually spinloop forever, so just short-circuit them. + #[cfg(secp256k1_fuzz)] + return Signature::from(ret); } } +} - /// Constructs a signature for `msg` using the secret key `sk`, RFC6979 nonce - /// and "grinds" the nonce by passing extra entropy if necessary to produce - /// a signature that is less than 71 - `bytes_to_grind` bytes. The number - /// of signing operation performed by this function is exponential in the - /// number of bytes grinded. - /// Requires a signing capable context. - pub fn sign_ecdsa_grind_r( - &self, - msg: impl Into, - sk: &SecretKey, - bytes_to_grind: usize, - ) -> Signature { - let len_check = |s: &ffi::Signature| der_length_check(s, 71 - bytes_to_grind); - self.sign_grind_with_check(msg, sk, len_check) - } +/// Constructs a signature for `msg` using the secret key `sk`, RFC6979 nonce +/// and "grinds" the nonce by passing extra entropy if necessary to produce +/// a signature that is less than 71 - `bytes_to_grind` bytes. The number +/// of signing operation performed by this function is exponential in the +/// number of bytes grinded. +/// Requires a signing capable context. +pub fn sign_grind_r(msg: impl Into, sk: &SecretKey, bytes_to_grind: usize) -> Signature { + let len_check = |s: &ffi::Signature| der_length_check(s, 71 - bytes_to_grind); + sign_grind_with_check(msg, sk, len_check) +} - /// Constructs a signature for `msg` using the secret key `sk`, RFC6979 nonce - /// and "grinds" the nonce by passing extra entropy if necessary to produce - /// a signature that is less than 71 bytes and compatible with the low r - /// signature implementation of bitcoin core. In average, this function - /// will perform two signing operations. - /// Requires a signing capable context. - pub fn sign_ecdsa_low_r(&self, msg: impl Into, sk: &SecretKey) -> Signature { - self.sign_grind_with_check(msg, sk, compact_sig_has_zero_first_bit) - } +/// Constructs a signature for `msg` using the secret key `sk`, RFC6979 nonce +/// and "grinds" the nonce by passing extra entropy if necessary to produce +/// a signature that is less than 71 bytes and compatible with the low r +/// signature implementation of bitcoin core. In average, this function +/// will perform two signing operations. +/// Requires a signing capable context. +pub fn sign_low_r(msg: impl Into, sk: &SecretKey) -> Signature { + sign_grind_with_check(msg, sk, compact_sig_has_zero_first_bit) } -impl Secp256k1 { - /// Checks that `sig` is a valid ECDSA signature for `msg` using the public - /// key `pubkey`. Returns `Ok(())` on success. Note that this function cannot - /// be used for Bitcoin consensus checking since there may exist signatures - /// which OpenSSL would verify but not libsecp256k1, or vice-versa. Requires a - /// verify-capable context. - /// - /// ```rust - /// # #[cfg(all(feature = "rand", feature = "std"))] { - /// # use secp256k1::{rand, Secp256k1, Message, Error}; - /// # - /// # let secp = Secp256k1::new(); - /// # let (secret_key, public_key) = secp.generate_keypair(&mut rand::rng()); - /// # - /// let message = Message::from_digest_slice(&[0xab; 32]).expect("32 bytes"); - /// let sig = secp.sign_ecdsa(message, &secret_key); - /// assert_eq!(secp.verify_ecdsa(&sig, message, &public_key), Ok(())); - /// - /// let message = Message::from_digest_slice(&[0xcd; 32]).expect("32 bytes"); - /// assert_eq!(secp.verify_ecdsa(&sig, message, &public_key), Err(Error::IncorrectSignature)); - /// # } - /// ``` - #[inline] - pub fn verify_ecdsa( - &self, - sig: &Signature, - msg: impl Into, - pk: &PublicKey, - ) -> Result<(), Error> { - let msg = msg.into(); - unsafe { - if ffi::secp256k1_ecdsa_verify( - self.ctx.as_ptr(), - sig.as_c_ptr(), - msg.as_c_ptr(), - pk.as_c_ptr(), - ) == 0 - { - Err(Error::IncorrectSignature) - } else { - Ok(()) - } +/// Checks that `sig` is a valid ECDSA signature for `msg` using the public +/// key `pubkey`. Returns `Ok(())` on success. Note that this function cannot +/// be used for Bitcoin consensus checking since there may exist signatures +/// which OpenSSL would verify but not libsecp256k1, or vice-versa. Requires a +/// verify-capable context. +/// +/// ```rust +/// # #[cfg(all(feature = "rand", feature = "std"))] { +/// # use secp256k1::{rand, ecdsa, Message, Error}; +/// # +/// # let (secret_key, public_key) = secp256k1::generate_keypair(&mut rand::rng()); +/// # +/// let message = Message::from_digest_slice(&[0xab; 32]).expect("32 bytes"); +/// let sig = ecdsa::sign(message, &secret_key); +/// assert_eq!(ecdsa::verify(&sig, message, &public_key), Ok(())); +/// +/// let message = Message::from_digest_slice(&[0xcd; 32]).expect("32 bytes"); +/// assert_eq!(ecdsa::verify(&sig, message, &public_key), Err(Error::IncorrectSignature)); +/// # } +/// ``` +#[inline] +pub fn verify(sig: &Signature, msg: impl Into, pk: &PublicKey) -> Result<(), Error> { + let msg = msg.into(); + // We have no seed here but we want rerandomiziation to happen for `rand` users. + let seed = [0_u8; 32]; + unsafe { + let res = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_ecdsa_verify( + secp.ctx.as_ptr(), + sig.as_c_ptr(), + msg.as_c_ptr(), + pk.as_c_ptr(), + ) + }, + Some(&seed), + ); + if res == 0 { + Err(Error::IncorrectSignature) + } else { + Ok(()) } } } diff --git a/src/ecdsa/recovery.rs b/src/ecdsa/recovery.rs index de674bd76..910ddc2c3 100644 --- a/src/ecdsa/recovery.rs +++ b/src/ecdsa/recovery.rs @@ -248,9 +248,9 @@ mod tests { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::wasm_bindgen_test as test; - use super::{RecoverableSignature, RecoveryId}; + use super::*; use crate::constants::ONE; - use crate::{Error, Message, Secp256k1, SecretKey}; + use crate::{ecdsa, Error, Message, SecretKey}; #[test] fn capabilities() { @@ -313,8 +313,6 @@ mod tests { #[test] #[cfg(feature = "std")] fn sign_and_verify_fail() { - let s = Secp256k1::new(); - let msg = Message::from_digest(crate::test_random_32_bytes()); let (sk, pk) = crate::test_random_keypair(); @@ -322,7 +320,7 @@ mod tests { let sig = sigr.to_standard(); let msg = Message::from_digest(crate::test_random_32_bytes()); - assert_eq!(s.verify_ecdsa(&sig, msg, &pk), Err(Error::IncorrectSignature)); + assert_eq!(ecdsa::verify(&sig, msg, &pk), Err(Error::IncorrectSignature)); let recovered_key = sigr.recover_ecdsa(msg).unwrap(); assert!(recovered_key != pk); diff --git a/src/ecdsa/serialized_signature.rs b/src/ecdsa/serialized_signature.rs index 090187aa1..f07b4a0b1 100644 --- a/src/ecdsa/serialized_signature.rs +++ b/src/ecdsa/serialized_signature.rs @@ -266,7 +266,7 @@ mod into_iter { #[cfg(test)] mod tests { - use super::{SerializedSignature, MAX_LEN}; + use super::*; #[test] fn iterator_ops_are_homomorphic() { diff --git a/src/ellswift.rs b/src/ellswift.rs index fe640b779..d01d6f55c 100644 --- a/src/ellswift.rs +++ b/src/ellswift.rs @@ -42,7 +42,7 @@ use core::str::FromStr; use ffi::CPtr; use secp256k1_sys::types::{c_int, c_uchar, c_void}; -use crate::{constants, ffi, from_hex, Error, PublicKey, Secp256k1, SecretKey, Verification}; +use crate::{constants, ffi, from_hex, Error, PublicKey, Secp256k1, SecretKey}; unsafe extern "C" fn hash_callback( output: *mut c_uchar, @@ -109,25 +109,25 @@ impl ElligatorSwift { /// # Example /// ``` /// # #[cfg(feature = "alloc")] { - /// use secp256k1::{ellswift::ElligatorSwift, PublicKey, Secp256k1, SecretKey}; - /// let secp = Secp256k1::new(); + /// use secp256k1::{ellswift::ElligatorSwift, PublicKey, SecretKey}; /// let sk = SecretKey::from_secret_bytes([1; 32]).unwrap(); - /// let es = ElligatorSwift::from_seckey(&secp, sk, None); + /// let es = ElligatorSwift::from_seckey(sk, None); /// # } /// ``` - pub fn from_seckey( - secp: &Secp256k1, - sk: SecretKey, - aux_rand: Option<[u8; 32]>, - ) -> ElligatorSwift { + pub fn from_seckey(sk: SecretKey, aux_rand: Option<[u8; 32]>) -> ElligatorSwift { let mut es_out = [0u8; constants::ELLSWIFT_ENCODING_SIZE]; let aux_rand_ptr = aux_rand.as_c_ptr(); unsafe { - let ret = ffi::secp256k1_ellswift_create( - secp.ctx().as_ptr(), - es_out.as_mut_c_ptr(), - sk.as_c_ptr(), - aux_rand_ptr, + let ret = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_ellswift_create( + secp.ctx().as_ptr(), + es_out.as_mut_c_ptr(), + sk.as_c_ptr(), + aux_rand_ptr, + ) + }, + Some(&sk.to_secret_bytes()), ); debug_assert_eq!(ret, 1); } @@ -138,10 +138,9 @@ impl ElligatorSwift { /// # Example /// ``` /// # #[cfg(feature = "alloc")] { - /// use secp256k1::{ellswift::ElligatorSwift, PublicKey, Secp256k1, SecretKey}; - /// let secp = Secp256k1::new(); + /// use secp256k1::{ellswift::ElligatorSwift, PublicKey, SecretKey}; /// let sk = SecretKey::from_secret_bytes([1; 32]).unwrap(); - /// let pk = PublicKey::from_secret_key(&secp, &sk); + /// let pk = PublicKey::from_secret_key(&sk); /// let es = ElligatorSwift::from_pubkey(pk); /// # } /// @@ -155,17 +154,15 @@ impl ElligatorSwift { /// # #[cfg(feature = "alloc")] { /// use secp256k1::{ /// ellswift::{ElligatorSwift, Party}, - /// PublicKey, SecretKey, XOnlyPublicKey, Secp256k1, + /// PublicKey, SecretKey, XOnlyPublicKey, /// }; /// use core::str::FromStr; /// - /// let secp = Secp256k1::new(); - /// /// let alice_sk = SecretKey::from_str("e714e76bdd67ad9f495683c37934148f4efc25ce3f01652c8a906498339e1f3a").unwrap(); /// let bob_sk = SecretKey::from_str("b6c4b0e2f8c4359caf356a618cd1649d18790a1d67f7c2d1e4760e04c785db4f").unwrap(); /// - /// let alice_es = ElligatorSwift::from_seckey(&secp, alice_sk, None); - /// let bob_es = ElligatorSwift::from_seckey(&secp, bob_sk, None); + /// let alice_es = ElligatorSwift::from_seckey(alice_sk, None); + /// let bob_es = ElligatorSwift::from_seckey(bob_sk, None); /// /// let alice_shared_secret = ElligatorSwift::shared_secret(alice_es, bob_es, alice_sk, Party::Initiator); /// let bob_shared_secret = ElligatorSwift::shared_secret(alice_es, bob_es, bob_sk, Party::Responder); @@ -375,9 +372,8 @@ mod tests { #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] fn test_elligator_swift_rtt() { // Test that we can round trip an ElligatorSwift encoding - let secp = crate::Secp256k1::new(); let public_key = - PublicKey::from_secret_key(&secp, &SecretKey::from_secret_bytes([1u8; 32]).unwrap()); + PublicKey::from_secret_key(&SecretKey::from_secret_bytes([1u8; 32]).unwrap()); let ell = ElligatorSwift::from_pubkey(public_key); let pk = PublicKey::from_ellswift(ell); @@ -387,14 +383,11 @@ mod tests { #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] fn test_create_elligator_swift_create_rtt() { // Test that we can round trip an ElligatorSwift created from a secret key - let secp = crate::Secp256k1::new(); let rand32 = [1u8; 32]; let priv32 = [1u8; 32]; - let ell = - ElligatorSwift::from_seckey(&secp, SecretKey::from_secret_bytes(rand32).unwrap(), None); + let ell = ElligatorSwift::from_seckey(SecretKey::from_secret_bytes(rand32).unwrap(), None); let pk = PublicKey::from_ellswift(ell); - let expected = - PublicKey::from_secret_key(&secp, &SecretKey::from_secret_bytes(priv32).unwrap()); + let expected = PublicKey::from_secret_key(&SecretKey::from_secret_bytes(priv32).unwrap()); assert_eq!(pk, expected); } @@ -402,11 +395,9 @@ mod tests { #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] fn test_xdh_with_custom_hasher() { // Test the ECDH with a custom hash function - let secp = crate::Secp256k1::new(); let rand32 = [1u8; 32]; let priv32 = [2u8; 32]; let ell = ElligatorSwift::from_seckey( - &secp, SecretKey::from_secret_bytes(rand32).unwrap(), Some(rand32), ); diff --git a/src/key/mod.rs b/src/key/mod.rs index 36cfc8b6e..c7a829b6b 100644 --- a/src/key/mod.rs +++ b/src/key/mod.rs @@ -10,7 +10,6 @@ use core::{fmt, ptr, str}; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; -use secp256k1_sys::secp256k1_ec_pubkey_sort; #[cfg(feature = "serde")] use serde::ser::SerializeTuple; @@ -19,11 +18,7 @@ use crate::ellswift::ElligatorSwift; use crate::ffi::types::c_uint; use crate::ffi::{self, CPtr}; use crate::Error::{self, InvalidPublicKey, InvalidPublicKeySum}; -#[cfg(feature = "global-context")] -use crate::SECP256K1; -use crate::{ - constants, ecdsa, from_hex, schnorr, Message, Scalar, Secp256k1, Signing, Verification, -}; +use crate::{constants, ecdsa, from_hex, schnorr, Message, Scalar, Secp256k1, Verification}; /// Public key - used to verify ECDSA signatures and to do Taproot tweaks. /// @@ -39,11 +34,10 @@ use crate::{ /// /// ``` /// # #[cfg(feature = "alloc")] { -/// use secp256k1::{SecretKey, Secp256k1, PublicKey}; +/// use secp256k1::{SecretKey, PublicKey}; /// -/// let secp = Secp256k1::new(); /// let secret_key = SecretKey::from_byte_array([0xcd; 32]).expect("32 bytes, within curve order"); -/// let public_key = PublicKey::from_secret_key(&secp, &secret_key); +/// let public_key = PublicKey::from_secret_key(&secret_key); /// # } /// ``` /// [`bincode`]: https://docs.rs/bincode @@ -108,20 +102,24 @@ impl PublicKey { /// /// ``` /// # #[cfg(all(feature = "rand", feature = "std"))] { - /// use secp256k1::{rand, Secp256k1, SecretKey, PublicKey}; + /// use secp256k1::{rand, SecretKey, PublicKey}; /// - /// let secp = Secp256k1::new(); /// let secret_key = SecretKey::new(&mut rand::rng()); - /// let public_key = PublicKey::from_secret_key(&secp, &secret_key); + /// let public_key = PublicKey::from_secret_key(&secret_key); /// # } /// ``` #[inline] - pub fn from_secret_key(secp: &Secp256k1, sk: &SecretKey) -> PublicKey { + pub fn from_secret_key(sk: &SecretKey) -> PublicKey { unsafe { let mut pk = ffi::PublicKey::new(); // We can assume the return value because it's not possible to construct // an invalid `SecretKey` without transmute trickery or something. - let res = ffi::secp256k1_ec_pubkey_create(secp.ctx.as_ptr(), &mut pk, sk.as_c_ptr()); + let res = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_ec_pubkey_create(secp.ctx.as_ptr(), &mut pk, sk.as_c_ptr()) + }, + Some(&sk.to_secret_bytes()), + ); debug_assert_eq!(res, 1); PublicKey(pk) } @@ -130,12 +128,11 @@ impl PublicKey { #[inline] pub fn from_ellswift(ellswift: ElligatorSwift) -> PublicKey { ElligatorSwift::decode(ellswift) } - /// Creates a new public key from a [`SecretKey`] and the global [`SECP256K1`] context. + /// Creates a new public key from a [`SecretKey`]. #[inline] #[cfg(feature = "global-context")] - pub fn from_secret_key_global(sk: &SecretKey) -> PublicKey { - PublicKey::from_secret_key(SECP256K1, sk) - } + #[deprecated(since = "TBD", note = "use from_secret_key instead")] + pub fn from_secret_key_global(sk: &SecretKey) -> PublicKey { PublicKey::from_secret_key(sk) } /// Creates a public key directly from a slice. #[inline] @@ -199,10 +196,9 @@ impl PublicKey { /// /// ``` /// # #[cfg(all(feature = "rand", feature = "std"))] { - /// use secp256k1::{rand, Secp256k1, PublicKey, Keypair}; + /// use secp256k1::{rand, PublicKey, Keypair}; /// - /// let secp = Secp256k1::new(); - /// let keypair = Keypair::new(&secp, &mut rand::rng()); + /// let keypair = Keypair::new(&mut rand::rng()); /// let public_key = PublicKey::from_keypair(&keypair); /// # } /// ``` @@ -305,15 +301,21 @@ impl PublicKey { /// /// Returns an error if the resulting key would be invalid. #[inline] - pub fn mul_tweak( - mut self, - secp: &Secp256k1, - other: &Scalar, - ) -> Result { + pub fn mul_tweak(mut self, other: &Scalar) -> Result { + // We have no seed here but we want rerandomiziation to happen for `rand` users. + let seed = [0_u8; 32]; unsafe { - if ffi::secp256k1_ec_pubkey_tweak_mul(secp.ctx.as_ptr(), &mut self.0, other.as_c_ptr()) - == 1 - { + let res = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_ec_pubkey_tweak_mul( + secp.ctx.as_ptr(), + &mut self.0, + other.as_c_ptr(), + ) + }, + Some(&seed), + ); + if res == 1 { Ok(self) } else { Err(Error::InvalidTweak) @@ -331,12 +333,11 @@ impl PublicKey { /// /// ``` /// # #[cfg(all(feature = "rand", feature = "std"))] { - /// use secp256k1::{rand, Secp256k1}; + /// use secp256k1::rand; /// - /// let secp = Secp256k1::new(); /// let mut rng = rand::rng(); - /// let (_, pk1) = secp.generate_keypair(&mut rng); - /// let (_, pk2) = secp.generate_keypair(&mut rng); + /// let (_, pk1) = secp256k1::generate_keypair(&mut rng); + /// let (_, pk2) = secp256k1::generate_keypair(&mut rng); /// let sum = pk1.combine(&pk2).expect("It's improbable to fail for 2 random public keys"); /// # } /// ``` @@ -357,13 +358,12 @@ impl PublicKey { /// /// ``` /// # #[cfg(all(feature = "rand", feature = "std"))] { - /// use secp256k1::{rand, Secp256k1, PublicKey}; + /// use secp256k1::{rand, PublicKey}; /// - /// let secp = Secp256k1::new(); /// let mut rng = rand::rng(); - /// let (_, pk1) = secp.generate_keypair(&mut rng); - /// let (_, pk2) = secp.generate_keypair(&mut rng); - /// let (_, pk3) = secp.generate_keypair(&mut rng); + /// let (_, pk1) = secp256k1::generate_keypair(&mut rng); + /// let (_, pk2) = secp256k1::generate_keypair(&mut rng); + /// let (_, pk3) = secp256k1::generate_keypair(&mut rng); /// let sum = PublicKey::combine_keys(&[&pk1, &pk2, &pk3]).expect("It's improbable to fail for 3 random public keys"); /// # } /// ``` @@ -413,13 +413,8 @@ impl PublicKey { } /// Checks that `sig` is a valid ECDSA signature for `msg` using this public key. - pub fn verify( - &self, - secp: &Secp256k1, - msg: impl Into, - sig: &ecdsa::Signature, - ) -> Result<(), Error> { - secp.verify_ecdsa(sig, msg, self) + pub fn verify(&self, msg: impl Into, sig: &ecdsa::Signature) -> Result<(), Error> { + ecdsa::verify(sig, msg, self) } } @@ -491,11 +486,10 @@ impl<'de> serde::Deserialize<'de> for PublicKey { /// /// ``` /// # #[cfg(all(feature = "rand", feature = "std"))] { -/// use secp256k1::{rand, Keypair, Secp256k1}; +/// use secp256k1::{rand, Keypair}; /// -/// let secp = Secp256k1::new(); -/// let (secret_key, public_key) = secp.generate_keypair(&mut rand::rng()); -/// let keypair = Keypair::from_secret_key(&secp, &secret_key); +/// let (secret_key, public_key) = secp256k1::generate_keypair(&mut rand::rng()); +/// let keypair = Keypair::from_secret_key(&secret_key); /// # } /// ``` /// [`bincode`]: https://docs.rs/bincode @@ -520,10 +514,17 @@ impl Keypair { /// Creates a [`Keypair`] directly from a Secp256k1 secret key. #[inline] - pub fn from_secret_key(secp: &Secp256k1, sk: &SecretKey) -> Keypair { + pub fn from_secret_key(sk: &SecretKey) -> Keypair { unsafe { let mut kp = ffi::Keypair::new(); - if ffi::secp256k1_keypair_create(secp.ctx.as_ptr(), &mut kp, sk.as_c_ptr()) == 1 { + let res = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_keypair_create(secp.ctx.as_ptr(), &mut kp, sk.as_c_ptr()) + }, + Some(&sk.to_secret_bytes()), + ); + + if res == 1 { Keypair(kp) } else { panic!("the provided secret key is invalid: it is corrupted or was not produced by Secp256k1 library") @@ -579,7 +580,7 @@ impl Keypair { #[deprecated(note = "use FromStr or parse instead")] pub fn from_seckey_str(s: &str) -> Result { s.parse() } - /// Creates a [`Keypair`] directly from a secret key string and the global [`SECP256K1`] context. + /// Creates a [`Keypair`] directly from a secret key string. /// /// # Errors /// @@ -594,33 +595,48 @@ impl Keypair { /// /// ``` /// # #[cfg(all(feature = "rand", feature = "std"))] { - /// use secp256k1::{rand, Secp256k1, SecretKey, Keypair}; + /// use secp256k1::{rand, SecretKey, Keypair}; /// - /// let secp = Secp256k1::new(); - /// let keypair = Keypair::new(&secp, &mut rand::rng()); + /// let keypair = Keypair::new(&mut rand::rng()); /// # } /// ``` #[inline] #[cfg(feature = "rand")] - pub fn new(secp: &Secp256k1, rng: &mut R) -> Keypair { + pub fn new(rng: &mut R) -> Keypair { let mut data = crate::random_32_bytes(rng); + let mut ret = 0; + unsafe { let mut keypair = ffi::Keypair::new(); - while ffi::secp256k1_keypair_create(secp.ctx.as_ptr(), &mut keypair, data.as_c_ptr()) - == 0 - { + + while ret == 0 { + ret = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_keypair_create( + secp.ctx.as_ptr(), + &mut keypair, + data.as_c_ptr(), + ) + }, + Some(&data), + ); + + if ret != 0 { + break; + } + data = crate::random_32_bytes(rng); } + Keypair(keypair) } } - /// Generates a new random secret key using the global [`SECP256K1`] context. + /// Generates a new random secret key. #[inline] #[cfg(all(feature = "global-context", feature = "rand"))] - pub fn new_global(rng: &mut R) -> Keypair { - Keypair::new(SECP256K1, rng) - } + #[deprecated(since = "TBD", note = "use Keypair::new instead")] + pub fn new_global(rng: &mut R) -> Keypair { Keypair::new(rng) } /// Returns the secret bytes for this key pair. #[inline] @@ -641,27 +657,29 @@ impl Keypair { /// /// ``` /// # #[cfg(all(feature = "rand", feature = "std"))] { - /// use secp256k1::{Secp256k1, Keypair, Scalar}; + /// use secp256k1::{Keypair, Scalar}; /// - /// let secp = Secp256k1::new(); /// let tweak = Scalar::random(); /// - /// let mut keypair = Keypair::new(&secp, &mut rand::rng()); - /// let tweaked = keypair.add_xonly_tweak(&secp, &tweak).expect("Improbable to fail with a randomly generated tweak"); + /// let mut keypair = Keypair::new(&mut rand::rng()); + /// let tweaked = keypair.add_xonly_tweak(&tweak).expect("Improbable to fail with a randomly generated tweak"); /// # } /// ``` // TODO: Add checked implementation #[inline] - pub fn add_xonly_tweak( - mut self, - secp: &Secp256k1, - tweak: &Scalar, - ) -> Result { + pub fn add_xonly_tweak(mut self, tweak: &Scalar) -> Result { + // We have no seed here but we want rerandomiziation to happen for `rand` users. + let seed = [0_u8; 32]; unsafe { - let err = ffi::secp256k1_keypair_xonly_tweak_add( - secp.ctx.as_ptr(), - &mut self.0, - tweak.as_c_ptr(), + let err = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_keypair_xonly_tweak_add( + secp.ctx.as_ptr(), + &mut self.0, + tweak.as_c_ptr(), + ) + }, + Some(&seed), ); if err != 1 { return Err(Error::InvalidTweak); @@ -691,19 +709,15 @@ impl Keypair { XOnlyPublicKey::from_keypair(self) } - /// Constructs a schnorr signature for `msg` using the global [`SECP256K1`] context. + /// Constructs a schnorr signature for `msg`. #[inline] - #[cfg(all(feature = "global-context", feature = "rand", feature = "std"))] - pub fn sign_schnorr(&self, msg: &[u8]) -> schnorr::Signature { - SECP256K1.sign_schnorr(msg, self) - } + #[cfg(all(feature = "rand", feature = "std"))] + pub fn sign_schnorr(&self, msg: &[u8]) -> schnorr::Signature { schnorr::sign(msg, self) } - /// Constructs a schnorr signature without aux rand for `msg` using the global - /// [`SECP256K1`] context. + /// Constructs a schnorr signature without aux rand for `msg`. #[inline] - #[cfg(all(feature = "global-context", feature = "std"))] pub fn sign_schnorr_no_aux_rand(&self, msg: &[u8]) -> schnorr::Signature { - SECP256K1.sign_schnorr_no_aux_rand(msg, self) + schnorr::sign_no_aux_rand(msg, self) } /// Attempts to erase the secret within the underlying array. @@ -719,10 +733,7 @@ impl Keypair { #[cfg(test)] pub fn test_random() -> Self { let sk = SecretKey::test_random(); - crate::with_global_context( - |secp: &Secp256k1| Self::from_secret_key(secp, &sk), - Some(&sk.to_secret_bytes()), - ) + Self::from_secret_key(&sk) } } @@ -824,10 +835,9 @@ impl CPtr for Keypair { /// /// ``` /// # #[cfg(all(feature = "rand", feature = "std"))] { -/// use secp256k1::{rand, Secp256k1, Keypair, XOnlyPublicKey}; +/// use secp256k1::{rand, Keypair, XOnlyPublicKey}; /// -/// let secp = Secp256k1::new(); -/// let keypair = Keypair::new(&secp, &mut rand::rng()); +/// let keypair = Keypair::new(&mut rand::rng()); /// let xonly = XOnlyPublicKey::from_keypair(&keypair); /// # } /// ``` @@ -972,39 +982,46 @@ impl XOnlyPublicKey { /// /// ``` /// # #[cfg(all(feature = "rand", feature = "std"))] { - /// use secp256k1::{Secp256k1, Keypair, Scalar, XOnlyPublicKey}; + /// use secp256k1::{Keypair, Scalar, XOnlyPublicKey}; /// - /// let secp = Secp256k1::new(); /// let tweak = Scalar::random(); /// - /// let mut keypair = Keypair::new(&secp, &mut rand::rng()); + /// let mut keypair = Keypair::new(&mut rand::rng()); /// let (xonly, _parity) = keypair.x_only_public_key(); - /// let tweaked = xonly.add_tweak(&secp, &tweak).expect("Improbable to fail with a randomly generated tweak"); + /// let tweaked = xonly.add_tweak(&tweak).expect("Improbable to fail with a randomly generated tweak"); /// # } /// ``` - pub fn add_tweak( - mut self, - secp: &Secp256k1, - tweak: &Scalar, - ) -> Result<(XOnlyPublicKey, Parity), Error> { + pub fn add_tweak(mut self, tweak: &Scalar) -> Result<(XOnlyPublicKey, Parity), Error> { let mut pk_parity = 0; + // We have no seed here but we want rerandomiziation to happen for `rand` users. + let seed = [0_u8; 32]; unsafe { let mut pubkey = ffi::PublicKey::new(); - let mut err = ffi::secp256k1_xonly_pubkey_tweak_add( - secp.ctx.as_ptr(), - &mut pubkey, - self.as_c_ptr(), - tweak.as_c_ptr(), + let mut err = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_xonly_pubkey_tweak_add( + secp.ctx.as_ptr(), + &mut pubkey, + self.as_c_ptr(), + tweak.as_c_ptr(), + ) + }, + Some(&seed), ); if err != 1 { return Err(Error::InvalidTweak); } - err = ffi::secp256k1_xonly_pubkey_from_pubkey( - secp.ctx.as_ptr(), - &mut self.0, - &mut pk_parity, - &pubkey, + err = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_xonly_pubkey_from_pubkey( + secp.ctx.as_ptr(), + &mut self.0, + &mut pk_parity, + &pubkey, + ) + }, + Some(&seed), ); if err == 0 { return Err(Error::InvalidPublicKey); @@ -1032,33 +1049,38 @@ impl XOnlyPublicKey { /// /// ``` /// # #[cfg(all(feature = "rand", feature = "std"))] { - /// use secp256k1::{Secp256k1, Keypair, Scalar}; + /// use secp256k1::{Keypair, Scalar}; /// - /// let secp = Secp256k1::new(); /// let tweak = Scalar::random(); /// - /// let mut keypair = Keypair::new(&secp, &mut rand::rng()); + /// let mut keypair = Keypair::new(&mut rand::rng()); /// let (mut public_key, _) = keypair.x_only_public_key(); /// let original = public_key; - /// let (tweaked, parity) = public_key.add_tweak(&secp, &tweak).expect("Improbable to fail with a randomly generated tweak"); - /// assert!(original.tweak_add_check(&secp, &tweaked, parity, tweak)); + /// let (tweaked, parity) = public_key.add_tweak(&tweak).expect("Improbable to fail with a randomly generated tweak"); + /// assert!(original.tweak_add_check(&tweaked, parity, tweak)); /// # } /// ``` - pub fn tweak_add_check( + pub fn tweak_add_check( &self, - secp: &Secp256k1, tweaked_key: &Self, tweaked_parity: Parity, tweak: Scalar, ) -> bool { let tweaked_ser = tweaked_key.serialize(); + // We have no seed here but we want rerandomiziation to happen for `rand` users. + let seed = [0_u8; 32]; unsafe { - let err = ffi::secp256k1_xonly_pubkey_tweak_add_check( - secp.ctx.as_ptr(), - tweaked_ser.as_c_ptr(), - tweaked_parity.to_i32(), - &self.0, - tweak.as_c_ptr(), + let err = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_xonly_pubkey_tweak_add_check( + secp.ctx.as_ptr(), + tweaked_ser.as_c_ptr(), + tweaked_parity.to_i32(), + &self.0, + tweak.as_c_ptr(), + ) + }, + Some(&seed), ); err == 1 @@ -1076,11 +1098,10 @@ impl XOnlyPublicKey { /// Checks that `sig` is a valid schnorr signature for `msg` using this public key. pub fn verify( &self, - secp: &Secp256k1, msg: &[u8], sig: &schnorr::Signature, ) -> Result<(), Error> { - secp.verify_schnorr(sig, msg, self) + schnorr::verify(sig, msg, self) } } @@ -1283,38 +1304,44 @@ impl<'de> serde::Deserialize<'de> for XOnlyPublicKey { } } -impl Secp256k1 { - /// Sort public keys using lexicographic (of compressed serialization) order. - /// - /// This is the canonical way to sort public keys for use with Musig2. - /// - /// Example: - /// - /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{rng, RngCore}; - /// # use secp256k1::{Secp256k1, SecretKey, Keypair, PublicKey, pubkey_sort}; - /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut rng()); - /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut rng()); - /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); - /// # - /// # let pubkeys = [pub_key1, pub_key2]; - /// # let mut pubkeys_ref: Vec<&PublicKey> = pubkeys.iter().collect(); - /// # let pubkeys_ref = pubkeys_ref.as_mut_slice(); - /// # - /// # secp.sort_pubkeys(pubkeys_ref); - /// # } - /// ``` - pub fn sort_pubkeys(&self, pubkeys: &mut [&PublicKey]) { - let cx = self.ctx().as_ptr(); - unsafe { - // SAFETY: `PublicKey` has repr(transparent) so we can convert to `ffi::PublicKey` - let pubkeys_ptr = pubkeys.as_mut_c_ptr() as *mut *const ffi::PublicKey; - if secp256k1_ec_pubkey_sort(cx, pubkeys_ptr, pubkeys.len()) == 0 { - unreachable!("Invalid public keys for sorting function") - } +/// Sort public keys using lexicographic (of compressed serialization) order. +/// +/// This is the canonical way to sort public keys for use with Musig2. +/// +/// Example: +/// +/// ```rust +/// # # [cfg(any(test, feature = "rand-std"))] { +/// # use secp256k1::rand::{rng, RngCore}; +/// # use secp256k1::{SecretKey, Keypair, PublicKey, pubkey_sort}; +/// # let sk1 = SecretKey::new(&mut rng()); +/// # let pub_key1 = PublicKey::from_secret_key(&sk1); +/// # let sk2 = SecretKey::new(&mut rng()); +/// # let pub_key2 = PublicKey::from_secret_key(&sk2); +/// # +/// # let pubkeys = [pub_key1, pub_key2]; +/// # let mut pubkeys_ref: Vec<&PublicKey> = pubkeys.iter().collect(); +/// # let pubkeys_ref = pubkeys_ref.as_mut_slice(); +/// # +/// # secp256k1::sort_pubkeys(pubkeys_ref); +/// # } +/// ``` +pub fn sort_pubkeys(pubkeys: &mut [&PublicKey]) { + // We have no seed here but we want rerandomiziation to happen for `rand` users. + let seed = [0_u8; 32]; + unsafe { + // SAFETY: `PublicKey` has repr(transparent) so we can convert to `ffi::PublicKey` + let pubkeys_ptr = pubkeys.as_mut_c_ptr() as *mut *const ffi::PublicKey; + + let ret = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_ec_pubkey_sort(secp.ctx.as_ptr(), pubkeys_ptr, pubkeys.len()) + }, + Some(&seed), + ); + + if ret == 0 { + unreachable!("Invalid public keys for sorting function") } } } @@ -1387,7 +1414,7 @@ mod test { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::wasm_bindgen_test as test; - use super::{Keypair, Parity, PublicKey, Secp256k1, SecretKey, XOnlyPublicKey, *}; + use super::*; use crate::Error::{InvalidPublicKey, InvalidSecretKey}; use crate::{constants, from_hex, to_hex, Scalar}; @@ -1480,8 +1507,7 @@ mod test { } } - let s = Secp256k1::new(); - s.generate_keypair(&mut BadRng(0xff)); + crate::generate_keypair(&mut BadRng(0xff)); } #[test] @@ -1519,8 +1545,7 @@ mod test { #[test] #[cfg(all(feature = "rand", feature = "alloc"))] fn test_debug_output() { - let s = Secp256k1::new(); - let (sk, _) = s.generate_keypair(&mut SmallRng::from_seed([0; 16])); + let (sk, _) = crate::generate_keypair(&mut SmallRng::from_seed([0; 16])); assert_eq!(&format!("{:?}", sk), "SecretKey(55f970894288f83a)"); @@ -1542,14 +1567,12 @@ mod test { 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, ]; - #[cfg(not(secp256k1_fuzz))] - let s = Secp256k1::signing_only(); let sk = SecretKey::from_secret_bytes(SK_BYTES).expect("sk"); // In fuzzing mode secret->public key derivation is different, so // hard-code the expected result. #[cfg(not(secp256k1_fuzz))] - let pk = PublicKey::from_secret_key(&s, &sk); + let pk = PublicKey::from_secret_key(&sk); #[cfg(secp256k1_fuzz)] let pk = PublicKey::from_slice(&[ 0x02, 0x18, 0x84, 0x57, 0x81, 0xf6, 0x31, 0xc4, 0x8f, 0x1c, 0x97, 0x09, 0xe2, 0x30, @@ -1638,8 +1661,7 @@ mod test { #[cfg(not(secp256k1_fuzz))] #[cfg(all(feature = "alloc", feature = "rand"))] fn test_pubkey_serialize() { - let s = Secp256k1::new(); - let (_, pk1) = s.generate_keypair(&mut SmallRng::from_seed([1; 16])); + let (_, pk1) = crate::generate_keypair(&mut SmallRng::from_seed([1; 16])); assert_eq!( &pk1.serialize_uncompressed()[..], &[ @@ -1661,10 +1683,8 @@ mod test { #[test] #[cfg(feature = "std")] fn tweak_add_arbitrary_data() { - let s = Secp256k1::new(); - let (sk, pk) = crate::test_random_keypair(); - assert_eq!(PublicKey::from_secret_key(&s, &sk), pk); // Sanity check. + assert_eq!(PublicKey::from_secret_key(&sk), pk); // Sanity check. // TODO: This would be better tested with a _lot_ of different tweaks. let tweak = Scalar::test_random(); @@ -1674,7 +1694,7 @@ mod test { let tweaked_pk = pk.add_exp_tweak(&tweak).unwrap(); assert_ne!(pk, tweaked_pk); - assert_eq!(PublicKey::from_secret_key(&s, &tweaked_sk), tweaked_pk); + assert_eq!(PublicKey::from_secret_key(&tweaked_sk), tweaked_pk); } #[test] @@ -1692,19 +1712,17 @@ mod test { #[test] #[cfg(feature = "std")] fn tweak_mul_arbitrary_data() { - let s = Secp256k1::new(); - let (sk, pk) = crate::test_random_keypair(); - assert_eq!(PublicKey::from_secret_key(&s, &sk), pk); // Sanity check. + assert_eq!(PublicKey::from_secret_key(&sk), pk); // Sanity check. for _ in 0..10 { let tweak = Scalar::test_random(); let tweaked_sk = sk.mul_tweak(&tweak).unwrap(); assert_ne!(sk, tweaked_sk); // Make sure we did something. - let tweaked_pk = pk.mul_tweak(&s, &tweak).unwrap(); + let tweaked_pk = pk.mul_tweak(&tweak).unwrap(); assert_ne!(pk, tweaked_pk); - assert_eq!(PublicKey::from_secret_key(&s, &tweaked_sk), tweaked_pk); + assert_eq!(PublicKey::from_secret_key(&tweaked_sk), tweaked_pk); } } @@ -1719,11 +1737,9 @@ mod test { #[test] #[cfg(feature = "std")] fn test_negation() { - let s = Secp256k1::new(); - let (sk, pk) = crate::test_random_keypair(); - assert_eq!(PublicKey::from_secret_key(&s, &sk), pk); // Sanity check. + assert_eq!(PublicKey::from_secret_key(&sk), pk); // Sanity check. let neg = sk.negate(); assert_ne!(sk, neg); @@ -1735,7 +1751,7 @@ mod test { let back_pk = neg.negate(); assert_eq!(pk, back_pk); - assert_eq!(PublicKey::from_secret_key(&s, &back_sk), pk); + assert_eq!(PublicKey::from_secret_key(&back_sk), pk); } #[test] @@ -1823,8 +1839,6 @@ mod test { #[test] #[cfg(feature = "std")] fn create_pubkey_combine() { - let s = Secp256k1::new(); - let (sk1, pk1) = crate::test_random_keypair(); let (sk2, pk2) = crate::test_random_keypair(); @@ -1835,7 +1849,7 @@ mod test { assert_eq!(sum1, sum2); let tweaked = sk1.add_tweak(&Scalar::from(sk2)).unwrap(); - let sksum = PublicKey::from_secret_key(&s, &tweaked); + let sksum = PublicKey::from_secret_key(&tweaked); assert_eq!(Ok(sksum), sum1); } @@ -1889,14 +1903,12 @@ mod test { ]; static PK_STR: &str = "0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166"; - #[cfg(not(secp256k1_fuzz))] - let s = Secp256k1::new(); let sk = SecretKey::from_secret_bytes(SK_BYTES).unwrap(); // In fuzzing mode secret->public key derivation is different, so // hard-code the expected result. #[cfg(not(secp256k1_fuzz))] - let pk = PublicKey::from_secret_key(&s, &sk); + let pk = PublicKey::from_secret_key(&sk); #[cfg(secp256k1_fuzz)] let pk = PublicKey::from_slice(&PK_BYTES).expect("pk"); @@ -1933,24 +1945,22 @@ mod test { #[test] #[cfg(feature = "std")] fn test_tweak_add_then_tweak_add_check() { - let s = Secp256k1::new(); - for _ in 0..10 { let tweak = Scalar::test_random(); let kp = Keypair::test_random(); let (xonly, _) = XOnlyPublicKey::from_keypair(&kp); - let tweaked_kp = kp.add_xonly_tweak(&s, &tweak).expect("keypair tweak add failed"); + let tweaked_kp = kp.add_xonly_tweak(&tweak).expect("keypair tweak add failed"); let (tweaked_xonly, parity) = - xonly.add_tweak(&s, &tweak).expect("xonly pubkey tweak failed"); + xonly.add_tweak(&tweak).expect("xonly pubkey tweak failed"); let (want_tweaked_xonly, tweaked_kp_parity) = XOnlyPublicKey::from_keypair(&tweaked_kp); assert_eq!(tweaked_xonly, want_tweaked_xonly); assert_eq!(parity, tweaked_kp_parity); - assert!(xonly.tweak_add_check(&s, &tweaked_xonly, parity, tweak)); + assert!(xonly.tweak_add_check(&tweaked_xonly, parity, tweak)); } } @@ -2008,8 +2018,6 @@ mod test { #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] fn keys() -> (SecretKey, PublicKey, Keypair, XOnlyPublicKey) { - let secp = Secp256k1::new(); - #[rustfmt::skip] static SK_BYTES: [u8; 32] = [ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, @@ -2032,7 +2040,7 @@ mod test { let sk = SecretKey::from_secret_bytes(SK_BYTES).expect("failed to parse sk bytes"); let pk = PublicKey::from_slice(&pk_bytes).expect("failed to create pk from iterator"); - let kp = Keypair::from_secret_key(&secp, &sk); + let kp = Keypair::from_secret_key(&sk); let xonly = XOnlyPublicKey::from_byte_array(PK_BYTES).expect("failed to get xonly from slice"); @@ -2052,10 +2060,8 @@ mod test { #[test] #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] fn convert_secret_key_to_public_key() { - let secp = Secp256k1::new(); - let (sk, want, _kp, _xonly) = keys(); - let got = sk.public_key(&secp); + let got = sk.public_key(); assert_eq!(got, want) } @@ -2063,10 +2069,8 @@ mod test { #[test] #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] fn convert_secret_key_to_x_only_public_key() { - let secp = Secp256k1::new(); - let (sk, _pk, _kp, want) = keys(); - let (got, parity) = sk.x_only_public_key(&secp); + let (got, parity) = sk.x_only_public_key(); assert_eq!(parity, Parity::Even); assert_eq!(got, want) @@ -2095,10 +2099,9 @@ mod test { #[test] #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] fn roundtrip_secret_key_via_keypair() { - let secp = Secp256k1::new(); let (sk, _pk, _kp, _xonly) = keys(); - let kp = sk.keypair(&secp); + let kp = sk.keypair(); let back = kp.secret_key(); assert_eq!(back, sk) @@ -2108,11 +2111,10 @@ mod test { #[test] #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] fn roundtrip_keypair_via_secret_key() { - let secp = Secp256k1::new(); let (_sk, _pk, kp, _xonly) = keys(); let sk = kp.secret_key(); - let back = sk.keypair(&secp); + let back = sk.keypair(); assert_eq!(back, kp) } diff --git a/src/key/secret.rs b/src/key/secret.rs index 386c76bd7..3ddb150c2 100644 --- a/src/key/secret.rs +++ b/src/key/secret.rs @@ -8,11 +8,9 @@ use serde::ser::SerializeTuple; use crate::ffi::CPtr as _; use crate::{ - constants, ffi, from_hex, Error, Keypair, Parity, PublicKey, Scalar, Secp256k1, Signing, + constants, ecdsa, ffi, from_hex, Error, Keypair, Message, Parity, PublicKey, Scalar, XOnlyPublicKey, }; -#[cfg(feature = "global-context")] -use crate::{ecdsa, Message, SECP256K1}; mod encapsulate { use crate::constants::SECRET_KEY_SIZE; @@ -42,9 +40,8 @@ mod encapsulate { /// /// ``` /// # #[cfg(all(feature = "rand", feature = "std"))] { - /// use secp256k1::{rand, Secp256k1, SecretKey}; + /// use secp256k1::{rand, SecretKey}; /// - /// let secp = Secp256k1::new(); /// let secret_key = SecretKey::new(&mut rand::rng()); /// # } /// ``` @@ -194,10 +191,9 @@ impl SecretKey { /// /// ``` /// # #[cfg(all(feature = "rand", feature = "std"))] { - /// use secp256k1::{rand, Secp256k1, SecretKey, Keypair}; + /// use secp256k1::{rand, SecretKey, Keypair}; /// - /// let secp = Secp256k1::new(); - /// let keypair = Keypair::new(&secp, &mut rand::rng()); + /// let keypair = Keypair::new(&mut rand::rng()); /// let secret_key = SecretKey::from_keypair(&keypair); /// # } /// ``` @@ -276,35 +272,28 @@ impl SecretKey { } } - /// Constructs an ECDSA signature for `msg` using the global [`SECP256K1`] context. + /// Constructs an ECDSA signature for `msg`. #[inline] - #[cfg(feature = "global-context")] - pub fn sign_ecdsa(&self, msg: impl Into) -> ecdsa::Signature { - SECP256K1.sign_ecdsa(msg, self) - } + pub fn sign_ecdsa(&self, msg: impl Into) -> ecdsa::Signature { ecdsa::sign(msg, self) } /// Returns the [`Keypair`] for this [`SecretKey`]. /// /// This is equivalent to using [`Keypair::from_secret_key`]. #[inline] - pub fn keypair(&self, secp: &Secp256k1) -> Keypair { - Keypair::from_secret_key(secp, self) - } + pub fn keypair(&self) -> Keypair { Keypair::from_secret_key(self) } /// Returns the [`PublicKey`] for this [`SecretKey`]. /// /// This is equivalent to using [`PublicKey::from_secret_key`]. #[inline] - pub fn public_key(&self, secp: &Secp256k1) -> PublicKey { - PublicKey::from_secret_key(secp, self) - } + pub fn public_key(&self) -> PublicKey { PublicKey::from_secret_key(self) } /// Returns the [`XOnlyPublicKey`] (and its [`Parity`]) for this [`SecretKey`]. /// /// This is equivalent to `XOnlyPublicKey::from_keypair(self.keypair(secp))`. #[inline] - pub fn x_only_public_key(&self, secp: &Secp256k1) -> (XOnlyPublicKey, Parity) { - let kp = self.keypair(secp); + pub fn x_only_public_key(&self) -> (XOnlyPublicKey, Parity) { + let kp = self.keypair(); XOnlyPublicKey::from_keypair(&kp) } diff --git a/src/lib.rs b/src/lib.rs index 238ad2005..8f2abd21c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,7 +30,7 @@ //! ```rust //! # #[cfg(all(feature = "rand", feature = "std"))] { //! use secp256k1::rand; -//! use secp256k1::{Secp256k1, Message}; +//! use secp256k1::{ecdsa, Message}; //! //! // Our message to sign. We explicitly obtain a hash and convert it to a //! // `Message`. In a real application, we would produce a signature hash @@ -41,12 +41,11 @@ //! 0x61, 0x2b, 0x1f, 0xce, 0x77, 0xc8, 0x69, 0x34, 0x5b, 0xfc, 0x94, 0xc7, 0x58, 0x94, 0xed, 0xd3, //! ]; //! -//! let secp = Secp256k1::new(); -//! let (secret_key, public_key) = secp.generate_keypair(&mut rand::rng()); +//! let (secret_key, public_key) = secp256k1::generate_keypair(&mut rand::rng()); //! let message = Message::from_digest(HELLO_WORLD_SHA2); //! -//! let sig = secp.sign_ecdsa(message, &secret_key); -//! assert!(secp.verify_ecdsa(&sig, message, &public_key).is_ok()); +//! let sig = ecdsa::sign(message, &secret_key); +//! assert!(ecdsa::verify(&sig, message, &public_key).is_ok()); //! # } //! ``` //! @@ -54,7 +53,7 @@ //! //! ```rust //! # #[cfg(all(feature = "global-context", feature = "rand", feature = "std"))] { -//! use secp256k1::{rand, generate_keypair, Message}; +//! use secp256k1::{rand, Message}; //! //! // See previous example regarding this constant. //! const HELLO_WORLD_SHA2: [u8; 32] = [ @@ -62,7 +61,7 @@ //! 0x61, 0x2b, 0x1f, 0xce, 0x77, 0xc8, 0x69, 0x34, 0x5b, 0xfc, 0x94, 0xc7, 0x58, 0x94, 0xed, 0xd3, //! ]; //! -//! let (secret_key, public_key) = generate_keypair(&mut rand::rng()); +//! let (secret_key, public_key) = secp256k1::generate_keypair(&mut rand::rng()); //! let message = Message::from_digest(HELLO_WORLD_SHA2); //! //! let sig = secret_key.sign_ecdsa(message); @@ -76,18 +75,17 @@ //! //! ```rust //! # #[cfg(feature = "alloc")] { -//! use secp256k1::{Secp256k1, Message, SecretKey, PublicKey}; +//! use secp256k1::{ecdsa, Message, SecretKey, PublicKey}; //! # fn compute_hash(_: &[u8]) -> [u8; 32] { [0xab; 32] } //! -//! let secp = Secp256k1::new(); //! let secret_key = SecretKey::from_secret_bytes([0xcd; 32]).expect("32 bytes, within curve order"); -//! let public_key = PublicKey::from_secret_key(&secp, &secret_key); +//! let public_key = PublicKey::from_secret_key(&secret_key); //! // If the supplied byte slice was *not* the output of a cryptographic hash function this would //! // be cryptographically broken. It has been trivially used in the past to execute attacks. //! let message = Message::from_digest(compute_hash(b"CSW is not Satoshi")); //! -//! let sig = secp.sign_ecdsa(message, &secret_key); -//! assert!(secp.verify_ecdsa(&sig, message, &public_key).is_ok()); +//! let sig = ecdsa::sign(message, &secret_key); +//! assert!(ecdsa::verify(&sig, message, &public_key).is_ok()); //! # } //! ``` //! @@ -95,9 +93,7 @@ //! //! ```rust //! # #[cfg(feature = "alloc")] { -//! use secp256k1::{Secp256k1, Message, ecdsa, PublicKey}; -//! -//! let secp = Secp256k1::verification_only(); +//! use secp256k1::{ecdsa, Message, PublicKey}; //! //! let public_key = PublicKey::from_slice(&[ //! 0x02, @@ -126,7 +122,7 @@ //! ]).expect("compact signatures are 64 bytes; DER signatures are 68-72 bytes"); //! //! # #[cfg(not(secp256k1_fuzz))] -//! assert!(secp.verify_ecdsa(&sig, message, &public_key).is_ok()); +//! assert!(ecdsa::verify(&sig, message, &public_key).is_ok()); //! # } //! ``` //! @@ -206,7 +202,9 @@ pub use crate::{ Context, PreallocatedContext, SignOnlyPreallocated, Signing, Verification, VerifyOnlyPreallocated, }, - key::{InvalidParityValue, Keypair, Parity, PublicKey, SecretKey, XOnlyPublicKey}, + key::{ + sort_pubkeys, InvalidParityValue, Keypair, Parity, PublicKey, SecretKey, XOnlyPublicKey, + }, scalar::Scalar, }; @@ -447,26 +445,14 @@ impl Secp256k1 { } } -impl Secp256k1 { - /// Generates a random keypair. Convenience function for [`SecretKey::new`] and - /// [`PublicKey::from_secret_key`]. - #[inline] - #[cfg(feature = "rand")] - pub fn generate_keypair( - &self, - rng: &mut R, - ) -> (key::SecretKey, key::PublicKey) { - let sk = key::SecretKey::new(rng); - let pk = key::PublicKey::from_secret_key(self, &sk); - (sk, pk) - } -} - -/// Generates a random keypair using the global [`SECP256K1`] context. +/// Generates a random keypair. Convenience function for [`SecretKey::new`] and +/// [`PublicKey::from_secret_key`]. #[inline] -#[cfg(all(feature = "global-context", feature = "rand"))] +#[cfg(feature = "rand")] pub fn generate_keypair(rng: &mut R) -> (key::SecretKey, key::PublicKey) { - SECP256K1.generate_keypair(rng) + let sk = key::SecretKey::new(rng); + let pk = key::PublicKey::from_secret_key(&sk); + (sk, pk) } /// Constructor for unit testing. (Calls `generate_keypair` if all @@ -480,10 +466,7 @@ fn test_random_keypair() -> (key::SecretKey, key::PublicKey) { generate_keypair( #[cfg(not(all(feature = "global-context", feature = "rand", feature = "std")))] fn test_random_keypair() -> (key::SecretKey, key::PublicKey) { let sk = SecretKey::test_random(); - let pk = with_global_context( - |secp: &Secp256k1| key::PublicKey::from_secret_key(secp, &sk), - Some(&[0xab; 32]), - ); + let pk = key::PublicKey::from_secret_key(&sk); (sk, pk) } @@ -596,12 +579,12 @@ mod tests { let (sk, pk) = crate::test_random_keypair(); let msg = Message::from_digest([2u8; 32]); // Try signing - assert_eq!(sign.sign_ecdsa(msg, &sk), full.sign_ecdsa(msg, &sk)); - let sig = full.sign_ecdsa(msg, &sk); + assert_eq!(ecdsa::sign(msg, &sk), ecdsa::sign(msg, &sk)); + let sig = ecdsa::sign(msg, &sk); // Try verifying - assert!(vrfy.verify_ecdsa(&sig, msg, &pk).is_ok()); - assert!(full.verify_ecdsa(&sig, msg, &pk).is_ok()); + assert!(ecdsa::verify(&sig, msg, &pk).is_ok()); + assert!(ecdsa::verify(&sig, msg, &pk).is_ok()); // The following drop will have no effect; in fact, they will trigger a compiler // error because manually dropping a `ManuallyDrop` is almost certainly incorrect. @@ -647,50 +630,33 @@ mod tests { #[test] #[cfg(all(feature = "rand", feature = "std"))] fn test_preallocation() { - use crate::ffi::types::AlignedType; - - let mut buf_ful = vec![AlignedType::zeroed(); Secp256k1::preallocate_size()]; - let mut buf_sign = vec![AlignedType::zeroed(); Secp256k1::preallocate_signing_size()]; - let mut buf_vfy = vec![AlignedType::zeroed(); Secp256k1::preallocate_verification_size()]; - - let full = Secp256k1::preallocated_new(&mut buf_ful).unwrap(); - let sign = Secp256k1::preallocated_signing_only(&mut buf_sign).unwrap(); - let vrfy = Secp256k1::preallocated_verification_only(&mut buf_vfy).unwrap(); - - // drop(buf_vfy); // The buffer can't get dropped before the context. - // println!("{:?}", buf_ful[5]); // Can't even read the data thanks to the borrow checker. - - let (sk, pk) = full.generate_keypair(&mut rand::rng()); + let (sk, pk) = crate::generate_keypair(&mut rand::rng()); let msg = Message::from_digest([2u8; 32]); // Try signing - assert_eq!(sign.sign_ecdsa(msg, &sk), full.sign_ecdsa(msg, &sk)); - let sig = full.sign_ecdsa(msg, &sk); + assert_eq!(ecdsa::sign(msg, &sk), ecdsa::sign(msg, &sk)); + let sig = ecdsa::sign(msg, &sk); // Try verifying - assert!(vrfy.verify_ecdsa(&sig, msg, &pk).is_ok()); - assert!(full.verify_ecdsa(&sig, msg, &pk).is_ok()); + assert!(ecdsa::verify(&sig, msg, &pk).is_ok()); + assert!(ecdsa::verify(&sig, msg, &pk).is_ok()); } #[test] #[cfg(all(feature = "rand", feature = "std"))] fn capabilities() { - let sign = Secp256k1::signing_only(); - let vrfy = Secp256k1::verification_only(); - let full = Secp256k1::new(); - let msg = crate::random_32_bytes(&mut rand::rng()); let msg = Message::from_digest(msg); // Try key generation - let (sk, pk) = full.generate_keypair(&mut rand::rng()); + let (sk, pk) = crate::generate_keypair(&mut rand::rng()); // Try signing - assert_eq!(sign.sign_ecdsa(msg, &sk), full.sign_ecdsa(msg, &sk)); - let sig = full.sign_ecdsa(msg, &sk); + assert_eq!(ecdsa::sign(msg, &sk), ecdsa::sign(msg, &sk)); + let sig = ecdsa::sign(msg, &sk); // Try verifying - assert!(vrfy.verify_ecdsa(&sig, msg, &pk).is_ok()); - assert!(full.verify_ecdsa(&sig, msg, &pk).is_ok()); + assert!(ecdsa::verify(&sig, msg, &pk).is_ok()); + assert!(ecdsa::verify(&sig, msg, &pk).is_ok()); // Check that we can produce keys from slices with no precomputation let pk_slice = &pk.serialize(); @@ -710,8 +676,8 @@ mod tests { let msg = crate::random_32_bytes(&mut rand::rng()); let msg = Message::from_digest(msg); - let (sk, _) = s.generate_keypair(&mut rand::rng()); - let sig1 = s.sign_ecdsa(msg, &sk); + let (sk, _) = crate::generate_keypair(&mut rand::rng()); + let sig1 = ecdsa::sign(msg, &sk); let der = sig1.serialize_der(); let sig2 = ecdsa::Signature::from_der(&der[..]).unwrap(); assert_eq!(sig1, sig2); @@ -801,15 +767,15 @@ mod tests { let msg = crate::random_32_bytes(&mut rand::rng()); let msg = Message::from_digest(msg); - let (sk, pk) = s.generate_keypair(&mut rand::rng()); - let sig = s.sign_ecdsa(msg, &sk); - assert_eq!(s.verify_ecdsa(&sig, msg, &pk), Ok(())); - let noncedata_sig = s.sign_ecdsa_with_noncedata(msg, &sk, &noncedata); - assert_eq!(s.verify_ecdsa(&noncedata_sig, msg, &pk), Ok(())); - let low_r_sig = s.sign_ecdsa_low_r(msg, &sk); - assert_eq!(s.verify_ecdsa(&low_r_sig, msg, &pk), Ok(())); - let grind_r_sig = s.sign_ecdsa_grind_r(msg, &sk, 1); - assert_eq!(s.verify_ecdsa(&grind_r_sig, msg, &pk), Ok(())); + let (sk, pk) = crate::generate_keypair(&mut rand::rng()); + let sig = ecdsa::sign(msg, &sk); + assert_eq!(ecdsa::verify(&sig, msg, &pk), Ok(())); + let noncedata_sig = ecdsa::sign_with_noncedata(msg, &sk, &noncedata); + assert_eq!(ecdsa::verify(&noncedata_sig, msg, &pk), Ok(())); + let low_r_sig = ecdsa::sign_low_r(msg, &sk); + assert_eq!(ecdsa::verify(&low_r_sig, msg, &pk), Ok(())); + let grind_r_sig = ecdsa::sign_grind_r(msg, &sk, 1); + assert_eq!(ecdsa::verify(&grind_r_sig, msg, &pk), Ok(())); let compact = sig.serialize_compact(); if compact[0] < 0x80 { assert_eq!(sig, low_r_sig); @@ -847,13 +813,13 @@ mod tests { for key in wild_keys.iter().copied().map(SecretKey::from_secret_bytes).map(Result::unwrap) { for msg in wild_msgs.into_iter().map(Message::from_digest) { - let sig = s.sign_ecdsa(msg, &key); - let low_r_sig = s.sign_ecdsa_low_r(msg, &key); - let grind_r_sig = s.sign_ecdsa_grind_r(msg, &key, 1); - let pk = PublicKey::from_secret_key(&s, &key); - assert_eq!(s.verify_ecdsa(&sig, msg, &pk), Ok(())); - assert_eq!(s.verify_ecdsa(&low_r_sig, msg, &pk), Ok(())); - assert_eq!(s.verify_ecdsa(&grind_r_sig, msg, &pk), Ok(())); + let sig = ecdsa::sign(msg, &key); + let low_r_sig = ecdsa::sign_low_r(msg, &key); + let grind_r_sig = ecdsa::sign_grind_r(msg, &key, 1); + let pk = PublicKey::from_secret_key(&key); + assert_eq!(ecdsa::verify(&sig, msg, &pk), Ok(())); + assert_eq!(ecdsa::verify(&low_r_sig, msg, &pk), Ok(())); + assert_eq!(ecdsa::verify(&grind_r_sig, msg, &pk), Ok(())); } } } @@ -867,13 +833,13 @@ mod tests { let msg = crate::random_32_bytes(&mut rand::rng()); let msg = Message::from_digest(msg); - let (sk, pk) = s.generate_keypair(&mut rand::rng()); + let (sk, pk) = crate::generate_keypair(&mut rand::rng()); - let sig = s.sign_ecdsa(msg, &sk); + let sig = ecdsa::sign(msg, &sk); let msg = crate::random_32_bytes(&mut rand::rng()); let msg = Message::from_digest(msg); - assert_eq!(s.verify_ecdsa(&sig, msg, &pk), Err(Error::IncorrectSignature)); + assert_eq!(ecdsa::verify(&sig, msg, &pk), Err(Error::IncorrectSignature)); } #[test] @@ -934,7 +900,6 @@ mod tests { #[cfg(not(secp256k1_fuzz))] // fuzz-sigs have fixed size/format #[cfg(any(feature = "alloc", feature = "std"))] fn test_noncedata() { - let secp = Secp256k1::new(); let msg = hex!("887d04bb1cf1b1554f1b268dfe62d13064ca67ae45348d50d1392ce2d13418ac"); let msg = Message::from_digest(msg); let noncedata = [42u8; 32]; @@ -944,7 +909,7 @@ mod tests { let expected_sig = hex!("24861b3edd4e7da43319c635091405feced6efa4ec99c3c3c35f6c3ba0ed8816116772e84994084db85a6c20589f6a85af569d42275c2a5dd900da5776b99d5d"); let expected_sig = ecdsa::Signature::from_compact(&expected_sig).unwrap(); - let sig = secp.sign_ecdsa_with_noncedata(msg, &sk, &noncedata); + let sig = ecdsa::sign_with_noncedata(msg, &sk, &noncedata); assert_eq!(expected_sig, sig); } @@ -960,23 +925,21 @@ mod tests { let pk = hex!("031ee99d2b786ab3b0991325f2de8489246a6a3fdb700f6d0511b1d80cf5f4cd43"); let msg = hex!("a4965ca63b7d8562736ceec36dfa5a11bf426eb65be8ea3f7a49ae363032da0d"); - let secp = Secp256k1::new(); let mut sig = ecdsa::Signature::from_der(&sig[..]).unwrap(); let pk = PublicKey::from_slice(&pk[..]).unwrap(); let msg = Message::from_digest(msg); // without normalization we expect this will fail - assert_eq!(secp.verify_ecdsa(&sig, msg, &pk), Err(Error::IncorrectSignature)); + assert_eq!(ecdsa::verify(&sig, msg, &pk), Err(Error::IncorrectSignature)); // after normalization it should pass sig.normalize_s(); - assert_eq!(secp.verify_ecdsa(&sig, msg, &pk), Ok(())); + assert_eq!(ecdsa::verify(&sig, msg, &pk), Ok(())); } #[test] #[cfg(not(secp256k1_fuzz))] // fuzz-sigs have fixed size/format #[cfg(any(feature = "alloc", feature = "std"))] fn test_low_r() { - let secp = Secp256k1::new(); let msg = hex!("887d04bb1cf1b1554f1b268dfe62d13064ca67ae45348d50d1392ce2d13418ac"); let msg = Message::from_digest(msg); let sk = @@ -985,7 +948,7 @@ mod tests { let expected_sig = hex!("047dd4d049db02b430d24c41c7925b2725bcd5a85393513bdec04b4dc363632b1054d0180094122b380f4cfa391e6296244da773173e78fc745c1b9c79f7b713"); let expected_sig = ecdsa::Signature::from_compact(&expected_sig).unwrap(); - let sig = secp.sign_ecdsa_low_r(msg, &sk); + let sig = ecdsa::sign_low_r(msg, &sk); assert_eq!(expected_sig, sig); } @@ -994,7 +957,6 @@ mod tests { #[cfg(not(secp256k1_fuzz))] // fuzz-sigs have fixed size/format #[cfg(any(feature = "alloc", feature = "std"))] fn test_grind_r() { - let secp = Secp256k1::new(); let msg = hex!("ef2d5b9a7c61865a95941d0f04285420560df7e9d76890ac1b8867b12ce43167"); let msg = Message::from_digest(msg); let sk = @@ -1002,7 +964,7 @@ mod tests { .unwrap(); let expected_sig = ecdsa::Signature::from_str("304302202ffc447100d518c8ba643d11f3e6a83a8640488e7d2537b1954b942408be6ea3021f26e1248dd1e52160c3a38af9769d91a1a806cab5f9d508c103464d3c02d6e1").unwrap(); - let sig = secp.sign_ecdsa_grind_r(msg, &sk, 2); + let sig = ecdsa::sign_grind_r(msg, &sk, 2); assert_eq!(expected_sig, sig); } @@ -1014,11 +976,9 @@ mod tests { fn test_serde() { use serde_test::{assert_tokens, Configure, Token}; - let s = Secp256k1::new(); - let msg = Message::from_digest([1; 32]); let sk = SecretKey::from_secret_bytes([2; 32]).unwrap(); - let sig = s.sign_ecdsa(msg, &sk); + let sig = ecdsa::sign(msg, &sk); static SIG_BYTES: [u8; 71] = [ 48, 69, 2, 33, 0, 157, 11, 173, 87, 103, 25, 211, 42, 231, 107, 237, 179, 76, 119, 72, 102, 103, 60, 189, 227, 244, 225, 41, 81, 85, 92, 148, 8, 230, 206, 119, 75, 2, 32, 40, @@ -1042,18 +1002,17 @@ mod tests { #[cfg(feature = "global-context")] #[test] fn test_global_context() { - use crate::SECP256K1; let sk_data = hex!("e6dd32f8761625f105c39a39f19370b3521d845a12456d60ce44debd0a362641"); let sk = SecretKey::from_secret_bytes(sk_data).unwrap(); let msg_data = hex!("a4965ca63b7d8562736ceec36dfa5a11bf426eb65be8ea3f7a49ae363032da0d"); let msg = Message::from_digest(msg_data); // Check usage as explicit parameter - let pk = PublicKey::from_secret_key(SECP256K1, &sk); + let pk = PublicKey::from_secret_key(&sk); // Check usage as self - let sig = SECP256K1.sign_ecdsa(msg, &sk); - assert!(SECP256K1.verify_ecdsa(&sig, msg, &pk).is_ok()); + let sig = ecdsa::sign(msg, &sk); + assert!(ecdsa::verify(&sig, msg, &pk).is_ok()); } } @@ -1063,7 +1022,7 @@ mod benches { use rand::rngs::mock::StepRng; use test::{black_box, Bencher}; - use super::{Message, Secp256k1}; + use super::*; #[bench] pub fn generate(bh: &mut Bencher) { @@ -1098,7 +1057,7 @@ mod benches { let sig = s.sign_ecdsa(msg, &sk); bh.iter(|| { - let res = s.verify_ecdsa(&sig, msg, &pk).unwrap(); + let res = ecdsa::verify(&sig, msg, &pk).unwrap(); black_box(res); }); } diff --git a/src/musig.rs b/src/musig.rs index 95369c177..f1a08fa8f 100644 --- a/src/musig.rs +++ b/src/musig.rs @@ -12,9 +12,10 @@ use core::mem::MaybeUninit; use std; use crate::ffi::{self, CPtr}; +#[cfg(doc)] +use crate::key; use crate::{ - from_hex, schnorr, Error, Keypair, PublicKey, Scalar, Secp256k1, SecretKey, Signing, - Verification, XOnlyPublicKey, + from_hex, schnorr, Error, Keypair, PublicKey, Scalar, Secp256k1, SecretKey, XOnlyPublicKey, }; /// Serialized size (in bytes) of the aggregated nonce. @@ -147,7 +148,6 @@ impl fmt::Display for InvalidTweakErr { /// /// # Arguments: /// -/// * `secp` : [`Secp256k1`] context object initialized for signing /// * `session_secrand`: [`SessionSecretRand`] Uniform random identifier for this session. Each call to this /// function must have a UNIQUE `session_secrand`. /// * `sec_key`: Optional [`SecretKey`] that we will use to sign to a create partial signature. Provide this @@ -164,22 +164,20 @@ impl fmt::Display for InvalidTweakErr { /// ```rust /// # #[cfg(feature = "std")] /// # #[cfg(feature = "rand")] { -/// # use secp256k1::{PublicKey, Secp256k1, SecretKey}; +/// # use secp256k1::{PublicKey, SecretKey}; /// # use secp256k1::musig::{new_nonce_pair, SessionSecretRand}; -/// # let secp = Secp256k1::new(); /// // The session id must be sampled at random. Read documentation for more details. /// let session_secrand = SessionSecretRand::from_rng(&mut rand::rng()); /// let sk = SecretKey::new(&mut rand::rng()); -/// let pk = PublicKey::from_secret_key(&secp, &sk); +/// let pk = PublicKey::from_secret_key(&sk); /// /// // Supply extra auxiliary randomness to prevent misuse(for example, time of day) /// let extra_rand : Option<[u8; 32]> = None; /// -/// let (_sec_nonce, _pub_nonce) = new_nonce_pair(&secp, session_secrand, None, Some(sk), pk, None, None); +/// let (_sec_nonce, _pub_nonce) = new_nonce_pair(session_secrand, None, Some(sk), pk, None, None); /// # } /// ``` -pub fn new_nonce_pair( - secp: &Secp256k1, +pub fn new_nonce_pair( mut session_secrand: SessionSecretRand, key_agg_cache: Option<&KeyAggCache>, sec_key: Option, @@ -187,11 +185,23 @@ pub fn new_nonce_pair( msg: Option<&[u8; 32]>, extra_rand: Option<[u8; 32]>, ) -> (SecretNonce, PublicNonce) { - let cx = secp.ctx().as_ptr(); let extra_ptr = extra_rand.as_ref().map(|e| e.as_ptr()).unwrap_or(core::ptr::null()); let sk_ptr = sec_key.as_ref().map(|e| e.as_c_ptr()).unwrap_or(core::ptr::null()); let msg_ptr = msg.as_ref().map(|e| e.as_c_ptr()).unwrap_or(core::ptr::null()); let cache_ptr = key_agg_cache.map(|e| e.as_ptr()).unwrap_or(core::ptr::null()); + + let mut seed = session_secrand.to_byte_array(); + if let Some(bytes) = sec_key { + for (this, that) in seed.iter_mut().zip(bytes.to_secret_bytes().iter()) { + *this ^= *that; + } + } + if let Some(bytes) = extra_rand { + for (this, that) in seed.iter_mut().zip(bytes.iter()) { + *this ^= *that; + } + } + unsafe { // The use of a mutable pointer to `session_secrand`, which is a local variable, // may seem concerning/wrong. It is ok: this pointer is only mutable because the @@ -201,18 +211,25 @@ pub fn new_nonce_pair( // caller or anything. let mut sec_nonce = MaybeUninit::::uninit(); let mut pub_nonce = MaybeUninit::::uninit(); - if ffi::secp256k1_musig_nonce_gen( - cx, - sec_nonce.as_mut_ptr(), - pub_nonce.as_mut_ptr(), - session_secrand.as_mut_ptr(), - sk_ptr, - pub_key.as_c_ptr(), - msg_ptr, - cache_ptr, - extra_ptr, - ) == 0 - { + + let ret = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_musig_nonce_gen( + secp.ctx.as_ptr(), + sec_nonce.as_mut_ptr(), + pub_nonce.as_mut_ptr(), + session_secrand.as_mut_ptr(), + sk_ptr, + pub_key.as_c_ptr(), + msg_ptr, + cache_ptr, + extra_ptr, + ) + }, + Some(&seed), + ); + + if ret == 0 { // Rust type system guarantees that // - input secret key is valid // - msg is 32 bytes @@ -354,7 +371,7 @@ impl KeyAggCache { /// ensures the same resulting `agg_pk` for the same multiset of pubkeys. /// This is useful to do before aggregating pubkeys, such that the order of pubkeys /// does not affect the combined public key. - /// To do this, call [`Secp256k1::sort_pubkeys`]. + /// To do this, call [`key::sort_pubkeys`]. /// /// # Returns /// @@ -371,15 +388,14 @@ impl KeyAggCache { /// ```rust /// # #[cfg(feature = "std")] /// # #[cfg(feature = "rand")] { - /// # use secp256k1::{Secp256k1, SecretKey, Keypair, PublicKey}; + /// # use secp256k1::{SecretKey, Keypair, PublicKey}; /// # use secp256k1::musig::KeyAggCache; - /// # let secp = Secp256k1::new(); /// # let sk1 = SecretKey::new(&mut rand::rng()); - /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); + /// # let pub_key1 = PublicKey::from_secret_key(&sk1); /// # let sk2 = SecretKey::new(&mut rand::rng()); - /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); + /// # let pub_key2 = PublicKey::from_secret_key(&sk2); /// # - /// let key_agg_cache = KeyAggCache::new(&secp, &[&pub_key1, &pub_key2]); + /// let key_agg_cache = KeyAggCache::new(&[&pub_key1, &pub_key2]); /// let _agg_pk = key_agg_cache.agg_pk(); /// # } /// ``` @@ -387,30 +403,36 @@ impl KeyAggCache { /// # Panics /// /// Panics if an empty slice of pubkeys is provided. - pub fn new(secp: &Secp256k1, pubkeys: &[&PublicKey]) -> Self { + pub fn new(pubkeys: &[&PublicKey]) -> Self { if pubkeys.is_empty() { panic!("Cannot aggregate an empty slice of pubkeys"); } - let cx = secp.ctx().as_ptr(); - let mut key_agg_cache = MaybeUninit::::uninit(); let mut agg_pk = MaybeUninit::::uninit(); + // We have no seed here but we want rerandomiziation to happen for `rand` users. + let seed = [0_u8; 32]; + unsafe { let pubkeys_ref = core::slice::from_raw_parts( pubkeys.as_c_ptr() as *const *const ffi::PublicKey, pubkeys.len(), ); - if ffi::secp256k1_musig_pubkey_agg( - cx, - agg_pk.as_mut_ptr(), - key_agg_cache.as_mut_ptr(), - pubkeys_ref.as_ptr(), - pubkeys_ref.len(), - ) == 0 - { + let ret = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_musig_pubkey_agg( + secp.ctx.as_ptr(), + agg_pk.as_mut_ptr(), + key_agg_cache.as_mut_ptr(), + pubkeys_ref.as_ptr(), + pubkeys_ref.len(), + ) + }, + Some(&seed), + ); + if ret == 0 { // Returns 0 only if the keys are malformed that never happens in safe rust type system. unreachable!("Invalid XOnlyPublicKey in input pubkeys") } else { @@ -470,36 +492,38 @@ impl KeyAggCache { /// # #[cfg(not(secp256k1_fuzz))] /// # #[cfg(feature = "std")] /// # #[cfg(feature = "rand")] { - /// # use secp256k1::{Scalar, Secp256k1, SecretKey, Keypair, PublicKey}; + /// # use secp256k1::{Scalar, SecretKey, Keypair, PublicKey}; /// # use secp256k1::musig::KeyAggCache; - /// # let secp = Secp256k1::new(); /// # let sk1 = SecretKey::new(&mut rand::rng()); - /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); + /// # let pub_key1 = PublicKey::from_secret_key(&sk1); /// # let sk2 = SecretKey::new(&mut rand::rng()); - /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); + /// # let pub_key2 = PublicKey::from_secret_key(&sk2); /// # - /// let mut key_agg_cache = KeyAggCache::new(&secp, &[&pub_key1, &pub_key2]); + /// let mut key_agg_cache = KeyAggCache::new(&[&pub_key1, &pub_key2]); /// /// let tweak: [u8; 32] = *b"this could be a BIP32 tweak....\0"; /// let tweak = Scalar::from_be_bytes(tweak).unwrap(); - /// let tweaked_key = key_agg_cache.pubkey_ec_tweak_add(&secp, &tweak).unwrap(); + /// let tweaked_key = key_agg_cache.pubkey_ec_tweak_add(&tweak).unwrap(); /// # } /// ``` - pub fn pubkey_ec_tweak_add( - &mut self, - secp: &Secp256k1, - tweak: &Scalar, - ) -> Result { - let cx = secp.ctx().as_ptr(); + pub fn pubkey_ec_tweak_add(&mut self, tweak: &Scalar) -> Result { + // We have no seed here but we want rerandomiziation to happen for `rand` users. + let seed = [0_u8; 32]; unsafe { let mut out = PublicKey::from(ffi::PublicKey::new()); - if ffi::secp256k1_musig_pubkey_ec_tweak_add( - cx, - out.as_mut_c_ptr(), - self.as_mut_ptr(), - tweak.as_c_ptr(), - ) == 0 - { + + let ret = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_musig_pubkey_ec_tweak_add( + secp.ctx.as_ptr(), + out.as_mut_c_ptr(), + self.as_mut_ptr(), + tweak.as_c_ptr(), + ) + }, + Some(&seed), + ); + if ret == 0 { Err(InvalidTweakErr) } else { self.aggregated_xonly_public_key = out.x_only_public_key().0; @@ -531,35 +555,37 @@ impl KeyAggCache { /// # #[cfg(not(secp256k1_fuzz))] /// # #[cfg(feature = "std")] /// # #[cfg(feature = "rand")] { - /// # use secp256k1::{Scalar, Secp256k1, SecretKey, Keypair, PublicKey}; + /// # use secp256k1::{Scalar, SecretKey, Keypair, PublicKey}; /// # use secp256k1::musig::KeyAggCache; - /// # let secp = Secp256k1::new(); /// # let sk1 = SecretKey::new(&mut rand::rng()); - /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); + /// # let pub_key1 = PublicKey::from_secret_key(&sk1); /// # let sk2 = SecretKey::new(&mut rand::rng()); - /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); + /// # let pub_key2 = PublicKey::from_secret_key(&sk2); /// - /// let mut key_agg_cache = KeyAggCache::new(&secp, &[&pub_key1, &pub_key2]); + /// let mut key_agg_cache = KeyAggCache::new(&[&pub_key1, &pub_key2]); /// /// let tweak = Scalar::from_be_bytes(*b"Insecure tweak, Don't use this!!").unwrap(); // tweak could be from tap - /// let _x_only_key_tweaked = key_agg_cache.pubkey_xonly_tweak_add(&secp, &tweak).unwrap(); + /// let _x_only_key_tweaked = key_agg_cache.pubkey_xonly_tweak_add(&tweak).unwrap(); /// # } /// ``` - pub fn pubkey_xonly_tweak_add( - &mut self, - secp: &Secp256k1, - tweak: &Scalar, - ) -> Result { - let cx = secp.ctx().as_ptr(); + pub fn pubkey_xonly_tweak_add(&mut self, tweak: &Scalar) -> Result { + // We have no seed here but we want rerandomiziation to happen for `rand` users. + let seed = [0_u8; 32]; unsafe { let mut out = PublicKey::from(ffi::PublicKey::new()); - if ffi::secp256k1_musig_pubkey_xonly_tweak_add( - cx, - out.as_mut_c_ptr(), - self.as_mut_ptr(), - tweak.as_c_ptr(), - ) == 0 - { + + let ret = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_musig_pubkey_xonly_tweak_add( + secp.ctx.as_ptr(), + out.as_mut_c_ptr(), + self.as_mut_ptr(), + tweak.as_c_ptr(), + ) + }, + Some(&seed), + ); + if ret == 0 { Err(InvalidTweakErr) } else { self.aggregated_xonly_public_key = out.x_only_public_key().0; @@ -604,27 +630,25 @@ impl KeyAggCache { /// ```rust /// # #[cfg(feature = "std")] /// # #[cfg(feature = "rand")] { - /// # use secp256k1::{Secp256k1, SecretKey, Keypair, PublicKey}; + /// # use secp256k1::{SecretKey, Keypair, PublicKey}; /// # use secp256k1::musig::{KeyAggCache, SessionSecretRand}; - /// # let secp = Secp256k1::new(); /// # let sk1 = SecretKey::new(&mut rand::rng()); - /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); + /// # let pub_key1 = PublicKey::from_secret_key(&sk1); /// # let sk2 = SecretKey::new(&mut rand::rng()); - /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); + /// # let pub_key2 = PublicKey::from_secret_key(&sk2); /// # - /// let key_agg_cache = KeyAggCache::new(&secp, &[&pub_key1, &pub_key2]); + /// let key_agg_cache = KeyAggCache::new(&[&pub_key1, &pub_key2]); /// // The session id must be sampled at random. Read documentation for more details. /// let session_secrand = SessionSecretRand::from_rng(&mut rand::rng()); /// /// // Provide the current time for mis-use resistance /// let msg = b"Public message we want to sign!!"; /// let extra_rand : Option<[u8; 32]> = None; - /// let (_sec_nonce, _pub_nonce) = key_agg_cache.nonce_gen(&secp, session_secrand, pub_key1, msg, extra_rand); + /// let (_sec_nonce, _pub_nonce) = key_agg_cache.nonce_gen(session_secrand, pub_key1, msg, extra_rand); /// # } /// ``` - pub fn nonce_gen( + pub fn nonce_gen( &self, - secp: &Secp256k1, session_secrand: SessionSecretRand, pub_key: PublicKey, msg: &[u8; 32], @@ -633,7 +657,7 @@ impl KeyAggCache { // The secret key here is supplied as NULL. This is okay because we supply the // public key and the message. // This makes a simple API for the user because it does not require them to pass here. - new_nonce_pair(secp, session_secrand, Some(self), None, pub_key, Some(msg), extra_rand) + new_nonce_pair(session_secrand, Some(self), None, pub_key, Some(msg), extra_rand) } /// Get a const pointer to the inner KeyAggCache @@ -899,53 +923,60 @@ impl AggregatedNonce { /// ```rust /// # #[cfg(feature = "std")] /// # #[cfg(feature = "rand")] { - /// # use secp256k1::{Secp256k1, SecretKey, Keypair, PublicKey}; + /// # use secp256k1::{SecretKey, Keypair, PublicKey}; /// # use secp256k1::musig::{AggregatedNonce, KeyAggCache, SessionSecretRand}; - /// # let secp = Secp256k1::new(); /// # let sk1 = SecretKey::new(&mut rand::rng()); - /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); + /// # let pub_key1 = PublicKey::from_secret_key(&sk1); /// # let sk2 = SecretKey::new(&mut rand::rng()); - /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); + /// # let pub_key2 = PublicKey::from_secret_key(&sk2); /// - /// # let key_agg_cache = KeyAggCache::new(&secp, &[&pub_key1, &pub_key2]); + /// # let key_agg_cache = KeyAggCache::new(&[&pub_key1, &pub_key2]); /// // The session id must be sampled at random. Read documentation for more details. /// /// let msg = b"Public message we want to sign!!"; /// /// let session_secrand1 = SessionSecretRand::from_rng(&mut rand::rng()); - /// let (_sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(&secp, session_secrand1, pub_key1, msg, None); + /// let (_sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(session_secrand1, pub_key1, msg, None); /// /// // Signer two does the same: Possibly on a different device /// let session_secrand2 = SessionSecretRand::from_rng(&mut rand::rng()); - /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_secrand2, pub_key2, msg, None); + /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(session_secrand2, pub_key2, msg, None); /// - /// let aggnonce = AggregatedNonce::new(&secp, &[&pub_nonce1, &pub_nonce2]); + /// let aggnonce = AggregatedNonce::new(&[&pub_nonce1, &pub_nonce2]); /// # } /// ``` /// # Panics /// /// Panics if an empty slice of nonces is provided. /// - pub fn new(secp: &Secp256k1, nonces: &[&PublicNonce]) -> Self { + pub fn new(nonces: &[&PublicNonce]) -> Self { if nonces.is_empty() { panic!("Cannot aggregate an empty slice of nonces"); } let mut aggnonce = MaybeUninit::::uninit(); + // We have no seed here but we want rerandomiziation to happen for `rand` users. + let seed = [0_u8; 32]; + unsafe { let pubnonces = core::slice::from_raw_parts( nonces.as_c_ptr() as *const *const ffi::MusigPubNonce, nonces.len(), ); - if ffi::secp256k1_musig_nonce_agg( - secp.ctx().as_ptr(), - aggnonce.as_mut_ptr(), - pubnonces.as_ptr(), - pubnonces.len(), - ) == 0 - { + let ret = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_musig_nonce_agg( + secp.ctx().as_ptr(), + aggnonce.as_mut_ptr(), + pubnonces.as_ptr(), + pubnonces.len(), + ) + }, + Some(&seed), + ); + if ret == 0 { // This can only crash if the individual nonces are invalid which is not possible is rust. // Note that even if aggregate nonce is point at infinity, the musig spec sets it as `G` unreachable!("Public key nonces are well-formed and valid in rust typesystem") @@ -1021,14 +1052,13 @@ impl AggregatedSignature { /// Verify the aggregated signature against the aggregate public key and message /// before returning the signature. - pub fn verify( + pub fn verify( self, - secp: &Secp256k1, aggregate_key: &XOnlyPublicKey, message: &[u8], ) -> Result { let sig = schnorr::Signature::from_byte_array(self.0); - secp.verify_schnorr(&sig, message, aggregate_key) + schnorr::verify(&sig, message, aggregate_key) .map(|_| sig) .map_err(|_| Error::IncorrectSignature) } @@ -1060,15 +1090,14 @@ impl Session { /// ```rust /// # #[cfg(feature = "std")] /// # #[cfg(feature = "rand")] { - /// # use secp256k1::{Secp256k1, SecretKey, Keypair, PublicKey}; + /// # use secp256k1::{SecretKey, Keypair, PublicKey}; /// # use secp256k1::musig::{AggregatedNonce, KeyAggCache, Session, SessionSecretRand}; - /// # let secp = Secp256k1::new(); /// # let sk1 = SecretKey::new(&mut rand::rng()); - /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); + /// # let pub_key1 = PublicKey::from_secret_key(&sk1); /// # let sk2 = SecretKey::new(&mut rand::rng()); - /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); + /// # let pub_key2 = PublicKey::from_secret_key(&sk2); /// - /// # let key_agg_cache = KeyAggCache::new(&secp, &[&pub_key1, &pub_key2]); + /// # let key_agg_cache = KeyAggCache::new(&[&pub_key1, &pub_key2]); /// // The session id must be sampled at random. Read documentation for more details. /// /// let msg = b"Public message we want to sign!!"; @@ -1076,40 +1105,42 @@ impl Session { /// // Provide the current time for mis-use resistance /// let session_secrand1 = SessionSecretRand::from_rng(&mut rand::rng()); /// let extra_rand1 : Option<[u8; 32]> = None; - /// let (_sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(&secp, session_secrand1, pub_key1, msg, extra_rand1); + /// let (_sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(session_secrand1, pub_key1, msg, extra_rand1); /// /// // Signer two does the same. Possibly on a different device /// let session_secrand2 = SessionSecretRand::from_rng(&mut rand::rng()); /// let extra_rand2 : Option<[u8; 32]> = None; - /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_secrand2, pub_key2, msg, extra_rand2); + /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(session_secrand2, pub_key2, msg, extra_rand2); /// - /// let aggnonce = AggregatedNonce::new(&secp, &[&pub_nonce1, &pub_nonce2]); + /// let aggnonce = AggregatedNonce::new(&[&pub_nonce1, &pub_nonce2]); /// /// let session = Session::new( - /// &secp, /// &key_agg_cache, /// aggnonce, /// msg, /// ); /// # } /// ``` - pub fn new( - secp: &Secp256k1, - key_agg_cache: &KeyAggCache, - agg_nonce: AggregatedNonce, - msg: &[u8; 32], - ) -> Self { + pub fn new(key_agg_cache: &KeyAggCache, agg_nonce: AggregatedNonce, msg: &[u8; 32]) -> Self { let mut session = MaybeUninit::::uninit(); + // We have no seed here but we want rerandomiziation to happen for `rand` users. + let seed = [0_u8; 32]; + unsafe { - if ffi::secp256k1_musig_nonce_process( - secp.ctx().as_ptr(), - session.as_mut_ptr(), - agg_nonce.as_ptr(), - msg.as_c_ptr(), - key_agg_cache.as_ptr(), - ) == 0 - { + let ret = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_musig_nonce_process( + secp.ctx().as_ptr(), + session.as_mut_ptr(), + agg_nonce.as_ptr(), + msg.as_c_ptr(), + key_agg_cache.as_ptr(), + ) + }, + Some(&seed), + ); + if ret == 0 { // Only fails on cryptographically unreachable codes or if the args are invalid. // None of which can occur in safe rust. unreachable!("Impossible to construct invalid arguments in safe rust. @@ -1142,23 +1173,29 @@ impl Session { /// /// - If the provided [`SecretNonce`] has already been used for signing /// - pub fn partial_sign( + pub fn partial_sign( &self, - secp: &Secp256k1, mut secnonce: SecretNonce, keypair: &Keypair, key_agg_cache: &KeyAggCache, ) -> PartialSignature { + // We have no seed here but we want rerandomiziation to happen for `rand` users. + let seed = [0_u8; 32]; unsafe { let mut partial_sig = MaybeUninit::::uninit(); - let res = ffi::secp256k1_musig_partial_sign( - secp.ctx().as_ptr(), - partial_sig.as_mut_ptr(), - secnonce.as_mut_ptr(), - keypair.as_c_ptr(), - key_agg_cache.as_ptr(), - self.as_ptr(), + let res = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_musig_partial_sign( + secp.ctx().as_ptr(), + partial_sig.as_mut_ptr(), + secnonce.as_mut_ptr(), + keypair.as_c_ptr(), + key_agg_cache.as_ptr(), + self.as_ptr(), + ) + }, + Some(&seed), ); assert_eq!(res, 1); @@ -1196,46 +1233,42 @@ impl Session { /// # #[cfg(not(secp256k1_fuzz))] /// # #[cfg(feature = "std")] /// # #[cfg(feature = "rand")] { - /// # use secp256k1::{Secp256k1, SecretKey, Keypair, PublicKey}; + /// # use secp256k1::{SecretKey, Keypair, PublicKey}; /// # use secp256k1::musig::{AggregatedNonce, KeyAggCache, SessionSecretRand, Session}; - /// # let secp = Secp256k1::new(); /// # let sk1 = SecretKey::new(&mut rand::rng()); - /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); + /// # let pub_key1 = PublicKey::from_secret_key(&sk1); /// # let sk2 = SecretKey::new(&mut rand::rng()); - /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); + /// # let pub_key2 = PublicKey::from_secret_key(&sk2); /// - /// # let key_agg_cache = KeyAggCache::new(&secp, &[&pub_key1, &pub_key2]); + /// # let key_agg_cache = KeyAggCache::new(&[&pub_key1, &pub_key2]); /// // The session id must be sampled at random. Read documentation for more details. /// /// let msg = b"Public message we want to sign!!"; /// /// // Provide the current time for mis-use resistance /// let session_secrand1 = SessionSecretRand::from_rng(&mut rand::rng()); - /// let (mut sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(&secp, session_secrand1, pub_key1, msg, None); + /// let (mut sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(session_secrand1, pub_key1, msg, None); /// /// // Signer two does the same. Possibly on a different device /// let session_secrand2 = SessionSecretRand::from_rng(&mut rand::rng()); - /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_secrand2, pub_key2, msg, None); + /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(session_secrand2, pub_key2, msg, None); /// - /// let aggnonce = AggregatedNonce::new(&secp, &[&pub_nonce1, &pub_nonce2]); + /// let aggnonce = AggregatedNonce::new(&[&pub_nonce1, &pub_nonce2]); /// /// let session = Session::new( - /// &secp, /// &key_agg_cache, /// aggnonce, /// msg, /// ); /// - /// let keypair = Keypair::from_secret_key(&secp, &sk1); + /// let keypair = Keypair::from_secret_key(&sk1); /// let partial_sig1 = session.partial_sign( - /// &secp, /// sec_nonce1, /// &keypair, /// &key_agg_cache, /// ); /// /// assert!(session.partial_verify( - /// &secp, /// &key_agg_cache, /// &partial_sig1, /// &pub_nonce1, @@ -1243,24 +1276,30 @@ impl Session { /// )); /// # } /// ``` - pub fn partial_verify( + pub fn partial_verify( &self, - secp: &Secp256k1, key_agg_cache: &KeyAggCache, partial_sig: &PartialSignature, pub_nonce: &PublicNonce, pub_key: PublicKey, ) -> bool { - let cx = secp.ctx().as_ptr(); + // We have no seed here but we want rerandomiziation to happen for `rand` users. + let seed = [0_u8; 32]; unsafe { - ffi::secp256k1_musig_partial_sig_verify( - cx, - partial_sig.as_ptr(), - pub_nonce.as_ptr(), - pub_key.as_c_ptr(), - key_agg_cache.as_ptr(), - self.as_ptr(), - ) == 1 + let ret = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_musig_partial_sig_verify( + secp.ctx.as_ptr(), + partial_sig.as_ptr(), + pub_nonce.as_ptr(), + pub_key.as_c_ptr(), + key_agg_cache.as_ptr(), + self.as_ptr(), + ) + }, + Some(&seed), + ); + ret == 1 } } @@ -1277,49 +1316,45 @@ impl Session { /// /// ```rust /// # #[cfg(feature = "rand-std")] { - /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, SessionSecretRand, AggregatedNonce, Session}; - /// # let secp = Secp256k1::new(); + /// # use secp256k1::{KeyAggCache, SecretKey, Keypair, PublicKey, SessionSecretRand, AggregatedNonce, Session}; /// # let sk1 = SecretKey::new(&mut rand::rng()); - /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); + /// # let pub_key1 = PublicKey::from_secret_key(&sk1); /// # let sk2 = SecretKey::new(&mut rand::rng()); - /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); + /// # let pub_key2 = PublicKey::from_secret_key(&sk2); /// - /// let key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); + /// let key_agg_cache = KeyAggCache::new(&[pub_key1, pub_key2]); /// // The session id must be sampled at random. Read documentation for more details. /// /// let msg = b"Public message we want to sign!!"; /// /// // Provide the current time for mis-use resistance /// let session_secrand1 = SessionSecretRand::from_rng(&mut rand::rng()); - /// let (mut sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(&secp, session_secrand1, pub_key1, msg, None) + /// let (mut sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(session_secrand1, pub_key1, msg, None) /// .expect("non zero session id"); /// /// // Signer two does the same. Possibly on a different device /// let session_secrand2 = SessionSecretRand::from_rng(&mut rand::rng()); - /// let (mut sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_secrand2, pub_key2, msg, None) + /// let (mut sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(session_secrand2, pub_key2, msg, None) /// .expect("non zero session id"); /// - /// let aggnonce = AggregatedNonce::new(&secp, &[pub_nonce1, pub_nonce2]); + /// let aggnonce = AggregatedNonce::new(&[pub_nonce1, pub_nonce2]); /// /// let session = Session::new( - /// &secp, /// &key_agg_cache, /// aggnonce, /// msg, /// ); /// /// let partial_sig1 = session.partial_sign( - /// &secp, /// sec_nonce1, - /// &Keypair::from_secret_key(&secp, &sk1), + /// &Keypair::from_secret_key(&sk1), /// &key_agg_cache, /// ).unwrap(); /// /// // Other party creates the other partial signature /// let partial_sig2 = session.partial_sign( - /// &secp, /// sec_nonce2, - /// &Keypair::from_secret_key(&secp, &sk2), + /// &Keypair::from_secret_key(&sk2), /// &key_agg_cache, /// ).unwrap(); /// @@ -1330,7 +1365,7 @@ impl Session { /// let aggregated_signature = session.partial_sig_agg(partial_sigs_ref); /// /// // Get the final schnorr signature - /// assert!(aggregated_signature.verify(&secp, &agg_pk, &msg_bytes).is_ok()); + /// assert!(aggregated_signature.verify(&agg_pk, &msg_bytes).is_ok()); /// # } /// ``` /// @@ -1378,7 +1413,7 @@ mod tests { use super::*; #[cfg(feature = "std")] #[cfg(feature = "rand")] - use crate::{PublicKey, Secp256k1}; + use crate::PublicKey; #[test] #[cfg(feature = "std")] @@ -1410,13 +1445,11 @@ mod tests { #[cfg(not(secp256k1_fuzz))] #[cfg(feature = "std")] fn key_agg_cache() { - let secp = Secp256k1::new(); - let (_seckey1, pubkey1) = crate::test_random_keypair(); let (_seckey2, pubkey2) = crate::test_random_keypair(); let pubkeys = [&pubkey1, &pubkey2]; - let key_agg_cache = KeyAggCache::new(&secp, &pubkeys); + let key_agg_cache = KeyAggCache::new(&pubkeys); let agg_pk = key_agg_cache.agg_pk(); // Test agg_pk_full @@ -1428,15 +1461,13 @@ mod tests { #[cfg(not(secp256k1_fuzz))] #[cfg(feature = "std")] fn key_agg_cache_tweaking() { - let secp = Secp256k1::new(); - let (_seckey1, pubkey1) = crate::test_random_keypair(); let (_seckey2, pubkey2) = crate::test_random_keypair(); - let mut key_agg_cache = KeyAggCache::new(&secp, &[&pubkey1, &pubkey2]); - let key_agg_cache1 = KeyAggCache::new(&secp, &[&pubkey2, &pubkey1]); - let key_agg_cache2 = KeyAggCache::new(&secp, &[&pubkey1, &pubkey1]); - let key_agg_cache3 = KeyAggCache::new(&secp, &[&pubkey1, &pubkey1, &pubkey2]); + let mut key_agg_cache = KeyAggCache::new(&[&pubkey1, &pubkey2]); + let key_agg_cache1 = KeyAggCache::new(&[&pubkey2, &pubkey1]); + let key_agg_cache2 = KeyAggCache::new(&[&pubkey1, &pubkey1]); + let key_agg_cache3 = KeyAggCache::new(&[&pubkey1, &pubkey1, &pubkey2]); assert_ne!(key_agg_cache, key_agg_cache1); // swapped keys DOES mean not equal assert_ne!(key_agg_cache, key_agg_cache2); // missing keys assert_ne!(key_agg_cache, key_agg_cache3); // repeated key @@ -1448,49 +1479,44 @@ mod tests { // Test EC tweaking let plain_tweak: [u8; 32] = *b"this could be a BIP32 tweak....\0"; let plain_tweak = Scalar::from_be_bytes(plain_tweak).unwrap(); - let tweaked_key = key_agg_cache.pubkey_ec_tweak_add(&secp, &plain_tweak).unwrap(); + let tweaked_key = key_agg_cache.pubkey_ec_tweak_add(&plain_tweak).unwrap(); assert_ne!(key_agg_cache.agg_pk(), original_agg_pk); assert_eq!(key_agg_cache.agg_pk(), tweaked_key.x_only_public_key().0); // Test xonly tweaking let xonly_tweak: [u8; 32] = *b"this could be a Taproot tweak..\0"; let xonly_tweak = Scalar::from_be_bytes(xonly_tweak).unwrap(); - let tweaked_agg_pk = key_agg_cache.pubkey_xonly_tweak_add(&secp, &xonly_tweak).unwrap(); + let tweaked_agg_pk = key_agg_cache.pubkey_xonly_tweak_add(&xonly_tweak).unwrap(); assert_eq!(key_agg_cache.agg_pk(), tweaked_agg_pk.x_only_public_key().0); } #[test] #[cfg(feature = "std")] #[should_panic(expected = "Cannot aggregate an empty slice of pubkeys")] - fn key_agg_cache_empty_panic() { - let secp = Secp256k1::new(); - let _ = KeyAggCache::new(&secp, &[]); - } + fn key_agg_cache_empty_panic() { let _ = KeyAggCache::new(&[]); } #[test] #[cfg(feature = "std")] #[cfg(feature = "rand")] fn nonce_generation() { - let secp = Secp256k1::new(); let mut rng = rand::rng(); let (_seckey1, pubkey1) = crate::test_random_keypair(); let (seckey2, pubkey2) = crate::test_random_keypair(); - let key_agg_cache = KeyAggCache::new(&secp, &[&pubkey1, &pubkey2]); + let key_agg_cache = KeyAggCache::new(&[&pubkey1, &pubkey2]); let msg: &[u8; 32] = b"This message is exactly 32 bytes"; // Test nonce generation with KeyAggCache let session_secrand1 = SessionSecretRand::from_rng(&mut rng); let (_sec_nonce1, pub_nonce1) = - key_agg_cache.nonce_gen(&secp, session_secrand1, pubkey1, msg, None); + key_agg_cache.nonce_gen(session_secrand1, pubkey1, msg, None); // Test direct nonce generation let session_secrand2 = SessionSecretRand::from_rng(&mut rng); let extra_rand = Some([42u8; 32]); let (_sec_nonce2, _pub_nonce2) = new_nonce_pair( - &secp, session_secrand2, Some(&key_agg_cache), Some(seckey2), @@ -1509,27 +1535,26 @@ mod tests { #[cfg(feature = "std")] #[cfg(feature = "rand")] fn aggregated_nonce() { - let secp = Secp256k1::new(); let mut rng = rand::rng(); let (_seckey1, pubkey1) = crate::test_random_keypair(); let (_seckey2, pubkey2) = crate::test_random_keypair(); - let key_agg_cache = KeyAggCache::new(&secp, &[&pubkey1, &pubkey2]); + let key_agg_cache = KeyAggCache::new(&[&pubkey1, &pubkey2]); let msg: &[u8; 32] = b"This message is exactly 32 bytes"; let session_secrand1 = SessionSecretRand::from_rng(&mut rng); - let (_, pub_nonce1) = key_agg_cache.nonce_gen(&secp, session_secrand1, pubkey1, msg, None); + let (_, pub_nonce1) = key_agg_cache.nonce_gen(session_secrand1, pubkey1, msg, None); let session_secrand2 = SessionSecretRand::from_rng(&mut rng); - let (_, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_secrand2, pubkey2, msg, None); + let (_, pub_nonce2) = key_agg_cache.nonce_gen(session_secrand2, pubkey2, msg, None); // Test AggregatedNonce creation - let agg_nonce = AggregatedNonce::new(&secp, &[&pub_nonce1, &pub_nonce2]); - let agg_nonce1 = AggregatedNonce::new(&secp, &[&pub_nonce2, &pub_nonce1]); - let agg_nonce2 = AggregatedNonce::new(&secp, &[&pub_nonce2, &pub_nonce2]); - let agg_nonce3 = AggregatedNonce::new(&secp, &[&pub_nonce2, &pub_nonce2]); + let agg_nonce = AggregatedNonce::new(&[&pub_nonce1, &pub_nonce2]); + let agg_nonce1 = AggregatedNonce::new(&[&pub_nonce2, &pub_nonce1]); + let agg_nonce2 = AggregatedNonce::new(&[&pub_nonce2, &pub_nonce2]); + let agg_nonce3 = AggregatedNonce::new(&[&pub_nonce2, &pub_nonce2]); assert_eq!(agg_nonce, agg_nonce1); // swapped nonces assert_ne!(agg_nonce, agg_nonce2); // repeated/different nonces assert_ne!(agg_nonce, agg_nonce3); // repeated nonce but still both nonces present @@ -1545,9 +1570,8 @@ mod tests { #[cfg(feature = "std")] #[should_panic(expected = "Cannot aggregate an empty slice of nonces")] fn aggregated_nonce_empty_panic() { - let secp = Secp256k1::new(); let empty_nonces: Vec<&PublicNonce> = vec![]; - let _agg_nonce = AggregatedNonce::new(&secp, &empty_nonces); + let _agg_nonce = AggregatedNonce::new(&empty_nonces); } #[test] @@ -1555,75 +1579,44 @@ mod tests { #[cfg(feature = "std")] #[cfg(feature = "rand")] fn session_and_partial_signing() { - let secp = Secp256k1::new(); let mut rng = rand::rng(); let (seckey1, pubkey1) = crate::test_random_keypair(); let (seckey2, pubkey2) = crate::test_random_keypair(); let pubkeys = [&pubkey1, &pubkey2]; - let key_agg_cache = KeyAggCache::new(&secp, &pubkeys); + let key_agg_cache = KeyAggCache::new(&pubkeys); let msg: &[u8; 32] = b"This message is exactly 32 bytes"; let session_secrand1 = SessionSecretRand::from_rng(&mut rng); let (sec_nonce1, pub_nonce1) = - key_agg_cache.nonce_gen(&secp, session_secrand1, pubkey1, msg, None); + key_agg_cache.nonce_gen(session_secrand1, pubkey1, msg, None); let session_secrand2 = SessionSecretRand::from_rng(&mut rng); let (sec_nonce2, pub_nonce2) = - key_agg_cache.nonce_gen(&secp, session_secrand2, pubkey2, msg, None); + key_agg_cache.nonce_gen(session_secrand2, pubkey2, msg, None); let nonces = [&pub_nonce1, &pub_nonce2]; - let agg_nonce = AggregatedNonce::new(&secp, &nonces); + let agg_nonce = AggregatedNonce::new(&nonces); // Test Session creation - let session = Session::new(&secp, &key_agg_cache, agg_nonce, msg); + let session = Session::new(&key_agg_cache, agg_nonce, msg); // Test partial signing - let keypair1 = Keypair::from_secret_key(&secp, &seckey1); - let partial_sign1 = session.partial_sign(&secp, sec_nonce1, &keypair1, &key_agg_cache); + let keypair1 = Keypair::from_secret_key(&seckey1); + let partial_sign1 = session.partial_sign(sec_nonce1, &keypair1, &key_agg_cache); - let keypair2 = Keypair::from_secret_key(&secp, &seckey2); - let partial_sign2 = session.partial_sign(&secp, sec_nonce2, &keypair2, &key_agg_cache); + let keypair2 = Keypair::from_secret_key(&seckey2); + let partial_sign2 = session.partial_sign(sec_nonce2, &keypair2, &key_agg_cache); // Test partial signature verification - assert!(session.partial_verify( - &secp, - &key_agg_cache, - &partial_sign1, - &pub_nonce1, - pubkey1 - )); - assert!(session.partial_verify( - &secp, - &key_agg_cache, - &partial_sign2, - &pub_nonce2, - pubkey2 - )); + assert!(session.partial_verify(&key_agg_cache, &partial_sign1, &pub_nonce1, pubkey1)); + assert!(session.partial_verify(&key_agg_cache, &partial_sign2, &pub_nonce2, pubkey2)); // Test that they are invalid if you switch keys - assert!(!session.partial_verify( - &secp, - &key_agg_cache, - &partial_sign2, - &pub_nonce2, - pubkey1 - )); - assert!(!session.partial_verify( - &secp, - &key_agg_cache, - &partial_sign2, - &pub_nonce1, - pubkey2 - )); - assert!(!session.partial_verify( - &secp, - &key_agg_cache, - &partial_sign2, - &pub_nonce1, - pubkey1 - )); + assert!(!session.partial_verify(&key_agg_cache, &partial_sign2, &pub_nonce2, pubkey1)); + assert!(!session.partial_verify(&key_agg_cache, &partial_sign2, &pub_nonce1, pubkey2)); + assert!(!session.partial_verify(&key_agg_cache, &partial_sign2, &pub_nonce1, pubkey1)); // Test PartialSignature serialization/deserialization let serialized_partial_sig = partial_sign1.serialize(); @@ -1637,55 +1630,54 @@ mod tests { #[cfg(feature = "std")] #[cfg(feature = "rand")] fn signature_aggregation_and_verification() { - let secp = Secp256k1::new(); let mut rng = rand::rng(); let (seckey1, pubkey1) = crate::test_random_keypair(); let (seckey2, pubkey2) = crate::test_random_keypair(); let pubkeys = [&pubkey1, &pubkey2]; - let key_agg_cache = KeyAggCache::new(&secp, &pubkeys); + let key_agg_cache = KeyAggCache::new(&pubkeys); let msg: &[u8; 32] = b"This message is exactly 32 bytes"; let session_secrand1 = SessionSecretRand::from_rng(&mut rng); let (sec_nonce1, pub_nonce1) = - key_agg_cache.nonce_gen(&secp, session_secrand1, pubkey1, msg, None); + key_agg_cache.nonce_gen(session_secrand1, pubkey1, msg, None); let session_secrand2 = SessionSecretRand::from_rng(&mut rng); let (sec_nonce2, pub_nonce2) = - key_agg_cache.nonce_gen(&secp, session_secrand2, pubkey2, msg, None); + key_agg_cache.nonce_gen(session_secrand2, pubkey2, msg, None); let nonces = [&pub_nonce1, &pub_nonce2]; - let agg_nonce = AggregatedNonce::new(&secp, &nonces); - let session = Session::new(&secp, &key_agg_cache, agg_nonce, msg); + let agg_nonce = AggregatedNonce::new(&nonces); + let session = Session::new(&key_agg_cache, agg_nonce, msg); - let keypair1 = Keypair::from_secret_key(&secp, &seckey1); - let partial_sign1 = session.partial_sign(&secp, sec_nonce1, &keypair1, &key_agg_cache); + let keypair1 = Keypair::from_secret_key(&seckey1); + let partial_sign1 = session.partial_sign(sec_nonce1, &keypair1, &key_agg_cache); - let keypair2 = Keypair::from_secret_key(&secp, &seckey2); - let partial_sign2 = session.partial_sign(&secp, sec_nonce2, &keypair2, &key_agg_cache); + let keypair2 = Keypair::from_secret_key(&seckey2); + let partial_sign2 = session.partial_sign(sec_nonce2, &keypair2, &key_agg_cache); // Test signature verification let aggregated_signature = session.partial_sig_agg(&[&partial_sign1, &partial_sign2]); let agg_pk = key_agg_cache.agg_pk(); - aggregated_signature.verify(&secp, &agg_pk, msg).unwrap(); + aggregated_signature.verify(&agg_pk, msg).unwrap(); // Test assume_valid let schnorr_sig = aggregated_signature.assume_valid(); - secp.verify_schnorr(&schnorr_sig, msg, &agg_pk).unwrap(); + schnorr::verify(&schnorr_sig, msg, &agg_pk).unwrap(); // Test with wrong aggregate (repeated sigs) let aggregated_signature = session.partial_sig_agg(&[&partial_sign1, &partial_sign1]); - aggregated_signature.verify(&secp, &agg_pk, msg).unwrap_err(); + aggregated_signature.verify(&agg_pk, msg).unwrap_err(); let schnorr_sig = aggregated_signature.assume_valid(); - secp.verify_schnorr(&schnorr_sig, msg, &agg_pk).unwrap_err(); + schnorr::verify(&schnorr_sig, msg, &agg_pk).unwrap_err(); // Test with swapped sigs -- this will work. Unlike keys, sigs are not ordered. let aggregated_signature = session.partial_sig_agg(&[&partial_sign2, &partial_sign1]); - aggregated_signature.verify(&secp, &agg_pk, msg).unwrap(); + aggregated_signature.verify(&agg_pk, msg).unwrap(); let schnorr_sig = aggregated_signature.assume_valid(); - secp.verify_schnorr(&schnorr_sig, msg, &agg_pk).unwrap(); + schnorr::verify(&schnorr_sig, msg, &agg_pk).unwrap(); } #[test] @@ -1693,7 +1685,6 @@ mod tests { #[cfg(feature = "rand")] #[should_panic(expected = "Cannot aggregate an empty slice of partial signatures")] fn partial_sig_agg_empty_panic() { - let secp = Secp256k1::new(); let mut rng = rand::rng(); let (_seckey1, pubkey1) = crate::test_random_keypair(); @@ -1703,18 +1694,18 @@ mod tests { let mut pubkeys_ref: Vec<&PublicKey> = pubkeys.iter().collect(); let pubkeys_ref = pubkeys_ref.as_mut_slice(); - let key_agg_cache = KeyAggCache::new(&secp, pubkeys_ref); + let key_agg_cache = KeyAggCache::new(pubkeys_ref); let msg: &[u8; 32] = b"This message is exactly 32 bytes"; let session_secrand1 = SessionSecretRand::from_rng(&mut rng); - let (_, pub_nonce1) = key_agg_cache.nonce_gen(&secp, session_secrand1, pubkey1, msg, None); + let (_, pub_nonce1) = key_agg_cache.nonce_gen(session_secrand1, pubkey1, msg, None); let session_secrand2 = SessionSecretRand::from_rng(&mut rng); - let (_, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_secrand2, pubkey2, msg, None); + let (_, pub_nonce2) = key_agg_cache.nonce_gen(session_secrand2, pubkey2, msg, None); let nonces = [pub_nonce1, pub_nonce2]; let nonces_ref: Vec<&PublicNonce> = nonces.iter().collect(); - let agg_nonce = AggregatedNonce::new(&secp, &nonces_ref); - let session = Session::new(&secp, &key_agg_cache, agg_nonce, msg); + let agg_nonce = AggregatedNonce::new(&nonces_ref); + let session = Session::new(&key_agg_cache, agg_nonce, msg); let _agg_sig = session.partial_sig_agg(&[]); } diff --git a/src/schnorr.rs b/src/schnorr.rs index d016a9030..aac356d84 100644 --- a/src/schnorr.rs +++ b/src/schnorr.rs @@ -11,9 +11,7 @@ use secp256k1_sys::SchnorrSigExtraParams; use crate::ffi::{self, CPtr}; use crate::key::{Keypair, XOnlyPublicKey}; -#[cfg(feature = "global-context")] -use crate::SECP256K1; -use crate::{constants, from_hex, Error, Secp256k1, Signing, Verification}; +use crate::{constants, from_hex, Error, Secp256k1}; /// Represents a schnorr signature. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -103,99 +101,86 @@ impl Signature { #[inline] pub fn as_byte_array(&self) -> &[u8; constants::SCHNORR_SIGNATURE_SIZE] { &self.0 } - /// Verifies a schnorr signature for `msg` using `pk` and the global [`SECP256K1`] context. + /// Verifies a schnorr signature for `msg` using `pk`. #[inline] #[cfg(feature = "global-context")] pub fn verify(&self, msg: &[u8], pk: &XOnlyPublicKey) -> Result<(), Error> { - SECP256K1.verify_schnorr(self, msg, pk) + verify(self, msg, pk) } } -impl Secp256k1 { - fn sign_schnorr_helper( - &self, - msg: &[u8], - keypair: &Keypair, - nonce_data: *const ffi::types::c_uchar, - ) -> Signature { - unsafe { - let mut sig = [0u8; constants::SCHNORR_SIGNATURE_SIZE]; - let extra = SchnorrSigExtraParams::new(None, nonce_data.cast()); - assert_eq!( - 1, +fn sign_helper(msg: &[u8], keypair: &Keypair, nonce_data: *const ffi::types::c_uchar) -> Signature { + unsafe { + let mut sig = [0u8; constants::SCHNORR_SIGNATURE_SIZE]; + let extra = SchnorrSigExtraParams::new(None, nonce_data.cast()); + + let res = crate::with_global_context( + |secp: &Secp256k1| { ffi::secp256k1_schnorrsig_sign_custom( - self.ctx.as_ptr(), + secp.ctx.as_ptr(), sig.as_mut_c_ptr(), msg.as_c_ptr(), msg.len(), keypair.as_c_ptr(), &extra, ) - ); + }, + Some(&keypair.secret_bytes()), + ); + assert_eq!(res, 1); - Signature(sig) - } + Signature(sig) } +} - /// Creates a schnorr signature internally using the [`rand::rngs::ThreadRng`] random number - /// generator to generate the auxiliary random data. - #[cfg(all(feature = "rand", feature = "std"))] - pub fn sign_schnorr(&self, msg: &[u8], keypair: &Keypair) -> Signature { - self.sign_schnorr_with_rng(msg, keypair, &mut rand::rng()) - } +/// Creates a schnorr signature internally using the [`rand::rngs::ThreadRng`] random number +/// generator to generate the auxiliary random data. +#[cfg(all(feature = "rand", feature = "std"))] +pub fn sign(msg: &[u8], keypair: &Keypair) -> Signature { + sign_with_rng(msg, keypair, &mut rand::rng()) +} - /// Creates a schnorr signature without using any auxiliary random data. - pub fn sign_schnorr_no_aux_rand(&self, msg: &[u8], keypair: &Keypair) -> Signature { - self.sign_schnorr_helper(msg, keypair, ptr::null()) - } +/// Creates a schnorr signature without using any auxiliary random data. +pub fn sign_no_aux_rand(msg: &[u8], keypair: &Keypair) -> Signature { + sign_helper(msg, keypair, ptr::null()) +} - /// Creates a schnorr signature using the given auxiliary random data. - pub fn sign_schnorr_with_aux_rand( - &self, - msg: &[u8], - keypair: &Keypair, - aux_rand: &[u8; 32], - ) -> Signature { - self.sign_schnorr_helper(msg, keypair, aux_rand.as_c_ptr() as *const ffi::types::c_uchar) - } +/// Creates a schnorr signature using the given auxiliary random data. +pub fn sign_with_aux_rand(msg: &[u8], keypair: &Keypair, aux_rand: &[u8; 32]) -> Signature { + sign_helper(msg, keypair, aux_rand.as_c_ptr() as *const ffi::types::c_uchar) +} - /// Creates a schnorr signature using the given random number generator to - /// generate the auxiliary random data. - #[cfg(feature = "rand")] - pub fn sign_schnorr_with_rng( - &self, - msg: &[u8], - keypair: &Keypair, - rng: &mut R, - ) -> Signature { - let mut aux = [0u8; 32]; - rng.fill_bytes(&mut aux); - self.sign_schnorr_helper(msg, keypair, aux.as_c_ptr() as *const ffi::types::c_uchar) - } +/// Creates a schnorr signature using the given random number generator to +/// generate the auxiliary random data. +#[cfg(feature = "rand")] +pub fn sign_with_rng(msg: &[u8], keypair: &Keypair, rng: &mut R) -> Signature { + let mut aux = [0u8; 32]; + rng.fill_bytes(&mut aux); + sign_helper(msg, keypair, aux.as_c_ptr() as *const ffi::types::c_uchar) } -impl Secp256k1 { - /// Verifies a schnorr signature. - pub fn verify_schnorr( - &self, - sig: &Signature, - msg: &[u8], - pubkey: &XOnlyPublicKey, - ) -> Result<(), Error> { - unsafe { - let ret = ffi::secp256k1_schnorrsig_verify( - self.ctx.as_ptr(), - sig.as_c_ptr(), - msg.as_c_ptr(), - msg.len(), - pubkey.as_c_ptr(), - ); - - if ret == 1 { - Ok(()) - } else { - Err(Error::IncorrectSignature) - } +/// Verifies a schnorr signature. +pub fn verify(sig: &Signature, msg: &[u8], pubkey: &XOnlyPublicKey) -> Result<(), Error> { + // We have no seed here but we want rerandomiziation to happen for `rand` users. + let seed = [0_u8; 32]; + unsafe { + let ret = crate::with_global_context( + |secp: &Secp256k1| { + ffi::secp256k1_schnorrsig_verify( + secp.ctx.as_ptr(), + sig.as_c_ptr(), + msg.as_c_ptr(), + msg.len(), + pubkey.as_c_ptr(), + ) + }, + Some(&seed), + ); + + if ret == 1 { + Ok(()) + } else { + Err(Error::IncorrectSignature) } } } @@ -227,48 +212,37 @@ mod tests { #[test] #[cfg(feature = "std")] fn schnorr_sign_with_aux_rand_verify() { - sign_helper((), |secp, msg, seckey, _| { + sign_helper((), |msg, seckey, _| { let aux_rand = crate::test_random_32_bytes(); - secp.sign_schnorr_with_aux_rand(msg, seckey, &aux_rand) + sign_with_aux_rand(msg, seckey, &aux_rand) }) } #[test] #[cfg(all(feature = "rand", feature = "std"))] - fn schnor_sign_with_rng_verify() { - sign_helper(&mut rand::rng(), |secp, msg, seckey, rng| { - secp.sign_schnorr_with_rng(msg, seckey, rng) - }) - } + fn schnor_sign_with_rng_verify() { sign_helper(&mut rand::rng(), sign_with_rng) } #[test] #[cfg(all(feature = "rand", feature = "std"))] // sign_schnorr requires "rand" - fn schnorr_sign_verify() { - sign_helper((), |secp, msg, seckey, _| secp.sign_schnorr(msg, seckey)) - } + fn schnorr_sign_verify() { sign_helper((), |msg, seckey, _| sign(msg, seckey)) } #[test] #[cfg(feature = "std")] fn schnorr_sign_no_aux_rand_verify() { - sign_helper((), |secp, msg, seckey, _| secp.sign_schnorr_no_aux_rand(msg, seckey)) + sign_helper((), |msg, seckey, _| sign_no_aux_rand(msg, seckey)) } #[cfg(feature = "std")] - fn sign_helper( - mut rng: R, - sign: fn(&Secp256k1, &[u8], &Keypair, &mut R) -> Signature, - ) { - let secp = Secp256k1::new(); - + fn sign_helper(mut rng: R, sign: fn(&[u8], &Keypair, &mut R) -> Signature) { let kp = Keypair::test_random(); let (pk, _parity) = kp.x_only_public_key(); for _ in 0..100 { let msg = crate::test_random_32_bytes(); - let sig = sign(&secp, &msg, &kp, &mut rng); + let sig = sign(&msg, &kp, &mut rng); - assert!(secp.verify_schnorr(&sig, &msg, &pk).is_ok()); + assert!(verify(&sig, &msg, &pk).is_ok()); } } @@ -276,8 +250,6 @@ mod tests { #[cfg(feature = "alloc")] #[cfg(not(secp256k1_fuzz))] // fixed sig vectors can't work with fuzz-sigs fn schnorr_sign() { - let secp = Secp256k1::new(); - let msg = hex_32!("E48441762FB75010B2AA31A512B62B4148AA3FB08EB0765D76B252559064A614"); let sk = Keypair::from_str("688C77BC2D5AAFF5491CF309D4753B732135470D05B7B2CD21ADD0744FE97BEF") @@ -286,7 +258,7 @@ mod tests { hex_32!("02CCE08E913F22A36C5648D6405A2C7C50106E7AA2F1649E381C7F09D16B80AB"); let expected_sig = Signature::from_str("6470FD1303DDA4FDA717B9837153C24A6EAB377183FC438F939E0ED2B620E9EE5077C4A8B8DCA28963D772A94F5F0DDF598E1C47C137F91933274C7C3EDADCE8").unwrap(); - let sig = secp.sign_schnorr_with_aux_rand(&msg, &sk, &aux_rand); + let sig = sign_with_aux_rand(&msg, &sk, &aux_rand); assert_eq!(expected_sig, sig); } @@ -295,8 +267,6 @@ mod tests { #[cfg(not(secp256k1_fuzz))] // fixed sig vectors can't work with fuzz-sigs #[cfg(feature = "alloc")] fn schnorr_verify() { - let secp = Secp256k1::new(); - let msg = hex_32!("E48441762FB75010B2AA31A512B62B4148AA3FB08EB0765D76B252559064A614"); let sig = Signature::from_str("6470FD1303DDA4FDA717B9837153C24A6EAB377183FC438F939E0ED2B620E9EE5077C4A8B8DCA28963D772A94F5F0DDF598E1C47C137F91933274C7C3EDADCE8").unwrap(); let pubkey = XOnlyPublicKey::from_str( @@ -304,7 +274,7 @@ mod tests { ) .unwrap(); - assert!(secp.verify_schnorr(&sig, &msg, &pubkey).is_ok()); + assert!(verify(&sig, &msg, &pubkey).is_ok()); } #[test] @@ -374,13 +344,12 @@ mod tests { #[test] #[cfg(feature = "alloc")] fn test_xonly_key_extraction() { - let secp = Secp256k1::new(); let sk_str = "688C77BC2D5AAFF5491CF309D4753B732135470D05B7B2CD21ADD0744FE97BEF"; let keypair = Keypair::from_str(sk_str).unwrap(); let sk = SecretKey::from_keypair(&keypair); assert_eq!(SecretKey::from_str(sk_str).unwrap(), sk); let pk = crate::key::PublicKey::from_keypair(&keypair); - assert_eq!(crate::key::PublicKey::from_secret_key(&secp, &sk), pk); + assert_eq!(crate::key::PublicKey::from_secret_key(&sk), pk); let (xpk, _parity) = keypair.x_only_public_key(); assert_eq!(XOnlyPublicKey::from(pk), xpk); } @@ -457,8 +426,7 @@ mod tests { use rand::SeedableRng as _; use rand_xoshiro::Xoshiro128PlusPlus as SmallRng; - let secp = Secp256k1::new(); - let kp = Keypair::new(&secp, &mut SmallRng::from_seed([2; 16])); + let kp = Keypair::new(&mut SmallRng::from_seed([2; 16])); let (pk, _parity) = kp.x_only_public_key(); assert_eq!( &pk.serialize()[..], @@ -475,12 +443,10 @@ mod tests { fn test_serde() { use serde_test::{assert_tokens, Configure, Token}; - let s = Secp256k1::new(); - let msg = [1; 32]; let keypair = Keypair::from_seckey_byte_array([2; 32]).unwrap(); let aux = [3u8; 32]; - let sig = s.sign_schnorr_with_aux_rand(&msg, &keypair, &aux); + let sig = sign_with_aux_rand(&msg, &keypair, &aux); static SIG_BYTES: [u8; constants::SCHNORR_SIGNATURE_SIZE] = [ 0x14, 0xd0, 0xbf, 0x1a, 0x89, 0x53, 0x50, 0x6f, 0xb4, 0x60, 0xf5, 0x8b, 0xe1, 0x41, 0xaf, 0x76, 0x7f, 0xd1, 0x12, 0x53, 0x5f, 0xb3, 0x92, 0x2e, 0xf2, 0x17, 0x30, 0x8e, @@ -699,7 +665,6 @@ mod tests { should_fail_verify: false, }, ]; - let secp = Secp256k1::new(); for TestVector { secret_key, @@ -713,12 +678,12 @@ mod tests { if let (Some(secret_key), Some(aux_rand)) = (secret_key, aux_rand) { let keypair = Keypair::from_seckey_byte_array(secret_key).unwrap(); assert_eq!(keypair.x_only_public_key().0.serialize(), public_key); - let sig = secp.sign_schnorr_with_aux_rand(&message, &keypair, &aux_rand); + let sig = sign_with_aux_rand(&message, &keypair, &aux_rand); assert_eq!(sig.to_byte_array(), signature); } let sig = Signature::from_byte_array(signature); let is_verified = if let Ok(pubkey) = XOnlyPublicKey::from_byte_array(public_key) { - secp.verify_schnorr(&sig, &message, &pubkey).is_ok() + verify(&sig, &message, &pubkey).is_ok() } else { false }; diff --git a/src/secret.rs b/src/secret.rs index 8a93c8947..8abb079d9 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -135,7 +135,7 @@ impl Keypair { /// /// let secp = Secp256k1::new(); /// let key = SecretKey::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap(); - /// let key = Keypair::from_secret_key(&secp, &key); + /// let key = Keypair::from_secret_key(&key); /// // Here we explicitly display the secret value: /// assert_eq!( /// "0000000000000000000000000000000000000000000000000000000000000001",