From 1591bba3f922ddacb47fccde1c09142c72bb392b Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Mon, 6 Apr 2015 00:13:38 -0500 Subject: [PATCH] Update bindings to current secp256k1 library rust-secp256k1 was based off of https://github.com/sipa/secp256k1, which has been inactive nearly as long as this repository (prior to a couple days ago anyway). The correct repository is https://github.com/bitcoin/secp256k1 This is a major breaking change to the library for one reason: there are no longer any Nonce types in the safe interface. The signing functions do not take a nonce; this is generated internally. This also means that I was able to drop all my RFC6979 code, since libsecp256k1 has its own implementation. If you need to generate your own nonces, you need to create an unsafe function of type `ffi::NonceFn`, then pass it to the appropriate functions in the `ffi` module. There is no safe interface for doing this, deliberately: there is basically no need to directly fiddle with nonces ever. --- .travis.yml | 2 +- src/constants.rs | 4 +- src/ffi.rs | 37 ++++++++-- src/key.rs | 171 ++--------------------------------------------- src/secp256k1.rs | 126 ++++++++++++++++++---------------- 5 files changed, 104 insertions(+), 236 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4f2898a..1fd3c43 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: rust install: - - git clone https://github.com/sipa/secp256k1.git + - git clone https://github.com/bitcoin/secp256k1.git - cd secp256k1 - ./autogen.sh && ./configure && make && sudo make install - sudo ldconfig /usr/local/lib diff --git a/src/constants.rs b/src/constants.rs index ba70fb3..1c9125c 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -15,8 +15,8 @@ //! Constants -/// The size (in bytes) of a nonce -pub const NONCE_SIZE: usize = 32; +/// The size (in bytes) of a message +pub const MESSAGE_SIZE: usize = 32; /// The size (in bytes) of a secret key pub const SECRET_KEY_SIZE: usize = 32; diff --git a/src/ffi.rs b/src/ffi.rs index 408aa06..d5b3493 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -14,18 +14,35 @@ // //! FFI bindings -use libc::{c_int, c_uchar, c_uint}; +use libc::{c_int, c_uchar, c_uint, c_void}; pub const SECP256K1_START_VERIFY: c_uint = 0x1; pub const SECP256K1_START_SIGN: c_uint = 0x2; +/// A nonce generation function. Ordinary users of the library +/// never need to see this type; only if you need to control +/// nonce generation do you need to use it. I have deliberately +/// made this hard to do: you have to write your own wrapper +/// around the FFI functions to use it. And it's an unsafe type. +/// Nonces are generated deterministically by RFC6979 by +/// default; there should be no need to ever change this. +pub type NonceFn = unsafe extern "C" fn(nonce32: *mut c_uchar, + msg32: *const c_uchar, + key32: *const c_uchar, + attempt: c_uint, + data: *const c_void); + #[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_stop(); - pub fn secp256k1_ecdsa_verify(msg: *const c_uchar, msg_len: c_int, + pub fn secp256k1_ecdsa_verify(msg32: *const c_uchar, sig: *const c_uchar, sig_len: c_int, pk: *const c_uchar, pk_len: c_int) -> c_int; @@ -34,17 +51,19 @@ extern "C" { sk: *const c_uchar, compressed: c_int) -> c_int; - pub fn secp256k1_ecdsa_sign(msg: *const c_uchar, msg_len: c_int, + pub fn secp256k1_ecdsa_sign(msg32: *const c_uchar, sig: *mut c_uchar, sig_len: *mut c_int, - sk: *const c_uchar, nonce: *const c_uchar) + sk: *const c_uchar, + noncefn: NonceFn, noncedata: *const c_void) -> c_int; - pub fn secp256k1_ecdsa_sign_compact(msg: *const c_uchar, msg_len: c_int, + pub fn secp256k1_ecdsa_sign_compact(msg: *const c_uchar, sig64: *mut c_uchar, sk: *const c_uchar, - nonce: *const c_uchar, recid: *mut c_int) + noncefn: NonceFn, noncedata: *const c_void, + recid: *mut c_int) -> c_int; - pub fn secp256k1_ecdsa_recover_compact(msg: *const c_uchar, msg_len: c_int, + pub fn secp256k1_ecdsa_recover_compact(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; @@ -54,6 +73,10 @@ extern "C" { pub fn secp256k1_ec_pubkey_verify(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, tweak: *const c_uchar) -> c_int; diff --git a/src/key.rs b/src/key.rs index 828b1f0..8606329 100644 --- a/src/key.rs +++ b/src/key.rs @@ -16,24 +16,15 @@ //! Public/Private keys use std::intrinsics::copy_nonoverlapping; -use std::{cmp, fmt, ops}; +use std::{fmt, ops}; use rand::Rng; use serialize::{Decoder, Decodable, Encoder, Encodable}; -use crypto::digest::Digest; -use crypto::sha2::Sha512; -use crypto::hmac::Hmac; -use crypto::mac::Mac; - use super::init; -use super::Error::{self, InvalidNonce, InvalidPublicKey, InvalidSecretKey, Unknown}; +use super::Error::{self, InvalidPublicKey, InvalidSecretKey, Unknown}; use constants; use ffi; -/// Secret 256-bit nonce used as `k` in an ECDSA signature -pub struct Nonce([u8; constants::NONCE_SIZE]); -impl_array_newtype!(Nonce, u8, constants::NONCE_SIZE); - /// Secret 256-bit key used as `x` in an ECDSA signature pub struct SecretKey([u8; constants::SECRET_KEY_SIZE]); impl_array_newtype!(SecretKey, u8, constants::SECRET_KEY_SIZE); @@ -60,100 +51,6 @@ fn random_32_bytes(rng: &mut R) -> [u8; 32] { ret } -/// As described in RFC 6979 -fn bits2octets(data: &[u8]) -> [u8; 32] { - let mut ret = [0; 32]; - unsafe { - copy_nonoverlapping(data.as_ptr(), - ret.as_mut_ptr(), - cmp::min(data.len(), 32)); - } - ret -} - -impl Nonce { - /// Creates a new random nonce - #[inline] - pub fn new(rng: &mut R) -> Nonce { - Nonce(random_32_bytes(rng)) - } - - /// Converts a `NONCE_SIZE`-byte slice to a nonce - #[inline] - pub fn from_slice(data: &[u8]) -> Result { - match data.len() { - constants::NONCE_SIZE => { - let mut ret = [0; constants::NONCE_SIZE]; - unsafe { - copy_nonoverlapping(data.as_ptr(), - ret.as_mut_ptr(), - data.len()); - } - Ok(Nonce(ret)) - } - _ => Err(InvalidNonce) - } - } - - /// Generates a deterministic nonce by RFC6979 with HMAC-SHA512 - #[inline] - #[allow(non_snake_case)] // so we can match the names in the RFC - pub fn deterministic(msg: &[u8], key: &SecretKey) -> Nonce { - const HMAC_SIZE: usize = 64; - - macro_rules! hmac { - ($res:expr; key $key:expr, data $($data:expr),+) => ({ - let mut hmacker = Hmac::new(Sha512::new(), &$key[..]); - $(hmacker.input(&$data[..]);)+ - hmacker.raw_result(&mut $res); - }) - } - - // Section 3.2a - // Goofy block just to avoid marking `msg_hash` as mutable - let mut hasher = Sha512::new(); - hasher.input(msg); - let mut x = [0; HMAC_SIZE]; - hasher.result(&mut x); - let msg_hash = bits2octets(&x); - - // Section 3.2b - let mut V = [0x01u8; HMAC_SIZE]; - // Section 3.2c - let mut K = [0x00u8; HMAC_SIZE]; - - // Section 3.2d - hmac!(K; key K, data V, [0x00], key, msg_hash); - - // Section 3.2e - hmac!(V; key K, data V); - - // Section 3.2f - hmac!(K; key K, data V, [0x01], key, msg_hash); - - // Section 3.2g - hmac!(V; key K, data V); - - // Section 3.2 - let mut k = Err(InvalidSecretKey); - while k.is_err() { - // Try to generate the nonce - let mut T = [0x00u8; HMAC_SIZE]; - hmac!(T; key K, data V); - - k = Nonce::from_slice(&T[..constants::NONCE_SIZE]); - - // Replace K, V - if k.is_err() { - hmac!(K; key K, data V, [0x00]); - hmac!(V; key K, data V); - } - } - - k.unwrap() - } -} - impl SecretKey { /// Creates a new random secret key #[inline] @@ -352,12 +249,6 @@ impl PublicKey { // We have to do all these impls ourselves as Rust can't derive // them for arrays -impl fmt::Debug for Nonce { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - (&self[..]).fmt(f) - } -} - impl Clone for PublicKeyData { fn clone(&self) -> PublicKeyData { *self } } @@ -527,23 +418,11 @@ impl fmt::Debug for SecretKey { #[cfg(test)] mod test { - use serialize::hex::FromHex; - use rand::thread_rng; - use test::Bencher; use super::super::Secp256k1; - use super::super::Error::{InvalidNonce, InvalidPublicKey, InvalidSecretKey}; - use super::{Nonce, PublicKey, SecretKey}; - - #[test] - fn nonce_from_slice() { - let n = Nonce::from_slice(&[1; 31]); - assert_eq!(n, Err(InvalidNonce)); - - let n = SecretKey::from_slice(&[1; 32]); - assert!(n.is_ok()); - } + use super::super::Error::{InvalidPublicKey, InvalidSecretKey}; + use super::{PublicKey, SecretKey}; #[test] fn skey_from_slice() { @@ -581,13 +460,6 @@ mod test { assert_eq!(PublicKey::from_slice(&pk2[..]), Ok(pk2)); } - #[test] - fn nonce_slice_round_trip() { - let mut rng = thread_rng(); - let nonce = Nonce::new(&mut rng); - assert_eq!(Nonce::from_slice(&nonce[..]), Ok(nonce)); - } - #[test] fn invalid_secret_key() { // Zero @@ -624,41 +496,6 @@ mod test { assert_eq!(PublicKey::from_secret_key(&sk2, true), pk2); } - #[test] - fn test_deterministic() { - // nb code in comments is equivalent python - - // from ecdsa import rfc6979 - // from ecdsa.curves import SECP256k1 - // # This key was generated randomly - // sk = 0x09e918bbea76205445e9a73eaad2080a135d1e33e9dd1b3ca8a9a1285e7c1f81 - let sk = SecretKey::from_slice(hex_slice!("09e918bbea76205445e9a73eaad2080a135d1e33e9dd1b3ca8a9a1285e7c1f81")).unwrap(); - - // "%x" % rfc6979.generate_k(SECP256k1.generator, sk, hashlib.sha512, hashlib.sha512('').digest()) - let nonce = Nonce::deterministic(&[], &sk); - assert_eq!(&nonce[..], - hex_slice!("d954eddd184cac2b60edcd0e6be9ec54d93f633b28b366420d38ed9c346ffe27")); - - // "%x" % rfc6979.generate_k(SECP256k1.generator, sk, hashlib.sha512, hashlib.sha512('test').digest()) - let nonce = Nonce::deterministic(b"test", &sk); - assert_eq!(&nonce[..], - hex_slice!("609cc24acce2f19e46e38a82afc56c1745dee16e04f2b27e24999e1fefeb08bd")); - - // # Decrease the secret key by one - // sk = 0x09e918bbea76205445e9a73eaad2080a135d1e33e9dd1b3ca8a9a1285e7c1f80 - let sk = SecretKey::from_slice(hex_slice!("09e918bbea76205445e9a73eaad2080a135d1e33e9dd1b3ca8a9a1285e7c1f80")).unwrap(); - - // "%x" % rfc6979.generate_k(SECP256k1.generator, sk, hashlib.sha512, hashlib.sha512('').digest()) - let nonce = Nonce::deterministic(&[], &sk); - assert_eq!(&nonce[..], - hex_slice!("9f45f8d0a28e8956673c8da6db3db86ca4f172f0a2dbd62364fdbf786c7d96df")); - - // "%x" % rfc6979.generate_k(SECP256k1.generator, sk, hashlib.sha512, hashlib.sha512('test').digest()) - let nonce = Nonce::deterministic(b"test", &sk); - assert_eq!(&nonce[..], - hex_slice!("355c589ff662c838aee454d62b12c50a87b7e95ede2431c7cfa40b6ba2fddccd")); - } - #[bench] pub fn sequence_iterate(bh: &mut Bencher) { let mut s = Secp256k1::new().unwrap(); diff --git a/src/secp256k1.rs b/src/secp256k1.rs index 7279970..69bf2f3 100644 --- a/src/secp256k1.rs +++ b/src/secp256k1.rs @@ -43,7 +43,7 @@ extern crate libc; extern crate rand; use std::intrinsics::copy_nonoverlapping; -use std::{fmt, io, ops}; +use std::{fmt, io, ops, ptr}; use std::sync::{Once, ONCE_INIT}; use libc::c_int; use rand::{OsRng, Rng, SeedableRng}; @@ -162,19 +162,44 @@ impl Clone for Signature { } } +/// A (hashed) message input to an ECDSA signature +pub struct Message([u8; constants::MESSAGE_SIZE]); +impl_array_newtype!(Message, u8, constants::MESSAGE_SIZE); + +impl Message { + /// Converts a `MESSAGE_SIZE`-byte slice to a nonce + #[inline] + pub fn from_slice(data: &[u8]) -> Result { + match data.len() { + constants::MESSAGE_SIZE => { + let mut ret = [0; constants::MESSAGE_SIZE]; + unsafe { + copy_nonoverlapping(data.as_ptr(), + ret.as_mut_ptr(), + data.len()); + } + Ok(Message(ret)) + } + _ => Err(Error::InvalidMessage) + } + } +} + /// An ECDSA error #[derive(Copy, PartialEq, Eq, Clone, Debug)] pub enum Error { /// Signature failed verification IncorrectSignature, + /// Badly sized message + InvalidMessage, /// Bad public key InvalidPublicKey, /// Bad signature InvalidSignature, /// Bad secret key InvalidSecretKey, - /// Bad nonce - InvalidNonce, + /// Signing failed: bad nonce, bad privkey or signature was too small + SignFailed, /// Boolean-returning function returned the wrong boolean Unknown } @@ -228,23 +253,17 @@ impl Secp256k1 { (sk, pk) } - /// Generates a random nonce. Convenience function for `key::Nonce::new`; call - /// that function directly for batch nonce generation - #[inline] - pub fn generate_nonce(&mut self) -> key::Nonce { - key::Nonce::new(&mut self.rng) - } - /// Constructs a signature for `msg` using the secret key `sk` and nonce `nonce` - pub fn sign(&self, msg: &[u8], sk: &key::SecretKey, nonce: &key::Nonce) + pub fn sign(&self, msg: &Message, sk: &key::SecretKey) -> Result { 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(), msg.len() as c_int, - (&mut sig).as_mut_ptr(), &mut len, - sk.as_ptr(), nonce.as_ptr()) != 1 { - return Err(Error::InvalidNonce); + if ffi::secp256k1_ecdsa_sign(msg.as_ptr(), (&mut sig).as_mut_ptr(), + &mut len, sk.as_ptr(), + ffi::secp256k1_nonce_function_rfc6979, + ptr::null()) != 1 { + return Err(Error::SignFailed); } // This assertation is probably too late :) assert!(len as usize <= constants::MAX_SIGNATURE_SIZE); @@ -253,15 +272,16 @@ impl Secp256k1 { } /// Constructs a compact signature for `msg` using the secret key `sk` - pub fn sign_compact(&self, msg: &[u8], sk: &key::SecretKey, nonce: &key::Nonce) + pub fn sign_compact(&self, msg: &Message, sk: &key::SecretKey) -> Result<(Signature, RecoveryId), Error> { let mut sig = [0; constants::MAX_SIGNATURE_SIZE]; let mut recid = 0; unsafe { - if ffi::secp256k1_ecdsa_sign_compact(msg.as_ptr(), msg.len() as c_int, - (&mut sig).as_mut_ptr(), sk.as_ptr(), - nonce.as_ptr(), &mut recid) != 1 { - return Err(Error::InvalidNonce); + if ffi::secp256k1_ecdsa_sign_compact(msg.as_ptr(), + sig.as_mut_ptr(), sk.as_ptr(), + ffi::secp256k1_nonce_function_default, + ptr::null(), &mut recid) != 1 { + return Err(Error::SignFailed); } }; Ok((Signature(constants::MAX_COMPACT_SIGNATURE_SIZE, sig), RecoveryId(recid))) @@ -269,7 +289,7 @@ impl Secp256k1 { /// Determines the public key for which `sig` is a valid signature for /// `msg`. Returns through the out-pointer `pubkey`. - pub fn recover_compact(&self, msg: &[u8], sig: &[u8], + pub fn recover_compact(&self, msg: &Message, sig: &[u8], compressed: bool, recid: RecoveryId) -> Result { let mut pk = key::PublicKey::new(compressed); @@ -277,7 +297,7 @@ impl Secp256k1 { unsafe { let mut len = 0; - if ffi::secp256k1_ecdsa_recover_compact(msg.as_ptr(), msg.len() as c_int, + if ffi::secp256k1_ecdsa_recover_compact(msg.as_ptr(), sig.as_ptr(), pk.as_mut_ptr(), &mut len, if compressed {1} else {0}, recid) != 1 { @@ -294,17 +314,17 @@ impl Secp256k1 { /// there with zero-padded signatures that don't fit in the `Signature` type. /// Use `verify_raw` instead. #[inline] - pub fn verify(msg: &[u8], sig: &Signature, pk: &key::PublicKey) -> Result<(), Error> { + pub fn verify(msg: &Message, sig: &Signature, pk: &key::PublicKey) -> Result<(), Error> { Secp256k1::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: &[u8], sig: &[u8], pk: &key::PublicKey) -> Result<(), Error> { + pub fn verify_raw(msg: &Message, sig: &[u8], pk: &key::PublicKey) -> Result<(), Error> { init(); // This is a static function, so we have to init let res = unsafe { - ffi::secp256k1_ecdsa_verify(msg.as_ptr(), msg.len() as c_int, + ffi::secp256k1_ecdsa_verify(msg.as_ptr(), sig.as_ptr(), sig.len() as c_int, pk.as_ptr(), pk.len() as c_int) }; @@ -327,19 +347,19 @@ mod tests { use test::{Bencher, black_box}; - use key::{PublicKey, Nonce}; - use super::{Secp256k1, Signature}; + use key::PublicKey; + use super::{Secp256k1, Signature, Message}; use super::Error::{InvalidPublicKey, IncorrectSignature, InvalidSignature}; #[test] fn invalid_pubkey() { - let mut msg: Vec = repeat(0).take(32).collect(); 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(&mut msg, &sig, &pk), Err(InvalidPublicKey)); + assert_eq!(Secp256k1::verify(&msg, &sig, &pk), Err(InvalidPublicKey)); } #[test] @@ -348,12 +368,12 @@ mod tests { let (_, pk) = s.generate_keypair(false); - let mut msg: Vec = repeat(0).take(32).collect(); let sig = Signature::from_slice(&[0; 72]).unwrap(); - + let mut msg = [0u8; 32]; thread_rng().fill_bytes(&mut msg); + let msg = Message::from_slice(&msg).unwrap(); - assert_eq!(Secp256k1::verify(&mut msg, &sig, &pk), Err(InvalidSignature)); + assert_eq!(Secp256k1::verify(&msg, &sig, &pk), Err(InvalidSignature)); } #[test] @@ -361,12 +381,12 @@ mod tests { let mut s = Secp256k1::new().unwrap(); let (_, pk) = s.generate_keypair(true); - let mut msg: Vec = repeat(0).take(32).collect(); let sig = Signature::from_slice(&[0; 72]).unwrap(); - + let mut msg = [0u8; 32]; thread_rng().fill_bytes(&mut msg); + let msg = Message::from_slice(&msg).unwrap(); - assert_eq!(Secp256k1::verify(&mut msg, &sig, &pk), Err(InvalidSignature)); + assert_eq!(Secp256k1::verify(&msg, &sig, &pk), Err(InvalidSignature)); } #[test] @@ -375,11 +395,11 @@ mod tests { let mut msg = [0u8; 32]; thread_rng().fill_bytes(&mut msg); + let msg = Message::from_slice(&msg).unwrap(); let (sk, _) = s.generate_keypair(false); - let nonce = s.generate_nonce(); - s.sign(&msg, &sk, &nonce).unwrap(); + s.sign(&msg, &sk).unwrap(); } #[test] @@ -388,11 +408,11 @@ mod tests { let mut msg: Vec = repeat(0).take(32).collect(); thread_rng().fill_bytes(&mut msg); + let msg = Message::from_slice(&msg).unwrap(); let (sk, pk) = s.generate_keypair(false); - let nonce = s.generate_nonce(); - let sig = s.sign(&msg, &sk, &nonce).unwrap(); + let sig = s.sign(&msg, &sk).unwrap(); assert_eq!(Secp256k1::verify(&msg, &sig, &pk), Ok(())); } @@ -401,15 +421,17 @@ mod tests { fn sign_and_verify_fail() { let mut s = Secp256k1::new().unwrap(); - let mut msg: Vec = repeat(0).take(32).collect(); + 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 nonce = s.generate_nonce(); - let sig = s.sign(&msg, &sk, &nonce).unwrap(); + let sig = s.sign(&msg, &sk).unwrap(); + 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)); } @@ -419,29 +441,15 @@ mod tests { 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 nonce = s.generate_nonce(); - let (sig, recid) = s.sign_compact(&msg, &sk, &nonce).unwrap(); + let (sig, recid) = s.sign_compact(&msg, &sk).unwrap(); assert_eq!(s.recover_compact(&msg, &sig[..], false, recid), Ok(pk)); } - #[test] - fn deterministic_sign() { - let mut msg = [0u8; 32]; - thread_rng().fill_bytes(&mut msg); - - let mut s = Secp256k1::new().unwrap(); - let (sk, pk) = s.generate_keypair(true); - let nonce = Nonce::deterministic(&mut msg, &sk); - - let sig = s.sign(&msg, &sk, &nonce).unwrap(); - - assert_eq!(Secp256k1::verify(&msg, &sig, &pk), Ok(())); - } - #[bench] pub fn generate_compressed(bh: &mut Bencher) { let mut s = Secp256k1::new().unwrap();