[API BREAK] update for libsecp256k1 "explicit context" API break
Rather than have global initialization functions, which required expensive synchronization on the part of the Rust library, libsecp256k1 now carries its context in thread-local data which must be passed to every function. What this means for the rust-secp256k1 API is: - Most functions on `PublicKey` and `SecretKey` now require a `Secp256k1` to be given to them. - `Secp256k1::verify` and `::verify_raw` now take a `&self` - `SecretKey::new` now takes a `Secp256k1` rather than a Rng; a future commit will allow specifying the Rng in the `Secp256k1` so that functionality is not lost. - The FFI functions have all changed to take a context argument - `secp256k1::init()` is gone, as is the dependency on std::sync - There is a `ffi::Context` type which must be handled carefully by anyone using it directly (hopefully nobody :))
This commit is contained in:
parent
609f658bee
commit
e52faee98f
48
src/ffi.rs
48
src/ffi.rs
|
@ -32,65 +32,87 @@ pub type NonceFn = unsafe extern "C" fn(nonce32: *mut c_uchar,
|
||||||
attempt: c_uint,
|
attempt: c_uint,
|
||||||
data: *const c_void);
|
data: *const c_void);
|
||||||
|
|
||||||
|
#[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
|
||||||
|
/// with `secp256k1_context_create` you MUST destroy it with
|
||||||
|
/// `secp256k1_context_destroy`, or else you will have a memory leak.
|
||||||
|
/// Furthermore, you MUST NOT use this object after destroying it; it is
|
||||||
|
/// `Copy` so the compiler will not help you to avoid this. There is no
|
||||||
|
/// need for ordinary users of this library to ever use this type directly.
|
||||||
|
#[repr(C)]
|
||||||
|
#[allow(raw_pointer_derive)]
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct Context(*mut ContextInner);
|
||||||
|
|
||||||
#[link(name = "secp256k1")]
|
#[link(name = "secp256k1")]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub static secp256k1_nonce_function_rfc6979: NonceFn;
|
pub static secp256k1_nonce_function_rfc6979: NonceFn;
|
||||||
|
|
||||||
pub static secp256k1_nonce_function_default: NonceFn;
|
pub static secp256k1_nonce_function_default: NonceFn;
|
||||||
|
|
||||||
pub fn secp256k1_start(flags: c_uint);
|
pub fn secp256k1_context_create(flags: c_uint) -> Context;
|
||||||
|
|
||||||
pub fn secp256k1_stop();
|
pub fn secp256k1_context_destroy(cx: Context);
|
||||||
|
|
||||||
pub fn secp256k1_ecdsa_verify(msg32: *const c_uchar,
|
pub fn secp256k1_ecdsa_verify(cx: Context, msg32: *const c_uchar,
|
||||||
sig: *const c_uchar, sig_len: c_int,
|
sig: *const c_uchar, sig_len: c_int,
|
||||||
pk: *const c_uchar, pk_len: c_int)
|
pk: *const c_uchar, pk_len: c_int)
|
||||||
-> c_int;
|
-> c_int;
|
||||||
|
|
||||||
pub fn secp256k1_ec_pubkey_create(pk: *mut c_uchar, pk_len: *mut 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)
|
sk: *const c_uchar, compressed: c_int)
|
||||||
-> c_int;
|
-> c_int;
|
||||||
|
|
||||||
pub fn secp256k1_ecdsa_sign(msg32: *const c_uchar,
|
pub fn secp256k1_ecdsa_sign(cx: Context, msg32: *const c_uchar,
|
||||||
sig: *mut c_uchar, sig_len: *mut c_int,
|
sig: *mut c_uchar, sig_len: *mut c_int,
|
||||||
sk: *const c_uchar,
|
sk: *const c_uchar,
|
||||||
noncefn: NonceFn, noncedata: *const c_void)
|
noncefn: NonceFn, noncedata: *const c_void)
|
||||||
-> c_int;
|
-> c_int;
|
||||||
|
|
||||||
pub fn secp256k1_ecdsa_sign_compact(msg: *const c_uchar,
|
pub fn secp256k1_ecdsa_sign_compact(cx: Context, msg: *const c_uchar,
|
||||||
sig64: *mut c_uchar, sk: *const c_uchar,
|
sig64: *mut c_uchar, sk: *const c_uchar,
|
||||||
noncefn: NonceFn, noncedata: *const c_void,
|
noncefn: NonceFn, noncedata: *const c_void,
|
||||||
recid: *mut c_int)
|
recid: *mut c_int)
|
||||||
-> c_int;
|
-> c_int;
|
||||||
|
|
||||||
pub fn secp256k1_ecdsa_recover_compact(msg32: *const c_uchar,
|
pub fn secp256k1_ecdsa_recover_compact(cx: Context, msg32: *const c_uchar,
|
||||||
sig64: *const c_uchar, pk: *mut c_uchar,
|
sig64: *const c_uchar, pk: *mut c_uchar,
|
||||||
pk_len: *mut c_int, compressed: c_int,
|
pk_len: *mut c_int, compressed: c_int,
|
||||||
recid: c_int) -> c_int;
|
recid: c_int) -> c_int;
|
||||||
|
|
||||||
pub fn secp256k1_ec_seckey_verify(sk: *const c_uchar) -> c_int;
|
pub fn secp256k1_ec_seckey_verify(cx: Context,
|
||||||
|
sk: *const c_uchar) -> c_int;
|
||||||
|
|
||||||
pub fn secp256k1_ec_pubkey_verify(pk: *const c_uchar,
|
pub fn secp256k1_ec_pubkey_verify(cx: Context,
|
||||||
|
pk: *const c_uchar,
|
||||||
pk_len: c_int) -> c_int;
|
pk_len: c_int) -> c_int;
|
||||||
|
|
||||||
//TODO secp256k1_ec_pubkey_decompress
|
//TODO secp256k1_ec_pubkey_decompress
|
||||||
//TODO secp256k1_ec_privkey_export
|
//TODO secp256k1_ec_privkey_export
|
||||||
//TODO secp256k1_ec_privkey_import
|
//TODO secp256k1_ec_privkey_import
|
||||||
|
|
||||||
pub fn secp256k1_ec_privkey_tweak_add(sk: *mut c_uchar,
|
pub fn secp256k1_ec_privkey_tweak_add(cx: Context,
|
||||||
|
sk: *mut c_uchar,
|
||||||
tweak: *const c_uchar)
|
tweak: *const c_uchar)
|
||||||
-> c_int;
|
-> c_int;
|
||||||
|
|
||||||
pub fn secp256k1_ec_pubkey_tweak_add(pk: *mut c_uchar,
|
pub fn secp256k1_ec_pubkey_tweak_add(cx: Context,
|
||||||
|
pk: *mut c_uchar,
|
||||||
pk_len: c_int,
|
pk_len: c_int,
|
||||||
tweak: *const c_uchar)
|
tweak: *const c_uchar)
|
||||||
-> c_int;
|
-> c_int;
|
||||||
|
|
||||||
pub fn secp256k1_ec_privkey_tweak_mul(sk: *mut c_uchar,
|
pub fn secp256k1_ec_privkey_tweak_mul(cx: Context,
|
||||||
|
sk: *mut c_uchar,
|
||||||
tweak: *const c_uchar)
|
tweak: *const c_uchar)
|
||||||
-> c_int;
|
-> c_int;
|
||||||
|
|
||||||
pub fn secp256k1_ec_pubkey_tweak_mul(pk: *mut c_uchar,
|
pub fn secp256k1_ec_pubkey_tweak_mul(cx: Context,
|
||||||
|
pk: *mut c_uchar,
|
||||||
pk_len: c_int,
|
pk_len: c_int,
|
||||||
tweak: *const c_uchar)
|
tweak: *const c_uchar)
|
||||||
-> c_int;
|
-> c_int;
|
||||||
|
|
86
src/key.rs
86
src/key.rs
|
@ -21,7 +21,7 @@ use rand::Rng;
|
||||||
use serialize::{Decoder, Decodable, Encoder, Encodable};
|
use serialize::{Decoder, Decodable, Encoder, Encodable};
|
||||||
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
||||||
|
|
||||||
use super::init;
|
use super::Secp256k1;
|
||||||
use super::Error::{self, InvalidPublicKey, InvalidSecretKey, Unknown};
|
use super::Error::{self, InvalidPublicKey, InvalidSecretKey, Unknown};
|
||||||
use constants;
|
use constants;
|
||||||
use ffi;
|
use ffi;
|
||||||
|
@ -55,12 +55,11 @@ fn random_32_bytes<R:Rng>(rng: &mut R) -> [u8; 32] {
|
||||||
impl SecretKey {
|
impl SecretKey {
|
||||||
/// Creates a new random secret key
|
/// Creates a new random secret key
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new<R:Rng>(rng: &mut R) -> SecretKey {
|
pub fn new(secp: &mut Secp256k1) -> SecretKey {
|
||||||
init();
|
let mut data = random_32_bytes(&mut secp.rng);
|
||||||
let mut data = random_32_bytes(rng);
|
|
||||||
unsafe {
|
unsafe {
|
||||||
while ffi::secp256k1_ec_seckey_verify(data.as_ptr()) == 0 {
|
while ffi::secp256k1_ec_seckey_verify(secp.ctx, data.as_ptr()) == 0 {
|
||||||
data = random_32_bytes(rng);
|
data = random_32_bytes(&mut secp.rng);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SecretKey(data)
|
SecretKey(data)
|
||||||
|
@ -68,13 +67,12 @@ impl SecretKey {
|
||||||
|
|
||||||
/// Converts a `SECRET_KEY_SIZE`-byte slice to a secret key
|
/// Converts a `SECRET_KEY_SIZE`-byte slice to a secret key
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_slice(data: &[u8]) -> Result<SecretKey, Error> {
|
pub fn from_slice(secp: &Secp256k1, data: &[u8]) -> Result<SecretKey, Error> {
|
||||||
init();
|
|
||||||
match data.len() {
|
match data.len() {
|
||||||
constants::SECRET_KEY_SIZE => {
|
constants::SECRET_KEY_SIZE => {
|
||||||
let mut ret = [0; constants::SECRET_KEY_SIZE];
|
let mut ret = [0; constants::SECRET_KEY_SIZE];
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::secp256k1_ec_seckey_verify(data.as_ptr()) == 0 {
|
if ffi::secp256k1_ec_seckey_verify(secp.ctx, data.as_ptr()) == 0 {
|
||||||
return Err(InvalidSecretKey);
|
return Err(InvalidSecretKey);
|
||||||
}
|
}
|
||||||
copy_nonoverlapping(data.as_ptr(),
|
copy_nonoverlapping(data.as_ptr(),
|
||||||
|
@ -89,13 +87,9 @@ impl SecretKey {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Adds one secret key to another, modulo the curve order
|
/// Adds one secret key to another, modulo the curve order
|
||||||
/// Marked `unsafe` since you must
|
pub fn add_assign(&mut self, secp: &Secp256k1, other: &SecretKey) -> Result<(), Error> {
|
||||||
/// call `init()` (or construct a `Secp256k1`, which does this for you) before
|
|
||||||
/// using this function
|
|
||||||
pub fn add_assign(&mut self, other: &SecretKey) -> Result<(), Error> {
|
|
||||||
init();
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::secp256k1_ec_privkey_tweak_add(self.as_mut_ptr(), other.as_ptr()) != 1 {
|
if ffi::secp256k1_ec_privkey_tweak_add(secp.ctx, self.as_mut_ptr(), other.as_ptr()) != 1 {
|
||||||
Err(Unknown)
|
Err(Unknown)
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -119,16 +113,16 @@ impl PublicKey {
|
||||||
|
|
||||||
/// Creates a new public key from a secret key.
|
/// Creates a new public key from a secret key.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_secret_key(sk: &SecretKey, compressed: bool) -> PublicKey {
|
pub fn from_secret_key(secp: &Secp256k1, sk: &SecretKey, compressed: bool) -> PublicKey {
|
||||||
let mut pk = PublicKey::new(compressed);
|
let mut pk = PublicKey::new(compressed);
|
||||||
let compressed = if compressed {1} else {0};
|
let compressed = if compressed {1} else {0};
|
||||||
let mut len = 0;
|
let mut len = 0;
|
||||||
|
|
||||||
init();
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// We can assume the return value because it's not possible to construct
|
// We can assume the return value because it's not possible to construct
|
||||||
// an invalid `SecretKey` without transmute trickery or something
|
// an invalid `SecretKey` without transmute trickery or something
|
||||||
assert_eq!(ffi::secp256k1_ec_pubkey_create(
|
assert_eq!(ffi::secp256k1_ec_pubkey_create(
|
||||||
|
secp.ctx,
|
||||||
pk.as_mut_ptr(), &mut len,
|
pk.as_mut_ptr(), &mut len,
|
||||||
sk.as_ptr(), compressed), 1);
|
sk.as_ptr(), compressed), 1);
|
||||||
}
|
}
|
||||||
|
@ -138,12 +132,12 @@ impl PublicKey {
|
||||||
|
|
||||||
/// Creates a public key directly from a slice
|
/// Creates a public key directly from a slice
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_slice(data: &[u8]) -> Result<PublicKey, Error> {
|
pub fn from_slice(secp: &Secp256k1, data: &[u8]) -> Result<PublicKey, Error> {
|
||||||
match data.len() {
|
match data.len() {
|
||||||
constants::COMPRESSED_PUBLIC_KEY_SIZE => {
|
constants::COMPRESSED_PUBLIC_KEY_SIZE => {
|
||||||
let mut ret = [0; constants::COMPRESSED_PUBLIC_KEY_SIZE];
|
let mut ret = [0; constants::COMPRESSED_PUBLIC_KEY_SIZE];
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::secp256k1_ec_pubkey_verify(data.as_ptr(),
|
if ffi::secp256k1_ec_pubkey_verify(secp.ctx, data.as_ptr(),
|
||||||
data.len() as ::libc::c_int) == 0 {
|
data.len() as ::libc::c_int) == 0 {
|
||||||
return Err(InvalidPublicKey);
|
return Err(InvalidPublicKey);
|
||||||
}
|
}
|
||||||
|
@ -210,10 +204,9 @@ impl PublicKey {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Adds the pk corresponding to `other` to the pk `self` in place
|
/// Adds the pk corresponding to `other` to the pk `self` in place
|
||||||
pub fn add_exp_assign(&mut self, other: &SecretKey) -> Result<(), Error> {
|
pub fn add_exp_assign(&mut self, secp: &Secp256k1, other: &SecretKey) -> Result<(), Error> {
|
||||||
init();
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::secp256k1_ec_pubkey_tweak_add(self.as_mut_ptr(),
|
if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx, self.as_mut_ptr(),
|
||||||
self.len() as ::libc::c_int,
|
self.len() as ::libc::c_int,
|
||||||
other.as_ptr()) != 1 {
|
other.as_ptr()) != 1 {
|
||||||
Err(Unknown)
|
Err(Unknown)
|
||||||
|
@ -459,23 +452,25 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn skey_from_slice() {
|
fn skey_from_slice() {
|
||||||
let sk = SecretKey::from_slice(&[1; 31]);
|
let s = Secp256k1::new().unwrap();
|
||||||
|
let sk = SecretKey::from_slice(&s, &[1; 31]);
|
||||||
assert_eq!(sk, Err(InvalidSecretKey));
|
assert_eq!(sk, Err(InvalidSecretKey));
|
||||||
|
|
||||||
let sk = SecretKey::from_slice(&[1; 32]);
|
let sk = SecretKey::from_slice(&s, &[1; 32]);
|
||||||
assert!(sk.is_ok());
|
assert!(sk.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pubkey_from_slice() {
|
fn pubkey_from_slice() {
|
||||||
assert_eq!(PublicKey::from_slice(&[]), Err(InvalidPublicKey));
|
let s = Secp256k1::new().unwrap();
|
||||||
assert_eq!(PublicKey::from_slice(&[1, 2, 3]), Err(InvalidPublicKey));
|
assert_eq!(PublicKey::from_slice(&s, &[]), Err(InvalidPublicKey));
|
||||||
|
assert_eq!(PublicKey::from_slice(&s, &[1, 2, 3]), Err(InvalidPublicKey));
|
||||||
|
|
||||||
let uncompressed = PublicKey::from_slice(&[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]);
|
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.is_ok());
|
||||||
assert!(!uncompressed.unwrap().is_compressed());
|
assert!(!uncompressed.unwrap().is_compressed());
|
||||||
|
|
||||||
let compressed = PublicKey::from_slice(&[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]);
|
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.is_ok());
|
||||||
assert!(compressed.unwrap().is_compressed());
|
assert!(compressed.unwrap().is_compressed());
|
||||||
}
|
}
|
||||||
|
@ -485,27 +480,30 @@ mod test {
|
||||||
let mut s = Secp256k1::new().unwrap();
|
let mut s = Secp256k1::new().unwrap();
|
||||||
|
|
||||||
let (sk1, pk1) = s.generate_keypair(true);
|
let (sk1, pk1) = s.generate_keypair(true);
|
||||||
assert_eq!(SecretKey::from_slice(&sk1[..]), Ok(sk1));
|
assert_eq!(SecretKey::from_slice(&s, &sk1[..]), Ok(sk1));
|
||||||
assert_eq!(PublicKey::from_slice(&pk1[..]), Ok(pk1));
|
assert_eq!(PublicKey::from_slice(&s, &pk1[..]), Ok(pk1));
|
||||||
|
|
||||||
let (sk2, pk2) = s.generate_keypair(false);
|
let (sk2, pk2) = s.generate_keypair(false);
|
||||||
assert_eq!(SecretKey::from_slice(&sk2[..]), Ok(sk2));
|
assert_eq!(SecretKey::from_slice(&s, &sk2[..]), Ok(sk2));
|
||||||
assert_eq!(PublicKey::from_slice(&pk2[..]), Ok(pk2));
|
assert_eq!(PublicKey::from_slice(&s, &pk2[..]), Ok(pk2));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invalid_secret_key() {
|
fn invalid_secret_key() {
|
||||||
|
let s = Secp256k1::new().unwrap();
|
||||||
// Zero
|
// Zero
|
||||||
assert_eq!(SecretKey::from_slice(&[0; 32]), Err(InvalidSecretKey));
|
assert_eq!(SecretKey::from_slice(&s, &[0; 32]), Err(InvalidSecretKey));
|
||||||
// -1
|
// -1
|
||||||
assert_eq!(SecretKey::from_slice(&[0xff; 32]), Err(InvalidSecretKey));
|
assert_eq!(SecretKey::from_slice(&s, &[0xff; 32]), Err(InvalidSecretKey));
|
||||||
// Top of range
|
// Top of range
|
||||||
assert!(SecretKey::from_slice(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
assert!(SecretKey::from_slice(&s,
|
||||||
|
&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
|
||||||
0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
|
0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
|
||||||
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x40]).is_ok());
|
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x40]).is_ok());
|
||||||
// One past top of range
|
// One past top of range
|
||||||
assert!(SecretKey::from_slice(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
assert!(SecretKey::from_slice(&s,
|
||||||
|
&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
|
||||||
0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
|
0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
|
||||||
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41]).is_err());
|
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41]).is_err());
|
||||||
|
@ -578,15 +576,15 @@ mod test {
|
||||||
let (mut sk1, mut pk1) = s.generate_keypair(true);
|
let (mut sk1, mut pk1) = s.generate_keypair(true);
|
||||||
let (mut sk2, mut pk2) = s.generate_keypair(true);
|
let (mut sk2, mut pk2) = s.generate_keypair(true);
|
||||||
|
|
||||||
assert_eq!(PublicKey::from_secret_key(&sk1, true), pk1);
|
assert_eq!(PublicKey::from_secret_key(&s, &sk1, true), pk1);
|
||||||
assert!(sk1.add_assign(&sk2).is_ok());
|
assert!(sk1.add_assign(&s, &sk2).is_ok());
|
||||||
assert!(pk1.add_exp_assign(&sk2).is_ok());
|
assert!(pk1.add_exp_assign(&s, &sk2).is_ok());
|
||||||
assert_eq!(PublicKey::from_secret_key(&sk1, true), pk1);
|
assert_eq!(PublicKey::from_secret_key(&s, &sk1, true), pk1);
|
||||||
|
|
||||||
assert_eq!(PublicKey::from_secret_key(&sk2, true), pk2);
|
assert_eq!(PublicKey::from_secret_key(&s, &sk2, true), pk2);
|
||||||
assert!(sk2.add_assign(&sk1).is_ok());
|
assert!(sk2.add_assign(&s, &sk1).is_ok());
|
||||||
assert!(pk2.add_exp_assign(&sk1).is_ok());
|
assert!(pk2.add_exp_assign(&s, &sk1).is_ok());
|
||||||
assert_eq!(PublicKey::from_secret_key(&sk2, true), pk2);
|
assert_eq!(PublicKey::from_secret_key(&s, &sk2, true), pk2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
64
src/lib.rs
64
src/lib.rs
|
@ -45,7 +45,6 @@ extern crate rand;
|
||||||
|
|
||||||
use std::intrinsics::copy_nonoverlapping;
|
use std::intrinsics::copy_nonoverlapping;
|
||||||
use std::{fmt, io, ops, ptr};
|
use std::{fmt, io, ops, ptr};
|
||||||
use std::sync::{Once, ONCE_INIT};
|
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
use rand::{OsRng, Rng, SeedableRng};
|
use rand::{OsRng, Rng, SeedableRng};
|
||||||
|
|
||||||
|
@ -212,35 +211,29 @@ impl fmt::Display for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut Secp256k1_init: Once = ONCE_INIT;
|
|
||||||
|
|
||||||
/// The secp256k1 engine, used to execute all signature operations
|
/// The secp256k1 engine, used to execute all signature operations
|
||||||
pub struct Secp256k1 {
|
pub struct Secp256k1 {
|
||||||
|
ctx: ffi::Context,
|
||||||
rng: Fortuna
|
rng: Fortuna
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Does one-time initialization of the secp256k1 engine. Can be called
|
impl Drop for Secp256k1 {
|
||||||
/// multiple times, and is called by the `Secp256k1` constructor. This
|
fn drop(&mut self) {
|
||||||
/// only needs to be called directly if you are using the library without
|
unsafe { ffi::secp256k1_context_destroy(self.ctx); }
|
||||||
/// a `Secp256k1` object, e.g. batch key generation through
|
|
||||||
/// `key::PublicKey::from_secret_key`.
|
|
||||||
pub fn init() {
|
|
||||||
unsafe {
|
|
||||||
Secp256k1_init.call_once(|| {
|
|
||||||
ffi::secp256k1_start(ffi::SECP256K1_START_VERIFY |
|
|
||||||
ffi::SECP256K1_START_SIGN);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Secp256k1 {
|
impl Secp256k1 {
|
||||||
/// Constructs a new secp256k1 engine.
|
/// Constructs a new secp256k1 engine.
|
||||||
pub fn new() -> io::Result<Secp256k1> {
|
pub fn new() -> io::Result<Secp256k1> {
|
||||||
init();
|
let ctx = unsafe {
|
||||||
|
ffi::secp256k1_context_create(ffi::SECP256K1_START_VERIFY |
|
||||||
|
ffi::SECP256K1_START_SIGN)
|
||||||
|
};
|
||||||
let mut osrng = try!(OsRng::new());
|
let mut osrng = try!(OsRng::new());
|
||||||
let mut seed = [0; 2048];
|
let mut seed = [0; 2048];
|
||||||
osrng.fill_bytes(&mut seed);
|
osrng.fill_bytes(&mut seed);
|
||||||
Ok(Secp256k1 { rng: SeedableRng::from_seed(&seed[..]) })
|
Ok(Secp256k1 { ctx: ctx, rng: SeedableRng::from_seed(&seed[..]) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a random keypair. Convenience function for `key::SecretKey::new`
|
/// Generates a random keypair. Convenience function for `key::SecretKey::new`
|
||||||
|
@ -249,8 +242,8 @@ impl Secp256k1 {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn generate_keypair(&mut self, compressed: bool)
|
pub fn generate_keypair(&mut self, compressed: bool)
|
||||||
-> (key::SecretKey, key::PublicKey) {
|
-> (key::SecretKey, key::PublicKey) {
|
||||||
let sk = key::SecretKey::new(&mut self.rng);
|
let sk = key::SecretKey::new(self);
|
||||||
let pk = key::PublicKey::from_secret_key(&sk, compressed);
|
let pk = key::PublicKey::from_secret_key(self, &sk, compressed);
|
||||||
(sk, pk)
|
(sk, pk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,7 +253,7 @@ impl Secp256k1 {
|
||||||
let mut sig = [0; constants::MAX_SIGNATURE_SIZE];
|
let mut sig = [0; constants::MAX_SIGNATURE_SIZE];
|
||||||
let mut len = constants::MAX_SIGNATURE_SIZE as c_int;
|
let mut len = constants::MAX_SIGNATURE_SIZE as c_int;
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::secp256k1_ecdsa_sign(msg.as_ptr(), (&mut sig).as_mut_ptr(),
|
if ffi::secp256k1_ecdsa_sign(self.ctx, msg.as_ptr(), sig.as_mut_ptr(),
|
||||||
&mut len, sk.as_ptr(),
|
&mut len, sk.as_ptr(),
|
||||||
ffi::secp256k1_nonce_function_rfc6979,
|
ffi::secp256k1_nonce_function_rfc6979,
|
||||||
ptr::null()) != 1 {
|
ptr::null()) != 1 {
|
||||||
|
@ -278,7 +271,7 @@ impl Secp256k1 {
|
||||||
let mut sig = [0; constants::MAX_SIGNATURE_SIZE];
|
let mut sig = [0; constants::MAX_SIGNATURE_SIZE];
|
||||||
let mut recid = 0;
|
let mut recid = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::secp256k1_ecdsa_sign_compact(msg.as_ptr(),
|
if ffi::secp256k1_ecdsa_sign_compact(self.ctx, msg.as_ptr(),
|
||||||
sig.as_mut_ptr(), sk.as_ptr(),
|
sig.as_mut_ptr(), sk.as_ptr(),
|
||||||
ffi::secp256k1_nonce_function_default,
|
ffi::secp256k1_nonce_function_default,
|
||||||
ptr::null(), &mut recid) != 1 {
|
ptr::null(), &mut recid) != 1 {
|
||||||
|
@ -298,7 +291,7 @@ impl Secp256k1 {
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut len = 0;
|
let mut len = 0;
|
||||||
if ffi::secp256k1_ecdsa_recover_compact(msg.as_ptr(),
|
if ffi::secp256k1_ecdsa_recover_compact(self.ctx, msg.as_ptr(),
|
||||||
sig.as_ptr(), pk.as_mut_ptr(), &mut len,
|
sig.as_ptr(), pk.as_mut_ptr(), &mut len,
|
||||||
if compressed {1} else {0},
|
if compressed {1} else {0},
|
||||||
recid) != 1 {
|
recid) != 1 {
|
||||||
|
@ -311,21 +304,17 @@ impl Secp256k1 {
|
||||||
|
|
||||||
/// Checks that `sig` is a valid ECDSA signature for `msg` using the public
|
/// Checks that `sig` is a valid ECDSA signature for `msg` using the public
|
||||||
/// key `pubkey`. Returns `Ok(true)` on success. Note that this function cannot
|
/// key `pubkey`. Returns `Ok(true)` on success. Note that this function cannot
|
||||||
/// be used for Bitcoin consensus checking since there are transactions out
|
/// be used for Bitcoin consensus checking since there may exist signatures
|
||||||
/// there with zero-padded signatures that don't fit in the `Signature` type.
|
/// which OpenSSL would verify but not libsecp256k1, or vice-versa.
|
||||||
/// Use `verify_raw` instead.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn verify(msg: &Message, sig: &Signature, pk: &key::PublicKey) -> Result<(), Error> {
|
pub fn verify(&self, msg: &Message, sig: &Signature, pk: &key::PublicKey) -> Result<(), Error> {
|
||||||
Secp256k1::verify_raw(msg, &sig[..], pk)
|
self.verify_raw(msg, &sig[..], pk)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks that `sig` is a valid ECDSA signature for `msg` using the public
|
/// Verifies a signature described as a slice of bytes rather than opaque `Signature`
|
||||||
/// key `pubkey`. Returns `Ok(true)` on success.
|
pub fn verify_raw(&self, msg: &Message, sig: &[u8], pk: &key::PublicKey) -> Result<(), Error> {
|
||||||
#[inline]
|
|
||||||
pub fn verify_raw(msg: &Message, sig: &[u8], pk: &key::PublicKey) -> Result<(), Error> {
|
|
||||||
init(); // This is a static function, so we have to init
|
|
||||||
let res = unsafe {
|
let res = unsafe {
|
||||||
ffi::secp256k1_ecdsa_verify(msg.as_ptr(),
|
ffi::secp256k1_ecdsa_verify(self.ctx, msg.as_ptr(),
|
||||||
sig.as_ptr(), sig.len() as c_int,
|
sig.as_ptr(), sig.len() as c_int,
|
||||||
pk.as_ptr(), pk.len() as c_int)
|
pk.as_ptr(), pk.len() as c_int)
|
||||||
};
|
};
|
||||||
|
@ -354,13 +343,14 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invalid_pubkey() {
|
fn invalid_pubkey() {
|
||||||
|
let s = Secp256k1::new().unwrap();
|
||||||
let sig = Signature::from_slice(&[0; 72]).unwrap();
|
let sig = Signature::from_slice(&[0; 72]).unwrap();
|
||||||
let pk = PublicKey::new(true);
|
let pk = PublicKey::new(true);
|
||||||
let mut msg = [0u8; 32];
|
let mut msg = [0u8; 32];
|
||||||
thread_rng().fill_bytes(&mut msg);
|
thread_rng().fill_bytes(&mut msg);
|
||||||
let msg = Message::from_slice(&msg).unwrap();
|
let msg = Message::from_slice(&msg).unwrap();
|
||||||
|
|
||||||
assert_eq!(Secp256k1::verify(&msg, &sig, &pk), Err(InvalidPublicKey));
|
assert_eq!(s.verify(&msg, &sig, &pk), Err(InvalidPublicKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -374,7 +364,7 @@ mod tests {
|
||||||
thread_rng().fill_bytes(&mut msg);
|
thread_rng().fill_bytes(&mut msg);
|
||||||
let msg = Message::from_slice(&msg).unwrap();
|
let msg = Message::from_slice(&msg).unwrap();
|
||||||
|
|
||||||
assert_eq!(Secp256k1::verify(&msg, &sig, &pk), Err(InvalidSignature));
|
assert_eq!(s.verify(&msg, &sig, &pk), Err(InvalidSignature));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -387,7 +377,7 @@ mod tests {
|
||||||
thread_rng().fill_bytes(&mut msg);
|
thread_rng().fill_bytes(&mut msg);
|
||||||
let msg = Message::from_slice(&msg).unwrap();
|
let msg = Message::from_slice(&msg).unwrap();
|
||||||
|
|
||||||
assert_eq!(Secp256k1::verify(&msg, &sig, &pk), Err(InvalidSignature));
|
assert_eq!(s.verify(&msg, &sig, &pk), Err(InvalidSignature));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -415,7 +405,7 @@ mod tests {
|
||||||
|
|
||||||
let sig = s.sign(&msg, &sk).unwrap();
|
let sig = s.sign(&msg, &sk).unwrap();
|
||||||
|
|
||||||
assert_eq!(Secp256k1::verify(&msg, &sig, &pk), Ok(()));
|
assert_eq!(s.verify(&msg, &sig, &pk), Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -433,7 +423,7 @@ mod tests {
|
||||||
let mut msg = [0u8; 32];
|
let mut msg = [0u8; 32];
|
||||||
thread_rng().fill_bytes(&mut msg);
|
thread_rng().fill_bytes(&mut msg);
|
||||||
let msg = Message::from_slice(&msg).unwrap();
|
let msg = Message::from_slice(&msg).unwrap();
|
||||||
assert_eq!(Secp256k1::verify(&msg, &sig, &pk), Err(IncorrectSignature));
|
assert_eq!(s.verify(&msg, &sig, &pk), Err(IncorrectSignature));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in New Issue