[API BREAK] Update for new libsecp256k1 API

This commit is contained in:
Andrew Poelstra 2015-07-28 11:03:10 -05:00
parent 0de8bfabb6
commit 77f6b6bf21
6 changed files with 346 additions and 645 deletions

View File

@ -17,6 +17,7 @@ name = "secp256k1"
path = "src/lib.rs"
[dependencies]
arrayvec = "0.3"
rand = "0.3"
libc = "0.1"
rustc-serialize = "0.3"

View File

@ -21,6 +21,10 @@ pub const MESSAGE_SIZE: usize = 32;
/// The size (in bytes) of a secret key
pub const SECRET_KEY_SIZE: usize = 32;
/// The size (in bytes) of a public key array. This only needs to be 65
/// but must be 72 for compatibility with the `ArrayVec` library.
pub const PUBLIC_KEY_SIZE: usize = 72;
/// The size (in bytes) of an uncompressed public key
pub const UNCOMPRESSED_PUBLIC_KEY_SIZE: usize = 65;

View File

@ -14,6 +14,7 @@
//
//! FFI bindings
use std::mem;
use libc::{c_int, c_uchar, c_uint, c_void};
pub const SECP256K1_START_VERIFY: c_uint = 0x1;
@ -29,11 +30,11 @@ pub const SECP256K1_START_SIGN: c_uint = 0x2;
pub type NonceFn = unsafe extern "C" fn(nonce32: *mut c_uchar,
msg32: *const c_uchar,
key32: *const c_uchar,
algo16: *const c_uchar,
attempt: c_uint,
data: *const c_void);
#[repr(C)]
struct ContextInner;
#[repr(C)] struct ContextInner;
/// A Secp256k1 context, containing various precomputed values and such
/// needed to do elliptic curve computations. If you create one of these
@ -47,6 +48,33 @@ struct ContextInner;
#[derive(Copy, Clone, Debug)]
pub struct Context(*mut ContextInner);
/// Library-internal representation of a Secp256k1 public key
#[repr(C)]
pub struct PublicKey([c_uchar; 64]);
impl_array_newtype!(PublicKey, c_uchar, 64);
impl_raw_debug!(PublicKey);
impl PublicKey {
/// Create a new (zeroed) public key usable for the FFI interface
pub fn new() -> PublicKey { PublicKey([0; 64]) }
/// Create a new (uninitialized) public key usable for the FFI interface
pub unsafe fn blank() -> PublicKey { mem::uninitialized() }
}
/// Library-internal representation of a Secp256k1 signature
#[repr(C)]
#[allow(raw_pointer_derive)]
pub struct Signature([c_uchar; 65]);
impl_array_newtype!(Signature, c_uchar, 65);
impl_raw_debug!(Signature);
impl Signature {
/// Create a new (zeroed) public key usable for the FFI interface
pub fn new() -> Signature { Signature([0; 65]) }
/// Create a new (uninitialized) public key usable for the FFI interface
pub unsafe fn blank() -> Signature { mem::uninitialized() }
}
unsafe impl Send for Context {}
unsafe impl Sync for Context {}
@ -56,47 +84,65 @@ extern "C" {
pub static secp256k1_nonce_function_default: NonceFn;
// Contexts
pub fn secp256k1_context_create(flags: c_uint) -> Context;
pub fn secp256k1_context_clone(cx: Context) -> Context;
pub fn secp256k1_context_destroy(cx: Context);
pub fn secp256k1_context_randomize(cx: Context,
seed32: *const c_uchar)
-> c_int;
// Pubkeys
pub fn secp256k1_ec_pubkey_parse(cx: Context, pk: *mut PublicKey,
input: *const c_uchar, in_len: c_int)
-> c_int;
pub fn secp256k1_ec_pubkey_serialize(cx: Context, output: *const c_uchar,
out_len: *mut c_int, pk: *const PublicKey
, compressed: c_int)
-> c_int;
// Signatures
pub fn secp256k1_ecdsa_signature_parse_der(cx: Context, sig: *mut Signature,
input: *const c_uchar, in_len: c_int)
-> c_int;
pub fn secp256k1_ecdsa_signature_parse_compact(cx: Context, sig: *mut Signature,
input64: *const c_uchar, recid: c_int)
-> c_int;
pub fn secp256k1_ecdsa_signature_serialize_der(cx: Context, output: *const c_uchar,
out_len: c_int, sig: *const Signature)
-> c_int;
pub fn secp256k1_ecdsa_signature_serialize_compact(cx: Context, output64: *const c_uchar,
recid: *mut c_int, sig: *const Signature)
-> c_int;
// ECDSA
pub fn secp256k1_ecdsa_verify(cx: Context, msg32: *const c_uchar,
sig: *const c_uchar, sig_len: c_int,
pk: *const c_uchar, pk_len: c_int)
sig: *const Signature, pk: *const PublicKey)
-> c_int;
pub fn secp256k1_ec_pubkey_create(cx: Context,
pk: *mut c_uchar, pk_len: *mut c_int,
sk: *const c_uchar, compressed: c_int)
-> c_int;
pub fn secp256k1_ecdsa_sign(cx: Context, msg32: *const c_uchar,
sig: *mut c_uchar, sig_len: *mut c_int,
sk: *const c_uchar,
sig: *mut Signature, sk: *const c_uchar,
noncefn: NonceFn, noncedata: *const c_void)
-> c_int;
pub fn secp256k1_ecdsa_sign_compact(cx: Context, msg: *const c_uchar,
sig64: *mut c_uchar, sk: *const c_uchar,
noncefn: NonceFn, noncedata: *const c_void,
recid: *mut c_int)
-> c_int;
pub fn secp256k1_ecdsa_recover_compact(cx: Context, msg32: *const c_uchar,
sig64: *const c_uchar, pk: *mut c_uchar,
pk_len: *mut c_int, compressed: c_int,
recid: c_int) -> c_int;
pub fn secp256k1_ecdsa_recover(cx: Context, msg32: *const c_uchar,
sig: *const Signature, pk: *mut PublicKey)
-> c_int;
// EC
pub fn secp256k1_ec_seckey_verify(cx: Context,
sk: *const c_uchar) -> c_int;
pub fn secp256k1_ec_pubkey_verify(cx: Context,
pk: *const c_uchar,
pk_len: c_int) -> c_int;
pub fn secp256k1_ec_pubkey_create(cx: Context, pk: *mut PublicKey,
sk: *const c_uchar) -> c_int;
//TODO secp256k1_ec_pubkey_decompress
//TODO secp256k1_ec_privkey_export
//TODO secp256k1_ec_privkey_import
@ -106,8 +152,7 @@ extern "C" {
-> c_int;
pub fn secp256k1_ec_pubkey_tweak_add(cx: Context,
pk: *mut c_uchar,
pk_len: c_int,
pk: *mut PublicKey,
tweak: *const c_uchar)
-> c_int;
@ -117,13 +162,14 @@ extern "C" {
-> c_int;
pub fn secp256k1_ec_pubkey_tweak_mul(cx: Context,
pk: *mut c_uchar,
pk_len: c_int,
pk: *mut PublicKey,
tweak: *const c_uchar)
-> c_int;
pub fn secp256k1_context_randomize(cx: Context,
seed32: *const c_uchar)
pub fn secp256k1_ec_pubkey_combine(cx: Context,
out: *mut PublicKey,
n: c_int,
ins: *const *const PublicKey)
-> c_int;
}

View File

@ -16,7 +16,8 @@
//! Public/Private keys
use std::intrinsics::copy_nonoverlapping;
use std::{fmt, marker, ops};
use std::marker;
use arrayvec::ArrayVec;
use rand::Rng;
use serialize::{Decoder, Decodable, Encoder, Encodable};
use serde::{Serialize, Deserialize, Serializer, Deserializer};
@ -29,6 +30,7 @@ use ffi;
/// 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);
impl_pretty_debug!(SecretKey);
/// The number 1 encoded as a secret key
pub static ONE: SecretKey = SecretKey([0, 0, 0, 0, 0, 0, 0, 0,
@ -36,15 +38,9 @@ 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, 1]);
/// Public key
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct PublicKey(PublicKeyData);
#[derive(Copy, Eq)]
enum PublicKeyData {
Compressed([u8; constants::COMPRESSED_PUBLIC_KEY_SIZE]),
Uncompressed([u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE])
}
/// A Secp256k1 public key, used for verification of signatures
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct PublicKey(ffi::PublicKey);
fn random_32_bytes<R: Rng>(rng: &mut R) -> [u8; 32] {
let mut ret = [0u8; 32];
@ -103,113 +99,76 @@ impl SecretKey {
impl PublicKey {
/// Creates a new zeroed out public key
#[inline]
pub fn new(compressed: bool) -> PublicKey {
PublicKey(
if compressed {
PublicKeyData::Compressed([0; constants::COMPRESSED_PUBLIC_KEY_SIZE])
} else {
PublicKeyData::Uncompressed([0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE])
}
)
pub fn new() -> PublicKey {
PublicKey(ffi::PublicKey::new())
}
/// Creates a new public key from a FFI public key
#[inline]
pub fn from_ffi(pk: ffi::PublicKey) -> PublicKey {
PublicKey(pk)
}
/// Determines whether a pubkey is valid
#[inline]
pub fn is_valid(&self) -> bool {
// The only invalid pubkey the API should be able to create is
// the zero one.
self.0[..].iter().any(|&x| x != 0)
}
/// Obtains a raw pointer suitable for use with FFI functions
#[inline]
pub fn as_ptr(&self) -> *const ffi::PublicKey {
&self.0 as *const _
}
/// Creates a new public key from a secret key.
#[inline]
pub fn from_secret_key(secp: &Secp256k1,
sk: &SecretKey,
compressed: bool)
-> PublicKey {
let mut pk = PublicKey::new(compressed);
let compressed = if compressed {1} else {0};
let mut len = 0;
sk: &SecretKey)
-> PublicKey {
let mut pk = unsafe { ffi::PublicKey::blank() };
unsafe {
// We can assume the return value because it's not possible to construct
// an invalid `SecretKey` without transmute trickery or something
let res = ffi::secp256k1_ec_pubkey_create(secp.ctx,
pk.as_mut_ptr(), &mut len,
sk.as_ptr(), compressed);
let res = ffi::secp256k1_ec_pubkey_create(secp.ctx, &mut pk, sk.as_ptr());
debug_assert_eq!(res, 1);
}
debug_assert_eq!(len as usize, pk.len());
pk
PublicKey(pk)
}
/// Creates a public key directly from a slice
#[inline]
pub fn from_slice(secp: &Secp256k1, data: &[u8])
-> Result<PublicKey, Error> {
match data.len() {
constants::COMPRESSED_PUBLIC_KEY_SIZE => {
let mut ret = [0; constants::COMPRESSED_PUBLIC_KEY_SIZE];
unsafe {
if ffi::secp256k1_ec_pubkey_verify(secp.ctx, data.as_ptr(),
data.len() as ::libc::c_int) == 0 {
return Err(InvalidPublicKey);
}
copy_nonoverlapping(data.as_ptr(),
ret.as_mut_ptr(),
data.len());
}
Ok(PublicKey(PublicKeyData::Compressed(ret)))
-> Result<PublicKey, Error> {
let mut pk = unsafe { ffi::PublicKey::blank() };
unsafe {
if ffi::secp256k1_ec_pubkey_parse(secp.ctx, &mut pk, data.as_ptr(),
data.len() as ::libc::c_int) == 1 {
Ok(PublicKey(pk))
} else {
Err(InvalidPublicKey)
}
constants::UNCOMPRESSED_PUBLIC_KEY_SIZE => {
let mut ret = [0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE];
unsafe {
if ffi::secp256k1_ec_pubkey_verify(secp.ctx, data.as_ptr(),
data.len() as ::libc::c_int) == 0 {
return Err(InvalidPublicKey);
}
copy_nonoverlapping(data.as_ptr(),
ret.as_mut_ptr(),
data.len());
}
Ok(PublicKey(PublicKeyData::Uncompressed(ret)))
}
_ => Err(InvalidPublicKey)
}
}
/// Returns whether the public key is compressed or uncompressed
#[inline]
pub fn is_compressed(&self) -> bool {
let &PublicKey(ref data) = self;
match *data {
PublicKeyData::Compressed(_) => true,
PublicKeyData::Uncompressed(_) => false
}
}
/// Serialize the key as a byte-encoded pair of values. In compressed form
/// the y-coordinate is represented by only a single bit, as x determines
/// it up to one bit.
pub fn serialize_vec(&self, secp: &Secp256k1, compressed: bool) -> ArrayVec<[u8; constants::PUBLIC_KEY_SIZE]> {
let mut ret = ArrayVec::new();
/// Returns the length of the public key
#[inline]
pub fn len(&self) -> usize {
let &PublicKey(ref data) = self;
match *data {
PublicKeyData::Compressed(ref x) => x.len(),
PublicKeyData::Uncompressed(ref x) => x.len()
}
}
/// Converts the public key to a raw pointer suitable for use
/// with the FFI functions
#[inline]
pub fn as_ptr(&self) -> *const u8 {
let &PublicKey(ref data) = self;
match *data {
PublicKeyData::Compressed(ref x) => x.as_ptr(),
PublicKeyData::Uncompressed(ref x) => x.as_ptr()
}
}
/// Converts the public key to a mutable raw pointer suitable for use
/// with the FFI functions
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut u8 {
let &mut PublicKey(ref mut data) = self;
match *data {
PublicKeyData::Compressed(ref mut x) => x.as_mut_ptr(),
PublicKeyData::Uncompressed(ref mut x) => x.as_mut_ptr()
unsafe {
let mut ret_len = ret.len() as ::libc::c_int;
debug_assert!(ffi::secp256k1_ec_pubkey_serialize(secp.ctx, ret.as_ptr(),
&mut ret_len, self.as_ptr(),
if compressed {1} else {0}) == 1);
ret.set_len(ret_len as usize);
}
ret
}
#[inline]
@ -217,152 +176,20 @@ impl PublicKey {
pub fn add_exp_assign(&mut self, secp: &Secp256k1, other: &SecretKey)
-> Result<(), Error> {
unsafe {
if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx, self.as_mut_ptr(),
self.len() as ::libc::c_int,
other.as_ptr()) != 1 {
Err(Unknown)
} else {
if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx, &mut self.0 as *mut _,
other.as_ptr()) == 1 {
Ok(())
} else {
Err(Unknown)
}
}
}
}
// We have to do all these impls ourselves as Rust can't derive
// them for arrays
impl Clone for PublicKeyData {
fn clone(&self) -> PublicKeyData { *self }
}
impl PartialEq for PublicKeyData {
fn eq(&self, other: &PublicKeyData) -> bool {
&self[..] == &other[..]
}
}
impl fmt::Debug for PublicKeyData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for i in self[..].iter().cloned() {
try!(write!(f, "{:02x}", i));
}
Ok(())
}
}
impl ops::Index<usize> for PublicKeyData {
type Output = u8;
#[inline]
fn index(&self, index: usize) -> &u8 {
match *self {
PublicKeyData::Compressed(ref x) => &x[index],
PublicKeyData::Uncompressed(ref x) => &x[index]
}
}
}
impl ops::Index<usize> for PublicKey {
type Output = u8;
#[inline]
fn index(&self, index: usize) -> &u8 {
let &PublicKey(ref dat) = self;
&dat[index]
}
}
impl ops::Index<ops::Range<usize>> for PublicKeyData {
type Output = [u8];
#[inline]
fn index(&self, index: ops::Range<usize>) -> &[u8] {
match *self {
PublicKeyData::Compressed(ref x) => &x[index],
PublicKeyData::Uncompressed(ref x) => &x[index]
}
}
}
impl ops::Index<ops::Range<usize>> for PublicKey {
type Output = [u8];
#[inline]
fn index(&self, index: ops::Range<usize>) -> &[u8] {
let &PublicKey(ref dat) = self;
&dat[index]
}
}
impl ops::Index<ops::RangeTo<usize>> for PublicKeyData {
type Output = [u8];
#[inline]
fn index(&self, index: ops::RangeTo<usize>) -> &[u8] {
match *self {
PublicKeyData::Compressed(ref x) => &x[index],
PublicKeyData::Uncompressed(ref x) => &x[index]
}
}
}
impl ops::Index<ops::RangeTo<usize>> for PublicKey {
type Output = [u8];
#[inline]
fn index(&self, index: ops::RangeTo<usize>) -> &[u8] {
let &PublicKey(ref dat) = self;
&dat[index]
}
}
impl ops::Index<ops::RangeFrom<usize>> for PublicKeyData {
type Output = [u8];
#[inline]
fn index(&self, index: ops::RangeFrom<usize>) -> &[u8] {
match *self {
PublicKeyData::Compressed(ref x) => &x[index],
PublicKeyData::Uncompressed(ref x) => &x[index]
}
}
}
impl ops::Index<ops::RangeFrom<usize>> for PublicKey {
type Output = [u8];
#[inline]
fn index(&self, index: ops::RangeFrom<usize>) -> &[u8] {
let &PublicKey(ref dat) = self;
&dat[index]
}
}
impl ops::Index<ops::RangeFull> for PublicKeyData {
type Output = [u8];
#[inline]
fn index(&self, _: ops::RangeFull) -> &[u8] {
match *self {
PublicKeyData::Compressed(ref x) => &x[..],
PublicKeyData::Uncompressed(ref x) => &x[..]
}
}
}
impl ops::Index<ops::RangeFull> for PublicKey {
type Output = [u8];
#[inline]
fn index(&self, _: ops::RangeFull) -> &[u8] {
let &PublicKey(ref dat) = self;
&dat[..]
}
}
impl Decodable for PublicKey {
fn decode<D: Decoder>(d: &mut D) -> Result<PublicKey, D::Error> {
d.read_seq(|d, len| {
let s = Secp256k1::with_caps(::ContextFlag::None);
if len == constants::UNCOMPRESSED_PUBLIC_KEY_SIZE {
unsafe {
use std::mem;
@ -370,7 +197,7 @@ impl Decodable for PublicKey {
for i in 0..len {
ret[i] = try!(d.read_seq_elt(i, |d| Decodable::decode(d)));
}
Ok(PublicKey(PublicKeyData::Uncompressed(ret)))
PublicKey::from_slice(&s, &ret).map_err(|_| d.error("invalid public key"))
}
} else if len == constants::COMPRESSED_PUBLIC_KEY_SIZE {
unsafe {
@ -379,7 +206,7 @@ impl Decodable for PublicKey {
for i in 0..len {
ret[i] = try!(d.read_seq_elt(i, |d| Decodable::decode(d)));
}
Ok(PublicKey(PublicKeyData::Compressed(ret)))
PublicKey::from_slice(&s, &ret).map_err(|_| d.error("invalid public key"))
}
} else {
Err(d.error("Invalid length"))
@ -390,7 +217,8 @@ impl Decodable for PublicKey {
impl Encodable for PublicKey {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
(&self[..]).encode(s)
let secp = Secp256k1::with_caps(::ContextFlag::None);
self.serialize_vec(&secp, true).encode(s)
}
}
@ -411,10 +239,10 @@ impl Deserialize for PublicKey {
{
debug_assert!(constants::UNCOMPRESSED_PUBLIC_KEY_SIZE >= constants::COMPRESSED_PUBLIC_KEY_SIZE);
let s = Secp256k1::with_caps(::ContextFlag::None);
unsafe {
use std::mem;
let mut ret_u: [u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE] = mem::uninitialized();
let mut ret_c: [u8; constants::COMPRESSED_PUBLIC_KEY_SIZE] = mem::uninitialized();
let mut ret: [u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE] = mem::uninitialized();
let mut read_len = 0;
while read_len < constants::UNCOMPRESSED_PUBLIC_KEY_SIZE {
@ -422,19 +250,12 @@ impl Deserialize for PublicKey {
Some(c) => c,
None => break
};
ret_u[read_len] = read_ch;
if read_len < constants::COMPRESSED_PUBLIC_KEY_SIZE { ret_c[read_len] = read_ch; }
ret[read_len] = read_ch;
read_len += 1;
}
try!(v.end());
if read_len == constants::UNCOMPRESSED_PUBLIC_KEY_SIZE {
Ok(PublicKey(PublicKeyData::Uncompressed(ret_u)))
} else if read_len == constants::COMPRESSED_PUBLIC_KEY_SIZE {
Ok(PublicKey(PublicKeyData::Compressed(ret_c)))
} else {
return Err(de::Error::syntax_error());
}
PublicKey::from_slice(&s, &ret[..read_len]).map_err(|_| de::Error::syntax_error())
}
}
}
@ -448,17 +269,8 @@ impl Serialize for PublicKey {
fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
where S: Serializer
{
(&self.0[..]).serialize(s)
}
}
impl fmt::Debug for SecretKey {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
try!(write!(f, "SecretKey("));
for i in self[..].iter().cloned() {
try!(write!(f, "{:02x}", i));
}
write!(f, ")")
let secp = Secp256k1::with_caps(::ContextFlag::None);
(&self.serialize_vec(&secp, true)[..]).serialize(s)
}
}
@ -489,24 +301,19 @@ mod test {
let uncompressed = PublicKey::from_slice(&s, &[4, 54, 57, 149, 239, 162, 148, 175, 246, 254, 239, 75, 154, 152, 10, 82, 234, 224, 85, 220, 40, 100, 57, 121, 30, 162, 94, 156, 135, 67, 74, 49, 179, 57, 236, 53, 162, 124, 149, 144, 168, 77, 74, 30, 72, 211, 229, 110, 111, 55, 96, 193, 86, 227, 183, 152, 195, 155, 51, 247, 123, 113, 60, 228, 188]);
assert!(uncompressed.is_ok());
assert!(!uncompressed.unwrap().is_compressed());
let compressed = PublicKey::from_slice(&s, &[3, 23, 183, 225, 206, 31, 159, 148, 195, 42, 67, 115, 146, 41, 248, 140, 11, 3, 51, 41, 111, 180, 110, 143, 114, 134, 88, 73, 198, 174, 52, 184, 78]);
assert!(compressed.is_ok());
assert!(compressed.unwrap().is_compressed());
}
#[test]
fn keypair_slice_round_trip() {
let s = Secp256k1::new();
let (sk1, pk1) = s.generate_keypair(&mut thread_rng(), true).unwrap();
let (sk1, pk1) = s.generate_keypair(&mut thread_rng()).unwrap();
assert_eq!(SecretKey::from_slice(&s, &sk1[..]), Ok(sk1));
assert_eq!(PublicKey::from_slice(&s, &pk1[..]), Ok(pk1));
let (sk2, pk2) = s.generate_keypair(&mut thread_rng(), false).unwrap();
assert_eq!(SecretKey::from_slice(&s, &sk2[..]), Ok(sk2));
assert_eq!(PublicKey::from_slice(&s, &pk2[..]), Ok(pk2));
assert_eq!(PublicKey::from_slice(&s, &pk1.serialize_vec(&s, true)[..]), Ok(pk1));
assert_eq!(PublicKey::from_slice(&s, &pk1.serialize_vec(&s, false)[..]), Ok(pk1));
}
#[test]
@ -554,7 +361,7 @@ mod test {
let mut decoder = json::Decoder::new(json32.clone());
assert!(<SecretKey as Decodable>::decode(&mut decoder).is_ok());
let mut decoder = json::Decoder::new(json65.clone());
assert!(<PublicKey as Decodable>::decode(&mut decoder).is_ok());
assert!(<PublicKey as Decodable>::decode(&mut decoder).is_err());
let mut decoder = json::Decoder::new(json65.clone());
assert!(<SecretKey as Decodable>::decode(&mut decoder).is_err());
@ -581,16 +388,13 @@ mod test {
let json = json::Json::from_reader(&mut Cursor::new(encoded.as_bytes())).unwrap();
let mut decoder = json::Decoder::new(json);
let decoded = Decodable::decode(&mut decoder);
assert_eq!(Some(start), decoded.ok());
assert_eq!(Ok(Some(start)), decoded);
})
);
let s = Secp256k1::new();
for _ in 0..500 {
let (sk, pk) = s.generate_keypair(&mut thread_rng(), false).unwrap();
round_trip!(sk);
round_trip!(pk);
let (sk, pk) = s.generate_keypair(&mut thread_rng(), true).unwrap();
let (sk, pk) = s.generate_keypair(&mut thread_rng()).unwrap();
round_trip!(sk);
round_trip!(pk);
}
@ -613,9 +417,10 @@ mod test {
let mut json = json::de::Deserializer::new(zero32.iter().map(|c| Ok(*c))).unwrap();
assert!(<SecretKey as Deserialize>::deserialize(&mut json).is_ok());
// All zeroes pk is invalid
let zero65 = "[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,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,0,0,0]".as_bytes();
let mut json = json::de::Deserializer::new(zero65.iter().map(|c| Ok(*c))).unwrap();
assert!(<PublicKey as Deserialize>::deserialize(&mut json).is_ok());
assert!(<PublicKey as Deserialize>::deserialize(&mut json).is_err());
let mut json = json::de::Deserializer::new(zero65.iter().map(|c| Ok(*c))).unwrap();
assert!(<SecretKey as Deserialize>::deserialize(&mut json).is_err());
@ -648,10 +453,7 @@ mod test {
let s = Secp256k1::new();
for _ in 0..500 {
let (sk, pk) = s.generate_keypair(&mut thread_rng(), false).unwrap();
round_trip!(sk);
round_trip!(pk);
let (sk, pk) = s.generate_keypair(&mut thread_rng(), true).unwrap();
let (sk, pk) = s.generate_keypair(&mut thread_rng()).unwrap();
round_trip!(sk);
round_trip!(pk);
}
@ -685,8 +487,7 @@ mod test {
}
let s = Secp256k1::new();
s.generate_keypair(&mut BadRng(0xff), false).unwrap();
s.generate_keypair(&mut BadRng(0xff), true).unwrap();
s.generate_keypair(&mut BadRng(0xff)).unwrap();
}
#[test]
@ -720,35 +521,46 @@ mod test {
}
let s = Secp256k1::new();
let (sk1, pk1) = s.generate_keypair(&mut DumbRng(0), false).unwrap();
let (sk2, pk2) = s.generate_keypair(&mut DumbRng(0), true).unwrap();
let (sk, _) = s.generate_keypair(&mut DumbRng(0)).unwrap();
assert_eq!(&format!("{:?}", sk1),
assert_eq!(&format!("{:?}", sk),
"SecretKey(0200000001000000040000000300000006000000050000000800000007000000)");
assert_eq!(&format!("{:?}", pk1),
"PublicKey(049510c48c265cefb3413be0e6b75beef02ebafcaf6634f962b27b4832abc4feec01bd8ff2e31057f7b7a244ed8c5ccd9781a63a6f607b40b493330cd159ecd5ce)");
assert_eq!(&format!("{:?}", sk2),
"SecretKey(0200000001000000040000000300000006000000050000000800000007000000)");
assert_eq!(&format!("{:?}", pk2),
"PublicKey(029510c48c265cefb3413be0e6b75beef02ebafcaf6634f962b27b4832abc4feec)");
}
#[test]
fn test_pubkey_serialize() {
struct DumbRng(u32);
impl Rng for DumbRng {
fn next_u32(&mut self) -> u32 {
self.0 = self.0.wrapping_add(1);
self.0
}
}
let s = Secp256k1::new();
let (_, pk1) = s.generate_keypair(&mut DumbRng(0)).unwrap();
assert_eq!(&pk1.serialize_vec(&s, false)[..],
&[4, 149, 16, 196, 140, 38, 92, 239, 179, 65, 59, 224, 230, 183, 91, 238, 240, 46, 186, 252, 175, 102, 52, 249, 98, 178, 123, 72, 50, 171, 196, 254, 236, 1, 189, 143, 242, 227, 16, 87, 247, 183, 162, 68, 237, 140, 92, 205, 151, 129, 166, 58, 111, 96, 123, 64, 180, 147, 51, 12, 209, 89, 236, 213, 206][..]);
assert_eq!(&pk1.serialize_vec(&s, true)[..],
&[2, 149, 16, 196, 140, 38, 92, 239, 179, 65, 59, 224, 230, 183, 91, 238, 240, 46, 186, 252, 175, 102, 52, 249, 98, 178, 123, 72, 50, 171, 196, 254, 236][..]);
}
#[test]
fn test_addition() {
let s = Secp256k1::new();
let (mut sk1, mut pk1) = s.generate_keypair(&mut thread_rng(), true).unwrap();
let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng(), true).unwrap();
let (mut sk1, mut pk1) = s.generate_keypair(&mut thread_rng()).unwrap();
let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng()).unwrap();
assert_eq!(PublicKey::from_secret_key(&s, &sk1, true), pk1);
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
assert!(sk1.add_assign(&s, &sk2).is_ok());
assert!(pk1.add_exp_assign(&s, &sk2).is_ok());
assert_eq!(PublicKey::from_secret_key(&s, &sk1, true), pk1);
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
assert_eq!(PublicKey::from_secret_key(&s, &sk2, true), pk2);
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
assert!(sk2.add_assign(&s, &sk1).is_ok());
assert!(pk2.add_exp_assign(&s, &sk1).is_ok());
assert_eq!(PublicKey::from_secret_key(&s, &sk2, true), pk2);
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
}
}

View File

@ -35,6 +35,7 @@
#![deny(unused_mut)]
#![warn(missing_docs)]
extern crate arrayvec;
extern crate rustc_serialize as serialize;
extern crate serde;
#[cfg(test)] extern crate test;
@ -43,7 +44,7 @@ extern crate libc;
extern crate rand;
use std::intrinsics::copy_nonoverlapping;
use std::{cmp, fmt, ops, ptr};
use std::{fmt, ops, ptr};
use libc::c_int;
use rand::Rng;
@ -58,57 +59,54 @@ pub mod key;
pub struct RecoveryId(i32);
/// An ECDSA signature
#[derive(Copy)]
pub struct Signature(usize, [u8; constants::MAX_SIGNATURE_SIZE]);
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Signature(ffi::Signature);
impl Signature {
/// Converts the signature to a raw pointer suitable for use
/// with the FFI functions
#[inline]
pub fn as_ptr(&self) -> *const u8 {
let &Signature(_, ref data) = self;
data.as_ptr()
}
/// Converts a DER-encoded byte slice to a signature
pub fn from_der(secp: &Secp256k1, data: &[u8]) -> Result<Signature, Error> {
let mut ret = unsafe { ffi::Signature::blank() };
/// Converts the signature to a mutable raw pointer suitable for use
/// with the FFI functions
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut u8 {
let &mut Signature(_, ref mut data) = self;
data.as_mut_ptr()
}
/// Returns the length of the signature
#[inline]
pub fn len(&self) -> usize {
let &Signature(len, _) = self;
len
}
/// Converts a byte slice to a signature
#[inline]
pub fn from_slice(data: &[u8]) -> Result<Signature, Error> {
if data.len() <= constants::MAX_SIGNATURE_SIZE {
let mut ret = [0; constants::MAX_SIGNATURE_SIZE];
unsafe {
copy_nonoverlapping(data.as_ptr(),
ret.as_mut_ptr(),
data.len());
unsafe {
if ffi::secp256k1_ecdsa_signature_parse_der(secp.ctx, &mut ret,
data.as_ptr(), data.len() as libc::c_int) == 1 {
Ok(Signature(ret))
} else {
Err(Error::InvalidSignature)
}
Ok(Signature(data.len(), ret))
} else {
Err(Error::InvalidSignature)
}
}
}
impl fmt::Debug for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "Signature("));
for i in self[..].iter().cloned() {
try!(write!(f, "{:02x}", i));
#[inline]
/// Converts a compact-encoded byte slice to a signature. This
/// representation is nonstandard and defined by the libsecp256k1
/// library.
pub fn from_compact(secp: &Secp256k1, data: &[u8], recid: RecoveryId) -> Result<Signature, Error> {
let mut ret = unsafe { ffi::Signature::blank() };
unsafe {
if data.len() != 64 {
Err(Error::InvalidSignature)
} else if ffi::secp256k1_ecdsa_signature_parse_compact(secp.ctx, &mut ret,
data.as_ptr(), recid.0) == 1 {
Ok(Signature(ret))
} else {
Err(Error::InvalidSignature)
}
}
write!(f, ")")
}
/// Creates a new public key from a FFI public key
#[inline]
pub fn from_ffi(sig: ffi::Signature) -> Signature {
Signature(sig)
}
/// Obtains a raw pointer suitable for use with FFI functions
#[inline]
pub fn as_ptr(&self) -> *const ffi::Signature {
&self.0 as *const _
}
}
@ -117,8 +115,7 @@ impl ops::Index<usize> for Signature {
#[inline]
fn index(&self, index: usize) -> &u8 {
assert!(index < self.0);
&self.1[index]
&self.0[index]
}
}
@ -127,8 +124,7 @@ impl ops::Index<ops::Range<usize>> for Signature {
#[inline]
fn index(&self, index: ops::Range<usize>) -> &[u8] {
assert!(index.end < self.0);
&self.1[index]
&self.0[index]
}
}
@ -137,7 +133,7 @@ impl ops::Index<ops::RangeFrom<usize>> for Signature {
#[inline]
fn index(&self, index: ops::RangeFrom<usize>) -> &[u8] {
&self.1[index.start..self.0]
&self.0[index.start..]
}
}
@ -146,35 +142,14 @@ impl ops::Index<ops::RangeFull> for Signature {
#[inline]
fn index(&self, _: ops::RangeFull) -> &[u8] {
&self.1[0..self.0]
}
}
impl cmp::PartialEq for Signature {
#[inline]
fn eq(&self, other: &Signature) -> bool {
&self[..] == &other[..]
}
}
impl cmp::Eq for Signature { }
impl Clone for Signature {
#[inline]
fn clone(&self) -> Signature {
unsafe {
use std::mem;
let mut ret: Signature = mem::uninitialized();
copy_nonoverlapping(self.as_ptr(),
ret.as_mut_ptr(),
mem::size_of::<Signature>());
ret
}
&self.0[..]
}
}
/// A (hashed) message input to an ECDSA signature
pub struct Message([u8; constants::MESSAGE_SIZE]);
impl_array_newtype!(Message, u8, constants::MESSAGE_SIZE);
impl_pretty_debug!(Message);
impl Message {
/// Converts a `MESSAGE_SIZE`-byte slice to a nonce
@ -195,16 +170,6 @@ impl Message {
}
}
impl fmt::Debug for Message {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "Message("));
for i in self[..].iter().cloned() {
try!(write!(f, "{:02x}", i));
}
write!(f, ")")
}
}
/// An ECDSA error
#[derive(Copy, PartialEq, Eq, Clone, Debug)]
pub enum Error {
@ -327,14 +292,14 @@ impl Secp256k1 {
/// and `key::PublicKey::from_secret_key`; call those functions directly for
/// batch key generation. Requires a signing-capable context.
#[inline]
pub fn generate_keypair<R: Rng>(&self, rng: &mut R, compressed: bool)
pub fn generate_keypair<R: Rng>(&self, rng: &mut R)
-> Result<(key::SecretKey, key::PublicKey), Error> {
if self.caps == ContextFlag::VerifyOnly || self.caps == ContextFlag::None {
return Err(Error::IncapableContext);
}
let sk = key::SecretKey::new(self, rng);
let pk = key::PublicKey::from_secret_key(self, &sk, compressed);
let pk = key::PublicKey::from_secret_key(self, &sk);
Ok((sk, pk))
}
@ -346,69 +311,35 @@ impl Secp256k1 {
return Err(Error::IncapableContext);
}
let mut sig = [0; constants::MAX_SIGNATURE_SIZE];
let mut len = constants::MAX_SIGNATURE_SIZE as c_int;
let mut ret = unsafe { ffi::Signature::blank() };
unsafe {
// We can assume the return value because it's not possible to construct
// an invalid signature from a valid `Message` and `SecretKey`
assert_eq!(ffi::secp256k1_ecdsa_sign(self.ctx, msg.as_ptr(), sig.as_mut_ptr(),
&mut len, sk.as_ptr(),
ffi::secp256k1_nonce_function_rfc6979,
assert_eq!(ffi::secp256k1_ecdsa_sign(self.ctx, msg.as_ptr(), &mut ret,
sk.as_ptr(), ffi::secp256k1_nonce_function_rfc6979,
ptr::null()), 1);
// This assertation is probably too late :)
debug_assert!(len as usize <= constants::MAX_SIGNATURE_SIZE);
}
Ok(Signature(len as usize, sig))
}
/// Constructs a compact signature for `msg` using the secret key `sk`.
/// Requires a signing-capable context.
pub fn sign_compact(&self, msg: &Message, sk: &key::SecretKey)
-> Result<(Signature, RecoveryId), Error> {
if self.caps == ContextFlag::VerifyOnly || self.caps == ContextFlag::None {
return Err(Error::IncapableContext);
}
let mut sig = [0; constants::MAX_SIGNATURE_SIZE];
let mut recid = 0;
unsafe {
// We can assume the return value because it's not possible to construct
// an invalid signature from a valid `Message` and `SecretKey`
assert_eq!(ffi::secp256k1_ecdsa_sign_compact(self.ctx, msg.as_ptr(),
sig.as_mut_ptr(), sk.as_ptr(),
ffi::secp256k1_nonce_function_default,
ptr::null(), &mut recid), 1);
}
Ok((Signature(constants::COMPACT_SIGNATURE_SIZE, sig), RecoveryId(recid)))
Ok(Signature::from_ffi(ret))
}
/// Determines the public key for which `sig` is a valid signature for
/// `msg`. Returns through the out-pointer `pubkey`. Requires a verify-capable
/// context.
pub fn recover_compact(&self, msg: &Message, sig: &[u8],
compressed: bool, recid: RecoveryId)
-> Result<key::PublicKey, Error> {
pub fn recover(&self, msg: &Message, sig: &Signature)
-> Result<key::PublicKey, Error> {
if self.caps == ContextFlag::SignOnly || self.caps == ContextFlag::None {
return Err(Error::IncapableContext);
}
let mut pk = key::PublicKey::new(compressed);
let RecoveryId(recid) = recid;
let mut pk = unsafe { ffi::PublicKey::blank() };
if sig.len() != constants::COMPACT_SIGNATURE_SIZE {
return Err(Error::InvalidSignature);
}
unsafe {
let mut len = 0;
if ffi::secp256k1_ecdsa_recover_compact(self.ctx, msg.as_ptr(),
sig.as_ptr(), pk.as_mut_ptr(), &mut len,
if compressed {1} else {0},
recid) != 1 {
if ffi::secp256k1_ecdsa_recover(self.ctx, msg.as_ptr(),
&sig.0, &mut pk) != 1 {
return Err(Error::InvalidSignature);
}
debug_assert_eq!(len as usize, pk.len());
};
Ok(pk)
Ok(key::PublicKey::from_ffi(pk))
}
/// Checks that `sig` is a valid ECDSA signature for `msg` using the public
@ -418,28 +349,17 @@ impl Secp256k1 {
/// verify-capable context.
#[inline]
pub fn verify(&self, msg: &Message, sig: &Signature, pk: &key::PublicKey) -> Result<(), Error> {
self.verify_raw(msg, &sig[..], pk)
}
/// Verifies a signature described as a slice of bytes rather than opaque `Signature`.
/// Requires a verify-capable context.
pub fn verify_raw(&self, msg: &Message, sig: &[u8], pk: &key::PublicKey) -> Result<(), Error> {
if self.caps == ContextFlag::SignOnly || self.caps == ContextFlag::None {
return Err(Error::IncapableContext);
}
let res = unsafe {
ffi::secp256k1_ecdsa_verify(self.ctx, msg.as_ptr(),
sig.as_ptr(), sig.len() as c_int,
pk.as_ptr(), pk.len() as c_int)
};
match res {
1 => Ok(()),
0 => Err(Error::IncorrectSignature),
-1 => Err(Error::InvalidPublicKey),
-2 => Err(Error::InvalidSignature),
_ => unreachable!()
if !pk.is_valid() {
Err(Error::InvalidPublicKey)
} else if unsafe { ffi::secp256k1_ecdsa_verify(self.ctx, msg.as_ptr(),
&sig.0, pk.as_ptr()) } == 0 {
Err(Error::IncorrectSignature)
} else {
Ok(())
}
}
}
@ -469,15 +389,11 @@ mod tests {
let msg = Message::from_slice(&msg).unwrap();
// Try key generation
assert_eq!(none.generate_keypair(&mut thread_rng(), true), Err(IncapableContext));
assert_eq!(none.generate_keypair(&mut thread_rng(), false), Err(IncapableContext));
assert_eq!(vrfy.generate_keypair(&mut thread_rng(), true), Err(IncapableContext));
assert_eq!(vrfy.generate_keypair(&mut thread_rng(), false), Err(IncapableContext));
assert!(sign.generate_keypair(&mut thread_rng(), true).is_ok());
assert!(sign.generate_keypair(&mut thread_rng(), false).is_ok());
assert!(full.generate_keypair(&mut thread_rng(), true).is_ok());
assert!(full.generate_keypair(&mut thread_rng(), false).is_ok());
let (sk, pk) = full.generate_keypair(&mut thread_rng(), true).unwrap();
assert_eq!(none.generate_keypair(&mut thread_rng()), Err(IncapableContext));
assert_eq!(vrfy.generate_keypair(&mut thread_rng()), Err(IncapableContext));
assert!(sign.generate_keypair(&mut thread_rng()).is_ok());
assert!(full.generate_keypair(&mut thread_rng()).is_ok());
let (sk, pk) = full.generate_keypair(&mut thread_rng()).unwrap();
// Try signing
assert_eq!(none.sign(&msg, &sk), Err(IncapableContext));
@ -493,32 +409,22 @@ mod tests {
assert!(vrfy.verify(&msg, &sig, &pk).is_ok());
assert!(full.verify(&msg, &sig, &pk).is_ok());
// Try compact signing
assert_eq!(none.sign_compact(&msg, &sk), Err(IncapableContext));
assert_eq!(vrfy.sign_compact(&msg, &sk), Err(IncapableContext));
assert!(sign.sign_compact(&msg, &sk).is_ok());
assert!(full.sign_compact(&msg, &sk).is_ok());
let (csig, recid) = full.sign_compact(&msg, &sk).unwrap();
// Try pk recovery
assert_eq!(none.recover_compact(&msg, &csig[..], true, recid), Err(IncapableContext));
assert_eq!(none.recover_compact(&msg, &csig[..], false, recid), Err(IncapableContext));
assert_eq!(sign.recover_compact(&msg, &csig[..], true, recid), Err(IncapableContext));
assert_eq!(sign.recover_compact(&msg, &csig[..], false, recid), Err(IncapableContext));
assert!(vrfy.recover_compact(&msg, &csig[..], false, recid).is_ok());
assert!(vrfy.recover_compact(&msg, &csig[..], true, recid).is_ok());
assert!(full.recover_compact(&msg, &csig[..], false, recid).is_ok());
assert!(full.recover_compact(&msg, &csig[..], true, recid).is_ok());
assert_eq!(none.recover(&msg, &sig), Err(IncapableContext));
assert_eq!(none.recover(&msg, &sig), Err(IncapableContext));
assert_eq!(sign.recover(&msg, &sig), Err(IncapableContext));
assert_eq!(sign.recover(&msg, &sig), Err(IncapableContext));
assert!(vrfy.recover(&msg, &sig).is_ok());
assert!(vrfy.recover(&msg, &sig).is_ok());
assert!(full.recover(&msg, &sig).is_ok());
assert!(full.recover(&msg, &sig).is_ok());
assert_eq!(vrfy.recover_compact(&msg, &csig[..], false, recid),
full.recover_compact(&msg, &csig[..], false, recid));
assert_eq!(vrfy.recover_compact(&msg, &csig[..], true, recid),
full.recover_compact(&msg, &csig[..], true, recid));
assert_eq!(full.recover_compact(&msg, &csig[..], true, recid), Ok(pk));
assert_eq!(vrfy.recover(&msg, &sig),
full.recover(&msg, &sig));
assert_eq!(full.recover(&msg, &sig), Ok(pk));
// Check that we can produce keys from slices with no precomputation
let (pk_slice, sk_slice) = (&pk[..], &sk[..]);
let (pk_slice, sk_slice) = (&pk.serialize_vec(&none, true), &sk[..]);
let new_pk = PublicKey::from_slice(&none, pk_slice).unwrap();
let new_sk = SecretKey::from_slice(&none, sk_slice).unwrap();
assert_eq!(sk, new_sk);
@ -534,8 +440,8 @@ mod tests {
#[test]
fn invalid_pubkey() {
let s = Secp256k1::new();
let sig = Signature::from_slice(&[0; 72]).unwrap();
let pk = PublicKey::new(true);
let sig = Signature::from_compact(&s, &[1; 64], RecoveryId(0)).unwrap();
let pk = PublicKey::new();
let mut msg = [0u8; 32];
thread_rng().fill_bytes(&mut msg);
let msg = Message::from_slice(&msg).unwrap();
@ -543,33 +449,6 @@ mod tests {
assert_eq!(s.verify(&msg, &sig, &pk), Err(InvalidPublicKey));
}
#[test]
fn valid_pubkey_uncompressed() {
let s = Secp256k1::new();
let (_, pk) = s.generate_keypair(&mut thread_rng(), false).unwrap();
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!(s.verify(&msg, &sig, &pk), Err(InvalidSignature));
}
#[test]
fn valid_pubkey_compressed() {
let s = Secp256k1::new();
let (_, pk) = s.generate_keypair(&mut thread_rng(), true).unwrap();
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!(s.verify(&msg, &sig, &pk), Err(InvalidSignature));
}
#[test]
fn sign() {
let mut s = Secp256k1::new();
@ -581,16 +460,16 @@ mod tests {
let msg = Message::from_slice(&one).unwrap();
let sig = s.sign(&msg, &sk).unwrap();
assert_eq!(sig, Signature(70, [
0x30, 0x44, 0x02, 0x20, 0x66, 0x73, 0xff, 0xad,
0x21, 0x47, 0x74, 0x1f, 0x04, 0x77, 0x2b, 0x6f,
0x92, 0x1f, 0x0b, 0xa6, 0xaf, 0x0c, 0x1e, 0x77,
0xfc, 0x43, 0x9e, 0x65, 0xc3, 0x6d, 0xed, 0xf4,
0x09, 0x2e, 0x88, 0x98, 0x02, 0x20, 0x4c, 0x1a,
0x97, 0x16, 0x52, 0xe0, 0xad, 0xa8, 0x80, 0x12,
0x0e, 0xf8, 0x02, 0x5e, 0x70, 0x9f, 0xff, 0x20,
0x80, 0xc4, 0xa3, 0x9a, 0xae, 0x06, 0x8d, 0x12,
0xee, 0xd0, 0x09, 0xb6, 0x8c, 0x89, 0x00, 0x00]))
assert_eq!(Ok(sig), Signature::from_compact(&s, &[
0x66, 0x73, 0xff, 0xad, 0x21, 0x47, 0x74, 0x1f,
0x04, 0x77, 0x2b, 0x6f, 0x92, 0x1f, 0x0b, 0xa6,
0xaf, 0x0c, 0x1e, 0x77, 0xfc, 0x43, 0x9e, 0x65,
0xc3, 0x6d, 0xed, 0xf4, 0x09, 0x2e, 0x88, 0x98,
0x4c, 0x1a, 0x97, 0x16, 0x52, 0xe0, 0xad, 0xa8,
0x80, 0x12, 0x0e, 0xf8, 0x02, 0x5e, 0x70, 0x9f,
0xff, 0x20, 0x80, 0xc4, 0xa3, 0x9a, 0xae, 0x06,
0x8d, 0x12, 0xee, 0xd0, 0x09, 0xb6, 0x8c, 0x89],
RecoveryId(1)))
}
#[test]
@ -603,7 +482,7 @@ mod tests {
thread_rng().fill_bytes(&mut msg);
let msg = Message::from_slice(&msg).unwrap();
let (sk, pk) = s.generate_keypair(&mut thread_rng(), false).unwrap();
let (sk, pk) = s.generate_keypair(&mut thread_rng()).unwrap();
let sig = s.sign(&msg, &sk).unwrap();
assert_eq!(s.verify(&msg, &sig, &pk), Ok(()));
}
@ -640,7 +519,7 @@ mod tests {
for key in wild_keys.iter().map(|k| SecretKey::from_slice(&s, &k[..]).unwrap()) {
for msg in wild_msgs.iter().map(|m| Message::from_slice(&m[..]).unwrap()) {
let sig = s.sign(&msg, &key).unwrap();
let pk = PublicKey::from_secret_key(&s, &key, true);
let pk = PublicKey::from_secret_key(&s, &key);
assert_eq!(s.verify(&msg, &sig, &pk), Ok(()));
}
}
@ -655,22 +534,21 @@ mod tests {
thread_rng().fill_bytes(&mut msg);
let msg = Message::from_slice(&msg).unwrap();
let (sk, pk) = s.generate_keypair(&mut thread_rng(), false).unwrap();
let (sk, pk) = s.generate_keypair(&mut thread_rng()).unwrap();
let sig = s.sign(&msg, &sk).unwrap();
let (sig_compact, recid) = s.sign_compact(&msg, &sk).unwrap();
let mut msg = [0u8; 32];
thread_rng().fill_bytes(&mut msg);
let msg = Message::from_slice(&msg).unwrap();
assert_eq!(s.verify(&msg, &sig, &pk), Err(IncorrectSignature));
let recovered_key = s.recover_compact(&msg, &sig_compact[..], false, recid).unwrap();
let recovered_key = s.recover(&msg, &sig).unwrap();
assert!(recovered_key != pk);
}
#[test]
fn sign_compact_with_recovery() {
fn sign_with_recovery() {
let mut s = Secp256k1::new();
s.randomize(&mut thread_rng());
@ -678,11 +556,11 @@ mod tests {
thread_rng().fill_bytes(&mut msg);
let msg = Message::from_slice(&msg).unwrap();
let (sk, pk) = s.generate_keypair(&mut thread_rng(), false).unwrap();
let (sk, pk) = s.generate_keypair(&mut thread_rng()).unwrap();
let (sig, recid) = s.sign_compact(&msg, &sk).unwrap();
let sig = s.sign(&msg, &sk).unwrap();
assert_eq!(s.recover_compact(&msg, &sig[..], false, recid), Ok(pk));
assert_eq!(s.recover(&msg, &sig), Ok(pk));
}
#[test]
@ -692,36 +570,43 @@ mod tests {
let msg = Message::from_slice(&[0x55; 32]).unwrap();
// Bad length
assert_eq!(s.recover_compact(&msg, &[1; 63], false, RecoveryId(0)), Err(InvalidSignature));
assert_eq!(s.recover_compact(&msg, &[1; 65], false, RecoveryId(0)), Err(InvalidSignature));
// Zero is not a valid sig
assert_eq!(s.recover_compact(&msg, &[0; 64], false, RecoveryId(0)), Err(InvalidSignature));
let sig = Signature::from_compact(&s, &[0; 64], RecoveryId(0)).unwrap();
assert_eq!(s.recover(&msg, &sig), Err(InvalidSignature));
// ...but 111..111 is
assert!(s.recover_compact(&msg, &[1; 64], false, RecoveryId(0)).is_ok());
let sig = Signature::from_compact(&s, &[1; 64], RecoveryId(0)).unwrap();
assert!(s.recover(&msg, &sig).is_ok());
}
#[test]
fn test_bad_slice() {
assert_eq!(Signature::from_slice(&[0; constants::MAX_SIGNATURE_SIZE + 1]),
let s = Secp256k1::new();
assert_eq!(Signature::from_der(&s, &[0; constants::MAX_SIGNATURE_SIZE + 1]),
Err(InvalidSignature));
assert_eq!(Signature::from_der(&s, &[0; constants::MAX_SIGNATURE_SIZE]),
Err(InvalidSignature));
assert!(Signature::from_slice(&[0; constants::MAX_SIGNATURE_SIZE]).is_ok());
assert_eq!(Message::from_slice(&[0; constants::MESSAGE_SIZE - 1]),
Err(InvalidMessage));
assert_eq!(Message::from_slice(&[0; constants::MESSAGE_SIZE + 1]),
Err(InvalidMessage));
assert!(Signature::from_slice(&[0; constants::MESSAGE_SIZE]).is_ok());
assert!(Message::from_slice(&[0; constants::MESSAGE_SIZE]).is_ok());
}
#[test]
fn test_debug_output() {
let sig = Signature(0, [4; 72]);
assert_eq!(&format!("{:?}", sig), "Signature()");
let sig = Signature(10, [5; 72]);
assert_eq!(&format!("{:?}", sig), "Signature(05050505050505050505)");
let sig = Signature(72, [6; 72]);
assert_eq!(&format!("{:?}", sig), "Signature(060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606)");
let s = Secp256k1::new();
let sig = Signature::from_compact(&s, &[
0x66, 0x73, 0xff, 0xad, 0x21, 0x47, 0x74, 0x1f,
0x04, 0x77, 0x2b, 0x6f, 0x92, 0x1f, 0x0b, 0xa6,
0xaf, 0x0c, 0x1e, 0x77, 0xfc, 0x43, 0x9e, 0x65,
0xc3, 0x6d, 0xed, 0xf4, 0x09, 0x2e, 0x88, 0x98,
0x4c, 0x1a, 0x97, 0x16, 0x52, 0xe0, 0xad, 0xa8,
0x80, 0x12, 0x0e, 0xf8, 0x02, 0x5e, 0x70, 0x9f,
0xff, 0x20, 0x80, 0xc4, 0xa3, 0x9a, 0xae, 0x06,
0x8d, 0x12, 0xee, 0xd0, 0x09, 0xb6, 0x8c, 0x89],
RecoveryId(1)).unwrap();
assert_eq!(&format!("{:?}", sig), "Signature(98882e09f4ed6dc3659e43fc771e0cafa60b1f926f2b77041f744721adff7366898cb609d0ee128d06ae9aa3c48020ff9f705e02f80e1280a8ade05216971a4c01)");
let msg = Message([1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16,
@ -731,7 +616,7 @@ mod tests {
}
#[bench]
pub fn generate_compressed(bh: &mut Bencher) {
pub fn generate(bh: &mut Bencher) {
struct CounterRng(u32);
impl Rng for CounterRng {
fn next_u32(&mut self) -> u32 { self.0 += 1; self.0 }
@ -740,35 +625,19 @@ mod tests {
let s = Secp256k1::new();
let mut r = CounterRng(0);
bh.iter( || {
let (sk, pk) = s.generate_keypair(&mut r, true).unwrap();
let (sk, pk) = s.generate_keypair(&mut r).unwrap();
black_box(sk);
black_box(pk);
});
}
#[bench]
pub fn generate_uncompressed(bh: &mut Bencher) {
struct CounterRng(u32);
impl Rng for CounterRng {
fn next_u32(&mut self) -> u32 { self.0 += 1; self.0 }
}
let s = Secp256k1::new();
let mut r = CounterRng(0);
bh.iter(|| {
let (sk, pk) = s.generate_keypair(&mut r, false).unwrap();
black_box(sk);
black_box(pk);
});
}
#[bench]
pub fn sign_uncompressed(bh: &mut Bencher) {
pub fn bench_sign(bh: &mut Bencher) {
let s = Secp256k1::new();
let mut msg = [0u8; 32];
thread_rng().fill_bytes(&mut msg);
let msg = Message::from_slice(&msg).unwrap();
let (sk, _) = s.generate_keypair(&mut thread_rng(), false).unwrap();
let (sk, _) = s.generate_keypair(&mut thread_rng()).unwrap();
bh.iter(|| {
let sig = s.sign(&msg, &sk).unwrap();
@ -777,54 +646,12 @@ mod tests {
}
#[bench]
pub fn sign_compressed(bh: &mut Bencher) {
pub fn bench_verify(bh: &mut Bencher) {
let s = Secp256k1::new();
let mut msg = [0u8; 32];
thread_rng().fill_bytes(&mut msg);
let msg = Message::from_slice(&msg).unwrap();
let (sk, _) = s.generate_keypair(&mut thread_rng(), true).unwrap();
bh.iter(|| {
let sig = s.sign(&msg, &sk).unwrap();
black_box(sig);
});
}
#[bench]
pub fn sign_uncompressed_compact(bh: &mut Bencher) {
let s = Secp256k1::new();
let mut msg = [0u8; 32];
thread_rng().fill_bytes(&mut msg);
let msg = Message::from_slice(&msg).unwrap();
let (sk, _) = s.generate_keypair(&mut thread_rng(), false).unwrap();
bh.iter(|| {
let sig = s.sign_compact(&msg, &sk).unwrap();
black_box(sig);
});
}
#[bench]
pub fn sign_compressed_compact(bh: &mut Bencher) {
let s = Secp256k1::new();
let mut msg = [0u8; 32];
thread_rng().fill_bytes(&mut msg);
let msg = Message::from_slice(&msg).unwrap();
let (sk, _) = s.generate_keypair(&mut thread_rng(), true).unwrap();
bh.iter(|| {
let sig = s.sign_compact(&msg, &sk).unwrap();
black_box(sig);
});
}
#[bench]
pub fn verify(bh: &mut Bencher) {
let s = Secp256k1::new();
let mut msg = [0u8; 32];
thread_rng().fill_bytes(&mut msg);
let msg = Message::from_slice(&msg).unwrap();
let (sk, pk) = s.generate_keypair(&mut thread_rng(), true).unwrap();
let (sk, pk) = s.generate_keypair(&mut thread_rng()).unwrap();
let sig = s.sign(&msg, &sk).unwrap();
bh.iter(|| {
@ -834,31 +661,16 @@ mod tests {
}
#[bench]
pub fn recover_uncompressed(bh: &mut Bencher) {
pub fn bench_recover(bh: &mut Bencher) {
let s = Secp256k1::new();
let mut msg = [0u8; 32];
thread_rng().fill_bytes(&mut msg);
let msg = Message::from_slice(&msg).unwrap();
let (sk, _) = s.generate_keypair(&mut thread_rng(), true).unwrap();
let (sig, rid) = s.sign_compact(&msg, &sk).unwrap();
let (sk, _) = s.generate_keypair(&mut thread_rng()).unwrap();
let sig = s.sign(&msg, &sk).unwrap();
bh.iter(|| {
let res = s.recover_compact(&msg, &sig[..], false, rid).unwrap();
black_box(res);
});
}
#[bench]
pub fn recover_compressed(bh: &mut Bencher) {
let s = Secp256k1::new();
let mut msg = [0u8; 32];
thread_rng().fill_bytes(&mut msg);
let msg = Message::from_slice(&msg).unwrap();
let (sk, _) = s.generate_keypair(&mut thread_rng(), true).unwrap();
let (sig, rid) = s.sign_compact(&msg, &sk).unwrap();
bh.iter(|| {
let res = s.recover_compact(&msg, &sig[..], true, rid).unwrap();
let res = s.recover(&msg, &sig).unwrap();
black_box(res);
});
}

View File

@ -187,6 +187,32 @@ macro_rules! impl_array_newtype {
}
}
macro_rules! impl_pretty_debug {
($thing:ident) => {
impl ::std::fmt::Debug for $thing {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
try!(write!(f, "{}(", stringify!($thing)));
for i in self[..].iter().cloned() {
try!(write!(f, "{:02x}", i));
}
write!(f, ")")
}
}
}
}
macro_rules! impl_raw_debug {
($thing:ident) => {
impl ::std::fmt::Debug for $thing {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
for i in self[..].iter().cloned() {
try!(write!(f, "{:02x}", i));
}
Ok(())
}
}
}
}
// for testing
macro_rules! hex_slice {