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:
parent
f6585616b1
commit
1591bba3f9
|
@ -1,7 +1,7 @@
|
||||||
language: rust
|
language: rust
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- git clone https://github.com/sipa/secp256k1.git
|
- git clone https://github.com/bitcoin/secp256k1.git
|
||||||
- cd secp256k1
|
- cd secp256k1
|
||||||
- ./autogen.sh && ./configure && make && sudo make install
|
- ./autogen.sh && ./configure && make && sudo make install
|
||||||
- sudo ldconfig /usr/local/lib
|
- sudo ldconfig /usr/local/lib
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
|
|
||||||
//! Constants
|
//! Constants
|
||||||
|
|
||||||
/// The size (in bytes) of a nonce
|
/// The size (in bytes) of a message
|
||||||
pub const NONCE_SIZE: usize = 32;
|
pub const MESSAGE_SIZE: usize = 32;
|
||||||
|
|
||||||
/// The size (in bytes) of a secret key
|
/// The size (in bytes) of a secret key
|
||||||
pub const SECRET_KEY_SIZE: usize = 32;
|
pub const SECRET_KEY_SIZE: usize = 32;
|
||||||
|
|
37
src/ffi.rs
37
src/ffi.rs
|
@ -14,18 +14,35 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
//! FFI bindings
|
//! 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_VERIFY: c_uint = 0x1;
|
||||||
pub const SECP256K1_START_SIGN: c_uint = 0x2;
|
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")]
|
#[link(name = "secp256k1")]
|
||||||
extern "C" {
|
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_start(flags: c_uint);
|
||||||
|
|
||||||
pub fn secp256k1_stop();
|
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,
|
sig: *const c_uchar, sig_len: c_int,
|
||||||
pk: *const c_uchar, pk_len: c_int)
|
pk: *const c_uchar, pk_len: c_int)
|
||||||
-> c_int;
|
-> c_int;
|
||||||
|
@ -34,17 +51,19 @@ extern "C" {
|
||||||
sk: *const c_uchar, compressed: c_int)
|
sk: *const c_uchar, compressed: c_int)
|
||||||
-> 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,
|
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;
|
-> 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,
|
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;
|
-> 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,
|
sig64: *const c_uchar, pk: *mut c_uchar,
|
||||||
pk_len: *mut c_int, compressed: c_int,
|
pk_len: *mut c_int, compressed: c_int,
|
||||||
recid: c_int) -> c_int;
|
recid: c_int) -> c_int;
|
||||||
|
@ -54,6 +73,10 @@ extern "C" {
|
||||||
pub fn secp256k1_ec_pubkey_verify(pk: *const c_uchar,
|
pub fn secp256k1_ec_pubkey_verify(pk: *const c_uchar,
|
||||||
pk_len: c_int) -> c_int;
|
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(sk: *mut c_uchar,
|
||||||
tweak: *const c_uchar)
|
tweak: *const c_uchar)
|
||||||
-> c_int;
|
-> c_int;
|
||||||
|
|
171
src/key.rs
171
src/key.rs
|
@ -16,24 +16,15 @@
|
||||||
//! Public/Private keys
|
//! Public/Private keys
|
||||||
|
|
||||||
use std::intrinsics::copy_nonoverlapping;
|
use std::intrinsics::copy_nonoverlapping;
|
||||||
use std::{cmp, fmt, ops};
|
use std::{fmt, ops};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use serialize::{Decoder, Decodable, Encoder, Encodable};
|
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::init;
|
||||||
use super::Error::{self, InvalidNonce, InvalidPublicKey, InvalidSecretKey, Unknown};
|
use super::Error::{self, InvalidPublicKey, InvalidSecretKey, Unknown};
|
||||||
use constants;
|
use constants;
|
||||||
use ffi;
|
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
|
/// Secret 256-bit key used as `x` in an ECDSA signature
|
||||||
pub struct SecretKey([u8; constants::SECRET_KEY_SIZE]);
|
pub struct SecretKey([u8; constants::SECRET_KEY_SIZE]);
|
||||||
impl_array_newtype!(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
|
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 {
|
impl SecretKey {
|
||||||
/// Creates a new random secret key
|
/// Creates a new random secret key
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -352,12 +249,6 @@ impl PublicKey {
|
||||||
|
|
||||||
// We have to do all these impls ourselves as Rust can't derive
|
// We have to do all these impls ourselves as Rust can't derive
|
||||||
// them for arrays
|
// them for arrays
|
||||||
impl fmt::Debug for Nonce {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
(&self[..]).fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clone for PublicKeyData {
|
impl Clone for PublicKeyData {
|
||||||
fn clone(&self) -> PublicKeyData { *self }
|
fn clone(&self) -> PublicKeyData { *self }
|
||||||
}
|
}
|
||||||
|
@ -527,23 +418,11 @@ impl fmt::Debug for SecretKey {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use serialize::hex::FromHex;
|
|
||||||
use rand::thread_rng;
|
|
||||||
|
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
use super::super::Secp256k1;
|
use super::super::Secp256k1;
|
||||||
use super::super::Error::{InvalidNonce, InvalidPublicKey, InvalidSecretKey};
|
use super::super::Error::{InvalidPublicKey, InvalidSecretKey};
|
||||||
use super::{Nonce, PublicKey, SecretKey};
|
use super::{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());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn skey_from_slice() {
|
fn skey_from_slice() {
|
||||||
|
@ -581,13 +460,6 @@ mod test {
|
||||||
assert_eq!(PublicKey::from_slice(&pk2[..]), Ok(pk2));
|
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]
|
#[test]
|
||||||
fn invalid_secret_key() {
|
fn invalid_secret_key() {
|
||||||
// Zero
|
// Zero
|
||||||
|
@ -624,41 +496,6 @@ mod test {
|
||||||
assert_eq!(PublicKey::from_secret_key(&sk2, true), pk2);
|
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]
|
#[bench]
|
||||||
pub fn sequence_iterate(bh: &mut Bencher) {
|
pub fn sequence_iterate(bh: &mut Bencher) {
|
||||||
let mut s = Secp256k1::new().unwrap();
|
let mut s = Secp256k1::new().unwrap();
|
||||||
|
|
126
src/secp256k1.rs
126
src/secp256k1.rs
|
@ -43,7 +43,7 @@ extern crate libc;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
|
||||||
use std::intrinsics::copy_nonoverlapping;
|
use std::intrinsics::copy_nonoverlapping;
|
||||||
use std::{fmt, io, ops};
|
use std::{fmt, io, ops, ptr};
|
||||||
use std::sync::{Once, ONCE_INIT};
|
use std::sync::{Once, ONCE_INIT};
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
use rand::{OsRng, Rng, SeedableRng};
|
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
|
/// An ECDSA error
|
||||||
#[derive(Copy, PartialEq, Eq, Clone, Debug)]
|
#[derive(Copy, PartialEq, Eq, Clone, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Signature failed verification
|
/// Signature failed verification
|
||||||
IncorrectSignature,
|
IncorrectSignature,
|
||||||
|
/// Badly sized message
|
||||||
|
InvalidMessage,
|
||||||
/// Bad public key
|
/// Bad public key
|
||||||
InvalidPublicKey,
|
InvalidPublicKey,
|
||||||
/// Bad signature
|
/// Bad signature
|
||||||
InvalidSignature,
|
InvalidSignature,
|
||||||
/// Bad secret key
|
/// Bad secret key
|
||||||
InvalidSecretKey,
|
InvalidSecretKey,
|
||||||
/// Bad nonce
|
/// Signing failed: bad nonce, bad privkey or signature was too small
|
||||||
InvalidNonce,
|
SignFailed,
|
||||||
/// Boolean-returning function returned the wrong boolean
|
/// Boolean-returning function returned the wrong boolean
|
||||||
Unknown
|
Unknown
|
||||||
}
|
}
|
||||||
|
@ -228,23 +253,17 @@ impl Secp256k1 {
|
||||||
(sk, pk)
|
(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`
|
/// 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> {
|
-> Result<Signature, Error> {
|
||||||
let mut sig = [0; constants::MAX_SIGNATURE_SIZE];
|
let mut sig = [0; constants::MAX_SIGNATURE_SIZE];
|
||||||
let mut len = constants::MAX_SIGNATURE_SIZE as c_int;
|
let mut len = constants::MAX_SIGNATURE_SIZE as c_int;
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::secp256k1_ecdsa_sign(msg.as_ptr(), msg.len() as c_int,
|
if ffi::secp256k1_ecdsa_sign(msg.as_ptr(), (&mut sig).as_mut_ptr(),
|
||||||
(&mut sig).as_mut_ptr(), &mut len,
|
&mut len, sk.as_ptr(),
|
||||||
sk.as_ptr(), nonce.as_ptr()) != 1 {
|
ffi::secp256k1_nonce_function_rfc6979,
|
||||||
return Err(Error::InvalidNonce);
|
ptr::null()) != 1 {
|
||||||
|
return Err(Error::SignFailed);
|
||||||
}
|
}
|
||||||
// This assertation is probably too late :)
|
// This assertation is probably too late :)
|
||||||
assert!(len as usize <= constants::MAX_SIGNATURE_SIZE);
|
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`
|
/// 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> {
|
-> Result<(Signature, RecoveryId), Error> {
|
||||||
let mut sig = [0; constants::MAX_SIGNATURE_SIZE];
|
let mut sig = [0; constants::MAX_SIGNATURE_SIZE];
|
||||||
let mut recid = 0;
|
let mut recid = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::secp256k1_ecdsa_sign_compact(msg.as_ptr(), msg.len() as c_int,
|
if ffi::secp256k1_ecdsa_sign_compact(msg.as_ptr(),
|
||||||
(&mut sig).as_mut_ptr(), sk.as_ptr(),
|
sig.as_mut_ptr(), sk.as_ptr(),
|
||||||
nonce.as_ptr(), &mut recid) != 1 {
|
ffi::secp256k1_nonce_function_default,
|
||||||
return Err(Error::InvalidNonce);
|
ptr::null(), &mut recid) != 1 {
|
||||||
|
return Err(Error::SignFailed);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok((Signature(constants::MAX_COMPACT_SIGNATURE_SIZE, sig), RecoveryId(recid)))
|
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
|
/// Determines the public key for which `sig` is a valid signature for
|
||||||
/// `msg`. Returns through the out-pointer `pubkey`.
|
/// `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)
|
compressed: bool, recid: RecoveryId)
|
||||||
-> Result<key::PublicKey, Error> {
|
-> Result<key::PublicKey, Error> {
|
||||||
let mut pk = key::PublicKey::new(compressed);
|
let mut pk = key::PublicKey::new(compressed);
|
||||||
|
@ -277,7 +297,7 @@ impl Secp256k1 {
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut len = 0;
|
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,
|
sig.as_ptr(), pk.as_mut_ptr(), &mut len,
|
||||||
if compressed {1} else {0},
|
if compressed {1} else {0},
|
||||||
recid) != 1 {
|
recid) != 1 {
|
||||||
|
@ -294,17 +314,17 @@ impl Secp256k1 {
|
||||||
/// there with zero-padded signatures that don't fit in the `Signature` type.
|
/// there with zero-padded signatures that don't fit in the `Signature` type.
|
||||||
/// Use `verify_raw` instead.
|
/// Use `verify_raw` instead.
|
||||||
#[inline]
|
#[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)
|
Secp256k1::verify_raw(msg, &sig[..], pk)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks that `sig` is a valid ECDSA signature for `msg` using the public
|
/// Checks that `sig` is a valid ECDSA signature for `msg` using the public
|
||||||
/// key `pubkey`. Returns `Ok(true)` on success.
|
/// key `pubkey`. Returns `Ok(true)` on success.
|
||||||
#[inline]
|
#[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
|
init(); // This is a static function, so we have to init
|
||||||
let res = unsafe {
|
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,
|
sig.as_ptr(), sig.len() as c_int,
|
||||||
pk.as_ptr(), pk.len() as c_int)
|
pk.as_ptr(), pk.len() as c_int)
|
||||||
};
|
};
|
||||||
|
@ -327,19 +347,19 @@ mod tests {
|
||||||
|
|
||||||
use test::{Bencher, black_box};
|
use test::{Bencher, black_box};
|
||||||
|
|
||||||
use key::{PublicKey, Nonce};
|
use key::PublicKey;
|
||||||
use super::{Secp256k1, Signature};
|
use super::{Secp256k1, Signature, Message};
|
||||||
use super::Error::{InvalidPublicKey, IncorrectSignature, InvalidSignature};
|
use super::Error::{InvalidPublicKey, IncorrectSignature, InvalidSignature};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invalid_pubkey() {
|
fn invalid_pubkey() {
|
||||||
let mut msg: Vec<u8> = repeat(0).take(32).collect();
|
|
||||||
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];
|
||||||
thread_rng().fill_bytes(&mut msg);
|
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]
|
#[test]
|
||||||
|
@ -348,12 +368,12 @@ mod tests {
|
||||||
|
|
||||||
let (_, pk) = s.generate_keypair(false);
|
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 sig = Signature::from_slice(&[0; 72]).unwrap();
|
||||||
|
let mut msg = [0u8; 32];
|
||||||
thread_rng().fill_bytes(&mut msg);
|
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]
|
#[test]
|
||||||
|
@ -361,12 +381,12 @@ mod tests {
|
||||||
let mut s = Secp256k1::new().unwrap();
|
let mut s = Secp256k1::new().unwrap();
|
||||||
|
|
||||||
let (_, pk) = s.generate_keypair(true);
|
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 sig = Signature::from_slice(&[0; 72]).unwrap();
|
||||||
|
let mut msg = [0u8; 32];
|
||||||
thread_rng().fill_bytes(&mut msg);
|
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]
|
#[test]
|
||||||
|
@ -375,11 +395,11 @@ mod tests {
|
||||||
|
|
||||||
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 (sk, _) = s.generate_keypair(false);
|
let (sk, _) = s.generate_keypair(false);
|
||||||
let nonce = s.generate_nonce();
|
|
||||||
|
|
||||||
s.sign(&msg, &sk, &nonce).unwrap();
|
s.sign(&msg, &sk).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -388,11 +408,11 @@ mod tests {
|
||||||
|
|
||||||
let mut msg: Vec<u8> = repeat(0).take(32).collect();
|
let mut msg: Vec<u8> = repeat(0).take(32).collect();
|
||||||
thread_rng().fill_bytes(&mut msg);
|
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(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(()));
|
assert_eq!(Secp256k1::verify(&msg, &sig, &pk), Ok(()));
|
||||||
}
|
}
|
||||||
|
@ -401,15 +421,17 @@ mod tests {
|
||||||
fn sign_and_verify_fail() {
|
fn sign_and_verify_fail() {
|
||||||
let mut s = Secp256k1::new().unwrap();
|
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);
|
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(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);
|
thread_rng().fill_bytes(&mut msg);
|
||||||
|
let msg = Message::from_slice(&msg).unwrap();
|
||||||
assert_eq!(Secp256k1::verify(&msg, &sig, &pk), Err(IncorrectSignature));
|
assert_eq!(Secp256k1::verify(&msg, &sig, &pk), Err(IncorrectSignature));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,29 +441,15 @@ mod tests {
|
||||||
|
|
||||||
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 (sk, pk) = s.generate_keypair(false);
|
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));
|
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]
|
#[bench]
|
||||||
pub fn generate_compressed(bh: &mut Bencher) {
|
pub fn generate_compressed(bh: &mut Bencher) {
|
||||||
let mut s = Secp256k1::new().unwrap();
|
let mut s = Secp256k1::new().unwrap();
|
||||||
|
|
Loading…
Reference in New Issue