From f5f90af2455b50c484500f8e88f89410a8ed013c Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Fri, 16 May 2025 00:32:02 +0000 Subject: [PATCH 01/15] fmt: stop blacklisting secp256k1-sys; just fmt whole crate --- rustfmt.toml | 5 - secp256k1-sys/build.rs | 44 +- secp256k1-sys/src/lib.rs | 1054 ++++++++++++++++++++------------- secp256k1-sys/src/macros.rs | 8 +- secp256k1-sys/src/recovery.rs | 107 ++-- secp256k1-sys/src/types.rs | 7 +- 6 files changed, 754 insertions(+), 471 deletions(-) diff --git a/rustfmt.toml b/rustfmt.toml index 47e9866ce..c3cb2bb62 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,8 +1,3 @@ -# Eventually this shoud be: ignore = [] -ignore = [ - "secp256k1-sys" -] - hard_tabs = false tab_spaces = 4 newline_style = "Auto" diff --git a/secp256k1-sys/build.rs b/secp256k1-sys/build.rs index e275b2251..f6e01126e 100644 --- a/secp256k1-sys/build.rs +++ b/secp256k1-sys/build.rs @@ -16,21 +16,22 @@ use std::env; fn main() { // Actual build let mut base_config = cc::Build::new(); - base_config.include("depend/secp256k1/") - .include("depend/secp256k1/include") - .include("depend/secp256k1/src") - .flag_if_supported("-Wno-unused-function") // some ecmult stuff is defined but not used upstream - .flag_if_supported("-Wno-unused-parameter") // patching out printf causes this warning - .define("SECP256K1_API", Some("")) - .define("ENABLE_MODULE_ECDH", Some("1")) - .define("ENABLE_MODULE_SCHNORRSIG", Some("1")) - .define("ENABLE_MODULE_EXTRAKEYS", Some("1")) - .define("ENABLE_MODULE_ELLSWIFT", Some("1")) - .define("ENABLE_MODULE_MUSIG", Some("1")) - // upstream sometimes introduces calls to printf, which we cannot compile - // with WASM due to its lack of libc. printf is never necessary and we can - // just #define it away. - .define("printf(...)", Some("")); + base_config + .include("depend/secp256k1/") + .include("depend/secp256k1/include") + .include("depend/secp256k1/src") + .flag_if_supported("-Wno-unused-function") // some ecmult stuff is defined but not used upstream + .flag_if_supported("-Wno-unused-parameter") // patching out printf causes this warning + .define("SECP256K1_API", Some("")) + .define("ENABLE_MODULE_ECDH", Some("1")) + .define("ENABLE_MODULE_SCHNORRSIG", Some("1")) + .define("ENABLE_MODULE_EXTRAKEYS", Some("1")) + .define("ENABLE_MODULE_ELLSWIFT", Some("1")) + .define("ENABLE_MODULE_MUSIG", Some("1")) + // upstream sometimes introduces calls to printf, which we cannot compile + // with WASM due to its lack of libc. printf is never necessary and we can + // just #define it away. + .define("printf(...)", Some("")); if cfg!(feature = "lowmemory") { base_config.define("ECMULT_WINDOW_SIZE", Some("4")); // A low-enough value to consume negligible memory @@ -45,15 +46,15 @@ fn main() { // WASM headers and size/align defines. if env::var("CARGO_CFG_TARGET_ARCH").unwrap() == "wasm32" { - base_config.include("wasm/wasm-sysroot") - .file("wasm/wasm.c"); + base_config.include("wasm/wasm-sysroot").file("wasm/wasm.c"); } // secp256k1 - base_config.file("depend/secp256k1/contrib/lax_der_parsing.c") - .file("depend/secp256k1/src/precomputed_ecmult_gen.c") - .file("depend/secp256k1/src/precomputed_ecmult.c") - .file("depend/secp256k1/src/secp256k1.c"); + base_config + .file("depend/secp256k1/contrib/lax_der_parsing.c") + .file("depend/secp256k1/src/precomputed_ecmult_gen.c") + .file("depend/secp256k1/src/precomputed_ecmult.c") + .file("depend/secp256k1/src/secp256k1.c"); if base_config.try_compile("libsecp256k1.a").is_err() { // Some embedded platforms may not have, eg, string.h available, so if the build fails @@ -63,4 +64,3 @@ fn main() { base_config.compile("libsecp256k1.a"); } } - diff --git a/secp256k1-sys/src/lib.rs b/secp256k1-sys/src/lib.rs index 69f3ab200..929db7c3e 100644 --- a/secp256k1-sys/src/lib.rs +++ b/secp256k1-sys/src/lib.rs @@ -6,7 +6,6 @@ // Coding conventions #![deny(non_upper_case_globals, non_camel_case_types, non_snake_case, unused_mut)] - #![cfg_attr(all(not(test), not(feature = "std")), no_std)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] @@ -25,8 +24,9 @@ pub mod types; #[cfg(feature = "recovery")] pub mod recovery; -use core::{slice, ptr}; use core::ptr::NonNull; +use core::{ptr, slice}; + use types::*; /// Flag for context to enable no precomputation @@ -49,23 +49,27 @@ pub const SECP256K1_SER_COMPRESSED: c_uint = (1 << 1) | (1 << 8); /// To use this type, you must write your own (unsafe) wrapper. It is unsafe /// because any secure implementation must dereference the passed-in raw /// pointers and/or call FFI functions. -pub type NonceFn = Option c_int>; +pub type NonceFn = Option< + unsafe extern "C" fn( + nonce32: *mut c_uchar, + msg32: *const c_uchar, + key32: *const c_uchar, + algo16: *const c_uchar, + data: *mut c_void, + attempt: c_uint, + ) -> c_int, +>; /// Hash function to use to post-process an ECDH point to get /// a shared secret. -pub type EcdhHashFn = Option c_int>; +pub type EcdhHashFn = Option< + unsafe extern "C" fn( + output: *mut c_uchar, + x: *const c_uchar, + y: *const c_uchar, + data: *mut c_void, + ) -> c_int, +>; /// Same as [`NonceFn`], but accepts an additional pubkey argument and does not /// accept an attempt argument. @@ -76,25 +80,29 @@ pub type EcdhHashFn = Option c_int>; +pub type SchnorrNonceFn = Option< + unsafe extern "C" fn( + nonce32: *mut c_uchar, + msg32: *const c_uchar, + msg_len: size_t, + key32: *const c_uchar, + xonly_pk32: *const c_uchar, + algo16: *const c_uchar, + algo_len: size_t, + data: *mut c_void, + ) -> c_int, +>; /// A hash function used by `ellswift_ecdh` to hash the final ECDH shared secret. -pub type EllswiftEcdhHashFn = Option c_int>; +pub type EllswiftEcdhHashFn = Option< + unsafe extern "C" fn( + output: *mut c_uchar, + x32: *const c_uchar, + ell_a64: *const c_uchar, + ell_b64: *const c_uchar, + data: *mut c_void, + ) -> c_int, +>; /// Data structure that contains additional arguments for schnorrsig_sign_custom. #[repr(C)] @@ -116,11 +124,7 @@ impl SchnorrSigExtraParams { /// then ndata must be a pointer to 32-byte auxiliary randomness as per /// BIP-340. pub fn new(nonce_fp: SchnorrNonceFn, ndata: *const c_void) -> Self { - SchnorrSigExtraParams { - magic: [0xda, 0x6f, 0xb3, 0x8c], - nonce_fp, - ndata, - } + SchnorrSigExtraParams { magic: [0xda, 0x6f, 0xb3, 0x8c], nonce_fp, ndata } } } @@ -138,7 +142,8 @@ impl SchnorrSigExtraParams { /// a memory leak; destroying it using any other allocator is undefined /// behavior.) #[derive(Clone, Debug)] -#[repr(C)] pub struct Context(c_int); +#[repr(C)] +pub struct Context(c_int); /// Library-internal representation of a Secp256k1 public key #[repr(C)] @@ -156,9 +161,7 @@ impl PublicKey { /// If you pass this to any FFI functions, except as an out-pointer, /// the result is likely to be an assertation failure and process /// termination. - pub unsafe fn new() -> Self { - Self::from_array_unchecked([0; 64]) - } + pub unsafe fn new() -> Self { Self::from_array_unchecked([0; 64]) } /// Create a new public key usable for the FFI interface from raw bytes /// @@ -169,17 +172,13 @@ impl PublicKey { /// the underlying library. You should not use this method except with data /// that you obtained from the FFI interface of the same version of this /// library. - pub unsafe fn from_array_unchecked(data: [c_uchar; 64]) -> Self { - PublicKey(data) - } + pub unsafe fn from_array_unchecked(data: [c_uchar; 64]) -> Self { PublicKey(data) } /// Returns the underlying FFI opaque representation of the public key /// /// You should not use this unless you really know what you are doing. It is /// essentially only useful for extending the FFI interface itself. - pub fn underlying_bytes(self) -> [c_uchar; 64] { - self.0 - } + pub fn underlying_bytes(self) -> [c_uchar; 64] { self.0 } /// Serializes this public key as a byte-encoded pair of values, in compressed form. fn serialize(&self) -> [u8; 33] { @@ -210,18 +209,14 @@ impl PartialOrd for PublicKey { #[cfg(not(secp256k1_fuzz))] impl Ord for PublicKey { fn cmp(&self, other: &PublicKey) -> core::cmp::Ordering { - let ret = unsafe { - secp256k1_ec_pubkey_cmp(secp256k1_context_no_precomp, self, other) - }; + let ret = unsafe { secp256k1_ec_pubkey_cmp(secp256k1_context_no_precomp, self, other) }; ret.cmp(&0i32) } } #[cfg(not(secp256k1_fuzz))] impl PartialEq for PublicKey { - fn eq(&self, other: &Self) -> bool { - self.cmp(other) == core::cmp::Ordering::Equal - } + fn eq(&self, other: &Self) -> bool { self.cmp(other) == core::cmp::Ordering::Equal } } #[cfg(not(secp256k1_fuzz))] @@ -251,9 +246,7 @@ impl Signature { /// If you pass this to any FFI functions, except as an out-pointer, /// the result is likely to be an assertation failure and process /// termination. - pub unsafe fn new() -> Self { - Self::from_array_unchecked([0; 64]) - } + pub unsafe fn new() -> Self { Self::from_array_unchecked([0; 64]) } /// Create a new signature usable for the FFI interface from raw bytes /// @@ -264,17 +257,13 @@ impl Signature { /// the underlying library. You should not use this method except with data /// that you obtained from the FFI interface of the same version of this /// library. - pub unsafe fn from_array_unchecked(data: [c_uchar; 64]) -> Self { - Signature(data) - } + pub unsafe fn from_array_unchecked(data: [c_uchar; 64]) -> Self { Signature(data) } /// Returns the underlying FFI opaque representation of the signature /// /// You should not use this unless you really know what you are doing. It is /// essentially only useful for extending the FFI interface itself. - pub fn underlying_bytes(self) -> [c_uchar; 64] { - self.0 - } + pub fn underlying_bytes(self) -> [c_uchar; 64] { self.0 } /// Serializes the signature in compact format. fn serialize(&self) -> [u8; 64] { @@ -309,9 +298,7 @@ impl Ord for Signature { #[cfg(not(secp256k1_fuzz))] impl PartialEq for Signature { - fn eq(&self, other: &Self) -> bool { - self.cmp(other) == core::cmp::Ordering::Equal - } + fn eq(&self, other: &Self) -> bool { self.cmp(other) == core::cmp::Ordering::Equal } } #[cfg(not(secp256k1_fuzz))] @@ -340,9 +327,7 @@ impl XOnlyPublicKey { /// If you pass this to any FFI functions, except as an out-pointer, /// the result is likely to be an assertation failure and process /// termination. - pub unsafe fn new() -> Self { - Self::from_array_unchecked([0; 64]) - } + pub unsafe fn new() -> Self { Self::from_array_unchecked([0; 64]) } /// Create a new x-only public key usable for the FFI interface from raw bytes /// @@ -353,17 +338,13 @@ impl XOnlyPublicKey { /// the underlying library. You should not use this method except with data /// that you obtained from the FFI interface of the same version of this /// library. - pub unsafe fn from_array_unchecked(data: [c_uchar; 64]) -> Self { - XOnlyPublicKey(data) - } + pub unsafe fn from_array_unchecked(data: [c_uchar; 64]) -> Self { XOnlyPublicKey(data) } /// Returns the underlying FFI opaque representation of the x-only public key /// /// You should not use this unless you really know what you are doing. It is /// essentially only useful for extending the FFI interface itself. - pub fn underlying_bytes(self) -> [c_uchar; 64] { - self.0 - } + pub fn underlying_bytes(self) -> [c_uchar; 64] { self.0 } /// Serializes this key as a byte-encoded x coordinate value (32 bytes). fn serialize(&self) -> [u8; 32] { @@ -390,18 +371,14 @@ impl PartialOrd for XOnlyPublicKey { #[cfg(not(secp256k1_fuzz))] impl Ord for XOnlyPublicKey { fn cmp(&self, other: &XOnlyPublicKey) -> core::cmp::Ordering { - let ret = unsafe { - secp256k1_xonly_pubkey_cmp(secp256k1_context_no_precomp, self, other) - }; + let ret = unsafe { secp256k1_xonly_pubkey_cmp(secp256k1_context_no_precomp, self, other) }; ret.cmp(&0i32) } } #[cfg(not(secp256k1_fuzz))] impl PartialEq for XOnlyPublicKey { - fn eq(&self, other: &Self) -> bool { - self.cmp(other) == core::cmp::Ordering::Equal - } + fn eq(&self, other: &Self) -> bool { self.cmp(other) == core::cmp::Ordering::Equal } } #[cfg(not(secp256k1_fuzz))] @@ -430,9 +407,7 @@ impl Keypair { /// If you pass this to any FFI functions, except as an out-pointer, /// the result is likely to be an assertation failure and process /// termination. - pub unsafe fn new() -> Self { - Self::from_array_unchecked([0; 96]) - } + pub unsafe fn new() -> Self { Self::from_array_unchecked([0; 96]) } /// Create a new keypair usable for the FFI interface from raw bytes /// @@ -443,27 +418,19 @@ impl Keypair { /// the underlying library. You should not use this method except with data /// that you obtained from the FFI interface of the same version of this /// library. - pub unsafe fn from_array_unchecked(data: [c_uchar; 96]) -> Self { - Keypair(data) - } + pub unsafe fn from_array_unchecked(data: [c_uchar; 96]) -> Self { Keypair(data) } /// Returns the underlying FFI opaque representation of the x-only public key /// /// You should not use this unless you really know what you are doing. It is /// essentially only useful for extending the FFI interface itself. - pub fn underlying_bytes(self) -> [c_uchar; 96] { - self.0 - } + pub fn underlying_bytes(self) -> [c_uchar; 96] { self.0 } /// Creates a new compressed public key from this key pair. fn public_key(&self) -> PublicKey { unsafe { let mut pk = PublicKey::new(); - let ret = secp256k1_keypair_pub( - secp256k1_context_no_precomp, - &mut pk, - self, - ); + let ret = secp256k1_keypair_pub(secp256k1_context_no_precomp, &mut pk, self); debug_assert_eq!(ret, 1); pk } @@ -476,18 +443,34 @@ impl Keypair { /// is very subtle. For more discussion on this, please see the documentation /// of the [`zeroize`](https://docs.rs/zeroize) crate. #[inline] - pub fn non_secure_erase(&mut self) { - non_secure_erase_impl(&mut self.0, DUMMY_KEYPAIR); - } + pub fn non_secure_erase(&mut self) { non_secure_erase_impl(&mut self.0, DUMMY_KEYPAIR); } } // DUMMY_KEYPAIR is the internal repr of a valid key pair with secret key `[1u8; 32]` #[cfg(target_endian = "little")] -const DUMMY_KEYPAIR: [c_uchar; 96] = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 143, 7, 221, 213, 233, 245, 23, 156, 255, 25, 72, 96, 52, 24, 30, 215, 101, 5, 186, 170, 213, 62, 93, 153, 64, 100, 18, 123, 86, 197, 132, 27, 209, 232, 168, 105, 122, 212, 34, 81, 222, 57, 246, 167, 32, 129, 223, 223, 66, 171, 197, 66, 166, 214, 254, 7, 21, 84, 139, 88, 143, 175, 190, 112]; +const DUMMY_KEYPAIR: [c_uchar; 96] = [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 143, 7, 221, 213, 233, 245, 23, 156, 255, 25, 72, 96, 52, 24, 30, 215, 101, 5, 186, 170, 213, + 62, 93, 153, 64, 100, 18, 123, 86, 197, 132, 27, 209, 232, 168, 105, 122, 212, 34, 81, 222, 57, + 246, 167, 32, 129, 223, 223, 66, 171, 197, 66, 166, 214, 254, 7, 21, 84, 139, 88, 143, 175, + 190, 112, +]; #[cfg(all(target_endian = "big", target_pointer_width = "32"))] -const DUMMY_KEYPAIR: [c_uchar; 96] = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 213, 221, 7, 143, 156, 23, 245, 233, 96, 72, 25, 255, 215, 30, 24, 52, 170, 186, 5, 101, 153, 93, 62, 213, 123, 18, 100, 64, 27, 132, 197, 86, 105, 168, 232, 209, 81, 34, 212, 122, 167, 246, 57, 222, 223, 223, 129, 32, 66, 197, 171, 66, 7, 254, 214, 166, 88, 139, 84, 21, 112, 190, 175, 143]; +const DUMMY_KEYPAIR: [c_uchar; 96] = [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 213, 221, 7, 143, 156, 23, 245, 233, 96, 72, 25, 255, 215, 30, 24, 52, 170, 186, 5, 101, 153, + 93, 62, 213, 123, 18, 100, 64, 27, 132, 197, 86, 105, 168, 232, 209, 81, 34, 212, 122, 167, + 246, 57, 222, 223, 223, 129, 32, 66, 197, 171, 66, 7, 254, 214, 166, 88, 139, 84, 21, 112, 190, + 175, 143, +]; #[cfg(all(target_endian = "big", target_pointer_width = "64"))] -const DUMMY_KEYPAIR: [c_uchar; 96] = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 156, 23, 245, 233, 213, 221, 7, 143, 215, 30, 24, 52, 96, 72, 25, 255, 153, 93, 62, 213, 170, 186, 5, 101, 27, 132, 197, 86, 123, 18, 100, 64, 81, 34, 212, 122, 105, 168, 232, 209, 223, 223, 129, 32, 167, 246, 57, 222, 7, 254, 214, 166, 66, 197, 171, 66, 112, 190, 175, 143, 88, 139, 84, 21]; +const DUMMY_KEYPAIR: [c_uchar; 96] = [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 156, 23, 245, 233, 213, 221, 7, 143, 215, 30, 24, 52, 96, 72, 25, 255, 153, 93, 62, 213, 170, + 186, 5, 101, 27, 132, 197, 86, 123, 18, 100, 64, 81, 34, 212, 122, 105, 168, 232, 209, 223, + 223, 129, 32, 167, 246, 57, 222, 7, 254, 214, 166, 66, 197, 171, 66, 112, 190, 175, 143, 88, + 139, 84, 21, +]; /// Does a best attempt at secure erasure using Rust intrinsics. /// @@ -496,7 +479,9 @@ const DUMMY_KEYPAIR: [c_uchar; 96] = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, pub fn non_secure_erase_impl(dst: &mut T, src: T) { use core::sync::atomic; // overwrite using volatile value - unsafe { ptr::write_volatile(dst, src); } + unsafe { + ptr::write_volatile(dst, src); + } // prevent future accesses from being reordered to before erasure atomic::compiler_fence(atomic::Ordering::SeqCst); @@ -504,9 +489,7 @@ pub fn non_secure_erase_impl(dst: &mut T, src: T) { #[cfg(not(secp256k1_fuzz))] impl PartialOrd for Keypair { - fn partial_cmp(&self, other: &Keypair) -> Option { - Some(self.cmp(other)) - } + fn partial_cmp(&self, other: &Keypair) -> Option { Some(self.cmp(other)) } } #[cfg(not(secp256k1_fuzz))] @@ -520,9 +503,7 @@ impl Ord for Keypair { #[cfg(not(secp256k1_fuzz))] impl PartialEq for Keypair { - fn eq(&self, other: &Self) -> bool { - self.cmp(other) == core::cmp::Ordering::Equal - } + fn eq(&self, other: &Self) -> bool { self.cmp(other) == core::cmp::Ordering::Equal } } #[cfg(not(secp256k1_fuzz))] @@ -546,12 +527,8 @@ impl core::hash::Hash for Keypair { pub struct ElligatorSwift([u8; 64]); impl ElligatorSwift { - pub fn from_array(arr: [u8; 64]) -> Self { - ElligatorSwift(arr) - } - pub fn to_array(self) -> [u8; 64] { - self.0 - } + pub fn from_array(arr: [u8; 64]) -> Self { ElligatorSwift(arr) } + pub fn to_array(self) -> [u8; 64] { self.0 } } impl_array_newtype!(ElligatorSwift, u8, 64); @@ -559,163 +536,265 @@ impl_raw_debug!(ElligatorSwift); extern "C" { /// Default ECDH hash function - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdh_hash_function_default")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ecdh_hash_function_default" + )] pub static secp256k1_ecdh_hash_function_default: EcdhHashFn; /// Default ECDH hash function for BIP324 key establishment - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ellswift_xdh_hash_function_bip324")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ellswift_xdh_hash_function_bip324" + )] pub static secp256k1_ellswift_xdh_hash_function_bip324: EllswiftEcdhHashFn; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_nonce_function_rfc6979")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_nonce_function_rfc6979" + )] pub static secp256k1_nonce_function_rfc6979: NonceFn; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_nonce_function_default")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_nonce_function_default" + )] pub static secp256k1_nonce_function_default: NonceFn; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_nonce_function_bip340")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_nonce_function_bip340" + )] pub static secp256k1_nonce_function_bip340: SchnorrNonceFn; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_context_no_precomp")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_context_no_precomp" + )] pub static secp256k1_context_no_precomp: *const Context; // Contexts - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_context_preallocated_destroy")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_context_preallocated_destroy" + )] pub fn secp256k1_context_preallocated_destroy(cx: NonNull); // Signatures - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_signature_parse_der")] - pub fn secp256k1_ecdsa_signature_parse_der(cx: *const Context, sig: *mut Signature, - input: *const c_uchar, in_len: size_t) - -> c_int; - - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_signature_parse_compact")] - pub fn secp256k1_ecdsa_signature_parse_compact(cx: *const Context, sig: *mut Signature, - input64: *const c_uchar) - -> c_int; - - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_signature_parse_der_lax")] - pub fn ecdsa_signature_parse_der_lax(cx: *const Context, sig: *mut Signature, - input: *const c_uchar, in_len: size_t) - -> c_int; - - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_signature_serialize_der")] - pub fn secp256k1_ecdsa_signature_serialize_der(cx: *const Context, output: *mut c_uchar, - out_len: *mut size_t, sig: *const Signature) - -> c_int; - - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_signature_serialize_compact")] - pub fn secp256k1_ecdsa_signature_serialize_compact(cx: *const Context, output64: *mut c_uchar, - sig: *const Signature) - -> c_int; - - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_signature_normalize")] - pub fn secp256k1_ecdsa_signature_normalize(cx: *const Context, out_sig: *mut Signature, - in_sig: *const Signature) - -> c_int; + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ecdsa_signature_parse_der" + )] + pub fn secp256k1_ecdsa_signature_parse_der( + cx: *const Context, + sig: *mut Signature, + input: *const c_uchar, + in_len: size_t, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ecdsa_signature_parse_compact" + )] + pub fn secp256k1_ecdsa_signature_parse_compact( + cx: *const Context, + sig: *mut Signature, + input64: *const c_uchar, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ecdsa_signature_parse_der_lax" + )] + pub fn ecdsa_signature_parse_der_lax( + cx: *const Context, + sig: *mut Signature, + input: *const c_uchar, + in_len: size_t, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ecdsa_signature_serialize_der" + )] + pub fn secp256k1_ecdsa_signature_serialize_der( + cx: *const Context, + output: *mut c_uchar, + out_len: *mut size_t, + sig: *const Signature, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ecdsa_signature_serialize_compact" + )] + pub fn secp256k1_ecdsa_signature_serialize_compact( + cx: *const Context, + output64: *mut c_uchar, + sig: *const Signature, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ecdsa_signature_normalize" + )] + pub fn secp256k1_ecdsa_signature_normalize( + cx: *const Context, + out_sig: *mut Signature, + in_sig: *const Signature, + ) -> c_int; // Secret Keys - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ec_seckey_verify")] - pub fn secp256k1_ec_seckey_verify(cx: *const Context, - sk: *const c_uchar) -> c_int; - - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ec_seckey_negate")] - pub fn secp256k1_ec_seckey_negate(cx: *const Context, - sk: *mut c_uchar) -> c_int; - - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ec_seckey_tweak_add")] - pub fn secp256k1_ec_seckey_tweak_add(cx: *const Context, - sk: *mut c_uchar, - tweak: *const c_uchar) - -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ec_seckey_tweak_mul")] - pub fn secp256k1_ec_seckey_tweak_mul(cx: *const Context, - sk: *mut c_uchar, - tweak: *const c_uchar) - -> c_int; + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_seckey_verify" + )] + pub fn secp256k1_ec_seckey_verify(cx: *const Context, sk: *const c_uchar) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_seckey_negate" + )] + pub fn secp256k1_ec_seckey_negate(cx: *const Context, sk: *mut c_uchar) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_seckey_tweak_add" + )] + pub fn secp256k1_ec_seckey_tweak_add( + cx: *const Context, + sk: *mut c_uchar, + tweak: *const c_uchar, + ) -> c_int; + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_seckey_tweak_mul" + )] + pub fn secp256k1_ec_seckey_tweak_mul( + cx: *const Context, + sk: *mut c_uchar, + tweak: *const c_uchar, + ) -> c_int; #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_keypair_sec")] - pub fn secp256k1_keypair_sec(cx: *const Context, - output_seckey: *mut c_uchar, - keypair: *const Keypair) - -> c_int; + pub fn secp256k1_keypair_sec( + cx: *const Context, + output_seckey: *mut c_uchar, + keypair: *const Keypair, + ) -> c_int; #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_keypair_pub")] - pub fn secp256k1_keypair_pub(cx: *const Context, - output_pubkey: *mut PublicKey, - keypair: *const Keypair) - -> c_int; + pub fn secp256k1_keypair_pub( + cx: *const Context, + output_pubkey: *mut PublicKey, + keypair: *const Keypair, + ) -> c_int; // Elligator Swift - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ellswift_encode")] - pub fn secp256k1_ellswift_encode(ctx: *const Context, - ell64: *mut c_uchar, - pubkey: *const PublicKey, - rnd32: *const c_uchar) - -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ellswift_decode")] - pub fn secp256k1_ellswift_decode(ctx: *const Context, - pubkey: *mut u8, - ell64: *const c_uchar) - -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ellswift_create")] - pub fn secp256k1_ellswift_create(ctx: *const Context, - ell64: *mut c_uchar, - seckey32: *const c_uchar, - aux_rand32: *const c_uchar) - -> c_int; + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ellswift_encode" + )] + pub fn secp256k1_ellswift_encode( + ctx: *const Context, + ell64: *mut c_uchar, + pubkey: *const PublicKey, + rnd32: *const c_uchar, + ) -> c_int; + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ellswift_decode" + )] + pub fn secp256k1_ellswift_decode( + ctx: *const Context, + pubkey: *mut u8, + ell64: *const c_uchar, + ) -> c_int; + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ellswift_create" + )] + pub fn secp256k1_ellswift_create( + ctx: *const Context, + ell64: *mut c_uchar, + seckey32: *const c_uchar, + aux_rand32: *const c_uchar, + ) -> c_int; #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ellswift_xdh")] - pub fn secp256k1_ellswift_xdh(ctx: *const Context, - output: *mut c_uchar, - ell_a64: *const c_uchar, - ell_b64: *const c_uchar, - seckey32: *const c_uchar, - party: c_int, - hashfp: EllswiftEcdhHashFn, - data: *mut c_void) - -> c_int; - - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_musig_pubnonce_parse")] + pub fn secp256k1_ellswift_xdh( + ctx: *const Context, + output: *mut c_uchar, + ell_a64: *const c_uchar, + ell_b64: *const c_uchar, + seckey32: *const c_uchar, + party: c_int, + hashfp: EllswiftEcdhHashFn, + data: *mut c_void, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_pubnonce_parse" + )] pub fn secp256k1_musig_pubnonce_parse( cx: *const Context, nonce: *mut MusigPubNonce, in66: *const c_uchar, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_musig_pubnonce_serialize")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_pubnonce_serialize" + )] pub fn secp256k1_musig_pubnonce_serialize( cx: *const Context, out66: *mut c_uchar, nonce: *const MusigPubNonce, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_musig_aggnonce_parse")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_aggnonce_parse" + )] pub fn secp256k1_musig_aggnonce_parse( cx: *const Context, nonce: *mut MusigAggNonce, in66: *const c_uchar, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_musig_aggnonce_serialize")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_aggnonce_serialize" + )] pub fn secp256k1_musig_aggnonce_serialize( cx: *const Context, out66: *mut c_uchar, nonce: *const MusigAggNonce, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_musig_partial_sig_parse")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_partial_sig_parse" + )] pub fn secp256k1_musig_partial_sig_parse( cx: *const Context, sig: *mut MusigPartialSignature, in32: *const c_uchar, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_musig_partial_sig_serialize")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_partial_sig_serialize" + )] pub fn secp256k1_musig_partial_sig_serialize( cx: *const Context, out32: *mut c_uchar, sig: *const MusigPartialSignature, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_musig_pubkey_agg")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_pubkey_agg" + )] pub fn secp256k1_musig_pubkey_agg( cx: *const Context, agg_pk: *mut XOnlyPublicKey, @@ -724,14 +803,20 @@ extern "C" { n_pubkeys: size_t, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming),link_name = "rustsecp256k1_v0_11_musig_pubkey_get")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_pubkey_get" + )] pub fn secp256k1_musig_pubkey_get( cx: *const Context, agg_pk: *mut PublicKey, keyagg_cache: *const MusigKeyAggCache, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_musig_pubkey_ec_tweak_add")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_pubkey_ec_tweak_add" + )] pub fn secp256k1_musig_pubkey_ec_tweak_add( cx: *const Context, output_pubkey: *mut PublicKey, @@ -739,7 +824,10 @@ extern "C" { tweak32: *const c_uchar, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_musig_pubkey_xonly_tweak_add")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_pubkey_xonly_tweak_add" + )] pub fn secp256k1_musig_pubkey_xonly_tweak_add( cx: *const Context, output_pubkey: *mut PublicKey, @@ -747,7 +835,10 @@ extern "C" { tweak32: *const c_uchar, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_musig_nonce_gen")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_nonce_gen" + )] pub fn secp256k1_musig_nonce_gen( cx: *const Context, secnonce: *mut MusigSecNonce, @@ -760,7 +851,10 @@ extern "C" { extra_input32: *const c_uchar, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_musig_nonce_agg")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_nonce_agg" + )] pub fn secp256k1_musig_nonce_agg( cx: *const Context, aggnonce: *mut MusigAggNonce, @@ -768,8 +862,10 @@ extern "C" { n_pubnonces: size_t, ) -> c_int; - - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_musig_nonce_process")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_nonce_process" + )] pub fn secp256k1_musig_nonce_process( cx: *const Context, session: *mut MusigSession, @@ -778,7 +874,10 @@ extern "C" { keyagg_cache: *const MusigKeyAggCache, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_musig_partial_sign")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_partial_sign" + )] pub fn secp256k1_musig_partial_sign( cx: *const Context, partial_sig: *mut MusigPartialSignature, @@ -788,7 +887,10 @@ extern "C" { session: *const MusigSession, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_musig_partial_sig_verify")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_partial_sig_verify" + )] pub fn secp256k1_musig_partial_sig_verify( cx: *const Context, partial_sig: *const MusigPartialSignature, @@ -798,7 +900,10 @@ extern "C" { session: *const MusigSession, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_musig_partial_sig_agg")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_partial_sig_agg" + )] pub fn secp256k1_musig_partial_sig_agg( cx: *const Context, sig64: *mut c_uchar, @@ -811,76 +916,126 @@ extern "C" { pub fn secp256k1_ec_pubkey_sort( ctx: *const Context, pubkeys: *mut *const PublicKey, - n_pubkeys: size_t + n_pubkeys: size_t, ) -> c_int; } #[cfg(not(secp256k1_fuzz))] extern "C" { // Contexts - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_context_preallocated_size")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_context_preallocated_size" + )] pub fn secp256k1_context_preallocated_size(flags: c_uint) -> size_t; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_context_preallocated_create")] - pub fn secp256k1_context_preallocated_create(prealloc: NonNull, flags: c_uint) -> NonNull; - - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_context_preallocated_clone_size")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_context_preallocated_create" + )] + pub fn secp256k1_context_preallocated_create( + prealloc: NonNull, + flags: c_uint, + ) -> NonNull; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_context_preallocated_clone_size" + )] pub fn secp256k1_context_preallocated_clone_size(cx: *const Context) -> size_t; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_context_preallocated_clone")] - pub fn secp256k1_context_preallocated_clone(cx: *const Context, prealloc: NonNull) -> NonNull; - - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_context_randomize")] - pub fn secp256k1_context_randomize(cx: NonNull, - seed32: *const c_uchar) - -> c_int; + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_context_preallocated_clone" + )] + pub fn secp256k1_context_preallocated_clone( + cx: *const Context, + prealloc: NonNull, + ) -> NonNull; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_context_randomize" + )] + pub fn secp256k1_context_randomize(cx: NonNull, seed32: *const c_uchar) -> c_int; // Pubkeys - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ec_pubkey_parse")] - pub fn secp256k1_ec_pubkey_parse(cx: *const Context, pk: *mut PublicKey, - input: *const c_uchar, in_len: size_t) - -> c_int; + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_pubkey_parse" + )] + pub fn secp256k1_ec_pubkey_parse( + cx: *const Context, + pk: *mut PublicKey, + input: *const c_uchar, + in_len: size_t, + ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ec_pubkey_serialize")] - pub fn secp256k1_ec_pubkey_serialize(cx: *const Context, output: *mut c_uchar, - out_len: *mut size_t, pk: *const PublicKey, - compressed: c_uint) - -> c_int; + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_pubkey_serialize" + )] + pub fn secp256k1_ec_pubkey_serialize( + cx: *const Context, + output: *mut c_uchar, + out_len: *mut size_t, + pk: *const PublicKey, + compressed: c_uint, + ) -> c_int; // EC - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ec_pubkey_create")] - pub fn secp256k1_ec_pubkey_create(cx: *const Context, pk: *mut PublicKey, - sk: *const c_uchar) -> c_int; + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_pubkey_create" + )] + pub fn secp256k1_ec_pubkey_create( + cx: *const Context, + pk: *mut PublicKey, + sk: *const c_uchar, + ) -> c_int; + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_pubkey_negate" + )] + pub fn secp256k1_ec_pubkey_negate(cx: *const Context, pk: *mut PublicKey) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ec_pubkey_negate")] - pub fn secp256k1_ec_pubkey_negate(cx: *const Context, - pk: *mut PublicKey) -> c_int; + #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ec_pubkey_cmp")] + pub fn secp256k1_ec_pubkey_cmp( + cx: *const Context, + pubkey1: *const PublicKey, + pubkey2: *const PublicKey, + ) -> c_int; + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_pubkey_tweak_add" + )] + pub fn secp256k1_ec_pubkey_tweak_add( + cx: *const Context, + pk: *mut PublicKey, + tweak: *const c_uchar, + ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ec_pubkey_cmp")] - pub fn secp256k1_ec_pubkey_cmp(cx: *const Context, - pubkey1: *const PublicKey, - pubkey2: *const PublicKey) - -> c_int; - - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ec_pubkey_tweak_add")] - pub fn secp256k1_ec_pubkey_tweak_add(cx: *const Context, - pk: *mut PublicKey, - tweak: *const c_uchar) - -> c_int; - - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ec_pubkey_tweak_mul")] - pub fn secp256k1_ec_pubkey_tweak_mul(cx: *const Context, - pk: *mut PublicKey, - tweak: *const c_uchar) - -> c_int; - - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ec_pubkey_combine")] - pub fn secp256k1_ec_pubkey_combine(cx: *const Context, - out: *mut PublicKey, - ins: *const *const PublicKey, - n: size_t) - -> c_int; + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_pubkey_tweak_mul" + )] + pub fn secp256k1_ec_pubkey_tweak_mul( + cx: *const Context, + pk: *mut PublicKey, + tweak: *const c_uchar, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_pubkey_combine" + )] + pub fn secp256k1_ec_pubkey_combine( + cx: *const Context, + out: *mut PublicKey, + ins: *const *const PublicKey, + n: size_t, + ) -> c_int; #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdh")] pub fn secp256k1_ecdh( @@ -894,33 +1049,41 @@ extern "C" { // ECDSA #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_verify")] - pub fn secp256k1_ecdsa_verify(cx: *const Context, - sig: *const Signature, - msg32: *const c_uchar, - pk: *const PublicKey) - -> c_int; + pub fn secp256k1_ecdsa_verify( + cx: *const Context, + sig: *const Signature, + msg32: *const c_uchar, + pk: *const PublicKey, + ) -> c_int; #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_sign")] - pub fn secp256k1_ecdsa_sign(cx: *const Context, - sig: *mut Signature, - msg32: *const c_uchar, - sk: *const c_uchar, - noncefn: NonceFn, - noncedata: *const c_void) - -> c_int; + pub fn secp256k1_ecdsa_sign( + cx: *const Context, + sig: *mut Signature, + msg32: *const c_uchar, + sk: *const c_uchar, + noncefn: NonceFn, + noncedata: *const c_void, + ) -> c_int; // Schnorr Signatures - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_schnorrsig_sign")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_schnorrsig_sign" + )] pub fn secp256k1_schnorrsig_sign( cx: *const Context, sig: *mut c_uchar, msg32: *const c_uchar, keypair: *const Keypair, - aux_rand32: *const c_uchar + aux_rand32: *const c_uchar, ) -> c_int; // Schnorr Signatures with extra parameters (see [`SchnorrSigExtraParams`]) - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_schnorrsig_sign_custom")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_schnorrsig_sign_custom" + )] pub fn secp256k1_schnorrsig_sign_custom( cx: *const Context, sig: *mut c_uchar, @@ -930,7 +1093,10 @@ extern "C" { extra_params: *const SchnorrSigExtraParams, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_schnorrsig_verify")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_schnorrsig_verify" + )] pub fn secp256k1_schnorrsig_verify( cx: *const Context, sig64: *const c_uchar, @@ -947,21 +1113,30 @@ extern "C" { seckey: *const c_uchar, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_xonly_pubkey_parse")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_xonly_pubkey_parse" + )] pub fn secp256k1_xonly_pubkey_parse( cx: *const Context, pubkey: *mut XOnlyPublicKey, input32: *const c_uchar, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_xonly_pubkey_serialize")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_xonly_pubkey_serialize" + )] pub fn secp256k1_xonly_pubkey_serialize( cx: *const Context, output32: *mut c_uchar, pubkey: *const XOnlyPublicKey, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_xonly_pubkey_from_pubkey")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_xonly_pubkey_from_pubkey" + )] pub fn secp256k1_xonly_pubkey_from_pubkey( cx: *const Context, xonly_pubkey: *mut XOnlyPublicKey, @@ -969,14 +1144,20 @@ extern "C" { pubkey: *const PublicKey, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_xonly_pubkey_cmp")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_xonly_pubkey_cmp" + )] pub fn secp256k1_xonly_pubkey_cmp( cx: *const Context, pubkey1: *const XOnlyPublicKey, - pubkey2: *const XOnlyPublicKey + pubkey2: *const XOnlyPublicKey, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_xonly_pubkey_tweak_add")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_xonly_pubkey_tweak_add" + )] pub fn secp256k1_xonly_pubkey_tweak_add( cx: *const Context, output_pubkey: *mut PublicKey, @@ -984,22 +1165,31 @@ extern "C" { tweak32: *const c_uchar, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_keypair_xonly_pub")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_keypair_xonly_pub" + )] pub fn secp256k1_keypair_xonly_pub( cx: *const Context, pubkey: *mut XOnlyPublicKey, pk_parity: *mut c_int, - keypair: *const Keypair + keypair: *const Keypair, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_keypair_xonly_tweak_add")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_keypair_xonly_tweak_add" + )] pub fn secp256k1_keypair_xonly_tweak_add( cx: *const Context, keypair: *mut Keypair, tweak32: *const c_uchar, ) -> c_int; - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check")] + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check" + )] pub fn secp256k1_xonly_pubkey_tweak_add_check( cx: *const Context, tweaked_pubkey32: *const c_uchar, @@ -1037,6 +1227,7 @@ pub unsafe fn secp256k1_context_create(flags: c_uint) -> NonNull { #[cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))] pub unsafe extern "C" fn rustsecp256k1_v0_11_context_create(flags: c_uint) -> NonNull { use core::mem; + use crate::alloc::alloc; assert!(ALIGN_TO >= mem::align_of::()); assert!(ALIGN_TO >= mem::align_of::<&usize>()); @@ -1110,7 +1301,10 @@ pub unsafe extern "C" fn rustsecp256k1_v0_11_context_destroy(mut ctx: NonNull usize { ctr } - /// A trait for producing pointers that will always be valid in C (assuming NULL pointer is a valid /// no-op). /// @@ -1209,21 +1405,16 @@ impl CPtr for &[T] { self.as_ptr() as *mut Self::Target } } - } impl CPtr for [u8; 32] { type Target = u8; - fn as_c_ptr(&self) -> *const Self::Target { - self.as_ptr() - } + fn as_c_ptr(&self) -> *const Self::Target { self.as_ptr() } - fn as_mut_c_ptr(&mut self) -> *mut Self::Target { - self.as_mut_ptr() - } + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.as_mut_ptr() } } -impl CPtr for Option { +impl CPtr for Option { type Target = T::Target; fn as_mut_c_ptr(&mut self) -> *mut Self::Target { match self { @@ -1298,9 +1489,7 @@ impl MusigSecNonce { MusigSecNonce(bytes) } - pub fn dangerous_into_bytes(self) -> [c_uchar; MUSIG_SECNONCE_LEN] { - self.0 - } + pub fn dangerous_into_bytes(self) -> [c_uchar; MUSIG_SECNONCE_LEN] { self.0 } } #[repr(C)] @@ -1329,15 +1518,23 @@ impl_raw_debug!(MusigPartialSignature); #[cfg(secp256k1_fuzz)] mod fuzz_dummy { - use super::*; use core::sync::atomic::{AtomicUsize, Ordering}; - #[cfg(rust_secp_no_symbol_renaming)] compile_error!("We do not support fuzzing with rust_secp_no_symbol_renaming"); + use super::*; + + #[cfg(rust_secp_no_symbol_renaming)] + compile_error!("We do not support fuzzing with rust_secp_no_symbol_renaming"); extern "C" { fn rustsecp256k1_v0_11_context_preallocated_size(flags: c_uint) -> size_t; - fn rustsecp256k1_v0_11_context_preallocated_create(prealloc: NonNull, flags: c_uint) -> NonNull; - fn rustsecp256k1_v0_11_context_preallocated_clone(cx: *const Context, prealloc: NonNull) -> NonNull; + fn rustsecp256k1_v0_11_context_preallocated_create( + prealloc: NonNull, + flags: c_uint, + ) -> NonNull; + fn rustsecp256k1_v0_11_context_preallocated_clone( + cx: *const Context, + prealloc: NonNull, + ) -> NonNull; } #[cfg(feature = "lowmemory")] @@ -1346,7 +1543,10 @@ mod fuzz_dummy { const CTX_SIZE: usize = 1024 * (1024 + 128); // Contexts pub unsafe fn secp256k1_context_preallocated_size(flags: c_uint) -> size_t { - assert!(rustsecp256k1_v0_11_context_preallocated_size(flags) + std::mem::size_of::() <= CTX_SIZE); + assert!( + rustsecp256k1_v0_11_context_preallocated_size(flags) + std::mem::size_of::() + <= CTX_SIZE + ); CTX_SIZE } @@ -1355,7 +1555,10 @@ mod fuzz_dummy { const HAVE_CONTEXT_WORKING: usize = 1; const HAVE_CONTEXT_DONE: usize = 2; static mut PREALLOCATED_CONTEXT: [u8; CTX_SIZE] = [0; CTX_SIZE]; - pub unsafe fn secp256k1_context_preallocated_create(prealloc: NonNull, flags: c_uint) -> NonNull { + pub unsafe fn secp256k1_context_preallocated_create( + prealloc: NonNull, + flags: c_uint, + ) -> NonNull { // While applications should generally avoid creating too many contexts, sometimes fuzzers // perform tasks repeatedly which real applications may only do rarely. Thus, we want to // avoid being overly slow here. We do so by having a static context and copying it into @@ -1366,13 +1569,27 @@ mod fuzz_dummy { if have_ctx == HAVE_CONTEXT_NONE { have_ctx = HAVE_PREALLOCATED_CONTEXT.swap(HAVE_CONTEXT_WORKING, Ordering::AcqRel); if have_ctx == HAVE_CONTEXT_NONE { - assert!(rustsecp256k1_v0_11_context_preallocated_size(SECP256K1_START_SIGN | SECP256K1_START_VERIFY) + std::mem::size_of::() <= CTX_SIZE); - assert_eq!(rustsecp256k1_v0_11_context_preallocated_create( - NonNull::new_unchecked(PREALLOCATED_CONTEXT[..].as_mut_ptr() as *mut c_void), - SECP256K1_START_SIGN | SECP256K1_START_VERIFY), - NonNull::new_unchecked(PREALLOCATED_CONTEXT[..].as_mut_ptr() as *mut Context)); - assert_eq!(HAVE_PREALLOCATED_CONTEXT.swap(HAVE_CONTEXT_DONE, Ordering::AcqRel), - HAVE_CONTEXT_WORKING); + assert!( + rustsecp256k1_v0_11_context_preallocated_size( + SECP256K1_START_SIGN | SECP256K1_START_VERIFY + ) + std::mem::size_of::() + <= CTX_SIZE + ); + assert_eq!( + rustsecp256k1_v0_11_context_preallocated_create( + NonNull::new_unchecked( + PREALLOCATED_CONTEXT[..].as_mut_ptr() as *mut c_void + ), + SECP256K1_START_SIGN | SECP256K1_START_VERIFY + ), + NonNull::new_unchecked( + PREALLOCATED_CONTEXT[..].as_mut_ptr() as *mut Context + ) + ); + assert_eq!( + HAVE_PREALLOCATED_CONTEXT.swap(HAVE_CONTEXT_DONE, Ordering::AcqRel), + HAVE_CONTEXT_WORKING + ); } else if have_ctx == HAVE_CONTEXT_DONE { // Another thread finished while we were swapping. HAVE_PREALLOCATED_CONTEXT.store(HAVE_CONTEXT_DONE, Ordering::Release); @@ -1385,23 +1602,34 @@ mod fuzz_dummy { std::thread::yield_now(); } } - ptr::copy_nonoverlapping(PREALLOCATED_CONTEXT[..].as_ptr(), prealloc.as_ptr() as *mut u8, CTX_SIZE); + ptr::copy_nonoverlapping( + PREALLOCATED_CONTEXT[..].as_ptr(), + prealloc.as_ptr() as *mut u8, + CTX_SIZE, + ); let ptr = (prealloc.as_ptr()).add(CTX_SIZE).sub(std::mem::size_of::()); (ptr as *mut c_uint).write(flags); NonNull::new_unchecked(prealloc.as_ptr() as *mut Context) } - pub unsafe fn secp256k1_context_preallocated_clone_size(_cx: *const Context) -> size_t { CTX_SIZE } - pub unsafe fn secp256k1_context_preallocated_clone(cx: *const Context, prealloc: NonNull) -> NonNull { + pub unsafe fn secp256k1_context_preallocated_clone_size(_cx: *const Context) -> size_t { + CTX_SIZE + } + pub unsafe fn secp256k1_context_preallocated_clone( + cx: *const Context, + prealloc: NonNull, + ) -> NonNull { let orig_ptr = (cx as *mut u8).add(CTX_SIZE).sub(std::mem::size_of::()); - let new_ptr = (prealloc.as_ptr() as *mut u8).add(CTX_SIZE).sub(std::mem::size_of::()); + let new_ptr = + (prealloc.as_ptr() as *mut u8).add(CTX_SIZE).sub(std::mem::size_of::()); let flags = (orig_ptr as *mut c_uint).read(); (new_ptr as *mut c_uint).write(flags); rustsecp256k1_v0_11_context_preallocated_clone(cx, prealloc) } - pub unsafe fn secp256k1_context_randomize(cx: NonNull, - _seed32: *const c_uchar) - -> c_int { + pub unsafe fn secp256k1_context_randomize( + cx: NonNull, + _seed32: *const c_uchar, + ) -> c_int { // This function is really slow, and unsuitable for fuzzing check_context_flags(cx.as_ptr(), 0); 1 @@ -1420,12 +1648,12 @@ mod fuzz_dummy { } /// Checks that pk != 0xffff...ffff and pk[1..32] == pk[33..64] - unsafe fn test_pk_validate(cx: *const Context, - pk: *const PublicKey) -> c_int { + unsafe fn test_pk_validate(cx: *const Context, pk: *const PublicKey) -> c_int { check_context_flags(cx, 0); - if (*pk).0[1..32] != (*pk).0[33..64] || - ((*pk).0[32] != 0 && (*pk).0[32] != 0xff) || - secp256k1_ec_seckey_verify(cx, (*pk).0[0..32].as_ptr()) == 0 { + if (*pk).0[1..32] != (*pk).0[33..64] + || ((*pk).0[32] != 0 && (*pk).0[32] != 0xff) + || secp256k1_ec_seckey_verify(cx, (*pk).0[0..32].as_ptr()) == 0 + { 0 } else { 1 @@ -1441,12 +1669,15 @@ mod fuzz_dummy { } // Pubkeys - pub unsafe fn secp256k1_ec_pubkey_parse(cx: *const Context, pk: *mut PublicKey, - input: *const c_uchar, in_len: size_t) - -> c_int { + pub unsafe fn secp256k1_ec_pubkey_parse( + cx: *const Context, + pk: *mut PublicKey, + input: *const c_uchar, + in_len: size_t, + ) -> c_int { check_context_flags(cx, 0); match in_len { - 33 => { + 33 => if *input != 2 && *input != 3 { 0 } else { @@ -1458,26 +1689,27 @@ mod fuzz_dummy { (*pk).0[32] = 0; } test_pk_validate(cx, pk) - } - }, - 65 => { + }, + 65 => if *input != 4 && *input != 6 && *input != 7 { 0 } else { ptr::copy(input.offset(1), (*pk).0.as_mut_ptr(), 64); test_cleanup_pk(pk); test_pk_validate(cx, pk) - } - }, - _ => 0 + }, + _ => 0, } } /// Serialize PublicKey back to 33/65 byte pubkey - pub unsafe fn secp256k1_ec_pubkey_serialize(cx: *const Context, output: *mut c_uchar, - out_len: *mut size_t, pk: *const PublicKey, - compressed: c_uint) - -> c_int { + pub unsafe fn secp256k1_ec_pubkey_serialize( + cx: *const Context, + output: *mut c_uchar, + out_len: *mut size_t, + pk: *const PublicKey, + compressed: c_uint, + ) -> c_int { check_context_flags(cx, 0); assert_eq!(test_pk_validate(cx, pk), 1); if compressed == SECP256K1_SER_COMPRESSED { @@ -1496,67 +1728,85 @@ mod fuzz_dummy { panic!("Bad flags"); } 1 - } + } // EC /// Sets pk to sk||sk - pub unsafe fn secp256k1_ec_pubkey_create(cx: *const Context, pk: *mut PublicKey, - sk: *const c_uchar) -> c_int { + pub unsafe fn secp256k1_ec_pubkey_create( + cx: *const Context, + pk: *mut PublicKey, + sk: *const c_uchar, + ) -> c_int { check_context_flags(cx, SECP256K1_START_SIGN); - if secp256k1_ec_seckey_verify(cx, sk) != 1 { return 0; } + if secp256k1_ec_seckey_verify(cx, sk) != 1 { + return 0; + } ptr::copy(sk, (*pk).0[0..32].as_mut_ptr(), 32); test_cleanup_pk(pk); assert_eq!(test_pk_validate(cx, pk), 1); 1 } - pub unsafe fn secp256k1_ec_pubkey_negate(cx: *const Context, - pk: *mut PublicKey) -> c_int { + pub unsafe fn secp256k1_ec_pubkey_negate(cx: *const Context, pk: *mut PublicKey) -> c_int { check_context_flags(cx, 0); assert_eq!(test_pk_validate(cx, pk), 1); - if secp256k1_ec_seckey_negate(cx, (*pk).0[..32].as_mut_ptr()) != 1 { return 0; } + if secp256k1_ec_seckey_negate(cx, (*pk).0[..32].as_mut_ptr()) != 1 { + return 0; + } test_cleanup_pk(pk); assert_eq!(test_pk_validate(cx, pk), 1); 1 } /// The PublicKey equivalent of secp256k1_ec_privkey_tweak_add - pub unsafe fn secp256k1_ec_pubkey_tweak_add(cx: *const Context, - pk: *mut PublicKey, - tweak: *const c_uchar) - -> c_int { + pub unsafe fn secp256k1_ec_pubkey_tweak_add( + cx: *const Context, + pk: *mut PublicKey, + tweak: *const c_uchar, + ) -> c_int { check_context_flags(cx, SECP256K1_START_VERIFY); assert_eq!(test_pk_validate(cx, pk), 1); - if secp256k1_ec_seckey_tweak_add(cx, (*pk).0[..32].as_mut_ptr(), tweak) != 1 { return 0; } + if secp256k1_ec_seckey_tweak_add(cx, (*pk).0[..32].as_mut_ptr(), tweak) != 1 { + return 0; + } test_cleanup_pk(pk); assert_eq!(test_pk_validate(cx, pk), 1); 1 } /// The PublicKey equivalent of secp256k1_ec_privkey_tweak_mul - pub unsafe fn secp256k1_ec_pubkey_tweak_mul(cx: *const Context, - pk: *mut PublicKey, - tweak: *const c_uchar) - -> c_int { + pub unsafe fn secp256k1_ec_pubkey_tweak_mul( + cx: *const Context, + pk: *mut PublicKey, + tweak: *const c_uchar, + ) -> c_int { check_context_flags(cx, 0); assert_eq!(test_pk_validate(cx, pk), 1); - if secp256k1_ec_seckey_tweak_mul(cx, (*pk).0[..32].as_mut_ptr(), tweak) != 1 { return 0; } + if secp256k1_ec_seckey_tweak_mul(cx, (*pk).0[..32].as_mut_ptr(), tweak) != 1 { + return 0; + } test_cleanup_pk(pk); assert_eq!(test_pk_validate(cx, pk), 1); 1 } - pub unsafe fn secp256k1_ec_pubkey_combine(cx: *const Context, - out: *mut PublicKey, - ins: *const *const PublicKey, - n: size_t) - -> c_int { + pub unsafe fn secp256k1_ec_pubkey_combine( + cx: *const Context, + out: *mut PublicKey, + ins: *const *const PublicKey, + n: size_t, + ) -> c_int { check_context_flags(cx, 0); assert!(n >= 1); (*out) = **ins; for i in 1..n { assert_eq!(test_pk_validate(cx, *ins.offset(i as isize)), 1); - if secp256k1_ec_seckey_tweak_add(cx, (*out).0[..32].as_mut_ptr(), (**ins.offset(i as isize)).0[..32].as_ptr()) != 1 { + if secp256k1_ec_seckey_tweak_add( + cx, + (*out).0[..32].as_mut_ptr(), + (**ins.offset(i as isize)).0[..32].as_ptr(), + ) != 1 + { return 0; } } @@ -1576,7 +1826,9 @@ mod fuzz_dummy { ) -> c_int { check_context_flags(cx, 0); assert_eq!(test_pk_validate(cx, point), 1); - if secp256k1_ec_seckey_verify(cx, scalar) != 1 { return 0; } + if secp256k1_ec_seckey_verify(cx, scalar) != 1 { + return 0; + } let scalar_slice = slice::from_raw_parts(scalar, 32); let pk_slice = &(*point).0[..32]; @@ -1598,11 +1850,12 @@ mod fuzz_dummy { // ECDSA /// Verifies that sig is msg32||pk[..32] - pub unsafe fn secp256k1_ecdsa_verify(cx: *const Context, - sig: *const Signature, - msg32: *const c_uchar, - pk: *const PublicKey) - -> c_int { + pub unsafe fn secp256k1_ecdsa_verify( + cx: *const Context, + sig: *const Signature, + msg32: *const c_uchar, + pk: *const PublicKey, + ) -> c_int { check_context_flags(cx, SECP256K1_START_VERIFY); // Actually verify let sig_sl = slice::from_raw_parts(sig as *const u8, 64); @@ -1615,13 +1868,14 @@ mod fuzz_dummy { } /// Sets sig to msg32||pk[..32] - pub unsafe fn secp256k1_ecdsa_sign(cx: *const Context, - sig: *mut Signature, - msg32: *const c_uchar, - sk: *const c_uchar, - _noncefn: NonceFn, - _noncedata: *const c_void) - -> c_int { + pub unsafe fn secp256k1_ecdsa_sign( + cx: *const Context, + sig: *mut Signature, + msg32: *const c_uchar, + sk: *const c_uchar, + _noncefn: NonceFn, + _noncedata: *const c_void, + ) -> c_int { check_context_flags(cx, SECP256K1_START_SIGN); // Check context is built for signing (and compute pk) let mut new_pk = PublicKey::new(); @@ -1665,7 +1919,7 @@ mod fuzz_dummy { sig64: *mut c_uchar, msg32: *const c_uchar, keypair: *const Keypair, - _aux_rand32: *const c_uchar + _aux_rand32: *const c_uchar, ) -> c_int { check_context_flags(cx, SECP256K1_START_SIGN); // Check context is built for signing @@ -1682,7 +1936,6 @@ mod fuzz_dummy { 1 } - // Forwards to regular schnorrsig_sign function. pub unsafe fn secp256k1_schnorrsig_sign_custom( cx: *const Context, @@ -1702,10 +1955,14 @@ mod fuzz_dummy { seckey: *const c_uchar, ) -> c_int { check_context_flags(cx, SECP256K1_START_SIGN); - if secp256k1_ec_seckey_verify(cx, seckey) == 0 { return 0; } + if secp256k1_ec_seckey_verify(cx, seckey) == 0 { + return 0; + } let mut pk = PublicKey::new(); - if secp256k1_ec_pubkey_create(cx, &mut pk, seckey) == 0 { return 0; } + if secp256k1_ec_pubkey_create(cx, &mut pk, seckey) == 0 { + return 0; + } let seckey_slice = slice::from_raw_parts(seckey, 32); (*keypair).0[..32].copy_from_slice(seckey_slice); @@ -1767,7 +2024,7 @@ mod fuzz_dummy { cx: *const Context, pubkey: *mut XOnlyPublicKey, pk_parity: *mut c_int, - keypair: *const Keypair + keypair: *const Keypair, ) -> c_int { check_context_flags(cx, 0); if !pk_parity.is_null() { @@ -1803,9 +2060,14 @@ mod fuzz_dummy { ) -> c_int { check_context_flags(cx, SECP256K1_START_VERIFY); let mut tweaked_pk = PublicKey::new(); - assert_eq!(secp256k1_xonly_pubkey_tweak_add(cx, &mut tweaked_pk, internal_pubkey, tweak32), 1); + assert_eq!( + secp256k1_xonly_pubkey_tweak_add(cx, &mut tweaked_pk, internal_pubkey, tweak32), + 1 + ); let in_slice = slice::from_raw_parts(tweaked_pubkey32, 32); - if &tweaked_pk.0[..32] == in_slice && tweaked_pubkey_parity == (tweaked_pk.0[32] == 0).into() { + if &tweaked_pk.0[..32] == in_slice + && tweaked_pubkey_parity == (tweaked_pk.0[32] == 0).into() + { 1 } else { 0 @@ -1822,12 +2084,12 @@ mod tests { #[test] fn test_strlen() { use std::ffi::CString; + use super::strlen; let orig = "test strlen \t \n"; let test = CString::new(orig).unwrap(); - assert_eq!(orig.len(), unsafe {strlen(test.as_ptr())}); + assert_eq!(orig.len(), unsafe { strlen(test.as_ptr()) }); } } - diff --git a/secp256k1-sys/src/macros.rs b/secp256k1-sys/src/macros.rs index ec225ab48..174e1d8d7 100644 --- a/secp256k1-sys/src/macros.rs +++ b/secp256k1-sys/src/macros.rs @@ -27,9 +27,7 @@ macro_rules! impl_array_newtype { /// serializing it to a guaranteed format). This means they may be slow, this function /// provides a faster equality check if you know that your types come from the same /// library version. - pub fn eq_fast_unstable(&self, other: &Self) -> bool { - self[..].eq(&other[..]) - } + pub fn eq_fast_unstable(&self, other: &Self) -> bool { self[..].eq(&other[..]) } } impl AsRef<[$ty; $len]> for $thing { @@ -64,7 +62,7 @@ macro_rules! impl_array_newtype { dat.as_mut_ptr() } } - } + }; } #[macro_export] @@ -78,5 +76,5 @@ macro_rules! impl_raw_debug { Ok(()) } } - } + }; } diff --git a/secp256k1-sys/src/recovery.rs b/secp256k1-sys/src/recovery.rs index 0a5c2aaea..9747fe00a 100644 --- a/secp256k1-sys/src/recovery.rs +++ b/secp256k1-sys/src/recovery.rs @@ -2,10 +2,13 @@ //! # FFI of the recovery module -use crate::{Context, Signature, NonceFn, PublicKey, CPtr, impl_array_newtype, secp256k1_context_no_precomp}; -use crate::types::*; use core::fmt; +use crate::types::*; +use crate::{ + impl_array_newtype, secp256k1_context_no_precomp, CPtr, Context, NonceFn, PublicKey, Signature, +}; + /// Library-internal representation of a Secp256k1 signature + recovery ID #[repr(C)] #[derive(Copy, Clone)] @@ -36,9 +39,7 @@ impl RecoverableSignature { } impl Default for RecoverableSignature { - fn default() -> Self { - RecoverableSignature::new() - } + fn default() -> Self { RecoverableSignature::new() } } impl fmt::Debug for RecoverableSignature { @@ -83,9 +84,7 @@ impl Ord for RecoverableSignature { #[cfg(not(secp256k1_fuzz))] impl PartialEq for RecoverableSignature { - fn eq(&self, other: &Self) -> bool { - self.cmp(other) == core::cmp::Ordering::Equal - } + fn eq(&self, other: &Self) -> bool { self.cmp(other) == core::cmp::Ordering::Equal } } #[cfg(not(secp256k1_fuzz))] @@ -100,48 +99,72 @@ impl core::hash::Hash for RecoverableSignature { } extern "C" { - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact")] - pub fn secp256k1_ecdsa_recoverable_signature_parse_compact(cx: *const Context, sig: *mut RecoverableSignature, - input64: *const c_uchar, recid: c_int) - -> c_int; - - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_recoverable_signature_serialize_compact")] - pub fn secp256k1_ecdsa_recoverable_signature_serialize_compact(cx: *const Context, output64: *mut c_uchar, - recid: *mut c_int, sig: *const RecoverableSignature) - -> c_int; - - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_recoverable_signature_convert")] - pub fn secp256k1_ecdsa_recoverable_signature_convert(cx: *const Context, sig: *mut Signature, - input: *const RecoverableSignature) - -> c_int; + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact" + )] + pub fn secp256k1_ecdsa_recoverable_signature_parse_compact( + cx: *const Context, + sig: *mut RecoverableSignature, + input64: *const c_uchar, + recid: c_int, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ecdsa_recoverable_signature_serialize_compact" + )] + pub fn secp256k1_ecdsa_recoverable_signature_serialize_compact( + cx: *const Context, + output64: *mut c_uchar, + recid: *mut c_int, + sig: *const RecoverableSignature, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ecdsa_recoverable_signature_convert" + )] + pub fn secp256k1_ecdsa_recoverable_signature_convert( + cx: *const Context, + sig: *mut Signature, + input: *const RecoverableSignature, + ) -> c_int; } #[cfg(not(secp256k1_fuzz))] extern "C" { - #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_sign_recoverable")] - pub fn secp256k1_ecdsa_sign_recoverable(cx: *const Context, - sig: *mut RecoverableSignature, - msg32: *const c_uchar, - sk: *const c_uchar, - noncefn: NonceFn, - noncedata: *const c_void) - -> c_int; + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ecdsa_sign_recoverable" + )] + pub fn secp256k1_ecdsa_sign_recoverable( + cx: *const Context, + sig: *mut RecoverableSignature, + msg32: *const c_uchar, + sk: *const c_uchar, + noncefn: NonceFn, + noncedata: *const c_void, + ) -> c_int; #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_recover")] - pub fn secp256k1_ecdsa_recover(cx: *const Context, - pk: *mut PublicKey, - sig: *const RecoverableSignature, - msg32: *const c_uchar) - -> c_int; + pub fn secp256k1_ecdsa_recover( + cx: *const Context, + pk: *mut PublicKey, + sig: *const RecoverableSignature, + msg32: *const c_uchar, + ) -> c_int; } - #[cfg(secp256k1_fuzz)] mod fuzz_dummy { use core::slice; - use crate::{secp256k1_ec_pubkey_create, secp256k1_ec_pubkey_parse, secp256k1_ec_pubkey_serialize, SECP256K1_SER_COMPRESSED}; use super::*; + use crate::{ + secp256k1_ec_pubkey_create, secp256k1_ec_pubkey_parse, secp256k1_ec_pubkey_serialize, + SECP256K1_SER_COMPRESSED, + }; /// Sets sig to msg32||full pk pub unsafe fn secp256k1_ecdsa_sign_recoverable( @@ -162,7 +185,13 @@ mod fuzz_dummy { let msg_sl = slice::from_raw_parts(msg32 as *const u8, 32); sig_sl[..32].copy_from_slice(msg_sl); let mut out_len: size_t = 33; - secp256k1_ec_pubkey_serialize(cx, sig_sl[32..].as_mut_ptr(), &mut out_len, &new_pk, SECP256K1_SER_COMPRESSED); + secp256k1_ec_pubkey_serialize( + cx, + sig_sl[32..].as_mut_ptr(), + &mut out_len, + &new_pk, + SECP256K1_SER_COMPRESSED, + ); // Encode the parity of the pubkey in the final byte as 0/1, // which is the same encoding (though the parity is computed // differently) as real recoverable signatures. @@ -175,7 +204,7 @@ mod fuzz_dummy { cx: *const Context, pk: *mut PublicKey, sig: *const RecoverableSignature, - msg32: *const c_uchar + msg32: *const c_uchar, ) -> c_int { let sig_sl = slice::from_raw_parts(sig as *const u8, 65); let msg_sl = slice::from_raw_parts(msg32 as *const u8, 32); diff --git a/secp256k1-sys/src/types.rs b/secp256k1-sys/src/types.rs index e52b5bfc9..87d75a84b 100644 --- a/secp256k1-sys/src/types.rs +++ b/secp256k1-sys/src/types.rs @@ -19,13 +19,11 @@ pub use core::ffi::c_void; // 16 matches is as big as the biggest alignment in any arch that rust currently supports https://github.com/rust-lang/rust/blob/2c31b45ae878b821975c4ebd94cc1e49f6073fd0/library/std/src/sys_common/alloc.rs #[repr(align(16))] #[derive(Default, Copy, Clone)] -#[allow(dead_code)] // We never access the inner data directly, only by way of a pointer. +#[allow(dead_code)] // We never access the inner data directly, only by way of a pointer. pub struct AlignedType([u8; 16]); impl AlignedType { - pub fn zeroed() -> Self { - AlignedType([0u8; 16]) - } + pub fn zeroed() -> Self { AlignedType([0u8; 16]) } /// A static zeroed out AlignedType for use in static assignments of [AlignedType; _] pub const ZERO: AlignedType = AlignedType([0u8; 16]); @@ -40,6 +38,7 @@ mod tests { use std::any::TypeId; use std::mem; use std::os::raw; + use crate::{types, AlignedType}; #[test] From 07922fd7ee4223f687ea1a4fe1fda75485327e10 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Thu, 15 May 2025 14:03:41 +0000 Subject: [PATCH 02/15] musig: fix a couple FFI bindings Claude identified a couple of the FFI bindings to MuSig that were incorrect. --- secp256k1-sys/src/lib.rs | 4 ++-- src/musig.rs | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/secp256k1-sys/src/lib.rs b/secp256k1-sys/src/lib.rs index 929db7c3e..408682d83 100644 --- a/secp256k1-sys/src/lib.rs +++ b/secp256k1-sys/src/lib.rs @@ -843,7 +843,7 @@ extern "C" { cx: *const Context, secnonce: *mut MusigSecNonce, pubnonce: *mut MusigPubNonce, - session_secrand32: *const c_uchar, + session_secrand32: *mut c_uchar, seckey: *const c_uchar, pubkey: *const PublicKey, msg32: *const c_uchar, @@ -915,7 +915,7 @@ extern "C" { #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ec_pubkey_sort")] pub fn secp256k1_ec_pubkey_sort( ctx: *const Context, - pubkeys: *mut *const PublicKey, + pubkeys: *const *const PublicKey, n_pubkeys: size_t, ) -> c_int; } diff --git a/src/musig.rs b/src/musig.rs index 68f6b0c73..8393b60ea 100644 --- a/src/musig.rs +++ b/src/musig.rs @@ -68,6 +68,11 @@ impl SessionSecretRand { /// Obtains a reference to the inner bytes of the [`SessionSecretRand`]. pub fn as_bytes(&self) -> &[u8; 32] { &self.0 } + + /// Obtains a mutable raw pointer to the beginning of the underlying storage. + /// + /// This is a low-level function and not exposed in the public API. + fn as_mut_ptr(&mut self) -> *mut u8 { self.0.as_mut_ptr() } } /// Cached data related to a key aggregation. @@ -154,7 +159,7 @@ impl fmt::Display for InvalidTweakErr { /// ``` pub fn new_nonce_pair( secp: &Secp256k1, - session_secrand: SessionSecretRand, + mut session_secrand: SessionSecretRand, key_agg_cache: Option<&KeyAggCache>, sec_key: Option, pub_key: PublicKey, @@ -167,13 +172,19 @@ pub fn new_nonce_pair( 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()); 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 + // behavior of `secp256k1_musig_nonce_gen` on error is to zero out the secret + // nonce. We guarantee this won't happen, but also if it does, it's harmless + // to zero out a local variable without propagating that change back to the + // 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_bytes().as_ptr(), + session_secrand.as_mut_ptr(), sk_ptr, pub_key.as_c_ptr(), msg_ptr, From 7c56bcc187b7bcd2ce860fffc1d280398ba42108 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Thu, 15 May 2025 19:46:10 +0000 Subject: [PATCH 03/15] clippy: whitelist a bunch of lints Copy the list of whitelisted lints from BlockstreamResearch/simfony. The "uninlined format args" one was the only one that was currently triggering here. --- Cargo.toml | 10 ++++++++++ secp256k1-sys/Cargo.toml | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 4e8614f7c..6c870a955 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,3 +73,13 @@ required-features = ["rand", "std"] [workspace] members = ["secp256k1-sys"] exclude = ["no_std_test"] + +[lints.clippy] +# Exclude lints we don't think are valuable. +large_enum_variant = "allow" # docs say "measure before paying attention to this"; why is it on by default?? +similar_names = "allow" # Too many (subjectively) false positives. +uninlined_format_args = "allow" # This is a subjective style choice. +indexing_slicing = "allow" # Too many false positives ... would be cool though +match_bool = "allow" # Adds extra indentation and LOC. +match_same_arms = "allow" # Collapses things that are conceptually unrelated to each other. +must_use_candidate = "allow" # Useful for audit but many false positives. diff --git a/secp256k1-sys/Cargo.toml b/secp256k1-sys/Cargo.toml index 7a5e98b62..3c7f7c36d 100644 --- a/secp256k1-sys/Cargo.toml +++ b/secp256k1-sys/Cargo.toml @@ -35,3 +35,13 @@ alloc = [] [lints.rust] unexpected_cfgs = { level = "deny", check-cfg = ['cfg(bench)', 'cfg(secp256k1_fuzz)', 'cfg(rust_secp_no_symbol_renaming)'] } + +[lints.clippy] +# Exclude lints we don't think are valuable. +large_enum_variant = "allow" # docs say "measure before paying attention to this"; why is it on by default?? +similar_names = "allow" # Too many (subjectively) false positives. +uninlined_format_args = "allow" # This is a subjective style choice. +indexing_slicing = "allow" # Too many false positives ... would be cool though +match_bool = "allow" # Adds extra indentation and LOC. +match_same_arms = "allow" # Collapses things that are conceptually unrelated to each other. +must_use_candidate = "allow" # Useful for audit but many false positives. \ No newline at end of file From 9615ec8a8dcf192054e19a40bfc5ffe230ad03c3 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Thu, 15 May 2025 19:46:10 +0000 Subject: [PATCH 04/15] context: whitelist new compiler warning The compiler doesn't like shared references to static mut variables, because it is worried that we'll share a reference while a mutation happens which is UB. We are only sharing references after using Once to do a one-time initialization, so this is fine, but in recent versions of the compiler there is an encapsulated form of this pattern called `OnceLock` and a variant called `LazyLock`. Neither of these are available on our MSRV so just whitelist the lint. --- src/context.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/context.rs b/src/context.rs index d8955a945..58348a090 100644 --- a/src/context.rs +++ b/src/context.rs @@ -42,6 +42,8 @@ pub mod global { type Target = Secp256k1; #[allow(unused_mut)] // Unused when `rand` + `std` is not enabled. + #[allow(static_mut_refs)] // The "proper" way to do this is with OnceLock (MSRV 1.70) or LazyLock (MSRV 1.80) + // See https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html fn deref(&self) -> &Self::Target { static ONCE: Once = Once::new(); static mut CONTEXT: Option> = None; From 4dd861fed4e5c2e2f41b42ddeeada4498233d33e Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Thu, 15 May 2025 13:34:30 +0000 Subject: [PATCH 05/15] stop using deprecated thread_rng In rand 0.9 `thread_rng` has been renamed to `rng`. The recent Musig2 PR predates the transition to rand 0.9. --- examples/musig.rs | 2 +- src/ecdsa/mod.rs | 2 +- src/key.rs | 6 ++-- src/musig.rs | 74 +++++++++++++++++++++++------------------------ 4 files changed, 42 insertions(+), 42 deletions(-) diff --git a/examples/musig.rs b/examples/musig.rs index edd654a80..7bb6aa64e 100644 --- a/examples/musig.rs +++ b/examples/musig.rs @@ -8,7 +8,7 @@ use secp256k1::{pubkey_sort, Keypair, Message, PublicKey, Scalar, Secp256k1, Sec fn main() { let secp = Secp256k1::new(); - let mut rng = rand::thread_rng(); + let mut rng = rand::rng(); let (seckey1, pubkey1) = secp.generate_keypair(&mut rng); diff --git a/src/ecdsa/mod.rs b/src/ecdsa/mod.rs index 1cf57c134..65c25d854 100644 --- a/src/ecdsa/mod.rs +++ b/src/ecdsa/mod.rs @@ -371,7 +371,7 @@ impl Secp256k1 { /// # use secp256k1::{rand, Secp256k1, Message, Error}; /// # /// # let secp = Secp256k1::new(); - /// # let (secret_key, public_key) = secp.generate_keypair(&mut rand::thread_rng()); + /// # 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); diff --git a/src/key.rs b/src/key.rs index b7977f5f6..47c263fea 100644 --- a/src/key.rs +++ b/src/key.rs @@ -1622,12 +1622,12 @@ impl<'de> serde::Deserialize<'de> for XOnlyPublicKey { /// /// ```rust /// # # [cfg(any(test, feature = "rand-std"))] { -/// # use secp256k1::rand::{thread_rng, RngCore}; +/// # use secp256k1::rand::{rng, RngCore}; /// # use secp256k1::{Secp256k1, SecretKey, Keypair, PublicKey, pubkey_sort}; /// # let secp = Secp256k1::new(); -/// # let sk1 = SecretKey::new(&mut thread_rng()); +/// # let sk1 = SecretKey::new(&mut rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); -/// # let sk2 = SecretKey::new(&mut thread_rng()); +/// # let sk2 = SecretKey::new(&mut rng()); /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); /// # /// # let pubkeys = [pub_key1, pub_key2]; diff --git a/src/musig.rs b/src/musig.rs index 8393b60ea..5413bed06 100644 --- a/src/musig.rs +++ b/src/musig.rs @@ -44,7 +44,7 @@ pub struct SessionSecretRand([u8; 32]); impl SessionSecretRand { /// Generates a new session ID using thread RNG. #[cfg(all(feature = "rand", feature = "std"))] - pub fn new() -> Self { Self::from_rng(&mut rand::thread_rng()) } + pub fn new() -> Self { Self::from_rng(&mut rand::rng()) } /// Creates a new [`SessionSecretRand`] with random bytes from the given rng #[cfg(feature = "rand")] @@ -142,12 +142,12 @@ impl fmt::Display for InvalidTweakErr { /// /// ```rust /// # # [cfg(any(test, feature = "rand-std"))] { -/// # use secp256k1::rand::{thread_rng, RngCore}; +/// # use secp256k1::rand::{rng, RngCore}; /// # use secp256k1::{PublicKey, Secp256k1, SecretKey, 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::new(&mut thread_rng()); -/// let sk = SecretKey::new(&mut thread_rng()); +/// let session_secrand = SessionSecretRand::new(&mut rng()); +/// let sk = SecretKey::new(&mut rng()); /// let pk = PublicKey::from_secret_key(&secp, &sk); /// /// // Supply extra auxillary randomness to prevent misuse(for example, time of day) @@ -298,12 +298,12 @@ impl KeyAggCache { /// /// ```rust /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{thread_rng, RngCore}; + /// # use secp256k1::rand::{rng, RngCore}; /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey}; /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut thread_rng()); + /// # let sk1 = SecretKey::new(&mut rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_rng()); + /// # let sk2 = SecretKey::new(&mut rng()); /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); /// # /// let key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); @@ -387,12 +387,12 @@ impl KeyAggCache { /// /// ```rust /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{thread_rng, RngCore}; + /// # use secp256k1::rand::{rng, RngCore}; /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey}; /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut thread_rng()); + /// # let sk1 = SecretKey::new(&mut rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_rng()); + /// # let sk2 = SecretKey::new(&mut rng()); /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); /// # /// let mut key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); @@ -446,12 +446,12 @@ impl KeyAggCache { /// /// ```rust /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{thread_rng, RngCore}; + /// # use secp256k1::rand::{rng, RngCore}; /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey}; /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut thread_rng()); + /// # let sk1 = SecretKey::new(&mut rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_rng()); + /// # let sk2 = SecretKey::new(&mut rng()); /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); /// /// let mut key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); @@ -520,17 +520,17 @@ impl KeyAggCache { /// /// ```rust /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{thread_rng, RngCore}; + /// # use secp256k1::rand::{rng, RngCore}; /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, SessionSecretRand, Message}; /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut thread_rng()); + /// # let sk1 = SecretKey::new(&mut rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_rng()); + /// # let sk2 = SecretKey::new(&mut rng()); /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); /// # /// let key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); /// // The session id must be sampled at random. Read documentation for more details. - /// let session_secrand = SessionSecretRand::new(&mut thread_rng()); + /// let session_secrand = SessionSecretRand::new(&mut rng()); /// /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); /// @@ -708,12 +708,12 @@ impl AggregatedNonce { /// /// ```rust /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{thread_rng, RngCore}; + /// # use secp256k1::rand::{rng, RngCore}; /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, SessionSecretRand, Message, AggregatedNonce}; /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut thread_rng()); + /// # let sk1 = SecretKey::new(&mut rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_rng()); + /// # let sk2 = SecretKey::new(&mut rng()); /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); /// /// # let key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); @@ -721,12 +721,12 @@ impl AggregatedNonce { /// /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); /// - /// let session_secrand1 = SessionSecretRand::new(&mut thread_rng()); + /// let session_secrand1 = SessionSecretRand::new(&mut rng()); /// let (_sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(&secp, 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::new(&mut thread_rng()); + /// let session_secrand2 = SessionSecretRand::new(&mut rng()); /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_secrand2, pub_key2, msg, None) /// .expect("non zero session id"); /// @@ -870,12 +870,12 @@ impl Session { /// /// ```rust /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{thread_rng, RngCore}; + /// # use secp256k1::rand::{rng, RngCore}; /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, SessionSecretRand, Message, AggregatedNonce, Session}; /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut thread_rng()); + /// # let sk1 = SecretKey::new(&mut rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_rng()); + /// # let sk2 = SecretKey::new(&mut rng()); /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); /// /// # let key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); @@ -884,13 +884,13 @@ impl Session { /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); /// /// // Provide the current time for mis-use resistance - /// let session_secrand1 = SessionSecretRand::new(&mut thread_rng()); + /// let session_secrand1 = SessionSecretRand::new(&mut 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) /// .expect("non zero session id"); /// /// // Signer two does the same. Possibly on a different device - /// let session_secrand2 = SessionSecretRand::new(&mut thread_rng()); + /// let session_secrand2 = SessionSecretRand::new(&mut 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) /// .expect("non zero session id"); @@ -1006,12 +1006,12 @@ impl Session { /// /// ```rust /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{thread_rng, RngCore}; + /// # use secp256k1::rand::{rng, RngCore}; /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, SessionSecretRand, Message, AggregatedNonce, Session}; /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut thread_rng()); + /// # let sk1 = SecretKey::new(&mut rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_rng()); + /// # let sk2 = SecretKey::new(&mut rng()); /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); /// /// # let key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); @@ -1020,12 +1020,12 @@ impl Session { /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); /// /// // Provide the current time for mis-use resistance - /// let session_secrand1 = SessionSecretRand::new(&mut thread_rng()); + /// let session_secrand1 = SessionSecretRand::new(&mut rng()); /// let (mut sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(&secp, 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::new(&mut thread_rng()); + /// let session_secrand2 = SessionSecretRand::new(&mut rng()); /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_secrand2, pub_key2, msg, None) /// .expect("non zero session id"); /// @@ -1089,12 +1089,12 @@ impl Session { /// /// ```rust /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{thread_rng, RngCore}; + /// # use secp256k1::rand::{rng, RngCore}; /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, SessionSecretRand, Message, AggregatedNonce, Session}; /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut thread_rng()); + /// # let sk1 = SecretKey::new(&mut rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_rng()); + /// # let sk2 = SecretKey::new(&mut rng()); /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); /// /// let key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); @@ -1103,12 +1103,12 @@ impl Session { /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); /// /// // Provide the current time for mis-use resistance - /// let session_secrand1 = SessionSecretRand::new(&mut thread_rng()); + /// let session_secrand1 = SessionSecretRand::new(&mut rng()); /// let (mut sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(&secp, 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::new(&mut thread_rng()); + /// let session_secrand2 = SessionSecretRand::new(&mut rng()); /// let (mut sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_secrand2, pub_key2, msg, None) /// .expect("non zero session id"); /// From 3b0232a7ebb92d5c173ee0da8f44ef6c18514f11 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Thu, 15 May 2025 19:46:10 +0000 Subject: [PATCH 06/15] musig: fix all the doctests Pretty-much all of the doctests included in #716 corresponded to an old version of the API. I'm unsure why it is that my local CI accepted this. The Github CI did not. --- src/musig.rs | 168 ++++++++++++++++++++++++++------------------------- 1 file changed, 85 insertions(+), 83 deletions(-) diff --git a/src/musig.rs b/src/musig.rs index 5413bed06..281ba51af 100644 --- a/src/musig.rs +++ b/src/musig.rs @@ -141,20 +141,20 @@ impl fmt::Display for InvalidTweakErr { /// Example: /// /// ```rust -/// # # [cfg(any(test, feature = "rand-std"))] { -/// # use secp256k1::rand::{rng, RngCore}; -/// # use secp256k1::{PublicKey, Secp256k1, SecretKey, new_nonce_pair, SessionSecretRand}; +/// # #[cfg(feature = "std")] +/// # #[cfg(feature = "rand")] { +/// # use secp256k1::{PublicKey, Secp256k1, 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::new(&mut rng()); -/// let sk = SecretKey::new(&mut rng()); +/// let session_secrand = SessionSecretRand::from_rng(&mut rand::rng()); +/// let sk = SecretKey::new(&mut rand::rng()); /// let pk = PublicKey::from_secret_key(&secp, &sk); /// /// // Supply extra auxillary 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) -/// .expect("non zero session id"); +/// let (_sec_nonce, _pub_nonce) = new_nonce_pair(&secp, session_secrand, None, Some(sk), pk, None, None); /// # } /// ``` pub fn new_nonce_pair( @@ -297,16 +297,17 @@ impl KeyAggCache { /// Example: /// /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{rng, RngCore}; - /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey}; + /// # #[cfg(feature = "std")] + /// # #[cfg(feature = "rand")] { + /// # use secp256k1::{Secp256k1, SecretKey, Keypair, PublicKey}; + /// # use secp256k1::musig::KeyAggCache; /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut rng()); + /// # let sk1 = SecretKey::new(&mut rand::rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut rng()); + /// # let sk2 = SecretKey::new(&mut rand::rng()); /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); /// # - /// let key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); + /// let key_agg_cache = KeyAggCache::new(&secp, &[&pub_key1, &pub_key2]); /// let _agg_pk = key_agg_cache.agg_pk(); /// # } /// ``` @@ -386,20 +387,22 @@ impl KeyAggCache { /// Example: /// /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{rng, RngCore}; - /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey}; + /// # #[cfg(not(secp256k1_fuzz))] + /// # #[cfg(feature = "std")] + /// # #[cfg(feature = "rand")] { + /// # use secp256k1::{Scalar, Secp256k1, SecretKey, Keypair, PublicKey}; + /// # use secp256k1::musig::KeyAggCache; /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut rng()); + /// # let sk1 = SecretKey::new(&mut rand::rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut rng()); + /// # let sk2 = SecretKey::new(&mut rand::rng()); /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); /// # - /// let mut key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); + /// let mut key_agg_cache = KeyAggCache::new(&secp, &[&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(&secp, &tweak).unwrap(); /// # } /// ``` pub fn pubkey_ec_tweak_add( @@ -445,19 +448,21 @@ impl KeyAggCache { /// Example: /// /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{rng, RngCore}; - /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey}; + /// # #[cfg(not(secp256k1_fuzz))] + /// # #[cfg(feature = "std")] + /// # #[cfg(feature = "rand")] { + /// # use secp256k1::{Scalar, Secp256k1, SecretKey, Keypair, PublicKey}; + /// # use secp256k1::musig::KeyAggCache; /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut rng()); + /// # let sk1 = SecretKey::new(&mut rand::rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut rng()); + /// # let sk2 = SecretKey::new(&mut rand::rng()); /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); /// - /// let mut key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); + /// let mut key_agg_cache = KeyAggCache::new(&secp, &[&pub_key1, &pub_key2]); /// - /// let tweak = SecretKey::from_slice(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 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(); /// # } /// ``` pub fn pubkey_xonly_tweak_add( @@ -519,25 +524,25 @@ impl KeyAggCache { /// Example: /// /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{rng, RngCore}; - /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, SessionSecretRand, Message}; + /// # #[cfg(feature = "std")] + /// # #[cfg(feature = "rand")] { + /// # use secp256k1::{Secp256k1, SecretKey, Keypair, PublicKey, Message}; + /// # use secp256k1::musig::{KeyAggCache, SessionSecretRand}; /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut rng()); + /// # let sk1 = SecretKey::new(&mut rand::rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut rng()); + /// # let sk2 = SecretKey::new(&mut rand::rng()); /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); /// # - /// let key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); + /// let key_agg_cache = KeyAggCache::new(&secp, &[&pub_key1, &pub_key2]); /// // The session id must be sampled at random. Read documentation for more details. - /// let session_secrand = SessionSecretRand::new(&mut rng()); + /// let session_secrand = SessionSecretRand::from_rng(&mut rand::rng()); /// /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); /// /// // Provide the current time for mis-use resistance /// 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) - /// .expect("non zero session id"); + /// let (_sec_nonce, _pub_nonce) = key_agg_cache.nonce_gen(&secp, session_secrand, pub_key1, msg, extra_rand); /// # } /// ``` pub fn nonce_gen( @@ -707,30 +712,29 @@ impl AggregatedNonce { /// Example: /// /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{rng, RngCore}; - /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, SessionSecretRand, Message, AggregatedNonce}; + /// # #[cfg(feature = "std")] + /// # #[cfg(feature = "rand")] { + /// # use secp256k1::{Secp256k1, SecretKey, Keypair, PublicKey, Message}; + /// # use secp256k1::musig::{AggregatedNonce, KeyAggCache, SessionSecretRand}; /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut rng()); + /// # let sk1 = SecretKey::new(&mut rand::rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut rng()); + /// # let sk2 = SecretKey::new(&mut rand::rng()); /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); /// - /// # let key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); + /// # let key_agg_cache = KeyAggCache::new(&secp, &[&pub_key1, &pub_key2]); /// // The session id must be sampled at random. Read documentation for more details. /// /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); /// - /// let session_secrand1 = SessionSecretRand::new(&mut rng()); - /// let (_sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(&secp, session_secrand1, pub_key1, msg, None) - /// .expect("non zero session id"); + /// 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); /// /// // Signer two does the same: Possibly on a different device - /// let session_secrand2 = SessionSecretRand::new(&mut rng()); - /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_secrand2, pub_key2, msg, None) - /// .expect("non zero session id"); + /// 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 aggnonce = AggregatedNonce::new(&secp, &[pub_nonce1, pub_nonce2]); + /// let aggnonce = AggregatedNonce::new(&secp, &[&pub_nonce1, &pub_nonce2]); /// # } /// ``` pub fn new(secp: &Secp256k1, nonces: &[&PublicNonce]) -> Self { @@ -869,33 +873,32 @@ impl Session { /// Example: /// /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{rng, RngCore}; - /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, SessionSecretRand, Message, AggregatedNonce, Session}; + /// # #[cfg(feature = "std")] + /// # #[cfg(feature = "rand")] { + /// # use secp256k1::{Secp256k1, SecretKey, Keypair, PublicKey, Message}; + /// # use secp256k1::musig::{AggregatedNonce, KeyAggCache, Session, SessionSecretRand}; /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut rng()); + /// # let sk1 = SecretKey::new(&mut rand::rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut rng()); + /// # let sk2 = SecretKey::new(&mut rand::rng()); /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); /// - /// # let key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); + /// # let key_agg_cache = KeyAggCache::new(&secp, &[&pub_key1, &pub_key2]); /// // The session id must be sampled at random. Read documentation for more details. /// /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); /// /// // Provide the current time for mis-use resistance - /// let session_secrand1 = SessionSecretRand::new(&mut rng()); + /// 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) - /// .expect("non zero session id"); + /// let (_sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(&secp, session_secrand1, pub_key1, msg, extra_rand1); /// /// // Signer two does the same. Possibly on a different device - /// let session_secrand2 = SessionSecretRand::new(&mut rng()); + /// 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) - /// .expect("non zero session id"); + /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_secrand2, pub_key2, msg, extra_rand2); /// - /// let aggnonce = AggregatedNonce::new(&secp, &[pub_nonce1, pub_nonce2]); + /// let aggnonce = AggregatedNonce::new(&secp, &[&pub_nonce1, &pub_nonce2]); /// /// let session = Session::new( /// &secp, @@ -1005,31 +1008,31 @@ impl Session { /// Example: /// /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{rng, RngCore}; - /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, SessionSecretRand, Message, AggregatedNonce, Session}; + /// # #[cfg(not(secp256k1_fuzz))] + /// # #[cfg(feature = "std")] + /// # #[cfg(feature = "rand")] { + /// # use secp256k1::{Secp256k1, SecretKey, Keypair, PublicKey, Message}; + /// # use secp256k1::musig::{AggregatedNonce, KeyAggCache, SessionSecretRand, Session}; /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut rng()); + /// # let sk1 = SecretKey::new(&mut rand::rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut rng()); + /// # let sk2 = SecretKey::new(&mut rand::rng()); /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); /// - /// # let key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); + /// # let key_agg_cache = KeyAggCache::new(&secp, &[&pub_key1, &pub_key2]); /// // The session id must be sampled at random. Read documentation for more details. /// /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); /// /// // Provide the current time for mis-use resistance - /// let session_secrand1 = SessionSecretRand::new(&mut rng()); - /// let (mut sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(&secp, session_secrand1, pub_key1, msg, None) - /// .expect("non zero session id"); + /// 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); /// /// // Signer two does the same. Possibly on a different device - /// let session_secrand2 = SessionSecretRand::new(&mut rng()); - /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_secrand2, pub_key2, msg, None) - /// .expect("non zero session id"); + /// 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 aggnonce = AggregatedNonce::new(&secp, &[pub_nonce1, pub_nonce2]); + /// let aggnonce = AggregatedNonce::new(&secp, &[&pub_nonce1, &pub_nonce2]); /// /// let session = Session::new( /// &secp, @@ -1044,7 +1047,7 @@ impl Session { /// sec_nonce1, /// &keypair, /// &key_agg_cache, - /// ).unwrap(); + /// ); /// /// assert!(session.partial_verify( /// &secp, @@ -1088,13 +1091,12 @@ impl Session { /// * `partial_sigs`: Array of [`PartialSignature`] to be aggregated /// /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{rng, RngCore}; + /// # #[cfg(feature = "rand-std")] { /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, SessionSecretRand, Message, AggregatedNonce, Session}; /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut rng()); + /// # let sk1 = SecretKey::new(&mut rand::rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut rng()); + /// # let sk2 = SecretKey::new(&mut rand::rng()); /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); /// /// let key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); @@ -1103,12 +1105,12 @@ impl Session { /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); /// /// // Provide the current time for mis-use resistance - /// let session_secrand1 = SessionSecretRand::new(&mut rng()); + /// 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) /// .expect("non zero session id"); /// /// // Signer two does the same. Possibly on a different device - /// let session_secrand2 = SessionSecretRand::new(&mut rng()); + /// 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) /// .expect("non zero session id"); /// From 00c8c75d1acc3e3b9d8d715e652778b5d8bba74c Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Thu, 15 May 2025 20:16:22 +0000 Subject: [PATCH 07/15] musig: remove outdated doc references to ZeroSession error --- src/musig.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/musig.rs b/src/musig.rs index 281ba51af..557087fbb 100644 --- a/src/musig.rs +++ b/src/musig.rs @@ -134,10 +134,6 @@ impl fmt::Display for InvalidTweakErr { /// /// Remember that nonce reuse will immediately leak the secret key! /// -/// # Errors: -/// -/// * `ZeroSession`: if the `session_secrand` is supplied is all zeros. -/// /// Example: /// /// ```rust @@ -517,10 +513,6 @@ impl KeyAggCache { /// * `msg`: [`Message`] that will be signed later on. /// * `extra_rand`: Additional randomness for mis-use resistance /// - /// # Errors: - /// - /// * `ZeroSession`: if the `session_secrand` is supplied is all zeros. - /// /// Example: /// /// ```rust From 6d938d30b790d7828579c3bfc1c0aa502998f3f3 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Thu, 15 May 2025 23:44:29 +0000 Subject: [PATCH 08/15] musig: add missing Panics sections to docs --- src/musig.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/musig.rs b/src/musig.rs index 557087fbb..9da84d63b 100644 --- a/src/musig.rs +++ b/src/musig.rs @@ -307,6 +307,10 @@ impl KeyAggCache { /// let _agg_pk = key_agg_cache.agg_pk(); /// # } /// ``` + /// + /// # Panics + /// + /// Panics if an empty slice of pubkeys is provided. pub fn new(secp: &Secp256k1, pubkeys: &[&PublicKey]) -> Self { let cx = secp.ctx().as_ptr(); @@ -729,6 +733,10 @@ impl AggregatedNonce { /// let aggnonce = AggregatedNonce::new(&secp, &[&pub_nonce1, &pub_nonce2]); /// # } /// ``` + /// # Panics + /// + /// Panics if an empty slice of nonces is provided. + /// pub fn new(secp: &Secp256k1, nonces: &[&PublicNonce]) -> Self { if nonces.is_empty() { panic!("Cannot aggregate an empty slice of nonces"); @@ -1140,6 +1148,10 @@ impl Session { /// assert!(aggregated_signature.verify(&secp, &agg_pk, &msg_bytes).is_ok()); /// # } /// ``` + /// + /// # Panics + /// + /// Panics if an empty slice of partial signatures is provided. pub fn partial_sig_agg(&self, partial_sigs: &[&PartialSignature]) -> AggregatedSignature { if partial_sigs.is_empty() { panic!("Cannot aggregate an empty slice of partial signatures"); From ec66003e68aa6dbfd25e1a72c095bd9586b776e9 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Thu, 15 May 2025 20:06:50 +0000 Subject: [PATCH 09/15] musig: remove SessionSecretRand::new constructor This is just a convenience wrapper around SessionSecretRand::from_rng(&mut rng()). The name `new` disguises the fact that this is an impure function and actually calls a RNG every time it is called. It is also unused, in the docs or in the tests. Finally, clippy complains about it because it feels that a `new` method should always be accompanied by a `Default` impl...which is fair, but the impurity is veen more surprising for `default` than for `new`. Since `rand` renamed `thread_rng` to just `rng` the keystroke-saving value of this method is less. So just delete it. --- src/musig.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/musig.rs b/src/musig.rs index 9da84d63b..8702056e7 100644 --- a/src/musig.rs +++ b/src/musig.rs @@ -42,10 +42,6 @@ impl fmt::Display for ParseError { pub struct SessionSecretRand([u8; 32]); impl SessionSecretRand { - /// Generates a new session ID using thread RNG. - #[cfg(all(feature = "rand", feature = "std"))] - pub fn new() -> Self { Self::from_rng(&mut rand::rng()) } - /// Creates a new [`SessionSecretRand`] with random bytes from the given rng #[cfg(feature = "rand")] pub fn from_rng(rng: &mut R) -> Self { @@ -59,8 +55,8 @@ impl SessionSecretRand { /// [`KeyAggCache::nonce_gen`] or [`new_nonce_pair`]. The simplest /// recommendation is to use a cryptographicaly random 32-byte value. /// - /// In rand-std environment, [`SessionSecretRand::new`] can be used to generate a random - /// session id using thread rng. + /// If the **rand** feature is enabled, [`SessionSecretRand::from_rng`] can be used to generate a + /// random session id. pub fn assume_unique_per_nonce_gen(inner: [u8; 32]) -> Self { SessionSecretRand(inner) } /// Obtains the inner bytes of the [`SessionSecretRand`]. From c492c75f2d6a08ccae1761d8256b41cef8e0bd17 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Thu, 15 May 2025 20:06:50 +0000 Subject: [PATCH 10/15] key: move pubkey_sort to method on Secp256k1; rename This feels more natural as `secp.musig_sort_pubkeys` rather than `musig::pubkey_sort. --- examples/musig.rs | 4 ++-- src/key.rs | 61 +++++++++++++++++++++++++---------------------- src/lib.rs | 4 +--- 3 files changed, 35 insertions(+), 34 deletions(-) diff --git a/examples/musig.rs b/examples/musig.rs index 7bb6aa64e..0f432bf5f 100644 --- a/examples/musig.rs +++ b/examples/musig.rs @@ -4,7 +4,7 @@ use secp256k1::musig::{ new_nonce_pair, AggregatedNonce, KeyAggCache, PartialSignature, PublicNonce, Session, SessionSecretRand, }; -use secp256k1::{pubkey_sort, Keypair, Message, PublicKey, Scalar, Secp256k1, SecretKey}; +use secp256k1::{Keypair, Message, PublicKey, Scalar, Secp256k1, SecretKey}; fn main() { let secp = Secp256k1::new(); @@ -19,7 +19,7 @@ fn main() { let mut pubkeys_ref: Vec<&PublicKey> = pubkeys.iter().collect(); let pubkeys_ref = pubkeys_ref.as_mut_slice(); - pubkey_sort(&secp, pubkeys_ref); + secp.musig_sort_pubkeys(pubkeys_ref); let mut musig_key_agg_cache = KeyAggCache::new(&secp, pubkeys_ref); diff --git a/src/key.rs b/src/key.rs index 47c263fea..b2e6b6874 100644 --- a/src/key.rs +++ b/src/key.rs @@ -1617,35 +1617,38 @@ impl<'de> serde::Deserialize<'de> for XOnlyPublicKey { } } -/// Sort public keys using lexicographic (of compressed serialization) order. -/// 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(); -/// # -/// # pubkey_sort(&secp, pubkeys_ref); -/// # } -/// ``` -pub fn pubkey_sort(secp: &Secp256k1, pubkeys: &mut [&PublicKey]) { - let cx = secp.ctx().as_ptr(); - unsafe { - let mut pubkeys_ref = core::slice::from_raw_parts( - pubkeys.as_c_ptr() as *mut *const ffi::PublicKey, - pubkeys.len(), - ); - if secp256k1_ec_pubkey_sort(cx, pubkeys_ref.as_mut_c_ptr(), pubkeys_ref.len()) == 0 { - unreachable!("Invalid public keys for sorting function") +impl Secp256k1 { + /// Sort public keys using lexicographic (of compressed serialization) order. + /// + /// 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.musig_sort_pubkeys(pubkeys_ref); + /// # } + /// ``` + pub fn musig_sort_pubkeys(&self, pubkeys: &mut [&PublicKey]) { + let cx = self.ctx().as_ptr(); + unsafe { + let mut pubkeys_ref = core::slice::from_raw_parts( + pubkeys.as_c_ptr() as *mut *const ffi::PublicKey, + pubkeys.len(), + ); + if secp256k1_ec_pubkey_sort(cx, pubkeys_ref.as_mut_c_ptr(), pubkeys_ref.len()) == 0 { + unreachable!("Invalid public keys for sorting function") + } } } } diff --git a/src/lib.rs b/src/lib.rs index 75a9fba23..b001db3e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -192,9 +192,7 @@ pub use crate::context::{ }; use crate::ffi::types::AlignedType; use crate::ffi::CPtr; -pub use crate::key::{ - pubkey_sort, InvalidParityValue, Keypair, Parity, PublicKey, SecretKey, XOnlyPublicKey, -}; +pub use crate::key::{InvalidParityValue, Keypair, Parity, PublicKey, SecretKey, XOnlyPublicKey}; pub use crate::scalar::Scalar; /// Trait describing something that promises to be a 32-byte uniformly random number. From dc04575e68a3e7181e1d022c263c24a4cdb3abd5 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Thu, 15 May 2025 20:19:22 +0000 Subject: [PATCH 11/15] musig: a couple small improvements of byte array APIs I decided not to rename the `serialize` functions to `to_byte_array`. Maybe we should do that, but we use the name `serialize` *all over* this library so we should do it in a separate PR that changes everything. Along the way we'll have to decide what to call the methods that produce e.g. a SerializedSignature; this is conceptually a byte array but it's actually not one. --- src/musig.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/musig.rs b/src/musig.rs index 8702056e7..8f96547b8 100644 --- a/src/musig.rs +++ b/src/musig.rs @@ -57,13 +57,23 @@ impl SessionSecretRand { /// /// If the **rand** feature is enabled, [`SessionSecretRand::from_rng`] can be used to generate a /// random session id. - pub fn assume_unique_per_nonce_gen(inner: [u8; 32]) -> Self { SessionSecretRand(inner) } + /// + /// # Panics + /// + /// Panics if passed the all-zeros string. This is disallowed by the upstream + /// library. The input to this function should either be the whitened output of + /// a random number generator, or if that is not available, the output of a + /// stable monotonic counter. + pub fn assume_unique_per_nonce_gen(inner: [u8; 32]) -> Self { + assert_ne!(inner, [0; 32], "session secrets may not be all zero"); + SessionSecretRand(inner) + } /// Obtains the inner bytes of the [`SessionSecretRand`]. - pub fn to_bytes(&self) -> [u8; 32] { self.0 } + pub fn to_byte_array(&self) -> [u8; 32] { self.0 } /// Obtains a reference to the inner bytes of the [`SessionSecretRand`]. - pub fn as_bytes(&self) -> &[u8; 32] { &self.0 } + pub fn as_byte_array(&self) -> &[u8; 32] { &self.0 } /// Obtains a mutable raw pointer to the beginning of the underlying storage. /// @@ -213,13 +223,9 @@ impl CPtr for PartialSignature { } impl PartialSignature { - /// Serialize a PartialSignature. - /// - /// # Returns - /// - /// 32-byte array - pub fn serialize(&self) -> [u8; 32] { - let mut data = MaybeUninit::<[u8; 32]>::uninit(); + /// Serialize a PartialSignature as a byte array. + pub fn serialize(&self) -> [u8; ffi::MUSIG_PART_SIG_SERIALIZED_LEN] { + let mut data = MaybeUninit::<[u8; ffi::MUSIG_PART_SIG_SERIALIZED_LEN]>::uninit(); unsafe { if ffi::secp256k1_musig_partial_sig_serialize( ffi::secp256k1_context_no_precomp, From ebdaec78597a00198e31895bbf8ba559a0095550 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Thu, 15 May 2025 20:27:00 +0000 Subject: [PATCH 12/15] musig: clarify doc comment about aggregate nonce proxy --- src/musig.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/musig.rs b/src/musig.rs index 8f96547b8..4bdd6721c 100644 --- a/src/musig.rs +++ b/src/musig.rs @@ -504,6 +504,8 @@ impl KeyAggCache { /// See the `new_nonce_pair` method that allows generating [`SecretNonce`] and [`PublicNonce`] /// with only the `session_secrand` field. /// + /// If the aggregator lies, the resulting signature will simply be invalid. + /// /// Remember that nonce reuse will immediately leak the secret key! /// /// # Returns: From 40a8b654979a3e6cc307a7923b17dd4567302764 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Thu, 15 May 2025 20:53:51 +0000 Subject: [PATCH 13/15] musig: explicitly panic when given an empty slice of pubkeys to aggregate The existing code panics somewhere in ffi.rs trying to do pointer alignment stuff, and is only not UB by accident. Guard this with an explicit panic. --- src/musig.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/musig.rs b/src/musig.rs index 4bdd6721c..445784ceb 100644 --- a/src/musig.rs +++ b/src/musig.rs @@ -314,6 +314,10 @@ impl KeyAggCache { /// /// Panics if an empty slice of pubkeys is provided. pub fn new(secp: &Secp256k1, 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(); From 8a43317781b1c48057d164561c9f16945bb26ead Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Thu, 15 May 2025 20:31:22 +0000 Subject: [PATCH 14/15] musig: add a bunch of unit tests I asked Claude to create an initial set of unit tests, which it did. I then manually cleaned up a lot of its repeated logic (though not all of it, as you can tell) and added a whole bunch more failure cases. For example it did not bother trying to repeat or swap keys/nonces. When it generated the tests, the empty-pubkey-list bug (fixed in the previous commit) was still present. It failed to find it, I think because it was reading the code looking for panics to trigger, and there wasn't one. In future I will try giving it only the API, and try telling it to be more adversarial. We'll see. --- src/musig.rs | 335 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 335 insertions(+) diff --git a/src/musig.rs b/src/musig.rs index 445784ceb..a3eae12fa 100644 --- a/src/musig.rs +++ b/src/musig.rs @@ -1195,3 +1195,338 @@ impl Session { /// Get a mut pointer to the inner Session pub fn as_mut_ptr(&mut self) -> *mut ffi::MusigSession { &mut self.0 } } + +#[cfg(test)] +mod tests { + use super::*; + #[cfg(feature = "std")] + #[cfg(feature = "rand")] + use crate::{Message, PublicKey, Secp256k1, SecretKey}; + + #[test] + #[cfg(feature = "std")] + #[cfg(feature = "rand")] + fn session_secret_rand() { + let mut rng = rand::rng(); + let session_secrand = SessionSecretRand::from_rng(&mut rng); + let session_secrand1 = SessionSecretRand::from_rng(&mut rng); + assert_ne!(session_secrand.to_byte_array(), [0; 32]); // with overwhelming probability + assert_ne!(session_secrand, session_secrand1); // with overwhelming probability + } + + #[test] + fn session_secret_no_rand() { + let custom_bytes = [42u8; 32]; + let session_secrand = SessionSecretRand::assume_unique_per_nonce_gen(custom_bytes); + assert_eq!(session_secrand.to_byte_array(), custom_bytes); + assert_eq!(session_secrand.as_byte_array(), &custom_bytes); + } + + #[test] + #[should_panic(expected = "session secrets may not be all zero")] + fn session_secret_rand_zero_panic() { + let zero_bytes = [0u8; 32]; + let _session_secrand = SessionSecretRand::assume_unique_per_nonce_gen(zero_bytes); + } + + #[test] + #[cfg(not(secp256k1_fuzz))] + #[cfg(feature = "std")] + #[cfg(feature = "rand")] + fn key_agg_cache() { + let secp = Secp256k1::new(); + let mut rng = rand::rng(); + + let (_seckey1, pubkey1) = secp.generate_keypair(&mut rng); + let seckey2 = SecretKey::new(&mut rng); + let pubkey2 = PublicKey::from_secret_key(&secp, &seckey2); + + let pubkeys = [&pubkey1, &pubkey2]; + let key_agg_cache = KeyAggCache::new(&secp, &pubkeys); + let agg_pk = key_agg_cache.agg_pk(); + + // Test agg_pk_full + let agg_pk_full = key_agg_cache.agg_pk_full(); + assert_eq!(agg_pk_full.x_only_public_key().0, agg_pk); + } + + #[test] + #[cfg(not(secp256k1_fuzz))] + #[cfg(feature = "std")] + #[cfg(feature = "rand")] + fn key_agg_cache_tweaking() { + let secp = Secp256k1::new(); + let mut rng = rand::rng(); + + let (_seckey1, pubkey1) = secp.generate_keypair(&mut rng); + let seckey2 = SecretKey::new(&mut rng); + let pubkey2 = PublicKey::from_secret_key(&secp, &seckey2); + + 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]); + 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 + let original_agg_pk = key_agg_cache.agg_pk(); + assert_ne!(key_agg_cache.agg_pk(), key_agg_cache1.agg_pk()); // swapped keys DOES mean not equal + assert_ne!(key_agg_cache.agg_pk(), key_agg_cache2.agg_pk()); // missing keys + assert_ne!(key_agg_cache.agg_pk(), key_agg_cache3.agg_pk()); // repeated key + + // 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(); + 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(); + assert_eq!(key_agg_cache.agg_pk(), tweaked_agg_pk.x_only_public_key().0); + } + + #[test] + #[cfg(feature = "std")] + #[cfg(feature = "rand")] + #[should_panic(expected = "Cannot aggregate an empty slice of pubkeys")] + fn key_agg_cache_empty_panic() { + let secp = Secp256k1::new(); + let _ = KeyAggCache::new(&secp, &[]); + } + + #[test] + #[cfg(feature = "std")] + #[cfg(feature = "rand")] + fn nonce_generation() { + let secp = Secp256k1::new(); + let mut rng = rand::rng(); + + let (_seckey1, pubkey1) = secp.generate_keypair(&mut rng); + let seckey2 = SecretKey::new(&mut rng); + let pubkey2 = PublicKey::from_secret_key(&secp, &seckey2); + + let key_agg_cache = KeyAggCache::new(&secp, &[&pubkey1, &pubkey2]); + + let msg_bytes: [u8; 32] = *b"this_could_be_the_hash_of_a_msg!"; + let msg = Message::from_digest_slice(&msg_bytes).unwrap(); + + // 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); + + // 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), + pubkey2, + Some(msg), + extra_rand, + ); + + // Test PublicNonce serialization/deserialization + let serialized_nonce = pub_nonce1.serialize(); + let deserialized_nonce = PublicNonce::from_byte_array(&serialized_nonce).unwrap(); + assert_eq!(pub_nonce1.serialize(), deserialized_nonce.serialize()); + } + + #[test] + #[cfg(feature = "std")] + #[cfg(feature = "rand")] + fn aggregated_nonce() { + let secp = Secp256k1::new(); + let mut rng = rand::rng(); + + let (_seckey1, pubkey1) = secp.generate_keypair(&mut rng); + let seckey2 = SecretKey::new(&mut rng); + let pubkey2 = PublicKey::from_secret_key(&secp, &seckey2); + + let key_agg_cache = KeyAggCache::new(&secp, &[&pubkey1, &pubkey2]); + + let msg_bytes: [u8; 32] = *b"this_could_be_the_hash_of_a_msg!"; + let msg = Message::from_digest_slice(&msg_bytes).unwrap(); + + let session_secrand1 = SessionSecretRand::from_rng(&mut rng); + let (_, pub_nonce1) = key_agg_cache.nonce_gen(&secp, 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); + + // 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]); + 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 + + // Test AggregatedNonce serialization/deserialization + let serialized_agg_nonce = agg_nonce.serialize(); + let deserialized_agg_nonce = + AggregatedNonce::from_byte_array(&serialized_agg_nonce).unwrap(); + assert_eq!(agg_nonce.serialize(), deserialized_agg_nonce.serialize()); + } + + #[test] + #[cfg(feature = "std")] + #[cfg(feature = "rand")] + #[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); + } + + #[test] + #[cfg(not(secp256k1_fuzz))] + #[cfg(feature = "std")] + #[cfg(feature = "rand")] + fn session_and_partial_signing() { + let secp = Secp256k1::new(); + let mut rng = rand::rng(); + + let (seckey1, pubkey1) = secp.generate_keypair(&mut rng); + let seckey2 = SecretKey::new(&mut rng); + let pubkey2 = PublicKey::from_secret_key(&secp, &seckey2); + + let pubkeys = [&pubkey1, &pubkey2]; + let key_agg_cache = KeyAggCache::new(&secp, &pubkeys); + + let msg_bytes: [u8; 32] = *b"this_could_be_the_hash_of_a_msg!"; + let msg = Message::from_digest_slice(&msg_bytes).unwrap(); + + let session_secrand1 = SessionSecretRand::from_rng(&mut rng); + let (sec_nonce1, pub_nonce1) = + key_agg_cache.nonce_gen(&secp, 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); + + let nonces = [&pub_nonce1, &pub_nonce2]; + let agg_nonce = AggregatedNonce::new(&secp, &nonces); + + // Test Session creation + let session = Session::new(&secp, &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 keypair2 = Keypair::from_secret_key(&secp, &seckey2); + let partial_sign2 = session.partial_sign(&secp, 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)); + // 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)); + + // Test PartialSignature serialization/deserialization + let serialized_partial_sig = partial_sign1.serialize(); + let deserialized_partial_sig = + PartialSignature::from_byte_array(&serialized_partial_sig).unwrap(); + assert_eq!(partial_sign1.serialize(), deserialized_partial_sig.serialize()); + } + + #[test] + #[cfg(not(secp256k1_fuzz))] + #[cfg(feature = "std")] + #[cfg(feature = "rand")] + fn signature_aggregation_and_verification() { + let secp = Secp256k1::new(); + let mut rng = rand::rng(); + + let (seckey1, pubkey1) = secp.generate_keypair(&mut rng); + let seckey2 = SecretKey::new(&mut rng); + let pubkey2 = PublicKey::from_secret_key(&secp, &seckey2); + + let pubkeys = [&pubkey1, &pubkey2]; + let key_agg_cache = KeyAggCache::new(&secp, &pubkeys); + + let msg_bytes: [u8; 32] = *b"this_could_be_the_hash_of_a_msg!"; + let msg = Message::from_digest_slice(&msg_bytes).unwrap(); + + let session_secrand1 = SessionSecretRand::from_rng(&mut rng); + let (sec_nonce1, pub_nonce1) = + key_agg_cache.nonce_gen(&secp, 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); + + 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 keypair1 = Keypair::from_secret_key(&secp, &seckey1); + let partial_sign1 = session.partial_sign(&secp, 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); + + // 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_bytes).unwrap(); + + // Test assume_valid + let schnorr_sig = aggregated_signature.assume_valid(); + secp.verify_schnorr(&schnorr_sig, &msg_bytes, &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_bytes).unwrap_err(); + let schnorr_sig = aggregated_signature.assume_valid(); + secp.verify_schnorr(&schnorr_sig, &msg_bytes, &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_bytes).unwrap(); + let schnorr_sig = aggregated_signature.assume_valid(); + secp.verify_schnorr(&schnorr_sig, &msg_bytes, &agg_pk).unwrap(); + } + + #[test] + #[cfg(feature = "std")] + #[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) = secp.generate_keypair(&mut rng); + let seckey2 = SecretKey::new(&mut rng); + let pubkey2 = PublicKey::from_secret_key(&secp, &seckey2); + + let pubkeys = [pubkey1, pubkey2]; + 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 msg_bytes: [u8; 32] = *b"this_could_be_the_hash_of_a_msg!"; + let msg = Message::from_digest_slice(&msg_bytes).unwrap(); + + let session_secrand1 = SessionSecretRand::from_rng(&mut rng); + let (_, pub_nonce1) = key_agg_cache.nonce_gen(&secp, 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 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_sig = session.partial_sig_agg(&[]); + } +} From d611a4f25eba6bba9e0586e8234e0c184192468e Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Mon, 26 May 2025 14:30:08 +0000 Subject: [PATCH 15/15] musig: weaken/simplify warnings about nonce reuse These warnings were repetitive and a bit overwrought. "Will leak your key in two signatures" is clear enough. The text also said some out-of-date things about whether it's possible to reuse a nonce -- you can do it directly now with dangerous_into_bytes, and also you could always do it indirectly by just constructing the same nonce twice by using a bad rng. --- src/musig.rs | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/src/musig.rs b/src/musig.rs index a3eae12fa..7fd28b84f 100644 --- a/src/musig.rs +++ b/src/musig.rs @@ -572,24 +572,15 @@ impl KeyAggCache { /// Musig Secret Nonce. /// -/// This structure MUST NOT be copied or -/// read or written to it directly. A signer who is online throughout the whole -/// process and can keep this structure in memory can use the provided API -/// functions for a safe standard workflow. See -/// for -/// more details about the risks associated with serializing or deserializing -/// this structure. There are no serialization and parsing functions (yet). +/// A signer who is online throughout the whole process and can keep this structure +/// in memory can use the provided API functions for a safe standard workflow. /// -/// Note this deliberately does not implement `Copy` or `Clone`. After creation, the only -/// use of this nonce is [`Session::partial_sign`] API that takes ownership of this -/// and drops it. This is to prevent accidental misuse of this nonce. +/// This structure does not implement `Copy` or `Clone`; after construction the only +/// thing that can or should be done with this nonce is to call [`Session::partial_sign`], +/// which will take ownership. This is to prevent accidental reuse of the nonce. /// -/// A signer who is online throughout the whole process and can keep this -/// structure in memory can use the provided API functions for a safe standard -/// workflow. -/// -/// Signers that pre-compute and save these nonces are not yet supported. Users -/// who want to serialize this must use unsafe rust to do so. +/// See the warning on [`Self::dangerous_into_bytes`] for more information about +/// the risks of non-standard workflows. #[allow(missing_copy_implementations)] #[derive(Debug)] pub struct SecretNonce(ffi::MusigSecNonce); @@ -612,20 +603,20 @@ impl SecretNonce { /// Function to return a copy of the internal array. See WARNING before using this function. /// /// # Warning: - /// This structure MUST NOT be copied or read or written to directly. A - /// signer who is online throughout the whole process and can keep this - /// structure in memory can use the provided API functions for a safe standard - /// workflow. /// - /// We repeat, copying this data structure can result in nonce reuse which will - /// leak the secret signing key. + /// Storing and re-creating this structure may leak to nonce reuse, which will leak + /// your secret key in two signing sessions, even if neither session is completed. + /// These functions should be avoided if possible and used with care. + /// + /// See + /// for more details about these risks. pub fn dangerous_into_bytes(self) -> [u8; secp256k1_sys::MUSIG_SECNONCE_LEN] { self.0.dangerous_into_bytes() } - /// Function to create a new MusigKeyAggCoef from a 32 byte array. See WARNING before using this function. + /// Function to create a new [`SecretNonce`] from a 32 byte array. /// - /// Refer to [`SecretNonce::dangerous_into_bytes`] for more details. + /// Refer to the warning on [`SecretNonce::dangerous_into_bytes`] for more details. pub fn dangerous_from_bytes(array: [u8; secp256k1_sys::MUSIG_SECNONCE_LEN]) -> Self { SecretNonce(ffi::MusigSecNonce::dangerous_from_bytes(array)) }