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/examples/musig.rs b/examples/musig.rs index edd654a80..0f432bf5f 100644 --- a/examples/musig.rs +++ b/examples/musig.rs @@ -4,11 +4,11 @@ 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(); - let mut rng = rand::thread_rng(); + let mut rng = rand::rng(); let (seckey1, pubkey1) = secp.generate_keypair(&mut rng); @@ -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/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/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 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..408682d83 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,12 +835,15 @@ 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, pubnonce: *mut MusigPubNonce, - session_secrand32: *const c_uchar, + session_secrand32: *mut c_uchar, seckey: *const c_uchar, pubkey: *const PublicKey, msg32: *const c_uchar, @@ -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, @@ -810,77 +915,127 @@ 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, - n_pubkeys: size_t + pubkeys: *const *const PublicKey, + 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] 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; 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..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::{thread_rng, RngCore}; -/// # use secp256k1::{Secp256k1, SecretKey, Keypair, PublicKey, pubkey_sort}; -/// # let secp = Secp256k1::new(); -/// # let sk1 = SecretKey::new(&mut thread_rng()); -/// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); -/// # let sk2 = SecretKey::new(&mut thread_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. diff --git a/src/musig.rs b/src/musig.rs index 68f6b0c73..a3eae12fa 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::thread_rng()) } - /// Creates a new [`SessionSecretRand`] with random bytes from the given rng #[cfg(feature = "rand")] pub fn from_rng(rng: &mut R) -> Self { @@ -59,15 +55,30 @@ 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. - pub fn assume_unique_per_nonce_gen(inner: [u8; 32]) -> Self { SessionSecretRand(inner) } + /// If the **rand** feature is enabled, [`SessionSecretRand::from_rng`] can be used to generate a + /// random session id. + /// + /// # 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. + /// + /// 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. @@ -129,32 +140,28 @@ 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 -/// # # [cfg(any(test, feature = "rand-std"))] { -/// # use secp256k1::rand::{thread_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 thread_rng()); -/// let sk = SecretKey::new(&mut thread_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( secp: &Secp256k1, - session_secrand: SessionSecretRand, + mut session_secrand: SessionSecretRand, key_agg_cache: Option<&KeyAggCache>, sec_key: Option, pub_key: PublicKey, @@ -167,13 +174,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, @@ -210,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, @@ -286,20 +295,29 @@ impl KeyAggCache { /// Example: /// /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{thread_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 thread_rng()); + /// # let sk1 = SecretKey::new(&mut rand::rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_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(); /// # } /// ``` + /// + /// # Panics + /// + /// 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(); @@ -375,20 +393,22 @@ impl KeyAggCache { /// Example: /// /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{thread_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 thread_rng()); + /// # let sk1 = SecretKey::new(&mut rand::rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_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( @@ -434,19 +454,21 @@ impl KeyAggCache { /// Example: /// /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{thread_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 thread_rng()); + /// # let sk1 = SecretKey::new(&mut rand::rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_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( @@ -486,6 +508,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: @@ -501,32 +525,28 @@ 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 - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{thread_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 thread_rng()); + /// # let sk1 = SecretKey::new(&mut rand::rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_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 thread_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( @@ -696,32 +716,35 @@ impl AggregatedNonce { /// Example: /// /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{thread_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 thread_rng()); + /// # let sk1 = SecretKey::new(&mut rand::rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_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 thread_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 thread_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]); /// # } /// ``` + /// # 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"); @@ -858,33 +881,32 @@ impl Session { /// Example: /// /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{thread_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 thread_rng()); + /// # let sk1 = SecretKey::new(&mut rand::rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_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 thread_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 thread_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, @@ -994,31 +1016,31 @@ impl Session { /// Example: /// /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{thread_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 thread_rng()); + /// # let sk1 = SecretKey::new(&mut rand::rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_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 thread_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 thread_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, @@ -1033,7 +1055,7 @@ impl Session { /// sec_nonce1, /// &keypair, /// &key_agg_cache, - /// ).unwrap(); + /// ); /// /// assert!(session.partial_verify( /// &secp, @@ -1077,13 +1099,12 @@ impl Session { /// * `partial_sigs`: Array of [`PartialSignature`] to be aggregated /// /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1::rand::{thread_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 thread_rng()); + /// # let sk1 = SecretKey::new(&mut rand::rng()); /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_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]); @@ -1092,12 +1113,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::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 thread_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"); /// @@ -1135,6 +1156,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"); @@ -1170,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(&[]); + } +}