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.
This commit is contained in:
Andrew Poelstra 2015-04-06 00:13:38 -05:00
parent f6585616b1
commit 1591bba3f9
5 changed files with 104 additions and 236 deletions

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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<R:Rng>(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<R:Rng>(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<Nonce, Error> {
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();

View File

@ -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<Message, Error> {
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<Signature, Error> {
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<key::PublicKey, Error> {
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<u8> = 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<u8> = 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<u8> = 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<u8> = 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<u8> = 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();