[API BREAK] Update for new libsecp256k1 API
This commit is contained in:
parent
0de8bfabb6
commit
77f6b6bf21
|
@ -17,6 +17,7 @@ name = "secp256k1"
|
|||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
arrayvec = "0.3"
|
||||
rand = "0.3"
|
||||
libc = "0.1"
|
||||
rustc-serialize = "0.3"
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
104
src/ffi.rs
104
src/ffi.rs
|
@ -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_ecdsa_verify(cx: Context, msg32: *const c_uchar,
|
||||
sig: *const c_uchar, sig_len: c_int,
|
||||
pk: *const c_uchar, pk_len: c_int)
|
||||
pub fn secp256k1_context_randomize(cx: Context,
|
||||
seed32: *const c_uchar)
|
||||
-> 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)
|
||||
// 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 Signature, pk: *const PublicKey)
|
||||
-> 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)
|
||||
pub fn secp256k1_ecdsa_recover(cx: Context, msg32: *const c_uchar,
|
||||
sig: *const Signature, pk: *mut PublicKey)
|
||||
-> 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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
|
394
src/key.rs
394
src/key.rs
|
@ -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)
|
||||
sk: &SecretKey)
|
||||
-> PublicKey {
|
||||
let mut pk = PublicKey::new(compressed);
|
||||
let compressed = if compressed {1} else {0};
|
||||
let mut len = 0;
|
||||
|
||||
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];
|
||||
|
||||
let mut pk = unsafe { ffi::PublicKey::blank() };
|
||||
unsafe {
|
||||
if ffi::secp256k1_ec_pubkey_verify(secp.ctx, data.as_ptr(),
|
||||
data.len() as ::libc::c_int) == 0 {
|
||||
return Err(InvalidPublicKey);
|
||||
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)
|
||||
}
|
||||
copy_nonoverlapping(data.as_ptr(),
|
||||
ret.as_mut_ptr(),
|
||||
data.len());
|
||||
}
|
||||
Ok(PublicKey(PublicKeyData::Compressed(ret)))
|
||||
}
|
||||
constants::UNCOMPRESSED_PUBLIC_KEY_SIZE => {
|
||||
let mut ret = [0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE];
|
||||
|
||||
#[inline]
|
||||
/// 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();
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/// 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()
|
||||
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)
|
||||
if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx, &mut self.0 as *mut _,
|
||||
other.as_ptr()) == 1 {
|
||||
Ok(())
|
||||
} else {
|
||||
Ok(())
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
446
src/lib.rs
446
src/lib.rs
|
@ -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());
|
||||
}
|
||||
Ok(Signature(data.len(), ret))
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue