Overhaul interface to use zero-on-free SecretKeys

Using the `secretdata` library, we can store SecretKeys in such a way
that they cannot be moved or copied, and their memory is zeroed out on
drop. This gives us some assurance that in the case of memory unsafety,
there is not secret key data lying around anywhere that we don't expect.

Unfortunately, it means that we cannot construct secret keys and then
return them, which forces the interface to change a fair bit. I removed
the `generate_keypair` function from Secp256k1, then `generate_nonce`
for symmetry, then dropped the `Secp256k1` struct entirely because it
turned out that none of the remaining functions used the `self` param.

So here we are. I bumped the version number. Sorry about this.
This commit is contained in:
Andrew Poelstra 2014-09-11 22:36:15 -05:00
parent 62504165e4
commit 9889090784
4 changed files with 265 additions and 248 deletions

View File

@ -1,7 +1,7 @@
[package]
name = "bitcoin-secp256k1-rs"
version = "0.0.1"
version = "0.1.1"
authors = [ "Dawid Ciężarkiewicz <dpc@ucore.info>",
"Andrew Poelstra <apoelstra@wpsoftware.net" ]
@ -12,3 +12,6 @@ path = "src/secp256k1.rs"
[dependencies.rust-crypto]
git = "https://github.com/DaGenix/rust-crypto.git"
[dependencies.secretdata]
git = "https://github.com/apoelstra/secretdata.git"

View File

