[API BREAK] Remove Rng from Secp256k1 and associated code

The Rng was only used for key generation, and for BIP32 users not even then;
thus hauling around a Rng is a waste of space in addition to causing a
massive amount of syntactic noise. For example rust-bitcoin almost always
uses `()` as the Rng; having `Secp256k1` default to a `Secp256k1<Fortuna>`
then means even more syntactic noise, rather than less.

Now key generation functions take a Rng as a parameter, and the rest can
forget about having a Rng. This also means that the Secp256k1 context
never needs a mutable reference and can be easily put into an Arc if so
desired.
This commit is contained in:
Andrew Poelstra 2015-04-12 15:54:22 -05:00
parent 83823379e4
commit fb75373b47
2 changed files with 94 additions and 119 deletions

View File

@ -46,7 +46,7 @@ enum PublicKeyData {
Uncompressed([u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE]) Uncompressed([u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE])
} }
fn random_32_bytes<R:Rng>(rng: &mut R) -> [u8; 32] { fn random_32_bytes<R: Rng>(rng: &mut R) -> [u8; 32] {
let mut ret = [0u8; 32]; let mut ret = [0u8; 32];
rng.fill_bytes(&mut ret); rng.fill_bytes(&mut ret);
ret ret
@ -55,11 +55,11 @@ fn random_32_bytes<R:Rng>(rng: &mut R) -> [u8; 32] {
impl SecretKey { impl SecretKey {
/// Creates a new random secret key /// Creates a new random secret key
#[inline] #[inline]
pub fn new<R: Rng>(secp: &mut Secp256k1<R>) -> SecretKey { pub fn new<R: Rng>(secp: &Secp256k1, rng: &mut R) -> SecretKey {
let mut data = random_32_bytes(&mut secp.rng); let mut data = random_32_bytes(rng);
unsafe { unsafe {
while ffi::secp256k1_ec_seckey_verify(secp.ctx, data.as_ptr()) == 0 { while ffi::secp256k1_ec_seckey_verify(secp.ctx, data.as_ptr()) == 0 {
data = random_32_bytes(&mut secp.rng); data = random_32_bytes(rng);
} }
} }
SecretKey(data) SecretKey(data)
@ -67,7 +67,7 @@ impl SecretKey {
/// Converts a `SECRET_KEY_SIZE`-byte slice to a secret key /// Converts a `SECRET_KEY_SIZE`-byte slice to a secret key
#[inline] #[inline]
pub fn from_slice<R>(secp: &Secp256k1<R>, data: &[u8]) pub fn from_slice(secp: &Secp256k1, data: &[u8])
-> Result<SecretKey, Error> { -> Result<SecretKey, Error> {
match data.len() { match data.len() {
constants::SECRET_KEY_SIZE => { constants::SECRET_KEY_SIZE => {
@ -88,10 +88,8 @@ impl SecretKey {
#[inline] #[inline]
/// Adds one secret key to another, modulo the curve order /// Adds one secret key to another, modulo the curve order
pub fn add_assign<R>(&mut self, pub fn add_assign(&mut self, secp: &Secp256k1, other: &SecretKey)
secp: &Secp256k1<R>, -> Result<(), Error> {
other: &SecretKey)
-> Result<(), Error> {
unsafe { unsafe {
if ffi::secp256k1_ec_privkey_tweak_add(secp.ctx, self.as_mut_ptr(), other.as_ptr()) != 1 { if ffi::secp256k1_ec_privkey_tweak_add(secp.ctx, self.as_mut_ptr(), other.as_ptr()) != 1 {
Err(Unknown) Err(Unknown)
@ -117,7 +115,7 @@ impl PublicKey {
/// Creates a new public key from a secret key. /// Creates a new public key from a secret key.
#[inline] #[inline]
pub fn from_secret_key<R>(secp: &Secp256k1<R>, pub fn from_secret_key(secp: &Secp256k1,
sk: &SecretKey, sk: &SecretKey,
compressed: bool) compressed: bool)
-> PublicKey { -> PublicKey {
@ -139,7 +137,7 @@ impl PublicKey {
/// Creates a public key directly from a slice /// Creates a public key directly from a slice
#[inline] #[inline]
pub fn from_slice<R>(secp: &Secp256k1<R>, data: &[u8]) pub fn from_slice(secp: &Secp256k1, data: &[u8])
-> Result<PublicKey, Error> { -> Result<PublicKey, Error> {
match data.len() { match data.len() {
constants::COMPRESSED_PUBLIC_KEY_SIZE => { constants::COMPRESSED_PUBLIC_KEY_SIZE => {
@ -216,10 +214,8 @@ impl PublicKey {
#[inline] #[inline]
/// Adds the pk corresponding to `other` to the pk `self` in place /// Adds the pk corresponding to `other` to the pk `self` in place
pub fn add_exp_assign<R>(&mut self, pub fn add_exp_assign(&mut self, secp: &Secp256k1, other: &SecretKey)
secp: &Secp256k1<R>, -> Result<(), Error> {
other: &SecretKey)
-> Result<(), Error> {
unsafe { unsafe {
if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx, self.as_mut_ptr(), if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx, self.as_mut_ptr(),
self.len() as ::libc::c_int, self.len() as ::libc::c_int,
@ -473,11 +469,11 @@ mod test {
use super::{PublicKey, SecretKey}; use super::{PublicKey, SecretKey};
use super::super::constants; use super::super::constants;
use rand::Rng; use rand::{Rng, thread_rng};
#[test] #[test]
fn skey_from_slice() { fn skey_from_slice() {
let s = Secp256k1::new().unwrap(); let s = Secp256k1::new();
let sk = SecretKey::from_slice(&s, &[1; 31]); let sk = SecretKey::from_slice(&s, &[1; 31]);
assert_eq!(sk, Err(InvalidSecretKey)); assert_eq!(sk, Err(InvalidSecretKey));
@ -487,7 +483,7 @@ mod test {
#[test] #[test]
fn pubkey_from_slice() { fn pubkey_from_slice() {
let s = Secp256k1::new().unwrap(); let s = Secp256k1::new();
assert_eq!(PublicKey::from_slice(&s, &[]), Err(InvalidPublicKey)); assert_eq!(PublicKey::from_slice(&s, &[]), Err(InvalidPublicKey));
assert_eq!(PublicKey::from_slice(&s, &[1, 2, 3]), Err(InvalidPublicKey)); assert_eq!(PublicKey::from_slice(&s, &[1, 2, 3]), Err(InvalidPublicKey));
@ -502,20 +498,20 @@ mod test {
#[test] #[test]
fn keypair_slice_round_trip() { fn keypair_slice_round_trip() {
let mut s = Secp256k1::new().unwrap(); let s = Secp256k1::new();
let (sk1, pk1) = s.generate_keypair(true); let (sk1, pk1) = s.generate_keypair(&mut thread_rng(), true);
assert_eq!(SecretKey::from_slice(&s, &sk1[..]), Ok(sk1)); assert_eq!(SecretKey::from_slice(&s, &sk1[..]), Ok(sk1));
assert_eq!(PublicKey::from_slice(&s, &pk1[..]), Ok(pk1)); assert_eq!(PublicKey::from_slice(&s, &pk1[..]), Ok(pk1));
let (sk2, pk2) = s.generate_keypair(false); let (sk2, pk2) = s.generate_keypair(&mut thread_rng(), false);
assert_eq!(SecretKey::from_slice(&s, &sk2[..]), Ok(sk2)); assert_eq!(SecretKey::from_slice(&s, &sk2[..]), Ok(sk2));
assert_eq!(PublicKey::from_slice(&s, &pk2[..]), Ok(pk2)); assert_eq!(PublicKey::from_slice(&s, &pk2[..]), Ok(pk2));
} }
#[test] #[test]
fn invalid_secret_key() { fn invalid_secret_key() {
let s = Secp256k1::new().unwrap(); let s = Secp256k1::new();
// Zero // Zero
assert_eq!(SecretKey::from_slice(&s, &[0; 32]), Err(InvalidSecretKey)); assert_eq!(SecretKey::from_slice(&s, &[0; 32]), Err(InvalidSecretKey));
// -1 // -1
@ -589,12 +585,12 @@ mod test {
}) })
); );
let mut s = Secp256k1::new().unwrap(); let s = Secp256k1::new();
for _ in 0..500 { for _ in 0..500 {
let (sk, pk) = s.generate_keypair(false); let (sk, pk) = s.generate_keypair(&mut thread_rng(), false);
round_trip!(sk); round_trip!(sk);
round_trip!(pk); round_trip!(pk);
let (sk, pk) = s.generate_keypair(true); let (sk, pk) = s.generate_keypair(&mut thread_rng(), true);
round_trip!(sk); round_trip!(sk);
round_trip!(pk); round_trip!(pk);
} }
@ -650,12 +646,12 @@ mod test {
}) })
); );
let mut s = Secp256k1::new().unwrap(); let s = Secp256k1::new();
for _ in 0..500 { for _ in 0..500 {
let (sk, pk) = s.generate_keypair(false); let (sk, pk) = s.generate_keypair(&mut thread_rng(), false);
round_trip!(sk); round_trip!(sk);
round_trip!(pk); round_trip!(pk);
let (sk, pk) = s.generate_keypair(true); let (sk, pk) = s.generate_keypair(&mut thread_rng(), true);
round_trip!(sk); round_trip!(sk);
round_trip!(pk); round_trip!(pk);
} }
@ -688,15 +684,14 @@ mod test {
} }
} }
let mut s = Secp256k1::with_rng(BadRng(0xff)); let s = Secp256k1::new();
s.generate_keypair(false); s.generate_keypair(&mut BadRng(0xff), false);
let mut s = Secp256k1::with_rng(BadRng(0xff)); s.generate_keypair(&mut BadRng(0xff), true);
s.generate_keypair(true);
} }
#[test] #[test]
fn test_pubkey_from_bad_slice() { fn test_pubkey_from_bad_slice() {
let s = Secp256k1::new_deterministic(); let s = Secp256k1::new();
// Bad sizes // Bad sizes
assert_eq!(PublicKey::from_slice(&s, &[0; constants::COMPRESSED_PUBLIC_KEY_SIZE - 1]), assert_eq!(PublicKey::from_slice(&s, &[0; constants::COMPRESSED_PUBLIC_KEY_SIZE - 1]),
Err(InvalidPublicKey)); Err(InvalidPublicKey));
@ -724,26 +719,26 @@ mod test {
} }
} }
let mut s = Secp256k1::with_rng(DumbRng(0)); let s = Secp256k1::new();
let (sk1, pk1) = s.generate_keypair(false); let (sk1, pk1) = s.generate_keypair(&mut DumbRng(0), false);
let (sk2, pk2) = s.generate_keypair(true); let (sk2, pk2) = s.generate_keypair(&mut DumbRng(0), true);
assert_eq!(&format!("{:?}", sk1), assert_eq!(&format!("{:?}", sk1),
"SecretKey(0200000001000000040000000300000006000000050000000800000007000000)"); "SecretKey(0200000001000000040000000300000006000000050000000800000007000000)");
assert_eq!(&format!("{:?}", pk1), assert_eq!(&format!("{:?}", pk1),
"PublicKey(049510c48c265cefb3413be0e6b75beef02ebafcaf6634f962b27b4832abc4feec01bd8ff2e31057f7b7a244ed8c5ccd9781a63a6f607b40b493330cd159ecd5ce)"); "PublicKey(049510c48c265cefb3413be0e6b75beef02ebafcaf6634f962b27b4832abc4feec01bd8ff2e31057f7b7a244ed8c5ccd9781a63a6f607b40b493330cd159ecd5ce)");
assert_eq!(&format!("{:?}", sk2), assert_eq!(&format!("{:?}", sk2),
"SecretKey(0a000000090000000c0000000b0000000e0000000d000000100000000f000000)"); "SecretKey(0200000001000000040000000300000006000000050000000800000007000000)");
assert_eq!(&format!("{:?}", pk2), assert_eq!(&format!("{:?}", pk2),
"PublicKey(024889f1f4a9407f8588b55358c2b392a6d9662872d5b9fff98b6f68c5e290a866)"); "PublicKey(029510c48c265cefb3413be0e6b75beef02ebafcaf6634f962b27b4832abc4feec)");
} }
#[test] #[test]
fn test_addition() { fn test_addition() {
let mut s = Secp256k1::new().unwrap(); let s = Secp256k1::new();
let (mut sk1, mut pk1) = s.generate_keypair(true); let (mut sk1, mut pk1) = s.generate_keypair(&mut thread_rng(), true);
let (mut sk2, mut pk2) = s.generate_keypair(true); let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng(), true);
assert_eq!(PublicKey::from_secret_key(&s, &sk1, true), pk1); assert_eq!(PublicKey::from_secret_key(&s, &sk1, true), pk1);
assert!(sk1.add_assign(&s, &sk2).is_ok()); assert!(sk1.add_assign(&s, &sk2).is_ok());

View File

@ -35,7 +35,6 @@
#![deny(unused_mut)] #![deny(unused_mut)]
#![warn(missing_docs)] #![warn(missing_docs)]
extern crate crypto;
extern crate rustc_serialize as serialize; extern crate rustc_serialize as serialize;
extern crate serde; extern crate serde;
#[cfg(test)] extern crate test; #[cfg(test)] extern crate test;
@ -44,11 +43,9 @@ extern crate libc;
extern crate rand; extern crate rand;
use std::intrinsics::copy_nonoverlapping; use std::intrinsics::copy_nonoverlapping;
use std::{cmp, fmt, io, ops, ptr}; use std::{cmp, fmt, ops, ptr};
use libc::c_int; use libc::c_int;
use rand::{OsRng, Rng, SeedableRng}; use rand::Rng;
use crypto::fortuna::Fortuna;
#[macro_use] #[macro_use]
mod macros; mod macros;
@ -233,84 +230,55 @@ impl fmt::Display for Error {
} }
/// The secp256k1 engine, used to execute all signature operations /// The secp256k1 engine, used to execute all signature operations
pub struct Secp256k1<R = Fortuna> { pub struct Secp256k1 {
ctx: ffi::Context, ctx: ffi::Context
rng: R
} }
impl<R: Clone> Clone for Secp256k1<R> { impl Clone for Secp256k1 {
fn clone(&self) -> Secp256k1<R> { fn clone(&self) -> Secp256k1 {
Secp256k1 { Secp256k1 {
ctx: unsafe { ffi::secp256k1_context_clone(self.ctx) }, ctx: unsafe { ffi::secp256k1_context_clone(self.ctx) }
rng: self.rng.clone()
} }
} }
} }
impl<R: PartialEq> PartialEq for Secp256k1<R> { impl PartialEq for Secp256k1 {
fn eq(&self, other: &Secp256k1<R>) -> bool { // Contexts will always be "equal" in a functional sense
// The contexts will always be "equal" in a functional sense fn eq(&self, _: &Secp256k1) -> bool { true }
self.rng == other.rng
}
} }
impl<R: Eq> Eq for Secp256k1<R> { } impl Eq for Secp256k1 { }
impl<R: fmt::Debug> fmt::Debug for Secp256k1<R> { impl fmt::Debug for Secp256k1 {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "Secp256k1 {{ ctx: (secp256k1 context), rng: {:?} }}", self.rng) write!(f, "Secp256k1 {{ secp256k1 context }}")
} }
} }
impl<R> Drop for Secp256k1<R> { impl Drop for Secp256k1 {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { ffi::secp256k1_context_destroy(self.ctx); } unsafe { ffi::secp256k1_context_destroy(self.ctx); }
} }
} }
impl Secp256k1<()> { impl Secp256k1 {
/// Constructs a new secp256k1 engine without a RNG. This is /// Creates a new Secp256k1 context
/// useful for, e.g. BIP32 implementations, where all keys are pub fn new() -> Secp256k1 {
/// computed externally to the secp256k1 engine. Note that if
/// you try to use this for `SecretKey::new`, which generates
/// a random key, it will panic.
pub fn new_deterministic() -> Secp256k1<()> {
Secp256k1::with_rng(())
}
}
impl Secp256k1<Fortuna> {
/// Constructs a new secp256k1 engine with the default key-generation Rng
/// (a Fortuna seeded with randomness from the OS during `new`)
pub fn new() -> io::Result<Secp256k1<Fortuna>> {
let mut osrng = try!(OsRng::new());
let mut seed = [0; 2048];
osrng.fill_bytes(&mut seed);
let rng: Fortuna = SeedableRng::from_seed(&seed[..]);
Ok(Secp256k1::with_rng(rng))
}
}
impl<R: Rng> Secp256k1<R> {
/// Generates a random keypair. Convenience function for `key::SecretKey::new`
/// and `key::PublicKey::from_secret_key`; call those functions directly for
/// batch key generation.
#[inline]
pub fn generate_keypair(&mut self, compressed: bool)
-> (key::SecretKey, key::PublicKey) {
let sk = key::SecretKey::new(self);
let pk = key::PublicKey::from_secret_key(self, &sk, compressed);
(sk, pk)
}
}
impl<R> Secp256k1<R> {
/// Constructs a new secp256k1 engine with its key-generation RNG specified
pub fn with_rng(rng: R) -> Secp256k1<R> {
let ctx = unsafe { let ctx = unsafe {
ffi::secp256k1_context_create(ffi::SECP256K1_START_VERIFY | ffi::secp256k1_context_create(ffi::SECP256K1_START_VERIFY |
ffi::SECP256K1_START_SIGN) ffi::SECP256K1_START_SIGN)
}; };
Secp256k1 { ctx: ctx, rng: rng } Secp256k1 { ctx: ctx }
}
/// Generates a random keypair. Convenience function for `key::SecretKey::new`
/// and `key::PublicKey::from_secret_key`; call those functions directly for
/// batch key generation.
#[inline]
pub fn generate_keypair<R: Rng>(&self, rng: &mut R, compressed: bool)
-> (key::SecretKey, key::PublicKey) {
let sk = key::SecretKey::new(self, rng);
let pk = key::PublicKey::from_secret_key(self, &sk, compressed);
(sk, pk)
} }
/// Constructs a signature for `msg` using the secret key `sk` and nonce `nonce` /// Constructs a signature for `msg` using the secret key `sk` and nonce `nonce`
@ -412,7 +380,7 @@ mod tests {
#[test] #[test]
fn invalid_pubkey() { fn invalid_pubkey() {
let s = Secp256k1::new_deterministic(); let s = Secp256k1::new();
let sig = Signature::from_slice(&[0; 72]).unwrap(); let sig = Signature::from_slice(&[0; 72]).unwrap();
let pk = PublicKey::new(true); let pk = PublicKey::new(true);
let mut msg = [0u8; 32]; let mut msg = [0u8; 32];
@ -424,9 +392,9 @@ mod tests {
#[test] #[test]
fn valid_pubkey_uncompressed() { fn valid_pubkey_uncompressed() {
let mut s = Secp256k1::new().unwrap(); let s = Secp256k1::new();
let (_, pk) = s.generate_keypair(false); let (_, pk) = s.generate_keypair(&mut thread_rng(), false);
let sig = Signature::from_slice(&[0; 72]).unwrap(); let sig = Signature::from_slice(&[0; 72]).unwrap();
let mut msg = [0u8; 32]; let mut msg = [0u8; 32];
@ -438,9 +406,9 @@ mod tests {
#[test] #[test]
fn valid_pubkey_compressed() { fn valid_pubkey_compressed() {
let mut s = Secp256k1::new().unwrap(); let s = Secp256k1::new();
let (_, pk) = s.generate_keypair(true); let (_, pk) = s.generate_keypair(&mut thread_rng(), true);
let sig = Signature::from_slice(&[0; 72]).unwrap(); let sig = Signature::from_slice(&[0; 72]).unwrap();
let mut msg = [0u8; 32]; let mut msg = [0u8; 32];
thread_rng().fill_bytes(&mut msg); thread_rng().fill_bytes(&mut msg);
@ -451,7 +419,7 @@ mod tests {
#[test] #[test]
fn sign() { fn sign() {
let s = Secp256k1::new_deterministic(); let s = Secp256k1::new();
let one = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, let one = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
@ -473,14 +441,14 @@ mod tests {
#[test] #[test]
fn sign_and_verify() { fn sign_and_verify() {
let mut s = Secp256k1::new().unwrap(); let s = Secp256k1::new();
let mut msg = [0; 32]; let mut msg = [0; 32];
for _ in 0..100 { for _ in 0..100 {
thread_rng().fill_bytes(&mut msg); thread_rng().fill_bytes(&mut msg);
let msg = Message::from_slice(&msg).unwrap(); let msg = Message::from_slice(&msg).unwrap();
let (sk, pk) = s.generate_keypair(false); let (sk, pk) = s.generate_keypair(&mut thread_rng(), false);
let sig = s.sign(&msg, &sk); let sig = s.sign(&msg, &sk);
assert_eq!(s.verify(&msg, &sig, &pk), Ok(())); assert_eq!(s.verify(&msg, &sig, &pk), Ok(()));
} }
@ -488,13 +456,13 @@ mod tests {
#[test] #[test]
fn sign_and_verify_fail() { fn sign_and_verify_fail() {
let mut s = Secp256k1::new().unwrap(); let s = Secp256k1::new();
let mut msg = [0u8; 32]; let mut msg = [0u8; 32];
thread_rng().fill_bytes(&mut msg); thread_rng().fill_bytes(&mut msg);
let msg = Message::from_slice(&msg).unwrap(); let msg = Message::from_slice(&msg).unwrap();
let (sk, pk) = s.generate_keypair(false); let (sk, pk) = s.generate_keypair(&mut thread_rng(), false);
let sig = s.sign(&msg, &sk); let sig = s.sign(&msg, &sk);
let (sig_compact, recid) = s.sign_compact(&msg, &sk); let (sig_compact, recid) = s.sign_compact(&msg, &sk);
@ -510,13 +478,13 @@ mod tests {
#[test] #[test]
fn sign_compact_with_recovery() { fn sign_compact_with_recovery() {
let mut s = Secp256k1::new().unwrap(); let s = Secp256k1::new();
let mut msg = [0u8; 32]; let mut msg = [0u8; 32];
thread_rng().fill_bytes(&mut msg); thread_rng().fill_bytes(&mut msg);
let msg = Message::from_slice(&msg).unwrap(); let msg = Message::from_slice(&msg).unwrap();
let (sk, pk) = s.generate_keypair(false); let (sk, pk) = s.generate_keypair(&mut thread_rng(), false);
let (sig, recid) = s.sign_compact(&msg, &sk); let (sig, recid) = s.sign_compact(&msg, &sk);
@ -525,7 +493,7 @@ mod tests {
#[test] #[test]
fn bad_recovery() { fn bad_recovery() {
let s = Secp256k1::new().unwrap(); let s = Secp256k1::new();
let msg = Message::from_slice(&[0x55; 32]).unwrap(); let msg = Message::from_slice(&[0x55; 32]).unwrap();
@ -569,9 +537,15 @@ mod tests {
#[bench] #[bench]
pub fn generate_compressed(bh: &mut Bencher) { pub fn generate_compressed(bh: &mut Bencher) {
let mut s = Secp256k1::new().unwrap(); struct CounterRng(u32);
impl Rng for CounterRng {
fn next_u32(&mut self) -> u32 { self.0 += 1; self.0 }
}
let s = Secp256k1::new();
let mut r = CounterRng(0);
bh.iter( || { bh.iter( || {
let (sk, pk) = s.generate_keypair(true); let (sk, pk) = s.generate_keypair(&mut r, true);
black_box(sk); black_box(sk);
black_box(pk); black_box(pk);
}); });
@ -579,9 +553,15 @@ mod tests {
#[bench] #[bench]
pub fn generate_uncompressed(bh: &mut Bencher) { pub fn generate_uncompressed(bh: &mut Bencher) {
let mut s = Secp256k1::new().unwrap(); struct CounterRng(u32);
impl Rng for CounterRng {
fn next_u32(&mut self) -> u32 { self.0 += 1; self.0 }
}
let s = Secp256k1::new();
let mut r = CounterRng(0);
bh.iter( || { bh.iter( || {
let (sk, pk) = s.generate_keypair(false); let (sk, pk) = s.generate_keypair(&mut r, false);
black_box(sk); black_box(sk);
black_box(pk); black_box(pk);
}); });