[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

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

View File

@ -35,7 +35,6 @@
#![deny(unused_mut)]
#![warn(missing_docs)]
extern crate crypto;
extern crate rustc_serialize as serialize;
extern crate serde;
#[cfg(test)] extern crate test;
@ -44,11 +43,9 @@ extern crate libc;
extern crate rand;
use std::intrinsics::copy_nonoverlapping;
use std::{cmp, fmt, io, ops, ptr};
use std::{cmp, fmt, ops, ptr};
use libc::c_int;
use rand::{OsRng, Rng, SeedableRng};
use crypto::fortuna::Fortuna;
use rand::Rng;
#[macro_use]
mod macros;
@ -233,84 +230,55 @@ impl fmt::Display for Error {
}
/// The secp256k1 engine, used to execute all signature operations
pub struct Secp256k1<R = Fortuna> {
ctx: ffi::Context,
rng: R
pub struct Secp256k1 {
ctx: ffi::Context
}
impl<R: Clone> Clone for Secp256k1<R> {
fn clone(&self) -> Secp256k1<R> {
impl Clone for Secp256k1 {
fn clone(&self) -> Secp256k1 {
Secp256k1 {
ctx: unsafe { ffi::secp256k1_context_clone(self.ctx) },
rng: self.rng.clone()
ctx: unsafe { ffi::secp256k1_context_clone(self.ctx) }
}
}
}
impl<R: PartialEq> PartialEq for Secp256k1<R> {
fn eq(&self, other: &Secp256k1<R>) -> bool {
// The contexts will always be "equal" in a functional sense
self.rng == other.rng
impl PartialEq for Secp256k1 {
// Contexts will always be "equal" in a functional sense
fn eq(&self, _: &Secp256k1) -> bool { true }
}
}
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> {
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) {
unsafe { ffi::secp256k1_context_destroy(self.ctx); }
}
}
impl Secp256k1<()> {
/// Constructs a new secp256k1 engine without a RNG. This is
/// useful for, e.g. BIP32 implementations, where all keys are
/// 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> {
impl Secp256k1 {
/// Creates a new Secp256k1 context
pub fn new() -> Secp256k1 {
let ctx = unsafe {
ffi::secp256k1_context_create(ffi::SECP256K1_START_VERIFY |
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`
@ -412,7 +380,7 @@ mod tests {
#[test]
fn invalid_pubkey() {
let s = Secp256k1::new_deterministic();
let s = Secp256k1::new();
let sig = Signature::from_slice(&[0; 72]).unwrap();
let pk = PublicKey::new(true);
let mut msg = [0u8; 32];
@ -424,9 +392,9 @@ mod tests {
#[test]
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 mut msg = [0u8; 32];
@ -438,9 +406,9 @@ mod tests {
#[test]
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 mut msg = [0u8; 32];
thread_rng().fill_bytes(&mut msg);
@ -451,7 +419,7 @@ mod tests {
#[test]
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,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
@ -473,14 +441,14 @@ mod tests {
#[test]
fn sign_and_verify() {
let mut s = Secp256k1::new().unwrap();
let s = Secp256k1::new();
let mut msg = [0; 32];
for _ in 0..100 {
thread_rng().fill_bytes(&mut msg);
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);
assert_eq!(s.verify(&msg, &sig, &pk), Ok(()));
}
@ -488,13 +456,13 @@ mod tests {
#[test]
fn sign_and_verify_fail() {
let mut s = Secp256k1::new().unwrap();
let s = Secp256k1::new();
let mut msg = [0u8; 32];
thread_rng().fill_bytes(&mut msg);
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_compact, recid) = s.sign_compact(&msg, &sk);
@ -510,13 +478,13 @@ mod tests {
#[test]
fn sign_compact_with_recovery() {
let mut s = Secp256k1::new().unwrap();
let s = Secp256k1::new();
let mut msg = [0u8; 32];
thread_rng().fill_bytes(&mut msg);
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);
@ -525,7 +493,7 @@ mod tests {
#[test]
fn bad_recovery() {
let s = Secp256k1::new().unwrap();
let s = Secp256k1::new();
let msg = Message::from_slice(&[0x55; 32]).unwrap();
@ -569,9 +537,15 @@ mod tests {
#[bench]
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( || {
let (sk, pk) = s.generate_keypair(true);
let (sk, pk) = s.generate_keypair(&mut r, true);
black_box(sk);
black_box(pk);
});
@ -579,9 +553,15 @@ mod tests {
#[bench]
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( || {
let (sk, pk) = s.generate_keypair(false);
let (sk, pk) = s.generate_keypair(&mut r, false);
black_box(sk);
black_box(pk);
});