@ -17,10 +17,13 @@
use std::intrinsics::copy_nonoverlapping_memory;
use std::cmp;
use std::default::Default;
use std::fmt;
use std::ptr::zero_memory;
use std::rand::Rng;
use serialize::{Decoder, Decodable, Encoder, Encodable};
use secretdata::SecretData;
use crypto::digest::Digest;
use crypto::sha2::Sha512;
use crypto::hmac::Hmac;
@ -36,14 +39,17 @@ 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)
pub struct SecretKey<'a>(SecretData<'a, SecretKeyData>);
/// The number 1 encoded as a secret key
pub static ONE: SecretKey = SecretKey([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]);
/// Secret 256-bit key used as `x` in an ECDSA signature
struct SecretKeyData([u8, ..constants::SECRET_KEY_SIZE]);
impl_array_newtype!(SecretKeyData, u8, constants::SECRET_KEY_SIZE)
impl Default for SecretKeyData {
fn default() -> SecretKeyData {
SecretKeyData([0, ..constants::SECRET_KEY_SIZE])
}
}
/// Public key
#[deriving(Clone, PartialEq, Eq, Show)]
@ -98,7 +104,7 @@ impl Nonce {
/// 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 {
pub fn deterministic<'a>(msg: &[u8], key: &SecretKey<'a>) -> Nonce {
static HMAC_SIZE: uint = 64;
macro_rules! hmac(
@ -154,10 +160,16 @@ impl Nonce {
}
}
impl SecretKey {
impl<'a> SecretKey<'a> {
/// Creates a new zeroed-out secret key
#[inline]
pub fn new() -> SecretKey<'a> {
SecretKey(SecretData::new())
}
/// Creates a new random secret key
#[inline]
pub fn new<R:Rng>(rng: &mut R) -> SecretKey {
pub fn init_rng<R:Rng>(&'a mut self, rng: &mut R) {
init();
let mut data = random_32_bytes(rng);
unsafe {
@ -165,36 +177,47 @@ impl SecretKey {
data = random_32_bytes(rng);
}
}
SecretKey(data)
let &SecretKey(ref mut selfdata) = self;
selfdata.move(&mut SecretKeyData(data))
}
/// Converts a `SECRET_KEY_SIZE`-byte slice to a secret key
/// Converts a `SECRET_KEY_SIZE`-byte slice to a secret key,
/// zeroing out the original data
#[inline]
pub fn from_slice(data: &[u8]) -> Result<SecretKey> {
pub fn init_slice(&'a mut self, data: &mut [u8]) -> Result<()> {
init();
match data.len() {
constants::SECRET_KEY_SIZE => {
let mut ret = [0, ..constants::SECRET_KEY_SIZE];
let &SecretKey(ref mut selfdata) = self;
unsafe {
if ffi::secp256k1_ecdsa_seckey_verify(data.as_ptr()) == 0 {
return Err(InvalidSecretKey);
}
copy_nonoverlapping_memory(ret.as_mut_ptr(),
copy_nonoverlapping_memory(selfdata.data_mut().as_mut_ptr(),
data.as_ptr(),
data.len());
zero_memory(data.as_mut_ptr(), data.len());
}
Ok(SecretKey(ret))
Ok(())
}
_ => Err(InvalidSecretKey)
}
}
/// Copies the data from one key to another without zeroing anyth out
#[inline]
pub fn clone_from<'b>(&'a mut self, other: &SecretKey<'b>) {
let &SecretKey(ref mut selfdata) = self;
let &SecretKey(ref otherdata) = other;
selfdata.clone_from(otherdata);
}
#[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<()> {
pub fn add_assign<'b>(&mut self, other: &SecretKey<'b>) -> Result<()> {
init();
unsafe {
if ffi::secp256k1_ecdsa_privkey_tweak_add(self.as_mut_ptr(), other.as_ptr()) != 1 {
@ -206,24 +229,24 @@ impl SecretKey {
}
#[inline]
/// Returns an iterator for the (sk, pk) pairs starting one after this one,
/// and incrementing by one each time
pub fn sequence(&self, compressed: bool) -> Sequence {
Sequence { last_sk: *self, compressed: compressed }
/// Returns an immutable view of the data as a byteslice
pub fn as_slice<'b>(&'b self) -> &'b [u8] {
let &SecretKey(ref selfdata) = self;
selfdata.data().as_slice()
}
}
/// An iterator of keypairs `(sk + 1, pk*G)`, `(sk + 2, pk*2G)`, ...
pub struct Sequence {
compressed: bool,
last_sk: SecretKey,
}
impl<'a> Iterator<(SecretKey, PublicKey)> for Sequence {
#[inline]
fn next(&mut self) -> Option<(SecretKey, PublicKey)> {
self.last_sk.add_assign(&ONE).unwrap();
Some((self.last_sk, PublicKey::from_secret_key(&self.last_sk, self.compressed)))
/// Returns a raw pointer to the underlying secret key data
pub fn as_ptr(&self) -> *const u8 {
let &SecretKey(ref selfdata) = self;
selfdata.data().as_ptr()
}
#[inline]
/// Returns a mutable raw pointer to the underlying secret key data
pub fn as_mut_ptr(&mut self) -> *mut u8 {
let &SecretKey(ref mut selfdata) = self;
selfdata.data_mut().as_mut_ptr()
}
}
@ -239,7 +262,7 @@ 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<'a>(sk: &SecretKey<'a>, compressed: bool) -> PublicKey {
let mut pk = PublicKey::new(compressed);
let compressed = if compressed {1} else {0};
let mut len = 0;
@ -337,7 +360,7 @@ 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<()> {
pub fn add_exp_assign<'a>(&mut self, other: &SecretKey<'a>) -> Result<()> {
init();
unsafe {
if ffi::secp256k1_ecdsa_pubkey_tweak_add(self.as_mut_ptr(),
@ -421,9 +444,17 @@ impl <E: Encoder<S>, S> Encodable<E, S> for PublicKey {
}
}
impl fmt::Show for SecretKey {
impl<'a> PartialEq for SecretKey<'a> {
fn eq(&self, other: &SecretKey<'a>) -> bool {
self.as_slice() == other.as_slice()
}
}
impl<'a> Eq for SecretKey<'a> {}
impl<'a> fmt::Show for SecretKey<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.as_slice().fmt(f)
write!(f, "[secret data]")
}
}
@ -432,9 +463,7 @@ mod test {
use serialize::hex::FromHex;
use std::rand::task_rng;
use test::Bencher;
use super::super::{Secp256k1, InvalidNonce, InvalidPublicKey, InvalidSecretKey};
use super::super::{InvalidNonce, InvalidPublicKey, InvalidSecretKey};
use super::{Nonce, PublicKey, SecretKey};
#[test]
@ -442,17 +471,16 @@ mod test {
let n = Nonce::from_slice([1, ..31]);
assert_eq!(n, Err(InvalidNonce));
let n = SecretKey::from_slice([1, ..32]);
assert!(n.is_ok());
let mut n = SecretKey::new();
assert_eq!(n.init_slice([1, ..32]), Ok(()));
}
#[test]
fn skey_from_slice() {
let sk = SecretKey::from_slice([1, ..31]);
assert_eq!(sk, Err(InvalidSecretKey));
let sk = SecretKey::from_slice([1, ..32]);
assert!(sk.is_ok());
let mut sk = SecretKey::new();
assert_eq!(sk.init_slice([1, ..31]), Err(InvalidSecretKey));
let mut sk = SecretKey::new();
assert_eq!(sk.init_slice([1, ..32]), Ok(()));
}
#[test]
@ -471,14 +499,17 @@ mod test {
#[test]
fn keypair_slice_round_trip() {
let mut s = Secp256k1::new().unwrap();
let mut rng = task_rng();
let mut sk1 = SecretKey::new();
sk1.init_rng(&mut rng);
let mut sk2 = SecretKey::new();
sk2.clone_from(&sk1);
let (sk1, pk1) = s.generate_keypair(true);
assert_eq!(SecretKey::from_slice(sk1.as_slice()), Ok(sk1));
assert_eq!(sk1, sk2);
let pk1 = PublicKey::from_secret_key(&sk1, false);
assert_eq!(PublicKey::from_slice(pk1.as_slice()), Ok(pk1));
let (sk2, pk2) = s.generate_keypair(false);
assert_eq!(SecretKey::from_slice(sk2.as_slice()), Ok(sk2));
let pk2 = PublicKey::from_secret_key(&sk1, true);
assert_eq!(PublicKey::from_slice(pk2.as_slice()), Ok(pk2));
}
@ -491,28 +522,33 @@ mod test {
#[test]
fn invalid_secret_key() {
let mut sk = SecretKey::new();
// Zero
assert_eq!(SecretKey::from_slice([0, ..32]), Err(InvalidSecretKey));
assert_eq!(sk.init_slice([0, ..32]), Err(InvalidSecretKey));
// -1
assert_eq!(SecretKey::from_slice([0xff, ..32]), Err(InvalidSecretKey));
assert_eq!(sk.init_slice([0xff, ..32]), Err(InvalidSecretKey));
// Top of range
assert!(SecretKey::from_slice([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());
assert_eq!(sk.init_slice([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]), Ok(()));
// One past top of range
assert!(SecretKey::from_slice([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());
assert_eq!(sk.init_slice([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]), Err(InvalidSecretKey));
}
#[test]
fn test_addition() {
let mut s = Secp256k1::new().unwrap();
let mut rng = task_rng();
let (mut sk1, mut pk1) = s.generate_keypair(true);
let (mut sk2, mut pk2) = s.generate_keypair(true);
let mut sk1 = SecretKey::new();
let mut sk2 = SecretKey::new();
sk1.init_rng(&mut rng);
sk2.init_rng(&mut rng);
let mut pk1 = PublicKey::from_secret_key(&sk1, true);
let mut pk2 = PublicKey::from_secret_key(&sk2, true);
assert_eq!(PublicKey::from_secret_key(&sk1, true), pk1);
assert!(sk1.add_assign(&sk2).is_ok());
@ -533,7 +569,10 @@ mod test {
// from ecdsa.curves import SECP256k1
// # This key was generated randomly
// sk = 0x09e918bbea76205445e9a73eaad2080a135d1e33e9dd1b3ca8a9a1285e7c1f81
let sk = SecretKey::from_slice(hex_slice!("09e918bbea76205445e9a73eaad2080a135d1e33e9dd1b3ca8a9a1285e7c1f81")).unwrap();
let mut sk = SecretKey::new();
sk.init_slice(hex_slice_mut!("09e918bbea76205445e9a73eaad2080a135d1e33e9dd1b3ca8a9a1285e7c1f81")).unwrap();
assert_eq!(sk.as_slice(),
hex_slice!("09e918bbea76205445e9a73eaad2080a135d1e33e9dd1b3ca8a9a1285e7c1f81"));
// "%x" % rfc6979.generate_k(SECP256k1.generator, sk, hashlib.sha512, hashlib.sha512('').digest())
let nonce = Nonce::deterministic([], &sk);
@ -547,7 +586,7 @@ mod test {
// # Decrease the secret key by one
// sk = 0x09e918bbea76205445e9a73eaad2080a135d1e33e9dd1b3ca8a9a1285e7c1f80
let sk = SecretKey::from_slice(hex_slice!("09e918bbea76205445e9a73eaad2080a135d1e33e9dd1b3ca8a9a1285e7c1f80")).unwrap();
sk.init_slice(hex_slice_mut!("09e918bbea76205445e9a73eaad2080a135d1e33e9dd1b3ca8a9a1285e7c1f80")).unwrap();
// "%x" % rfc6979.generate_k(SECP256k1.generator, sk, hashlib.sha512, hashlib.sha512('').digest())
let nonce = Nonce::deterministic([], &sk);
@ -559,14 +598,6 @@ mod test {
assert_eq!(nonce.as_slice(),
hex_slice!("355c589ff662c838aee454d62b12c50a87b7e95ede2431c7cfa40b6ba2fddccd"));
}
#[bench]
pub fn sequence_iterate(bh: &mut Bencher) {
let mut s = Secp256k1::new().unwrap();
let (sk, _) = s.generate_keypair(true);
let mut iter = sk.sequence(true);
bh.iter(|| iter.next())
}
}

View File

@ -27,6 +27,7 @@ macro_rules! impl_array_newtype(
}
#[inline]
#[allow(dead_code)]
/// Provides an immutable view into the object from index `s` inclusive to `e` exclusive
pub fn slice<'a>(&'a self, s: uint, e: uint) -> &'a [$ty] {
let &$thing(ref dat) = self;
@ -34,6 +35,7 @@ macro_rules! impl_array_newtype(
}
#[inline]
#[allow(dead_code)]
/// Provides an immutable view into the object, up to index `n` exclusive
pub fn slice_to<'a>(&'a self, n: uint) -> &'a [$ty] {
let &$thing(ref dat) = self;
@ -41,6 +43,7 @@ macro_rules! impl_array_newtype(
}
#[inline]
#[allow(dead_code)]
/// Provides an immutable view into the object, starting from index `n`
pub fn slice_from<'a>(&'a self, n: uint) -> &'a [$ty] {
let &$thing(ref dat) = self;
@ -62,6 +65,7 @@ macro_rules! impl_array_newtype(
}
#[inline]
#[allow(dead_code)]
/// Returns the length of the object as an array
pub fn len(&self) -> uint { $len }
}
@ -129,3 +133,10 @@ macro_rules! hex_slice(
)
)
macro_rules! hex_slice_mut(
($s:expr) => (
$s.from_hex().unwrap().as_mut_slice()
)
)

View File

@ -37,6 +37,7 @@
#![warn(missing_doc)]
extern crate "rust-crypto" as crypto;
extern crate secretdata;
extern crate libc;
extern crate serialize;
@ -44,13 +45,9 @@ extern crate sync;
extern crate test;
use std::intrinsics::copy_nonoverlapping_memory;
use std::io::IoResult;
use std::rand::{OsRng, Rng, SeedableRng};
use libc::c_int;
use sync::one::{Once, ONCE_INIT};
use crypto::fortuna::Fortuna;
mod macros;
pub mod constants;
pub mod ffi;
@ -135,11 +132,6 @@ pub type Result<T> = ::std::prelude::Result<T, Error>;
static mut Secp256k1_init : Once = ONCE_INIT;
/// The secp256k1 engine, used to execute all signature operations
pub struct Secp256k1 {
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
@ -153,114 +145,86 @@ pub fn init() {
}
}
impl Secp256k1 {
/// Constructs a new secp256k1 engine.
pub fn new() -> IoResult<Secp256k1> {
init();
let mut osrng = try!(OsRng::new());
let mut seed = [0, ..2048];
osrng.fill_bytes(seed.as_mut_slice());
Ok(Secp256k1 { rng: SeedableRng::from_seed(seed.as_slice()) })
}
/// 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(&mut self.rng);
(sk, key::PublicKey::from_secret_key(&sk, compressed))
}
/// 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)
-> Result<Signature> {
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,
sig.as_mut_slice().as_mut_ptr(), &mut len,
sk.as_ptr(), nonce.as_ptr()) != 1 {
return Err(InvalidNonce);
}
// This assertation is probably too late :)
assert!(len as uint <= constants::MAX_SIGNATURE_SIZE);
};
Ok(Signature(len as uint, sig))
}
/// Constructs a signature for `msg` using the secret key `sk` and nonce `nonce`
pub fn sign<'a>(msg: &[u8], sk: &key::SecretKey<'a>, nonce: &key::Nonce)
-> Result<Signature> {
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,
sig.as_mut_slice().as_mut_ptr(), &mut len,
sk.as_ptr(), nonce.as_ptr()) != 1 {
return Err(InvalidNonce);
}
// This assertation is probably too late :)
assert!(len as uint <= constants::MAX_SIGNATURE_SIZE);
};
Ok(Signature(len as uint, sig))
}
/// Constructs a compact signature for `msg` using the secret key `sk`
pub fn sign_compact(&self, msg: &[u8], sk: &key::SecretKey, nonce: &key::Nonce)
-> Result<(Signature, RecoveryId)> {
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,
sig.as_mut_slice().as_mut_ptr(), sk.as_ptr(),
nonce.as_ptr(), &mut recid) != 1 {
return Err(InvalidNonce);
}
};
Ok((Signature(constants::MAX_COMPACT_SIGNATURE_SIZE, sig), RecoveryId(recid)))
}
/// 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],
compressed: bool, recid: RecoveryId)
-> Result<key::PublicKey> {
let mut pk = key::PublicKey::new(compressed);
let RecoveryId(recid) = recid;
unsafe {
let mut len = 0;
if ffi::secp256k1_ecdsa_recover_compact(msg.as_ptr(), msg.len() as c_int,
sig.as_ptr(), pk.as_mut_ptr(), &mut len,
if compressed {1} else {0},
recid) != 1 {
return Err(InvalidSignature);
}
assert_eq!(len as uint, pk.len());
};
Ok(pk)
}
/// 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.
#[inline]
pub fn verify(msg: &[u8], sig: &Signature, pk: &key::PublicKey) -> Result<()> {
Secp256k1::verify_raw(msg, sig.as_slice(), 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<()> {
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,
sig.as_ptr(), sig.len() as c_int,
pk.as_ptr(), pk.len() as c_int)
};
match res {
1 => Ok(()),
0 => Err(IncorrectSignature),
-1 => Err(InvalidPublicKey),
-2 => Err(InvalidSignature),
_ => unreachable!()
pub fn sign_compact<'a>(msg: &[u8], sk: &key::SecretKey<'a>, nonce: &key::Nonce)
-> Result<(Signature, RecoveryId)> {
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,
sig.as_mut_slice().as_mut_ptr(), sk.as_ptr(),
nonce.as_ptr(), &mut recid) != 1 {
return Err(InvalidNonce);
}
};
Ok((Signature(constants::MAX_COMPACT_SIGNATURE_SIZE, sig), RecoveryId(recid)))
}
/// Determines the public key for which `sig` is a valid signature for
/// `msg`. Returns through the out-pointer `pubkey`.
pub fn recover_compact(msg: &[u8], sig: &[u8],
compressed: bool, recid: RecoveryId)
-> Result<key::PublicKey> {
let mut pk = key::PublicKey::new(compressed);
let RecoveryId(recid) = recid;
unsafe {
let mut len = 0;
if ffi::secp256k1_ecdsa_recover_compact(msg.as_ptr(), msg.len() as c_int,
sig.as_ptr(), pk.as_mut_ptr(), &mut len,
if compressed {1} else {0},
recid) != 1 {
return Err(InvalidSignature);
}
assert_eq!(len as uint, pk.len());
};
Ok(pk)
}
/// 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.
#[inline]
pub fn verify(msg: &[u8], sig: &Signature, pk: &key::PublicKey) -> Result<()> {
verify_raw(msg, sig.as_slice(), 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<()> {
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,
sig.as_ptr(), sig.len() as c_int,
pk.as_ptr(), pk.len() as c_int)
};
match res {
1 => Ok(()),
0 => Err(IncorrectSignature),
-1 => Err(InvalidPublicKey),
-2 => Err(InvalidSignature),
_ => unreachable!()
}
}
@ -272,9 +236,9 @@ mod tests {
use test::{Bencher, black_box};
use key::{PublicKey, Nonce};
use super::{Secp256k1, Signature};
use super::{InvalidPublicKey, IncorrectSignature, InvalidSignature};
use key::{SecretKey, PublicKey, Nonce};
use super::{verify, sign, sign_compact, recover_compact};
use super::{Signature, InvalidPublicKey, IncorrectSignature, InvalidSignature};
#[test]
fn invalid_pubkey() {
@ -284,126 +248,134 @@ mod tests {
rand::task_rng().fill_bytes(msg.as_mut_slice());
assert_eq!(Secp256k1::verify(msg.as_mut_slice(), &sig, &pk), Err(InvalidPublicKey));
assert_eq!(verify(msg.as_mut_slice(), &sig, &pk), Err(InvalidPublicKey));
}
#[test]
fn valid_pubkey_uncompressed() {
let mut s = Secp256k1::new().unwrap();
let (_, pk) = s.generate_keypair(false);
let mut sk = SecretKey::new();
sk.init_rng(&mut rand::task_rng());
let pk = PublicKey::from_secret_key(&sk, false);
let mut msg = Vec::from_elem(32, 0u8);
let sig = Signature::from_slice([0, ..72]).unwrap();
rand::task_rng().fill_bytes(msg.as_mut_slice());
assert_eq!(Secp256k1::verify(msg.as_mut_slice(), &sig, &pk), Err(InvalidSignature));
assert_eq!(verify(msg.as_mut_slice(), &sig, &pk), Err(InvalidSignature));
}
#[test]
fn valid_pubkey_compressed() {
let mut s = Secp256k1::new().unwrap();
let mut sk = SecretKey::new();
sk.init_rng(&mut rand::task_rng());
let pk = PublicKey::from_secret_key(&sk, true);
let (_, pk) = s.generate_keypair(true);
let mut msg = Vec::from_elem(32, 0u8);
let sig = Signature::from_slice([0, ..72]).unwrap();
rand::task_rng().fill_bytes(msg.as_mut_slice());
assert_eq!(Secp256k1::verify(msg.as_mut_slice(), &sig, &pk), Err(InvalidSignature));
assert_eq!(verify(msg.as_mut_slice(), &sig, &pk), Err(InvalidSignature));
}
#[test]
fn sign() {
let mut s = Secp256k1::new().unwrap();
fn sign_random() {
let mut rng = rand::task_rng();
let mut sk = SecretKey::new();
sk.init_rng(&mut rng);
let mut msg = [0u8, ..32];
rand::task_rng().fill_bytes(msg);
rng.fill_bytes(msg);
let (sk, _) = s.generate_keypair(false);
let nonce = s.generate_nonce();
let nonce = Nonce::new(&mut rng);
s.sign(msg.as_slice(), &sk, &nonce).unwrap();
sign(msg.as_slice(), &sk, &nonce).unwrap();
}
#[test]
fn sign_and_verify() {
let mut s = Secp256k1::new().unwrap();
let mut rng = rand::task_rng();
let mut msg = Vec::from_elem(32, 0u8);
rand::task_rng().fill_bytes(msg.as_mut_slice());
let mut sk = SecretKey::new();
sk.init_rng(&mut rng);
let pk = PublicKey::from_secret_key(&sk, true);
let mut msg = [0u8, ..32];
rng.fill_bytes(msg);
let nonce = Nonce::new(&mut rng);
let (sk, pk) = s.generate_keypair(false);
let nonce = s.generate_nonce();
let sig = s.sign(msg.as_slice(), &sk, &nonce).unwrap();
assert_eq!(Secp256k1::verify(msg.as_slice(), &sig, &pk), Ok(()));
let sig = sign(msg.as_slice(), &sk, &nonce).unwrap();
assert_eq!(verify(msg.as_slice(), &sig, &pk), Ok(()));
}
#[test]
fn sign_and_verify_fail() {
let mut s = Secp256k1::new().unwrap();
let mut rng = rand::task_rng();
let mut msg = Vec::from_elem(32, 0u8);
rand::task_rng().fill_bytes(msg.as_mut_slice());
let mut sk = SecretKey::new();
sk.init_rng(&mut rng);
let pk = PublicKey::from_secret_key(&sk, true);
let mut msg = [0u8, ..32];
rng.fill_bytes(msg);
let nonce = Nonce::new(&mut rng);
let (sk, pk) = s.generate_keypair(false);
let nonce = s.generate_nonce();
let sig = s.sign(msg.as_slice(), &sk, &nonce).unwrap();
rand::task_rng().fill_bytes(msg.as_mut_slice());
assert_eq!(Secp256k1::verify(msg.as_slice(), &sig, &pk), Err(IncorrectSignature));
let sig = sign(msg.as_slice(), &sk, &nonce).unwrap();
rng.fill_bytes(msg.as_mut_slice());
assert_eq!(verify(msg.as_slice(), &sig, &pk), Err(IncorrectSignature));
}
#[test]
fn sign_compact_with_recovery() {
let mut s = Secp256k1::new().unwrap();
let mut rng = rand::task_rng();
let mut sk = SecretKey::new();
sk.init_rng(&mut rng);
assert!(sk != SecretKey::new());
let pk = PublicKey::from_secret_key(&sk, false);
let pk_comp = PublicKey::from_secret_key(&sk, true);
let mut msg = [0u8, ..32];
rand::task_rng().fill_bytes(msg.as_mut_slice());
rng.fill_bytes(msg);
let nonce = Nonce::new(&mut rng);
let (sk, pk) = s.generate_keypair(false);
let nonce = s.generate_nonce();
let (sig, recid) = sign_compact(msg.as_slice(), &sk, &nonce).unwrap();
let (sig, recid) = s.sign_compact(msg.as_slice(), &sk, &nonce).unwrap();
assert_eq!(s.recover_compact(msg.as_slice(), sig.as_slice(), false, recid), Ok(pk));
assert_eq!(recover_compact(msg.as_slice(), sig.as_slice(), false, recid), Ok(pk));
assert_eq!(recover_compact(msg.as_slice(), sig.as_slice(), true, recid), Ok(pk_comp));
}
#[test]
fn deterministic_sign() {
let mut msg = [0u8, ..32];
rand::task_rng().fill_bytes(msg.as_mut_slice());
let mut rng = rand::task_rng();
let mut s = Secp256k1::new().unwrap();
let (sk, pk) = s.generate_keypair(true);
let mut sk = SecretKey::new();
sk.init_rng(&mut rng);
let pk = PublicKey::from_secret_key(&sk, true);
let mut msg = [0u8, ..32];
rng.fill_bytes(msg);
let nonce = Nonce::deterministic(msg, &sk);
let sig = s.sign(msg.as_slice(), &sk, &nonce).unwrap();
assert_eq!(Secp256k1::verify(msg.as_slice(), &sig, &pk), Ok(()));
let sig = sign(msg.as_slice(), &sk, &nonce).unwrap();
assert_eq!(verify(msg.as_slice(), &sig, &pk), Ok(()));
}
#[bench]
pub fn generate_compressed(bh: &mut Bencher) {
let mut s = Secp256k1::new().unwrap();
let mut rng = rand::task_rng();
let mut sk = SecretKey::new();
bh.iter( || {
let (sk, pk) = s.generate_keypair(true);
black_box(sk);
black_box(pk);
sk.init_rng(&mut rng);
black_box(PublicKey::from_secret_key(&sk, true));
});
}
#[bench]
pub fn generate_uncompressed(bh: &mut Bencher) {
let mut s = Secp256k1::new().unwrap();
let mut rng = rand::task_rng();
let mut sk = SecretKey::new();
bh.iter( || {
let (sk, pk) = s.generate_keypair(false);
black_box(sk);
black_box(pk);
sk.init_rng(&mut rng);
black_box(PublicKey::from_secret_key(&sk, false));
});
}
}