diff --git a/src/ffi.rs b/src/ffi.rs index d5b3493..dde4b0e 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -32,65 +32,87 @@ pub type NonceFn = unsafe extern "C" fn(nonce32: *mut c_uchar, attempt: c_uint, data: *const c_void); +#[repr(C)] +struct ContextInner; + +/// A Secp256k1 context, containing various precomputed values and such +/// needed to do elliptic curve computations. If you create one of these +/// with `secp256k1_context_create` you MUST destroy it with +/// `secp256k1_context_destroy`, or else you will have a memory leak. +/// Furthermore, you MUST NOT use this object after destroying it; it is +/// `Copy` so the compiler will not help you to avoid this. There is no +/// need for ordinary users of this library to ever use this type directly. +#[repr(C)] +#[allow(raw_pointer_derive)] +#[derive(Copy, Clone, Debug)] +pub struct Context(*mut ContextInner); + #[link(name = "secp256k1")] extern "C" { pub static secp256k1_nonce_function_rfc6979: NonceFn; pub static secp256k1_nonce_function_default: NonceFn; - pub fn secp256k1_start(flags: c_uint); + pub fn secp256k1_context_create(flags: c_uint) -> Context; - pub fn secp256k1_stop(); + pub fn secp256k1_context_destroy(cx: Context); - pub fn secp256k1_ecdsa_verify(msg32: *const c_uchar, + pub fn secp256k1_ecdsa_verify(cx: Context, msg32: *const c_uchar, sig: *const c_uchar, sig_len: c_int, pk: *const c_uchar, pk_len: c_int) -> c_int; - pub fn secp256k1_ec_pubkey_create(pk: *mut c_uchar, pk_len: *mut c_int, + pub fn secp256k1_ec_pubkey_create(cx: Context, + pk: *mut c_uchar, pk_len: *mut c_int, sk: *const c_uchar, compressed: c_int) -> c_int; - pub fn secp256k1_ecdsa_sign(msg32: *const c_uchar, + pub fn secp256k1_ecdsa_sign(cx: Context, msg32: *const c_uchar, sig: *mut c_uchar, sig_len: *mut c_int, sk: *const c_uchar, noncefn: NonceFn, noncedata: *const c_void) -> c_int; - pub fn secp256k1_ecdsa_sign_compact(msg: *const c_uchar, + pub fn secp256k1_ecdsa_sign_compact(cx: Context, msg: *const c_uchar, sig64: *mut c_uchar, sk: *const c_uchar, noncefn: NonceFn, noncedata: *const c_void, recid: *mut c_int) -> c_int; - pub fn secp256k1_ecdsa_recover_compact(msg32: *const c_uchar, + pub fn secp256k1_ecdsa_recover_compact(cx: Context, msg32: *const c_uchar, sig64: *const c_uchar, pk: *mut c_uchar, pk_len: *mut c_int, compressed: c_int, recid: c_int) -> c_int; - pub fn secp256k1_ec_seckey_verify(sk: *const c_uchar) -> c_int; + pub fn secp256k1_ec_seckey_verify(cx: Context, + sk: *const c_uchar) -> c_int; - pub fn secp256k1_ec_pubkey_verify(pk: *const c_uchar, + pub fn secp256k1_ec_pubkey_verify(cx: Context, + pk: *const c_uchar, pk_len: c_int) -> c_int; //TODO secp256k1_ec_pubkey_decompress //TODO secp256k1_ec_privkey_export //TODO secp256k1_ec_privkey_import - pub fn secp256k1_ec_privkey_tweak_add(sk: *mut c_uchar, + pub fn secp256k1_ec_privkey_tweak_add(cx: Context, + sk: *mut c_uchar, tweak: *const c_uchar) -> c_int; - pub fn secp256k1_ec_pubkey_tweak_add(pk: *mut c_uchar, + pub fn secp256k1_ec_pubkey_tweak_add(cx: Context, + pk: *mut c_uchar, pk_len: c_int, tweak: *const c_uchar) -> c_int; - pub fn secp256k1_ec_privkey_tweak_mul(sk: *mut c_uchar, + pub fn secp256k1_ec_privkey_tweak_mul(cx: Context, + sk: *mut c_uchar, tweak: *const c_uchar) -> c_int; - pub fn secp256k1_ec_pubkey_tweak_mul(pk: *mut c_uchar, + pub fn secp256k1_ec_pubkey_tweak_mul(cx: Context, + pk: *mut c_uchar, pk_len: c_int, tweak: *const c_uchar) -> c_int; diff --git a/src/key.rs b/src/key.rs index 1488cc1..4eced48 100644 --- a/src/key.rs +++ b/src/key.rs @@ -21,7 +21,7 @@ use rand::Rng; use serialize::{Decoder, Decodable, Encoder, Encodable}; use serde::{Serialize, Deserialize, Serializer, Deserializer}; -use super::init; +use super::Secp256k1; use super::Error::{self, InvalidPublicKey, InvalidSecretKey, Unknown}; use constants; use ffi; @@ -55,12 +55,11 @@ fn random_32_bytes(rng: &mut R) -> [u8; 32] { impl SecretKey { /// Creates a new random secret key #[inline] - pub fn new(rng: &mut R) -> SecretKey { - init(); - let mut data = random_32_bytes(rng); + pub fn new(secp: &mut Secp256k1) -> SecretKey { + let mut data = random_32_bytes(&mut secp.rng); unsafe { - while ffi::secp256k1_ec_seckey_verify(data.as_ptr()) == 0 { - data = random_32_bytes(rng); + while ffi::secp256k1_ec_seckey_verify(secp.ctx, data.as_ptr()) == 0 { + data = random_32_bytes(&mut secp.rng); } } SecretKey(data) @@ -68,13 +67,12 @@ impl SecretKey { /// Converts a `SECRET_KEY_SIZE`-byte slice to a secret key #[inline] - pub fn from_slice(data: &[u8]) -> Result { - init(); + pub fn from_slice(secp: &Secp256k1, data: &[u8]) -> Result { match data.len() { constants::SECRET_KEY_SIZE => { let mut ret = [0; constants::SECRET_KEY_SIZE]; unsafe { - if ffi::secp256k1_ec_seckey_verify(data.as_ptr()) == 0 { + if ffi::secp256k1_ec_seckey_verify(secp.ctx, data.as_ptr()) == 0 { return Err(InvalidSecretKey); } copy_nonoverlapping(data.as_ptr(), @@ -89,13 +87,9 @@ impl SecretKey { #[inline] /// Adds one secret key to another, modulo the curve order - /// Marked `unsafe` since you must - /// call `init()` (or construct a `Secp256k1`, which does this for you) before - /// using this function - pub fn add_assign(&mut self, other: &SecretKey) -> Result<(), Error> { - init(); + pub fn add_assign(&mut self, secp: &Secp256k1, other: &SecretKey) -> Result<(), Error> { unsafe { - if ffi::secp256k1_ec_privkey_tweak_add(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) } else { Ok(()) @@ -119,16 +113,16 @@ impl PublicKey { /// Creates a new public key from a secret key. #[inline] - pub fn from_secret_key(sk: &SecretKey, compressed: bool) -> PublicKey { + pub fn from_secret_key(secp: &Secp256k1, sk: &SecretKey, compressed: bool) -> PublicKey { let mut pk = PublicKey::new(compressed); let compressed = if compressed {1} else {0}; let mut len = 0; - init(); unsafe { // We can assume the return value because it's not possible to construct // an invalid `SecretKey` without transmute trickery or something assert_eq!(ffi::secp256k1_ec_pubkey_create( + secp.ctx, pk.as_mut_ptr(), &mut len, sk.as_ptr(), compressed), 1); } @@ -138,13 +132,13 @@ impl PublicKey { /// Creates a public key directly from a slice #[inline] - pub fn from_slice(data: &[u8]) -> Result { + pub fn from_slice(secp: &Secp256k1, data: &[u8]) -> Result { match data.len() { constants::COMPRESSED_PUBLIC_KEY_SIZE => { let mut ret = [0; constants::COMPRESSED_PUBLIC_KEY_SIZE]; unsafe { - if ffi::secp256k1_ec_pubkey_verify(data.as_ptr(), - data.len() as ::libc::c_int) == 0 { + if ffi::secp256k1_ec_pubkey_verify(secp.ctx, data.as_ptr(), + data.len() as ::libc::c_int) == 0 { return Err(InvalidPublicKey); } copy_nonoverlapping(data.as_ptr(), @@ -210,10 +204,9 @@ impl PublicKey { #[inline] /// Adds the pk corresponding to `other` to the pk `self` in place - pub fn add_exp_assign(&mut self, other: &SecretKey) -> Result<(), Error> { - init(); + pub fn add_exp_assign(&mut self, secp: &Secp256k1, other: &SecretKey) -> Result<(), Error> { unsafe { - if ffi::secp256k1_ec_pubkey_tweak_add(self.as_mut_ptr(), + if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx, self.as_mut_ptr(), self.len() as ::libc::c_int, other.as_ptr()) != 1 { Err(Unknown) @@ -459,23 +452,25 @@ mod test { #[test] fn skey_from_slice() { - let sk = SecretKey::from_slice(&[1; 31]); + let s = Secp256k1::new().unwrap(); + let sk = SecretKey::from_slice(&s, &[1; 31]); assert_eq!(sk, Err(InvalidSecretKey)); - let sk = SecretKey::from_slice(&[1; 32]); + let sk = SecretKey::from_slice(&s, &[1; 32]); assert!(sk.is_ok()); } #[test] fn pubkey_from_slice() { - assert_eq!(PublicKey::from_slice(&[]), Err(InvalidPublicKey)); - assert_eq!(PublicKey::from_slice(&[1, 2, 3]), Err(InvalidPublicKey)); + let s = Secp256k1::new().unwrap(); + assert_eq!(PublicKey::from_slice(&s, &[]), Err(InvalidPublicKey)); + assert_eq!(PublicKey::from_slice(&s, &[1, 2, 3]), Err(InvalidPublicKey)); - let uncompressed = PublicKey::from_slice(&[4, 54, 57, 149, 239, 162, 148, 175, 246, 254, 239, 75, 154, 152, 10, 82, 234, 224, 85, 220, 40, 100, 57, 121, 30, 162, 94, 156, 135, 67, 74, 49, 179, 57, 236, 53, 162, 124, 149, 144, 168, 77, 74, 30, 72, 211, 229, 110, 111, 55, 96, 193, 86, 227, 183, 152, 195, 155, 51, 247, 123, 113, 60, 228, 188]); + let uncompressed = PublicKey::from_slice(&s, &[4, 54, 57, 149, 239, 162, 148, 175, 246, 254, 239, 75, 154, 152, 10, 82, 234, 224, 85, 220, 40, 100, 57, 121, 30, 162, 94, 156, 135, 67, 74, 49, 179, 57, 236, 53, 162, 124, 149, 144, 168, 77, 74, 30, 72, 211, 229, 110, 111, 55, 96, 193, 86, 227, 183, 152, 195, 155, 51, 247, 123, 113, 60, 228, 188]); assert!(uncompressed.is_ok()); assert!(!uncompressed.unwrap().is_compressed()); - let compressed = PublicKey::from_slice(&[3, 23, 183, 225, 206, 31, 159, 148, 195, 42, 67, 115, 146, 41, 248, 140, 11, 3, 51, 41, 111, 180, 110, 143, 114, 134, 88, 73, 198, 174, 52, 184, 78]); + let compressed = PublicKey::from_slice(&s, &[3, 23, 183, 225, 206, 31, 159, 148, 195, 42, 67, 115, 146, 41, 248, 140, 11, 3, 51, 41, 111, 180, 110, 143, 114, 134, 88, 73, 198, 174, 52, 184, 78]); assert!(compressed.is_ok()); assert!(compressed.unwrap().is_compressed()); } @@ -485,27 +480,30 @@ mod test { let mut s = Secp256k1::new().unwrap(); let (sk1, pk1) = s.generate_keypair(true); - assert_eq!(SecretKey::from_slice(&sk1[..]), Ok(sk1)); - assert_eq!(PublicKey::from_slice(&pk1[..]), Ok(pk1)); + 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); - assert_eq!(SecretKey::from_slice(&sk2[..]), Ok(sk2)); - assert_eq!(PublicKey::from_slice(&pk2[..]), Ok(pk2)); + 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(); // Zero - assert_eq!(SecretKey::from_slice(&[0; 32]), Err(InvalidSecretKey)); + assert_eq!(SecretKey::from_slice(&s, &[0; 32]), Err(InvalidSecretKey)); // -1 - assert_eq!(SecretKey::from_slice(&[0xff; 32]), Err(InvalidSecretKey)); + assert_eq!(SecretKey::from_slice(&s, &[0xff; 32]), Err(InvalidSecretKey)); // Top of range - assert!(SecretKey::from_slice(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + assert!(SecretKey::from_slice(&s, + &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x40]).is_ok()); // One past top of range - assert!(SecretKey::from_slice(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + assert!(SecretKey::from_slice(&s, + &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41]).is_err()); @@ -578,15 +576,15 @@ mod test { let (mut sk1, mut pk1) = s.generate_keypair(true); let (mut sk2, mut pk2) = s.generate_keypair(true); - assert_eq!(PublicKey::from_secret_key(&sk1, true), pk1); - assert!(sk1.add_assign(&sk2).is_ok()); - assert!(pk1.add_exp_assign(&sk2).is_ok()); - assert_eq!(PublicKey::from_secret_key(&sk1, true), pk1); + assert_eq!(PublicKey::from_secret_key(&s, &sk1, true), pk1); + assert!(sk1.add_assign(&s, &sk2).is_ok()); + assert!(pk1.add_exp_assign(&s, &sk2).is_ok()); + assert_eq!(PublicKey::from_secret_key(&s, &sk1, true), pk1); - assert_eq!(PublicKey::from_secret_key(&sk2, true), pk2); - assert!(sk2.add_assign(&sk1).is_ok()); - assert!(pk2.add_exp_assign(&sk1).is_ok()); - assert_eq!(PublicKey::from_secret_key(&sk2, true), pk2); + assert_eq!(PublicKey::from_secret_key(&s, &sk2, true), pk2); + assert!(sk2.add_assign(&s, &sk1).is_ok()); + assert!(pk2.add_exp_assign(&s, &sk1).is_ok()); + assert_eq!(PublicKey::from_secret_key(&s, &sk2, true), pk2); } } diff --git a/src/lib.rs b/src/lib.rs index 6fc9339..33005ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,7 +45,6 @@ extern crate rand; use std::intrinsics::copy_nonoverlapping; use std::{fmt, io, ops, ptr}; -use std::sync::{Once, ONCE_INIT}; use libc::c_int; use rand::{OsRng, Rng, SeedableRng}; @@ -212,35 +211,29 @@ impl fmt::Display for Error { } } -static mut Secp256k1_init: Once = ONCE_INIT; - /// The secp256k1 engine, used to execute all signature operations pub struct Secp256k1 { + ctx: ffi::Context, rng: Fortuna } -/// Does one-time initialization of the secp256k1 engine. Can be called -/// multiple times, and is called by the `Secp256k1` constructor. This -/// only needs to be called directly if you are using the library without -/// a `Secp256k1` object, e.g. batch key generation through -/// `key::PublicKey::from_secret_key`. -pub fn init() { - unsafe { - Secp256k1_init.call_once(|| { - ffi::secp256k1_start(ffi::SECP256K1_START_VERIFY | - ffi::SECP256K1_START_SIGN); - }); +impl Drop for Secp256k1 { + fn drop(&mut self) { + unsafe { ffi::secp256k1_context_destroy(self.ctx); } } } impl Secp256k1 { /// Constructs a new secp256k1 engine. pub fn new() -> io::Result { - init(); + let ctx = unsafe { + ffi::secp256k1_context_create(ffi::SECP256K1_START_VERIFY | + ffi::SECP256K1_START_SIGN) + }; let mut osrng = try!(OsRng::new()); let mut seed = [0; 2048]; osrng.fill_bytes(&mut seed); - Ok(Secp256k1 { rng: SeedableRng::from_seed(&seed[..]) }) + Ok(Secp256k1 { ctx: ctx, rng: SeedableRng::from_seed(&seed[..]) }) } /// Generates a random keypair. Convenience function for `key::SecretKey::new` @@ -249,8 +242,8 @@ impl Secp256k1 { #[inline] pub fn generate_keypair(&mut self, compressed: bool) -> (key::SecretKey, key::PublicKey) { - let sk = key::SecretKey::new(&mut self.rng); - let pk = key::PublicKey::from_secret_key(&sk, compressed); + let sk = key::SecretKey::new(self); + let pk = key::PublicKey::from_secret_key(self, &sk, compressed); (sk, pk) } @@ -260,7 +253,7 @@ impl Secp256k1 { let mut sig = [0; constants::MAX_SIGNATURE_SIZE]; let mut len = constants::MAX_SIGNATURE_SIZE as c_int; unsafe { - if ffi::secp256k1_ecdsa_sign(msg.as_ptr(), (&mut sig).as_mut_ptr(), + if ffi::secp256k1_ecdsa_sign(self.ctx, msg.as_ptr(), sig.as_mut_ptr(), &mut len, sk.as_ptr(), ffi::secp256k1_nonce_function_rfc6979, ptr::null()) != 1 { @@ -278,7 +271,7 @@ impl Secp256k1 { let mut sig = [0; constants::MAX_SIGNATURE_SIZE]; let mut recid = 0; unsafe { - if ffi::secp256k1_ecdsa_sign_compact(msg.as_ptr(), + if ffi::secp256k1_ecdsa_sign_compact(self.ctx, msg.as_ptr(), sig.as_mut_ptr(), sk.as_ptr(), ffi::secp256k1_nonce_function_default, ptr::null(), &mut recid) != 1 { @@ -298,7 +291,7 @@ impl Secp256k1 { unsafe { let mut len = 0; - if ffi::secp256k1_ecdsa_recover_compact(msg.as_ptr(), + if ffi::secp256k1_ecdsa_recover_compact(self.ctx, msg.as_ptr(), sig.as_ptr(), pk.as_mut_ptr(), &mut len, if compressed {1} else {0}, recid) != 1 { @@ -311,21 +304,17 @@ impl Secp256k1 { /// Checks that `sig` is a valid ECDSA signature for `msg` using the public /// key `pubkey`. Returns `Ok(true)` on success. Note that this function cannot - /// be used for Bitcoin consensus checking since there are transactions out - /// there with zero-padded signatures that don't fit in the `Signature` type. - /// Use `verify_raw` instead. + /// be used for Bitcoin consensus checking since there may exist signatures + /// which OpenSSL would verify but not libsecp256k1, or vice-versa. #[inline] - pub fn verify(msg: &Message, sig: &Signature, pk: &key::PublicKey) -> Result<(), Error> { - Secp256k1::verify_raw(msg, &sig[..], pk) + pub fn verify(&self, msg: &Message, sig: &Signature, pk: &key::PublicKey) -> Result<(), Error> { + self.verify_raw(msg, &sig[..], pk) } - /// Checks that `sig` is a valid ECDSA signature for `msg` using the public - /// key `pubkey`. Returns `Ok(true)` on success. - #[inline] - pub fn verify_raw(msg: &Message, sig: &[u8], pk: &key::PublicKey) -> Result<(), Error> { - init(); // This is a static function, so we have to init + /// Verifies a signature described as a slice of bytes rather than opaque `Signature` + pub fn verify_raw(&self, msg: &Message, sig: &[u8], pk: &key::PublicKey) -> Result<(), Error> { let res = unsafe { - ffi::secp256k1_ecdsa_verify(msg.as_ptr(), + ffi::secp256k1_ecdsa_verify(self.ctx, msg.as_ptr(), sig.as_ptr(), sig.len() as c_int, pk.as_ptr(), pk.len() as c_int) }; @@ -354,13 +343,14 @@ mod tests { #[test] fn invalid_pubkey() { + let s = Secp256k1::new().unwrap(); let sig = Signature::from_slice(&[0; 72]).unwrap(); let pk = PublicKey::new(true); let mut msg = [0u8; 32]; thread_rng().fill_bytes(&mut msg); let msg = Message::from_slice(&msg).unwrap(); - assert_eq!(Secp256k1::verify(&msg, &sig, &pk), Err(InvalidPublicKey)); + assert_eq!(s.verify(&msg, &sig, &pk), Err(InvalidPublicKey)); } #[test] @@ -374,7 +364,7 @@ mod tests { thread_rng().fill_bytes(&mut msg); let msg = Message::from_slice(&msg).unwrap(); - assert_eq!(Secp256k1::verify(&msg, &sig, &pk), Err(InvalidSignature)); + assert_eq!(s.verify(&msg, &sig, &pk), Err(InvalidSignature)); } #[test] @@ -387,7 +377,7 @@ mod tests { thread_rng().fill_bytes(&mut msg); let msg = Message::from_slice(&msg).unwrap(); - assert_eq!(Secp256k1::verify(&msg, &sig, &pk), Err(InvalidSignature)); + assert_eq!(s.verify(&msg, &sig, &pk), Err(InvalidSignature)); } #[test] @@ -415,7 +405,7 @@ mod tests { let sig = s.sign(&msg, &sk).unwrap(); - assert_eq!(Secp256k1::verify(&msg, &sig, &pk), Ok(())); + assert_eq!(s.verify(&msg, &sig, &pk), Ok(())); } #[test] @@ -433,7 +423,7 @@ mod tests { let mut msg = [0u8; 32]; thread_rng().fill_bytes(&mut msg); let msg = Message::from_slice(&msg).unwrap(); - assert_eq!(Secp256k1::verify(&msg, &sig, &pk), Err(IncorrectSignature)); + assert_eq!(s.verify(&msg, &sig, &pk), Err(IncorrectSignature)); } #[test]