Skip to main content

secp256k1/
lib.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Rust bindings for Pieter Wuille's secp256k1 library, which is used for
4//! fast and accurate manipulation of ECDSA and Schnorr signatures on the secp256k1
5//! curve. Such signatures are used extensively by the Bitcoin network
6//! and its derivatives.
7//!
8//! To minimize dependencies, some functions are feature-gated. To generate
9//! random keys or to re-randomize the internal context, compile with the
10//! `rand` and `std` features. If you are willing to use these features, we
11//! have enabled an additional defense-in-depth sidechannel protection for
12//! our context objects, which re-blinds certain operations on secret key
13//! data. To de/serialize objects with serde, compile with "serde".
14//! **Important**: `serde` encoding is **not** the same as consensus
15//! encoding!
16//!
17//! The library handles the underlying `libsecp256k1` context object for
18//! you, with signing, verification and key generation as plain functions
19//! (or methods on the key and signature types). These use a
20//! lazily-initialized global context internally. That context holds
21//! precomputation tables which are built at most once per program run, since
22//! building them is a slow operation (10+ milliseconds, vs ~50 microseconds
23//! for typical crypto operations, on a 2.70 Ghz i7-6820HQ).
24//!
25//! ```rust
26//! # #[cfg(all(feature = "rand", feature = "std"))] {
27//! use secp256k1::rand;
28//! use secp256k1::{ecdsa, Message};
29//!
30//! // Our message to sign. We explicitly obtain a hash and convert it to a
31//! // `Message`. In a real application, we would produce a signature hash
32//! // type, e.g. `bitcoin::LegacySigHash`, which is convertible to `Message`
33//! // and can be passed directly to `sign_ecdsa`.
34//! const HELLO_WORLD_SHA2: [u8; 32] = [
35//!     0x31, 0x5f, 0x5b, 0xdb, 0x76, 0xd0, 0x78, 0xc4, 0x3b, 0x8a, 0xc0, 0x06, 0x4e, 0x4a, 0x01, 0x64,
36//!     0x61, 0x2b, 0x1f, 0xce, 0x77, 0xc8, 0x69, 0x34, 0x5b, 0xfc, 0x94, 0xc7, 0x58, 0x94, 0xed, 0xd3,
37//! ];
38//!
39//! let (secret_key, public_key) = secp256k1::generate_keypair(&mut rand::rng());
40//! let message = Message::from_digest(HELLO_WORLD_SHA2);
41//!
42//! let sig = ecdsa::sign(message, &secret_key);
43//! assert!(ecdsa::verify(&sig, message, &public_key).is_ok());
44//! # }
45//! ```
46//!
47//! The same operations are also available as methods on the key and signature
48//! types.
49//!
50//! ```rust
51//! # #[cfg(all(feature = "rand", feature = "std"))] {
52//! use secp256k1::{rand, Message};
53//!
54//! // See previous example regarding this constant.
55//! const HELLO_WORLD_SHA2: [u8; 32] = [
56//!     0x31, 0x5f, 0x5b, 0xdb, 0x76, 0xd0, 0x78, 0xc4, 0x3b, 0x8a, 0xc0, 0x06, 0x4e, 0x4a, 0x01, 0x64,
57//!     0x61, 0x2b, 0x1f, 0xce, 0x77, 0xc8, 0x69, 0x34, 0x5b, 0xfc, 0x94, 0xc7, 0x58, 0x94, 0xed, 0xd3,
58//! ];
59//!
60//! let (secret_key, public_key) = secp256k1::generate_keypair(&mut rand::rng());
61//! let message = Message::from_digest(HELLO_WORLD_SHA2);
62//!
63//! let sig = secret_key.sign_ecdsa(message);
64//! assert!(sig.verify(message, &public_key).is_ok());
65//! # }
66//! ```
67//!
68//! The above code requires `rust-secp256k1` to be compiled with the `rand` and `std` features
69//! enabled, to get access to [`generate_keypair`].
70//! Alternately, keys and messages can be parsed from slices, like
71//!
72//! ```rust
73//! # #[cfg(feature = "alloc")] {
74//! use secp256k1::{ecdsa, Message, SecretKey, PublicKey};
75//! # fn compute_hash(_: &[u8]) -> [u8; 32] { [0xab; 32] }
76//!
77//! let secret_key = SecretKey::from_secret_bytes([0xcd; 32]).expect("32 bytes, within curve order");
78//! let public_key = PublicKey::from_secret_key(&secret_key);
79//! // If the supplied byte slice was *not* the output of a cryptographic hash function this would
80//! // be cryptographically broken. It has been trivially used in the past to execute attacks.
81//! let message = Message::from_digest(compute_hash(b"CSW is not Satoshi"));
82//!
83//! let sig = ecdsa::sign(message, &secret_key);
84//! assert!(ecdsa::verify(&sig, message, &public_key).is_ok());
85//! # }
86//! ```
87//!
88//! Users who only want to verify signatures can do so:
89//!
90//! ```rust
91//! # #[cfg(feature = "alloc")] {
92//! use secp256k1::{ecdsa, Message, PublicKey};
93//!
94//! let public_key = PublicKey::from_slice(&[
95//!     0x02,
96//!     0xc6, 0x6e, 0x7d, 0x89, 0x66, 0xb5, 0xc5, 0x55,
97//!     0xaf, 0x58, 0x05, 0x98, 0x9d, 0xa9, 0xfb, 0xf8,
98//!     0xdb, 0x95, 0xe1, 0x56, 0x31, 0xce, 0x35, 0x8c,
99//!     0x3a, 0x17, 0x10, 0xc9, 0x62, 0x67, 0x90, 0x63,
100//! ]).expect("public keys must be 33 or 65 bytes, serialized according to SEC 2");
101//!
102//! let message = Message::from_digest([
103//!     0xaa, 0xdf, 0x7d, 0xe7, 0x82, 0x03, 0x4f, 0xbe,
104//!     0x3d, 0x3d, 0xb2, 0xcb, 0x13, 0xc0, 0xcd, 0x91,
105//!     0xbf, 0x41, 0xcb, 0x08, 0xfa, 0xc7, 0xbd, 0x61,
106//!     0xd5, 0x44, 0x53, 0xcf, 0x6e, 0x82, 0xb4, 0x50,
107//! ]);
108//!
109//! let sig = ecdsa::Signature::from_compact(&[
110//!     0xdc, 0x4d, 0xc2, 0x64, 0xa9, 0xfe, 0xf1, 0x7a,
111//!     0x3f, 0x25, 0x34, 0x49, 0xcf, 0x8c, 0x39, 0x7a,
112//!     0xb6, 0xf1, 0x6f, 0xb3, 0xd6, 0x3d, 0x86, 0x94,
113//!     0x0b, 0x55, 0x86, 0x82, 0x3d, 0xfd, 0x02, 0xae,
114//!     0x3b, 0x46, 0x1b, 0xb4, 0x33, 0x6b, 0x5e, 0xcb,
115//!     0xae, 0xfd, 0x66, 0x27, 0xaa, 0x92, 0x2e, 0xfc,
116//!     0x04, 0x8f, 0xec, 0x0c, 0x88, 0x1c, 0x10, 0xc4,
117//!     0xc9, 0x42, 0x8f, 0xca, 0x69, 0xc1, 0x32, 0xa2,
118//! ]).expect("compact signatures are 64 bytes; DER signatures are 68-72 bytes");
119//!
120//! # #[cfg(not(secp256k1_fuzz))]
121//! assert!(ecdsa::verify(&sig, message, &public_key).is_ok());
122//! # }
123//! ```
124//!
125//! ## Crate features/optional dependencies
126//!
127//! This crate provides the following opt-in Cargo features:
128//!
129//! * `std` - use standard Rust library, enabled by default.
130//! * `alloc` - use the `alloc` standard Rust library to provide heap allocations.
131//! * `rand` - use `rand` library to provide random generator (e.g. to generate keys).
132//! * `recovery` - enable functions that can compute the public key from signature.
133//! * `lowmemory` - optimize the library for low-memory environments.
134//! * `global-context` - enable use of global secp256k1 context (implies `std`).
135//! * `serde` - implements serialization and deserialization for types in this crate using `serde`.
136//!   **Important**: `serde` encoding is **not** the same as consensus encoding!
137//!
138
139// Coding conventions
140#![deny(non_upper_case_globals, non_camel_case_types, non_snake_case)]
141#![warn(missing_docs, missing_copy_implementations, missing_debug_implementations)]
142#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
143// Experimental features we need.
144#![cfg_attr(bench, feature(test))]
145
146#[cfg(feature = "alloc")]
147extern crate alloc;
148#[cfg(any(test, feature = "std"))]
149extern crate core;
150#[cfg(bench)]
151extern crate test;
152
153#[cfg(feature = "rand")]
154pub extern crate rand;
155#[cfg(feature = "serde")]
156pub extern crate serde;
157
158#[macro_use]
159mod macros;
160#[macro_use]
161mod secret;
162mod context;
163mod key;
164#[cfg(feature = "serde")]
165mod serde_util;
166
167pub mod constants;
168pub mod ecdh;
169pub mod ecdsa;
170pub mod ellswift;
171pub mod musig;
172pub mod scalar;
173pub mod schnorr;
174
175use core::marker::PhantomData;
176use core::ptr::NonNull;
177use core::{fmt, mem, str};
178
179use crate::ffi::types::AlignedType;
180use crate::ffi::CPtr;
181
182#[rustfmt::skip]                // Keep public re-exports separate.
183pub use secp256k1_sys as ffi;
184
185#[cfg(all(feature = "global-context", feature = "std"))]
186pub use crate::context::global::{self, SECP256K1};
187#[cfg(feature = "alloc")]
188pub use crate::context::{All, SignOnly, VerifyOnly};
189#[doc(inline)]
190pub use crate::{
191    context::{
192        rerandomize_global_context, with_global_context, with_raw_global_context, AllPreallocated,
193        Context, PreallocatedContext, SignOnlyPreallocated, Signing, Verification,
194        VerifyOnlyPreallocated,
195    },
196    key::{
197        sort_pubkeys, InvalidParityValue, Keypair, Parity, PublicKey, SecretKey, XOnlyPublicKey,
198    },
199    scalar::Scalar,
200};
201
202/// A (hashed) message input to an ECDSA signature.
203#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
204pub struct Message([u8; constants::MESSAGE_SIZE]);
205impl_array_newtype!(Message, u8, constants::MESSAGE_SIZE);
206impl_pretty_debug!(Message);
207
208impl Message {
209    /// Creates a [`Message`] from a `digest`.
210    ///
211    /// The `digest` array has to be a cryptographically secure hash of the actual message that's
212    /// going to be signed. Otherwise the result of signing isn't a [secure signature].
213    ///
214    /// [secure signature]: https://twitter.com/pwuille/status/1063582706288586752
215    #[inline]
216    pub fn from_digest(digest: [u8; 32]) -> Message { Message(digest) }
217
218    /// Creates a [`Message`] from a 32 byte slice `digest`.
219    ///
220    /// The slice has to be 32 bytes long and be a cryptographically secure hash of the actual
221    /// message that's going to be signed. Otherwise the result of signing isn't a [secure
222    /// signature].
223    ///
224    /// This method is deprecated. It's best to use [`Message::from_digest`] directly with an
225    /// array. If your hash engine doesn't return an array for some reason use `.try_into()` on its
226    /// output.
227    ///
228    /// # Errors
229    ///
230    /// If `digest` is not exactly 32 bytes long.
231    ///
232    /// [secure signature]: https://twitter.com/pwuille/status/1063582706288586752
233    #[inline]
234    #[deprecated(since = "0.31.0", note = "use from_digest instead")]
235    pub fn from_digest_slice(digest: &[u8]) -> Result<Message, Error> {
236        Ok(Message::from_digest(digest.try_into().map_err(|_| Error::InvalidMessage)?))
237    }
238}
239
240impl fmt::LowerHex for Message {
241    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
242        for byte in self.0.iter() {
243            write!(f, "{:02x}", byte)?;
244        }
245        Ok(())
246    }
247}
248
249impl fmt::Display for Message {
250    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
251}
252
253/// The main error type for this library.
254#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Debug)]
255pub enum Error {
256    /// Signature failed verification.
257    IncorrectSignature,
258    /// Bad sized message ("messages" are actually fixed-sized digests [`constants::MESSAGE_SIZE`]).
259    InvalidMessage,
260    /// Bad public key.
261    InvalidPublicKey,
262    /// Bad signature.
263    InvalidSignature,
264    /// Bad secret key.
265    InvalidSecretKey,
266    /// Bad shared secret.
267    InvalidSharedSecret,
268    /// Bad recovery id.
269    InvalidRecoveryId,
270    /// Tried to add/multiply by an invalid tweak.
271    InvalidTweak,
272    /// Didn't pass enough memory to context creation with preallocated memory.
273    NotEnoughMemory,
274    /// Bad set of public keys.
275    InvalidPublicKeySum,
276    /// The only valid parity values are 0 or 1.
277    InvalidParityValue(key::InvalidParityValue),
278    /// Bad EllSwift value
279    InvalidEllSwift,
280}
281
282impl fmt::Display for Error {
283    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
284        use Error::*;
285
286        match *self {
287            IncorrectSignature => f.write_str("signature failed verification"),
288            InvalidMessage => f.write_str("message was not 32 bytes (do you need to hash?)"),
289            InvalidPublicKey => f.write_str("malformed public key"),
290            InvalidSignature => f.write_str("malformed signature"),
291            InvalidSecretKey => f.write_str("malformed or out-of-range secret key"),
292            InvalidSharedSecret => f.write_str("malformed or out-of-range shared secret"),
293            InvalidRecoveryId => f.write_str("bad recovery id"),
294            InvalidTweak => f.write_str("bad tweak"),
295            NotEnoughMemory => f.write_str("not enough memory allocated"),
296            InvalidPublicKeySum => f.write_str(
297                "the sum of public keys was invalid or the input vector lengths was less than 1",
298            ),
299            InvalidParityValue(e) => write_err!(f, "couldn't create parity"; e),
300            InvalidEllSwift => f.write_str("malformed EllSwift value"),
301        }
302    }
303}
304
305#[cfg(feature = "std")]
306impl std::error::Error for Error {
307    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
308        match self {
309            Error::IncorrectSignature => None,
310            Error::InvalidMessage => None,
311            Error::InvalidPublicKey => None,
312            Error::InvalidSignature => None,
313            Error::InvalidSecretKey => None,
314            Error::InvalidSharedSecret => None,
315            Error::InvalidRecoveryId => None,
316            Error::InvalidTweak => None,
317            Error::NotEnoughMemory => None,
318            Error::InvalidPublicKeySum => None,
319            Error::InvalidParityValue(error) => Some(error),
320            Error::InvalidEllSwift => None,
321        }
322    }
323}
324
325/// The secp256k1 engine, used to execute all signature operations.
326pub struct Secp256k1<C: Context> {
327    ctx: NonNull<ffi::Context>,
328    phantom: PhantomData<C>,
329}
330
331// The underlying secp context does not contain any references to memory it does not own.
332unsafe impl<C: Context> Send for Secp256k1<C> {}
333// The API does not permit any mutation of `Secp256k1` objects except through `&mut` references.
334unsafe impl<C: Context> Sync for Secp256k1<C> {}
335
336impl<C: Context> PartialEq for Secp256k1<C> {
337    fn eq(&self, _other: &Secp256k1<C>) -> bool { true }
338}
339
340impl<C: Context> Eq for Secp256k1<C> {}
341
342impl<C: Context> Drop for Secp256k1<C> {
343    fn drop(&mut self) {
344        unsafe {
345            let size = ffi::secp256k1_context_preallocated_clone_size(self.ctx.as_ptr());
346            ffi::secp256k1_context_preallocated_destroy(self.ctx);
347
348            C::deallocate(self.ctx.as_ptr() as _, size);
349        }
350    }
351}
352
353impl<C: Context> fmt::Debug for Secp256k1<C> {
354    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
355        write!(f, "<secp256k1 context {:?}, {}>", self.ctx, C::DESCRIPTION)
356    }
357}
358
359impl<C: Context> Secp256k1<C> {
360    /// Getter for the raw pointer to the underlying secp256k1 context. This
361    /// shouldn't be needed with normal usage of the library. It enables
362    /// extending the Secp256k1 with more cryptographic algorithms outside of
363    /// this crate.
364    pub fn ctx(&self) -> NonNull<ffi::Context> { self.ctx }
365
366    /// Returns the required memory for a preallocated context buffer in a generic manner(sign/verify/all).
367    pub fn preallocate_size_gen() -> usize {
368        let word_size = mem::size_of::<AlignedType>();
369        let bytes = unsafe { ffi::secp256k1_context_preallocated_size(C::FLAGS) };
370
371        (bytes + word_size - 1) / word_size
372    }
373
374    /// (Re)randomizes the Secp256k1 context for extra sidechannel resistance.
375    ///
376    /// Requires compilation with "rand" feature. See comment by Gregory Maxwell in
377    /// [libsecp256k1](https://github.com/bitcoin-core/secp256k1/commit/d2275795ff22a6f4738869f5528fbbb61738aa48).
378    #[cfg(feature = "rand")]
379    pub fn randomize<R: rand::Rng + ?Sized>(&mut self, rng: &mut R) {
380        let mut seed = [0u8; 32];
381        rng.fill_bytes(&mut seed);
382        self.seeded_randomize(&seed);
383    }
384
385    /// (Re)randomizes the Secp256k1 context for extra sidechannel resistance given 32 bytes of
386    /// cryptographically-secure random data;
387    /// see comment in libsecp256k1 commit d2275795f by Gregory Maxwell.
388    pub fn seeded_randomize(&mut self, seed: &[u8; 32]) {
389        unsafe {
390            let err = ffi::secp256k1_context_randomize(self.ctx, seed.as_c_ptr());
391            // This function cannot fail; it has an error return for future-proofing.
392            // We do not expose this error since it is impossible to hit, and we have
393            // precedent for not exposing impossible errors (for example in
394            // `PublicKey::from_secret_key` where it is impossible to create an invalid
395            // secret key through the API.)
396            // However, if this DOES fail, the result is potentially weaker side-channel
397            // resistance, which is deadly and undetectable, so we take out the entire
398            // thread to be on the safe side.
399            assert_eq!(err, 1);
400        }
401    }
402}
403
404impl<C: Signing> Secp256k1<C> {
405    /// Generates a random keypair. Convenience function for [`SecretKey::new`] and
406    /// [`PublicKey::from_secret_key`].
407    #[inline]
408    #[cfg(feature = "rand")]
409    #[deprecated(since = "0.33.0", note = "use secp256k1::generate_keypair instead")]
410    pub fn generate_keypair<R: rand::Rng + ?Sized>(
411        &self,
412        rng: &mut R,
413    ) -> (key::SecretKey, key::PublicKey) {
414        generate_keypair(rng)
415    }
416}
417
418/// Generates a random keypair. Convenience function for [`SecretKey::new`] and
419/// [`PublicKey::from_secret_key`].
420#[inline]
421#[cfg(feature = "rand")]
422pub fn generate_keypair<R: rand::Rng + ?Sized>(rng: &mut R) -> (key::SecretKey, key::PublicKey) {
423    let sk = key::SecretKey::new(rng);
424    let pk = key::PublicKey::from_secret_key(&sk);
425    (sk, pk)
426}
427
428/// Constructor for unit testing. (Calls `generate_keypair` if all
429/// the relevant features are on to get coverage of that functoin.)
430#[cfg(test)]
431#[cfg(all(feature = "rand", feature = "std"))]
432fn test_random_keypair() -> (key::SecretKey, key::PublicKey) { generate_keypair(&mut rand::rng()) }
433
434/// Constructor for unit testing.
435#[cfg(test)]
436#[cfg(not(all(feature = "rand", feature = "std")))]
437fn test_random_keypair() -> (key::SecretKey, key::PublicKey) {
438    let sk = SecretKey::test_random();
439    let pk = key::PublicKey::from_secret_key(&sk);
440    (sk, pk)
441}
442
443/// Utility function used to parse hex into a target u8 buffer. Returns
444/// the number of bytes converted or an error if it encounters an invalid
445/// character or unexpected end of string.
446fn from_hex(hex: &str, target: &mut [u8]) -> Result<usize, ()> {
447    if hex.len() % 2 == 1 || hex.len() > target.len() * 2 {
448        return Err(());
449    }
450
451    let mut b = 0;
452    let mut idx = 0;
453    for c in hex.bytes() {
454        b <<= 4;
455        match c {
456            b'A'..=b'F' => b |= c - b'A' + 10,
457            b'a'..=b'f' => b |= c - b'a' + 10,
458            b'0'..=b'9' => b |= c - b'0',
459            _ => return Err(()),
460        }
461        if (idx & 1) == 1 {
462            target[idx / 2] = b;
463            b = 0;
464        }
465        idx += 1;
466    }
467    Ok(idx / 2)
468}
469
470/// Utility function used to encode hex into a target u8 buffer. Returns
471/// a reference to the target buffer as an str. Returns an error if the target
472/// buffer isn't big enough.
473#[inline]
474fn to_hex<'a>(src: &[u8], target: &'a mut [u8]) -> Result<&'a str, ()> {
475    let hex_len = src.len() * 2;
476    if target.len() < hex_len {
477        return Err(());
478    }
479    const HEX_TABLE: [u8; 16] = *b"0123456789abcdef";
480
481    let mut i = 0;
482    for &b in src {
483        target[i] = HEX_TABLE[usize::from(b >> 4)];
484        target[i + 1] = HEX_TABLE[usize::from(b & 0b00001111)];
485        i += 2;
486    }
487    let result = &target[..hex_len];
488    debug_assert!(str::from_utf8(result).is_ok());
489    unsafe { Ok(str::from_utf8_unchecked(result)) }
490}
491
492#[cfg(feature = "rand")]
493pub(crate) fn random_32_bytes<R: rand::Rng + ?Sized>(rng: &mut R) -> [u8; 32] {
494    let mut ret = [0u8; 32];
495    rng.fill(&mut ret);
496    ret
497}
498
499/// Generate "random" 32 bytes for unit testing purposes.
500#[cfg(test)]
501fn test_random_32_bytes() -> [u8; 32] {
502    // AtomicU64 not available on all platforms we support
503    use core::sync::atomic::{AtomicU32, Ordering};
504
505    const PRIME_1: u32 = 1021283;
506    const PRIME_2: u32 = 3348599;
507    static RNG: AtomicU32 = AtomicU32::new(0);
508
509    let mut ret = [0; 32];
510    for i in 0..8 {
511        #[allow(deprecated)]
512        let prev = RNG
513            .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |rng| {
514                Some(rng.wrapping_mul(PRIME_1).wrapping_add(PRIME_2))
515            })
516            .unwrap();
517        let rng = prev.wrapping_mul(PRIME_1).wrapping_add(PRIME_2);
518        ret[i * 4..(i + 1) * 4].copy_from_slice(&rng.to_be_bytes());
519    }
520    ret
521}
522
523#[cfg(test)]
524mod tests {
525    use std::str::FromStr;
526
527    use hex_lit::hex;
528    #[cfg(target_arch = "wasm32")]
529    use wasm_bindgen_test::wasm_bindgen_test as test;
530
531    use super::*;
532
533    #[test]
534    #[cfg(feature = "std")]
535    // In rustc 1.72 this Clippy lint was pulled out of clippy and into rustc, and
536    // was made deny-by-default, breaking compilation of this test. Aside from this
537    // breaking change, which there is no point in bugging, the rename was done so
538    // clumsily that you need four separate "allow"s to disable this wrong lint.
539    #[allow(unknown_lints)]
540    #[allow(renamed_and_removed_lints)]
541    #[allow(undropped_manually_drops)]
542    #[allow(clippy::unknown_manually_drops)]
543    fn test_raw_ctx() {
544        use std::mem::{forget, ManuallyDrop};
545
546        let ctx_full = Secp256k1::new();
547        let ctx_sign = Secp256k1::signing_only();
548        let ctx_vrfy = Secp256k1::verification_only();
549
550        let full = unsafe { Secp256k1::from_raw_all(ctx_full.ctx) };
551        let sign = unsafe { Secp256k1::from_raw_signing_only(ctx_sign.ctx) };
552        let mut vrfy = unsafe { Secp256k1::from_raw_verification_only(ctx_vrfy.ctx) };
553
554        let (sk, pk) = crate::test_random_keypair();
555        let msg = Message::from_digest([2u8; 32]);
556        // Try signing
557        assert_eq!(ecdsa::sign(msg, &sk), ecdsa::sign(msg, &sk));
558        let sig = ecdsa::sign(msg, &sk);
559
560        // Try verifying
561        assert!(ecdsa::verify(&sig, msg, &pk).is_ok());
562        assert!(ecdsa::verify(&sig, msg, &pk).is_ok());
563
564        // The following drop will have no effect; in fact, they will trigger a compiler
565        // error because manually dropping a `ManuallyDrop` is almost certainly incorrect.
566        // If you want to drop the inner object you should called `ManuallyDrop::drop`.
567        drop(full);
568        // This will actually drop the context, though it will leave `full` accessible and
569        // in an invalid state. However, this is almost certainly what you want to do.
570        drop(ctx_full);
571        unsafe {
572            // Need to compute the allocation size, and need to do so *before* dropping
573            // anything.
574            let sz = ffi::secp256k1_context_preallocated_clone_size(ctx_sign.ctx.as_ptr());
575            // We can alternately drop the `ManuallyDrop` by unwrapping it and then letting
576            // it be dropped. This is actually a safe function, but it will destruct the
577            // underlying context without deallocating it...
578            ManuallyDrop::into_inner(sign);
579            // ...leaving us holding the bag to deallocate the context's memory without
580            // double-calling `secp256k1_context_destroy`, which cannot be done safely.
581            SignOnly::deallocate(ctx_sign.ctx.as_ptr() as *mut u8, sz);
582            forget(ctx_sign);
583        }
584
585        unsafe {
586            // Finally, we can call `ManuallyDrop::drop`, which has the same effect, but
587            let sz = ffi::secp256k1_context_preallocated_clone_size(ctx_vrfy.ctx.as_ptr());
588            // leaves the `ManuallyDrop` itself accessible. This is marked unsafe.
589            ManuallyDrop::drop(&mut vrfy);
590            VerifyOnly::deallocate(ctx_vrfy.ctx.as_ptr() as *mut u8, sz);
591            forget(ctx_vrfy);
592        }
593    }
594
595    #[cfg(not(target_arch = "wasm32"))]
596    #[test]
597    #[ignore] // Panicking from C may trap (SIGILL) intentionally, so we test this manually.
598    #[cfg(feature = "alloc")]
599    fn test_panic_raw_ctx_should_terminate_abnormally() {
600        // Trying to use an all-zeros public key should cause an ARG_CHECK to trigger.
601        let pk = PublicKey::from(unsafe { ffi::PublicKey::new() });
602        pk.serialize();
603    }
604
605    #[test]
606    #[cfg(all(feature = "rand", feature = "std"))]
607    fn test_preallocation() {
608        let (sk, pk) = crate::generate_keypair(&mut rand::rng());
609        let msg = Message::from_digest([2u8; 32]);
610        // Try signing
611        assert_eq!(ecdsa::sign(msg, &sk), ecdsa::sign(msg, &sk));
612        let sig = ecdsa::sign(msg, &sk);
613
614        // Try verifying
615        assert!(ecdsa::verify(&sig, msg, &pk).is_ok());
616        assert!(ecdsa::verify(&sig, msg, &pk).is_ok());
617    }
618
619    #[test]
620    #[cfg(all(feature = "rand", feature = "std"))]
621    fn capabilities() {
622        let msg = crate::random_32_bytes(&mut rand::rng());
623        let msg = Message::from_digest(msg);
624
625        // Try key generation
626        let (sk, pk) = crate::generate_keypair(&mut rand::rng());
627
628        // Try signing
629        assert_eq!(ecdsa::sign(msg, &sk), ecdsa::sign(msg, &sk));
630        let sig = ecdsa::sign(msg, &sk);
631
632        // Try verifying
633        assert!(ecdsa::verify(&sig, msg, &pk).is_ok());
634        assert!(ecdsa::verify(&sig, msg, &pk).is_ok());
635
636        // Check that we can produce keys from slices with no precomputation
637        let pk_slice = &pk.serialize();
638        let new_pk = PublicKey::from_slice(pk_slice).unwrap();
639        let new_sk = SecretKey::from_secret_bytes(sk.to_secret_bytes()).unwrap();
640        assert_eq!(sk, new_sk);
641        assert_eq!(pk, new_pk);
642    }
643
644    #[test]
645    #[cfg(all(feature = "rand", feature = "std"))]
646    fn signature_serialize_roundtrip() {
647        let mut s = Secp256k1::new();
648        s.randomize(&mut rand::rng());
649
650        for _ in 0..100 {
651            let msg = crate::random_32_bytes(&mut rand::rng());
652            let msg = Message::from_digest(msg);
653
654            let (sk, _) = crate::generate_keypair(&mut rand::rng());
655            let sig1 = ecdsa::sign(msg, &sk);
656            let der = sig1.serialize_der();
657            let sig2 = ecdsa::Signature::from_der(&der[..]).unwrap();
658            assert_eq!(sig1, sig2);
659
660            let compact = sig1.serialize_compact();
661            let sig2 = ecdsa::Signature::from_compact(&compact[..]).unwrap();
662            assert_eq!(sig1, sig2);
663
664            assert!(ecdsa::Signature::from_compact(&der[..]).is_err());
665            assert!(ecdsa::Signature::from_compact(&compact[0..4]).is_err());
666            assert!(ecdsa::Signature::from_der(&compact[..]).is_err());
667            assert!(ecdsa::Signature::from_der(&der[0..4]).is_err());
668        }
669    }
670
671    #[test]
672    fn signature_display() {
673        const HEX_STR: &str = "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45";
674        let byte_str = hex!(HEX_STR);
675
676        assert_eq!(
677            ecdsa::Signature::from_der(&byte_str).expect("byte str decode"),
678            ecdsa::Signature::from_str(HEX_STR).expect("byte str decode")
679        );
680
681        let sig = ecdsa::Signature::from_str(HEX_STR).expect("byte str decode");
682        assert_eq!(&sig.to_string(), HEX_STR);
683        assert_eq!(&format!("{:?}", sig), HEX_STR);
684
685        assert!(ecdsa::Signature::from_str(
686            "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a\
687             72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab4"
688        )
689        .is_err());
690        assert!(ecdsa::Signature::from_str(
691            "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a\
692             72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab"
693        )
694        .is_err());
695        assert!(ecdsa::Signature::from_str(
696            "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a\
697             72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eabxx"
698        )
699        .is_err());
700        assert!(ecdsa::Signature::from_str(
701            "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a\
702             72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45\
703             72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45\
704             72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45\
705             72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45\
706             72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45"
707        )
708        .is_err());
709
710        // 71 byte signature
711        let hex_str = "30450221009d0bad576719d32ae76bedb34c774866673cbde3f4e12951555c9408e6ce774b02202876e7102f204f6bfee26c967c3926ce702cf97d4b010062e193f763190f6776";
712        let sig = ecdsa::Signature::from_str(hex_str).expect("byte str decode");
713        assert_eq!(&format!("{}", sig), hex_str);
714    }
715
716    #[test]
717    fn signature_lax_der() {
718        macro_rules! check_lax_sig(
719            ($hex:expr) => ({
720                let sig = hex!($hex);
721                assert!(ecdsa::Signature::from_der_lax(&sig[..]).is_ok());
722            })
723        );
724
725        check_lax_sig!("304402204c2dd8a9b6f8d425fcd8ee9a20ac73b619906a6367eac6cb93e70375225ec0160220356878eff111ff3663d7e6bf08947f94443845e0dcc54961664d922f7660b80c");
726        check_lax_sig!("304402202ea9d51c7173b1d96d331bd41b3d1b4e78e66148e64ed5992abd6ca66290321c0220628c47517e049b3e41509e9d71e480a0cdc766f8cdec265ef0017711c1b5336f");
727        check_lax_sig!("3045022100bf8e050c85ffa1c313108ad8c482c4849027937916374617af3f2e9a881861c9022023f65814222cab09d5ec41032ce9c72ca96a5676020736614de7b78a4e55325a");
728        check_lax_sig!("3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45");
729        check_lax_sig!("3046022100eaa5f90483eb20224616775891397d47efa64c68b969db1dacb1c30acdfc50aa022100cf9903bbefb1c8000cf482b0aeeb5af19287af20bd794de11d82716f9bae3db1");
730        check_lax_sig!("3045022047d512bc85842ac463ca3b669b62666ab8672ee60725b6c06759e476cebdc6c102210083805e93bd941770109bcc797784a71db9e48913f702c56e60b1c3e2ff379a60");
731        check_lax_sig!("3044022023ee4e95151b2fbbb08a72f35babe02830d14d54bd7ed1320e4751751d1baa4802206235245254f58fd1be6ff19ca291817da76da65c2f6d81d654b5185dd86b8acf");
732    }
733
734    #[test]
735    #[cfg(all(feature = "rand", feature = "std"))]
736    fn sign_and_verify_ecdsa() {
737        let mut s = Secp256k1::new();
738        s.randomize(&mut rand::rng());
739
740        let noncedata = [42u8; 32];
741        for _ in 0..100 {
742            let msg = crate::random_32_bytes(&mut rand::rng());
743            let msg = Message::from_digest(msg);
744
745            let (sk, pk) = crate::generate_keypair(&mut rand::rng());
746            let sig = ecdsa::sign(msg, &sk);
747            assert_eq!(ecdsa::verify(&sig, msg, &pk), Ok(()));
748            let noncedata_sig = ecdsa::sign_with_noncedata(msg, &sk, &noncedata);
749            assert_eq!(ecdsa::verify(&noncedata_sig, msg, &pk), Ok(()));
750            let low_r_sig = ecdsa::sign_low_r(msg, &sk);
751            assert_eq!(ecdsa::verify(&low_r_sig, msg, &pk), Ok(()));
752            let grind_r_sig = ecdsa::sign_grind_r(msg, &sk, 1);
753            assert_eq!(ecdsa::verify(&grind_r_sig, msg, &pk), Ok(()));
754            let compact = sig.serialize_compact();
755            if compact[0] < 0x80 {
756                assert_eq!(sig, low_r_sig);
757            } else {
758                #[cfg(not(secp256k1_fuzz))] // mocked sig generation doesn't produce low-R sigs
759                assert_ne!(sig, low_r_sig);
760            }
761            #[cfg(not(secp256k1_fuzz))] // mocked sig generation doesn't produce low-R sigs
762            assert!(ecdsa::compact_sig_has_zero_first_bit(&low_r_sig.0));
763            #[cfg(not(secp256k1_fuzz))] // mocked sig generation doesn't produce low-R sigs
764            assert!(ecdsa::der_length_check(&grind_r_sig.0, 70));
765        }
766    }
767
768    #[test]
769    #[cfg(all(feature = "rand", feature = "std"))]
770    fn sign_and_verify_extreme() {
771        let mut s = Secp256k1::new();
772        s.randomize(&mut rand::rng());
773
774        // Wild keys: 1, CURVE_ORDER - 1
775        // Wild msgs: 1, CURVE_ORDER - 1
776        let mut wild_keys = [[0u8; 32]; 2];
777        let mut wild_msgs = [[0u8; 32]; 2];
778
779        wild_keys[0][0] = 1;
780        wild_msgs[0][0] = 1;
781
782        use constants;
783        wild_keys[1][..].copy_from_slice(&constants::CURVE_ORDER[..]);
784        wild_msgs[1][..].copy_from_slice(&constants::CURVE_ORDER[..]);
785
786        wild_keys[1][0] -= 1;
787        wild_msgs[1][0] -= 1;
788
789        for key in wild_keys.iter().copied().map(SecretKey::from_secret_bytes).map(Result::unwrap) {
790            for msg in wild_msgs.into_iter().map(Message::from_digest) {
791                let sig = ecdsa::sign(msg, &key);
792                let low_r_sig = ecdsa::sign_low_r(msg, &key);
793                let grind_r_sig = ecdsa::sign_grind_r(msg, &key, 1);
794                let pk = PublicKey::from_secret_key(&key);
795                assert_eq!(ecdsa::verify(&sig, msg, &pk), Ok(()));
796                assert_eq!(ecdsa::verify(&low_r_sig, msg, &pk), Ok(()));
797                assert_eq!(ecdsa::verify(&grind_r_sig, msg, &pk), Ok(()));
798            }
799        }
800    }
801
802    #[test]
803    #[cfg(all(feature = "rand", feature = "std"))]
804    fn sign_and_verify_fail() {
805        let mut s = Secp256k1::new();
806        s.randomize(&mut rand::rng());
807
808        let msg = crate::random_32_bytes(&mut rand::rng());
809        let msg = Message::from_digest(msg);
810
811        let (sk, pk) = crate::generate_keypair(&mut rand::rng());
812
813        let sig = ecdsa::sign(msg, &sk);
814
815        let msg = crate::random_32_bytes(&mut rand::rng());
816        let msg = Message::from_digest(msg);
817        assert_eq!(ecdsa::verify(&sig, msg, &pk), Err(Error::IncorrectSignature));
818    }
819
820    #[test]
821    #[allow(deprecated)]
822    fn test_bad_slice() {
823        assert_eq!(
824            ecdsa::Signature::from_der(&[0; constants::MAX_SIGNATURE_SIZE + 1]),
825            Err(Error::InvalidSignature)
826        );
827        assert_eq!(
828            ecdsa::Signature::from_der(&[0; constants::MAX_SIGNATURE_SIZE]),
829            Err(Error::InvalidSignature)
830        );
831
832        assert_eq!(
833            Message::from_digest_slice(&[0; constants::MESSAGE_SIZE - 1]),
834            Err(Error::InvalidMessage)
835        );
836        assert_eq!(
837            Message::from_digest_slice(&[0; constants::MESSAGE_SIZE + 1]),
838            Err(Error::InvalidMessage)
839        );
840        assert!(Message::from_digest_slice(&[0; constants::MESSAGE_SIZE]).is_ok());
841        assert!(Message::from_digest_slice(&[1; constants::MESSAGE_SIZE]).is_ok());
842    }
843
844    #[test]
845    #[cfg(all(feature = "rand", feature = "std"))]
846    fn test_hex() {
847        use rand::RngCore;
848
849        use super::to_hex;
850
851        let mut rng = rand::rng();
852        const AMOUNT: usize = 1024;
853        for i in 0..AMOUNT {
854            // 255 isn't a valid utf8 character.
855            let mut hex_buf = [255u8; AMOUNT * 2];
856            let mut src_buf = [0u8; AMOUNT];
857            let mut result_buf = [0u8; AMOUNT];
858            let src = &mut src_buf[0..i];
859            rng.fill_bytes(src);
860
861            let hex = to_hex(src, &mut hex_buf).unwrap();
862            assert_eq!(from_hex(hex, &mut result_buf).unwrap(), i);
863            assert_eq!(src, &result_buf[..i]);
864        }
865
866        assert!(to_hex(&[1; 2], &mut [0u8; 3]).is_err());
867        assert!(to_hex(&[1; 2], &mut [0u8; 4]).is_ok());
868        assert!(from_hex("deadbeaf", &mut [0u8; 3]).is_err());
869        assert!(from_hex("deadbeaf", &mut [0u8; 4]).is_ok());
870        assert!(from_hex("a", &mut [0u8; 4]).is_err());
871        assert!(from_hex("ag", &mut [0u8; 4]).is_err());
872    }
873
874    #[test]
875    #[cfg(not(secp256k1_fuzz))] // fuzz-sigs have fixed size/format
876    #[cfg(any(feature = "alloc", feature = "std"))]
877    fn test_noncedata() {
878        let msg = hex!("887d04bb1cf1b1554f1b268dfe62d13064ca67ae45348d50d1392ce2d13418ac");
879        let msg = Message::from_digest(msg);
880        let noncedata = [42u8; 32];
881        let sk =
882            SecretKey::from_str("57f0148f94d13095cfda539d0da0d1541304b678d8b36e243980aab4e1b7cead")
883                .unwrap();
884        let expected_sig = hex!("24861b3edd4e7da43319c635091405feced6efa4ec99c3c3c35f6c3ba0ed8816116772e84994084db85a6c20589f6a85af569d42275c2a5dd900da5776b99d5d");
885        let expected_sig = ecdsa::Signature::from_compact(&expected_sig).unwrap();
886
887        let sig = ecdsa::sign_with_noncedata(msg, &sk, &noncedata);
888
889        assert_eq!(expected_sig, sig);
890    }
891
892    #[test]
893    #[cfg(not(secp256k1_fuzz))] // fixed sig vectors can't work with fuzz-sigs
894    #[cfg(any(feature = "alloc", feature = "std"))]
895    fn test_low_s() {
896        // nb this is a transaction on testnet
897        // txid 8ccc87b72d766ab3128f03176bb1c98293f2d1f85ebfaf07b82cc81ea6891fa9
898        //      input number 3
899        let sig = hex!("3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45");
900        let pk = hex!("031ee99d2b786ab3b0991325f2de8489246a6a3fdb700f6d0511b1d80cf5f4cd43");
901        let msg = hex!("a4965ca63b7d8562736ceec36dfa5a11bf426eb65be8ea3f7a49ae363032da0d");
902
903        let mut sig = ecdsa::Signature::from_der(&sig[..]).unwrap();
904        let pk = PublicKey::from_slice(&pk[..]).unwrap();
905        let msg = Message::from_digest(msg);
906
907        // without normalization we expect this will fail
908        assert_eq!(ecdsa::verify(&sig, msg, &pk), Err(Error::IncorrectSignature));
909        // after normalization it should pass
910        sig.normalize_s();
911        assert_eq!(ecdsa::verify(&sig, msg, &pk), Ok(()));
912    }
913
914    #[test]
915    #[cfg(not(secp256k1_fuzz))] // fuzz-sigs have fixed size/format
916    #[cfg(any(feature = "alloc", feature = "std"))]
917    fn test_low_r() {
918        let msg = hex!("887d04bb1cf1b1554f1b268dfe62d13064ca67ae45348d50d1392ce2d13418ac");
919        let msg = Message::from_digest(msg);
920        let sk =
921            SecretKey::from_str("57f0148f94d13095cfda539d0da0d1541304b678d8b36e243980aab4e1b7cead")
922                .unwrap();
923        let expected_sig = hex!("047dd4d049db02b430d24c41c7925b2725bcd5a85393513bdec04b4dc363632b1054d0180094122b380f4cfa391e6296244da773173e78fc745c1b9c79f7b713");
924        let expected_sig = ecdsa::Signature::from_compact(&expected_sig).unwrap();
925
926        let sig = ecdsa::sign_low_r(msg, &sk);
927
928        assert_eq!(expected_sig, sig);
929    }
930
931    #[test]
932    #[cfg(not(secp256k1_fuzz))] // fuzz-sigs have fixed size/format
933    #[cfg(any(feature = "alloc", feature = "std"))]
934    fn test_grind_r() {
935        let msg = hex!("ef2d5b9a7c61865a95941d0f04285420560df7e9d76890ac1b8867b12ce43167");
936        let msg = Message::from_digest(msg);
937        let sk =
938            SecretKey::from_str("848355d75fe1c354cf05539bb29b2015f1863065bcb6766b44d399ab95c3fa0b")
939                .unwrap();
940        let expected_sig = ecdsa::Signature::from_str("304302202ffc447100d518c8ba643d11f3e6a83a8640488e7d2537b1954b942408be6ea3021f26e1248dd1e52160c3a38af9769d91a1a806cab5f9d508c103464d3c02d6e1").unwrap();
941
942        let sig = ecdsa::sign_grind_r(msg, &sk, 2);
943
944        assert_eq!(expected_sig, sig);
945    }
946
947    #[cfg(feature = "serde")]
948    #[cfg(not(secp256k1_fuzz))] // fixed sig vectors can't work with fuzz-sigs
949    #[cfg(any(feature = "alloc", feature = "std"))]
950    #[test]
951    fn test_serde() {
952        use serde_test::{assert_tokens, Configure, Token};
953
954        let msg = Message::from_digest([1; 32]);
955        let sk = SecretKey::from_secret_bytes([2; 32]).unwrap();
956        let sig = ecdsa::sign(msg, &sk);
957        static SIG_BYTES: [u8; 71] = [
958            48, 69, 2, 33, 0, 157, 11, 173, 87, 103, 25, 211, 42, 231, 107, 237, 179, 76, 119, 72,
959            102, 103, 60, 189, 227, 244, 225, 41, 81, 85, 92, 148, 8, 230, 206, 119, 75, 2, 32, 40,
960            118, 231, 16, 47, 32, 79, 107, 254, 226, 108, 150, 124, 57, 38, 206, 112, 44, 249, 125,
961            75, 1, 0, 98, 225, 147, 247, 99, 25, 15, 103, 118,
962        ];
963        static SIG_STR: &str = "\
964            30450221009d0bad576719d32ae76bedb34c774866673cbde3f4e12951555c9408e6ce77\
965            4b02202876e7102f204f6bfee26c967c3926ce702cf97d4b010062e193f763190f6776\
966        ";
967
968        assert_tokens(&sig.compact(), &[Token::BorrowedBytes(&SIG_BYTES[..])]);
969        assert_tokens(&sig.compact(), &[Token::Bytes(&SIG_BYTES)]);
970        assert_tokens(&sig.compact(), &[Token::ByteBuf(&SIG_BYTES)]);
971
972        assert_tokens(&sig.readable(), &[Token::BorrowedStr(SIG_STR)]);
973        assert_tokens(&sig.readable(), &[Token::Str(SIG_STR)]);
974        assert_tokens(&sig.readable(), &[Token::String(SIG_STR)]);
975    }
976
977    #[test]
978    fn test_global_context() {
979        let sk_data = hex!("e6dd32f8761625f105c39a39f19370b3521d845a12456d60ce44debd0a362641");
980        let sk = SecretKey::from_secret_bytes(sk_data).unwrap();
981        let msg_data = hex!("a4965ca63b7d8562736ceec36dfa5a11bf426eb65be8ea3f7a49ae363032da0d");
982        let msg = Message::from_digest(msg_data);
983
984        // Check usage as explicit parameter
985        let pk = PublicKey::from_secret_key(&sk);
986
987        // Check usage as self
988        let sig = ecdsa::sign(msg, &sk);
989        assert!(ecdsa::verify(&sig, msg, &pk).is_ok());
990    }
991}
992
993#[cfg(bench)]
994#[cfg(all(feature = "rand", feature = "std"))]
995mod benches {
996    use rand::rngs::SmallRng;
997    use rand::SeedableRng as _;
998    use test::{black_box, Bencher};
999
1000    use super::*;
1001
1002    #[bench]
1003    pub fn generate(bh: &mut Bencher) {
1004        let mut r = SmallRng::seed_from_u64(1);
1005        bh.iter(|| {
1006            let (sk, pk) = crate::generate_keypair(&mut r);
1007            black_box(sk);
1008            black_box(pk);
1009        });
1010    }
1011
1012    #[bench]
1013    pub fn bench_sign_ecdsa(bh: &mut Bencher) {
1014        let msg = crate::random_32_bytes(&mut rand::rng());
1015        let msg = Message::from_digest(msg);
1016        let (sk, _) = crate::generate_keypair(&mut rand::rng());
1017
1018        bh.iter(|| {
1019            let sig = crate::ecdsa::sign(msg, &sk);
1020            black_box(sig);
1021        });
1022    }
1023
1024    #[bench]
1025    pub fn bench_verify_ecdsa(bh: &mut Bencher) {
1026        let msg = crate::random_32_bytes(&mut rand::rng());
1027        let msg = Message::from_digest(msg);
1028        let (sk, pk) = crate::generate_keypair(&mut rand::rng());
1029        let sig = crate::ecdsa::sign(msg, &sk);
1030
1031        bh.iter(|| {
1032            let res = ecdsa::verify(&sig, msg, &pk).unwrap();
1033            black_box(res);
1034        });
1035    }
1036}