Update secp256k1zlp to serde 1.0

This commit is contained in:
Ignotus Peverell 2017-05-28 20:20:56 -07:00
parent 1ae2e905d8
commit da41120293
No known key found for this signature in database
GPG key ID: 99CD25F39F8F8211
8 changed files with 2067 additions and 1999 deletions

View file

@ -29,6 +29,5 @@ clippy = {version = "0.0", optional = true}
rand = "0.3" rand = "0.3"
libc = "0.1" libc = "0.1"
rustc-serialize = "0.3" rustc-serialize = "0.3"
serde = "0.6" serde = "~1.0.8"
serde_json = "0.6" serde_json = "~1.0.2"

View file

@ -26,106 +26,106 @@ use ffi;
pub struct SharedSecret(ffi::SharedSecret); pub struct SharedSecret(ffi::SharedSecret);
impl SharedSecret { impl SharedSecret {
/// Creates a new shared secret from a pubkey and secret key /// Creates a new shared secret from a pubkey and secret key
#[inline] #[inline]
pub fn new(secp: &Secp256k1, point: &PublicKey, scalar: &SecretKey) -> SharedSecret { pub fn new(secp: &Secp256k1, point: &PublicKey, scalar: &SecretKey) -> SharedSecret {
unsafe { unsafe {
let mut ss = ffi::SharedSecret::blank(); let mut ss = ffi::SharedSecret::blank();
let res = ffi::secp256k1_ecdh(secp.ctx, &mut ss, point.as_ptr(), scalar.as_ptr()); let res = ffi::secp256k1_ecdh(secp.ctx, &mut ss, point.as_ptr(), scalar.as_ptr());
debug_assert_eq!(res, 1); debug_assert_eq!(res, 1);
SharedSecret(ss) SharedSecret(ss)
} }
} }
/// Obtains a raw pointer suitable for use with FFI functions /// Obtains a raw pointer suitable for use with FFI functions
#[inline] #[inline]
pub fn as_ptr(&self) -> *const ffi::SharedSecret { pub fn as_ptr(&self) -> *const ffi::SharedSecret {
&self.0 as *const _ &self.0 as *const _
} }
} }
/// Creates a new shared secret from a FFI shared secret /// Creates a new shared secret from a FFI shared secret
impl From<ffi::SharedSecret> for SharedSecret { impl From<ffi::SharedSecret> for SharedSecret {
#[inline] #[inline]
fn from(ss: ffi::SharedSecret) -> SharedSecret { fn from(ss: ffi::SharedSecret) -> SharedSecret {
SharedSecret(ss) SharedSecret(ss)
} }
} }
impl ops::Index<usize> for SharedSecret { impl ops::Index<usize> for SharedSecret {
type Output = u8; type Output = u8;
#[inline] #[inline]
fn index(&self, index: usize) -> &u8 { fn index(&self, index: usize) -> &u8 {
&self.0[index] &self.0[index]
} }
} }
impl ops::Index<ops::Range<usize>> for SharedSecret { impl ops::Index<ops::Range<usize>> for SharedSecret {
type Output = [u8]; type Output = [u8];
#[inline] #[inline]
fn index(&self, index: ops::Range<usize>) -> &[u8] { fn index(&self, index: ops::Range<usize>) -> &[u8] {
&self.0[index] &self.0[index]
} }
} }
impl ops::Index<ops::RangeFrom<usize>> for SharedSecret { impl ops::Index<ops::RangeFrom<usize>> for SharedSecret {
type Output = [u8]; type Output = [u8];
#[inline] #[inline]
fn index(&self, index: ops::RangeFrom<usize>) -> &[u8] { fn index(&self, index: ops::RangeFrom<usize>) -> &[u8] {
&self.0[index.start..] &self.0[index.start..]
} }
} }
impl ops::Index<ops::RangeFull> for SharedSecret { impl ops::Index<ops::RangeFull> for SharedSecret {
type Output = [u8]; type Output = [u8];
#[inline] #[inline]
fn index(&self, _: ops::RangeFull) -> &[u8] { fn index(&self, _: ops::RangeFull) -> &[u8] {
&self.0[..] &self.0[..]
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use rand::thread_rng; use rand::thread_rng;
use super::SharedSecret; use super::SharedSecret;
use super::super::Secp256k1; use super::super::Secp256k1;
#[test] #[test]
fn ecdh() { fn ecdh() {
let s = Secp256k1::with_caps(::ContextFlag::SignOnly); let s = Secp256k1::with_caps(::ContextFlag::SignOnly);
let (sk1, pk1) = s.generate_keypair(&mut thread_rng()).unwrap(); let (sk1, pk1) = s.generate_keypair(&mut thread_rng()).unwrap();
let (sk2, pk2) = s.generate_keypair(&mut thread_rng()).unwrap(); let (sk2, pk2) = s.generate_keypair(&mut thread_rng()).unwrap();
let sec1 = SharedSecret::new(&s, &pk1, &sk2); let sec1 = SharedSecret::new(&s, &pk1, &sk2);
let sec2 = SharedSecret::new(&s, &pk2, &sk1); let sec2 = SharedSecret::new(&s, &pk2, &sk1);
let sec_odd = SharedSecret::new(&s, &pk1, &sk1); let sec_odd = SharedSecret::new(&s, &pk1, &sk1);
assert_eq!(sec1, sec2); assert_eq!(sec1, sec2);
assert!(sec_odd != sec2); assert!(sec_odd != sec2);
} }
} }
#[cfg(all(test, feature = "unstable"))] #[cfg(all(test, feature = "unstable"))]
mod benches { mod benches {
use rand::thread_rng; use rand::thread_rng;
use test::{Bencher, black_box}; use test::{Bencher, black_box};
use super::SharedSecret; use super::SharedSecret;
use super::super::Secp256k1; use super::super::Secp256k1;
#[bench] #[bench]
pub fn bench_ecdh(bh: &mut Bencher) { pub fn bench_ecdh(bh: &mut Bencher) {
let s = Secp256k1::with_caps(::ContextFlag::SignOnly); let s = Secp256k1::with_caps(::ContextFlag::SignOnly);
let (sk, pk) = s.generate_keypair(&mut thread_rng()).unwrap(); let (sk, pk) = s.generate_keypair(&mut thread_rng()).unwrap();
let s = Secp256k1::new(); let s = Secp256k1::new();
bh.iter(|| { bh.iter(|| {
let res = SharedSecret::new(&s, &pk, &sk); let res = SharedSecret::new(&s, &pk, &sk);
black_box(res); black_box(res);
}); });
} }
} }

View file

@ -61,14 +61,14 @@ impl_array_newtype!(PublicKey, c_uchar, 64);
impl_raw_debug!(PublicKey); impl_raw_debug!(PublicKey);
impl PublicKey { impl PublicKey {
/// Create a new (zeroed) public key usable for the FFI interface /// Create a new (zeroed) public key usable for the FFI interface
pub fn new() -> PublicKey { pub fn new() -> PublicKey {
PublicKey([0; 64]) PublicKey([0; 64])
} }
/// Create a new (uninitialized) public key usable for the FFI interface /// Create a new (uninitialized) public key usable for the FFI interface
pub unsafe fn blank() -> PublicKey { pub unsafe fn blank() -> PublicKey {
mem::uninitialized() mem::uninitialized()
} }
} }
/// Library-internal representation of a Secp256k1 signature /// Library-internal representation of a Secp256k1 signature
@ -84,25 +84,25 @@ impl_array_newtype!(RecoverableSignature, c_uchar, 65);
impl_raw_debug!(RecoverableSignature); impl_raw_debug!(RecoverableSignature);
impl Signature { impl Signature {
/// Create a new (zeroed) signature usable for the FFI interface /// Create a new (zeroed) signature usable for the FFI interface
pub fn new() -> Signature { pub fn new() -> Signature {
Signature([0; 64]) Signature([0; 64])
} }
/// Create a new (uninitialized) signature usable for the FFI interface /// Create a new (uninitialized) signature usable for the FFI interface
pub unsafe fn blank() -> Signature { pub unsafe fn blank() -> Signature {
mem::uninitialized() mem::uninitialized()
} }
} }
impl RecoverableSignature { impl RecoverableSignature {
/// Create a new (zeroed) signature usable for the FFI interface /// Create a new (zeroed) signature usable for the FFI interface
pub fn new() -> RecoverableSignature { pub fn new() -> RecoverableSignature {
RecoverableSignature([0; 65]) RecoverableSignature([0; 65])
} }
/// Create a new (uninitialized) signature usable for the FFI interface /// Create a new (uninitialized) signature usable for the FFI interface
pub unsafe fn blank() -> RecoverableSignature { pub unsafe fn blank() -> RecoverableSignature {
mem::uninitialized() mem::uninitialized()
} }
} }
/// Library-internal representation of an ECDH shared secret /// Library-internal representation of an ECDH shared secret
@ -112,263 +112,263 @@ impl_array_newtype!(SharedSecret, c_uchar, 32);
impl_raw_debug!(SharedSecret); impl_raw_debug!(SharedSecret);
impl SharedSecret { impl SharedSecret {
/// Create a new (zeroed) signature usable for the FFI interface /// Create a new (zeroed) signature usable for the FFI interface
pub fn new() -> SharedSecret { pub fn new() -> SharedSecret {
SharedSecret([0; 32]) SharedSecret([0; 32])
} }
/// Create a new (uninitialized) signature usable for the FFI interface /// Create a new (uninitialized) signature usable for the FFI interface
pub unsafe fn blank() -> SharedSecret { pub unsafe fn blank() -> SharedSecret {
mem::uninitialized() mem::uninitialized()
} }
} }
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;
// Contexts // Contexts
pub fn secp256k1_context_create(flags: c_uint) -> *mut Context; pub fn secp256k1_context_create(flags: c_uint) -> *mut Context;
pub fn secp256k1_context_clone(cx: *mut Context) -> *mut Context; pub fn secp256k1_context_clone(cx: *mut Context) -> *mut Context;
pub fn secp256k1_context_destroy(cx: *mut Context); pub fn secp256k1_context_destroy(cx: *mut Context);
pub fn secp256k1_context_randomize(cx: *mut Context, seed32: *const c_uchar) -> c_int; pub fn secp256k1_context_randomize(cx: *mut Context, seed32: *const c_uchar) -> c_int;
pub fn secp256k1_pedersen_context_initialize(ctx: *mut Context); pub fn secp256k1_pedersen_context_initialize(ctx: *mut Context);
pub fn secp256k1_rangeproof_context_initialize(ctx: *mut Context); pub fn secp256k1_rangeproof_context_initialize(ctx: *mut Context);
// TODO secp256k1_context_set_illegal_callback // TODO secp256k1_context_set_illegal_callback
// TODO secp256k1_context_set_error_callback // TODO secp256k1_context_set_error_callback
// (Actually, I don't really want these exposed; if either of these // (Actually, I don't really want these exposed; if either of these
// are ever triggered it indicates a bug in rust-secp256k1, since // are ever triggered it indicates a bug in rust-secp256k1, since
// one goal is to use Rust's type system to eliminate all possible // one goal is to use Rust's type system to eliminate all possible
// bad inputs.) // bad inputs.)
// Pubkeys // Pubkeys
pub fn secp256k1_ec_pubkey_parse(cx: *const Context, pub fn secp256k1_ec_pubkey_parse(cx: *const Context,
pk: *mut PublicKey, pk: *mut PublicKey,
input: *const c_uchar, input: *const c_uchar,
in_len: size_t) in_len: size_t)
-> c_int; -> c_int;
pub fn secp256k1_ec_pubkey_serialize(cx: *const Context, pub fn secp256k1_ec_pubkey_serialize(cx: *const Context,
output: *const c_uchar, output: *const c_uchar,
out_len: *mut size_t, out_len: *mut size_t,
pk: *const PublicKey, pk: *const PublicKey,
compressed: c_uint) compressed: c_uint)
-> c_int; -> c_int;
// Signatures // Signatures
pub fn secp256k1_ecdsa_signature_parse_der(cx: *const Context, pub fn secp256k1_ecdsa_signature_parse_der(cx: *const Context,
sig: *mut Signature, sig: *mut Signature,
input: *const c_uchar, input: *const c_uchar,
in_len: size_t) in_len: size_t)
-> c_int; -> c_int;
pub fn ecdsa_signature_parse_der_lax(cx: *const Context, pub fn ecdsa_signature_parse_der_lax(cx: *const Context,
sig: *mut Signature, sig: *mut Signature,
input: *const c_uchar, input: *const c_uchar,
in_len: size_t) in_len: size_t)
-> c_int; -> c_int;
pub fn secp256k1_ecdsa_signature_serialize_der(cx: *const Context, pub fn secp256k1_ecdsa_signature_serialize_der(cx: *const Context,
output: *const c_uchar, output: *const c_uchar,
out_len: *mut size_t, out_len: *mut size_t,
sig: *const Signature) sig: *const Signature)
-> c_int; -> c_int;
pub fn secp256k1_ecdsa_recoverable_signature_parse_compact(cx: *const Context, pub fn secp256k1_ecdsa_recoverable_signature_parse_compact(cx: *const Context,
sig: *mut RecoverableSignature, sig: *mut RecoverableSignature,
input64: *const c_uchar, input64: *const c_uchar,
recid: c_int) recid: c_int)
-> c_int; -> c_int;
pub fn secp256k1_ecdsa_recoverable_signature_serialize_compact(cx: *const Context, output64: *const c_uchar, pub fn secp256k1_ecdsa_recoverable_signature_serialize_compact(cx: *const Context, output64: *const c_uchar,
recid: *mut c_int, sig: *const RecoverableSignature) recid: *mut c_int, sig: *const RecoverableSignature)
-> c_int; -> c_int;
pub fn secp256k1_ecdsa_recoverable_signature_convert(cx: *const Context, pub fn secp256k1_ecdsa_recoverable_signature_convert(cx: *const Context,
sig: *mut Signature, sig: *mut Signature,
input: *const RecoverableSignature) input: *const RecoverableSignature)
-> c_int; -> c_int;
pub fn secp256k1_ecdsa_signature_normalize(cx: *const Context, pub fn secp256k1_ecdsa_signature_normalize(cx: *const Context,
out_sig: *mut Signature, out_sig: *mut Signature,
in_sig: *const Signature) in_sig: *const Signature)
-> c_int; -> c_int;
// ECDSA // ECDSA
pub fn secp256k1_ecdsa_verify(cx: *const Context, pub fn secp256k1_ecdsa_verify(cx: *const Context,
sig: *const Signature, sig: *const Signature,
msg32: *const c_uchar, msg32: *const c_uchar,
pk: *const PublicKey) pk: *const PublicKey)
-> c_int; -> c_int;
pub fn secp256k1_ecdsa_sign(cx: *const Context, pub fn secp256k1_ecdsa_sign(cx: *const Context,
sig: *mut Signature, sig: *mut Signature,
msg32: *const c_uchar, msg32: *const c_uchar,
sk: *const c_uchar, sk: *const c_uchar,
noncefn: NonceFn, noncefn: NonceFn,
noncedata: *const c_void) noncedata: *const c_void)
-> c_int; -> c_int;
pub fn secp256k1_ecdsa_sign_recoverable(cx: *const Context, pub fn secp256k1_ecdsa_sign_recoverable(cx: *const Context,
sig: *mut RecoverableSignature, sig: *mut RecoverableSignature,
msg32: *const c_uchar, msg32: *const c_uchar,
sk: *const c_uchar, sk: *const c_uchar,
noncefn: NonceFn, noncefn: NonceFn,
noncedata: *const c_void) noncedata: *const c_void)
-> c_int; -> c_int;
pub fn secp256k1_ecdsa_recover(cx: *const Context, pub fn secp256k1_ecdsa_recover(cx: *const Context,
pk: *mut PublicKey, pk: *mut PublicKey,
sig: *const RecoverableSignature, sig: *const RecoverableSignature,
msg32: *const c_uchar) msg32: *const c_uchar)
-> c_int; -> c_int;
// Schnorr // Schnorr
pub fn secp256k1_schnorr_sign(cx: *const Context, pub fn secp256k1_schnorr_sign(cx: *const Context,
sig64: *mut c_uchar, sig64: *mut c_uchar,
msg32: *const c_uchar, msg32: *const c_uchar,
sk: *const c_uchar, sk: *const c_uchar,
noncefn: NonceFn, noncefn: NonceFn,
noncedata: *const c_void) noncedata: *const c_void)
-> c_int; -> c_int;
pub fn secp256k1_schnorr_verify(cx: *const Context, pub fn secp256k1_schnorr_verify(cx: *const Context,
sig64: *const c_uchar, sig64: *const c_uchar,
msg32: *const c_uchar, msg32: *const c_uchar,
pk: *const PublicKey) pk: *const PublicKey)
-> c_int; -> c_int;
pub fn secp256k1_schnorr_recover(cx: *const Context, pub fn secp256k1_schnorr_recover(cx: *const Context,
pk: *mut PublicKey, pk: *mut PublicKey,
sig64: *const c_uchar, sig64: *const c_uchar,
msg32: *const c_uchar) msg32: *const c_uchar)
-> c_int; -> c_int;
// EC // EC
pub fn secp256k1_ec_seckey_verify(cx: *const Context, sk: *const c_uchar) -> c_int; pub fn secp256k1_ec_seckey_verify(cx: *const Context, sk: *const c_uchar) -> c_int;
pub fn secp256k1_ec_pubkey_create(cx: *const Context, pub fn secp256k1_ec_pubkey_create(cx: *const Context,
pk: *mut PublicKey, pk: *mut PublicKey,
sk: *const c_uchar) sk: *const c_uchar)
-> c_int; -> c_int;
// 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(cx: *const Context, pub fn secp256k1_ec_privkey_tweak_add(cx: *const Context,
sk: *mut c_uchar, sk: *mut c_uchar,
tweak: *const c_uchar) tweak: *const c_uchar)
-> c_int; -> c_int;
pub fn secp256k1_ec_pubkey_tweak_add(cx: *const Context, pub fn secp256k1_ec_pubkey_tweak_add(cx: *const Context,
pk: *mut PublicKey, pk: *mut PublicKey,
tweak: *const c_uchar) tweak: *const c_uchar)
-> c_int; -> c_int;
pub fn secp256k1_ec_privkey_tweak_mul(cx: *const Context, pub fn secp256k1_ec_privkey_tweak_mul(cx: *const Context,
sk: *mut c_uchar, sk: *mut c_uchar,
tweak: *const c_uchar) tweak: *const c_uchar)
-> c_int; -> c_int;
pub fn secp256k1_ec_pubkey_tweak_mul(cx: *const Context, pub fn secp256k1_ec_pubkey_tweak_mul(cx: *const Context,
pk: *mut PublicKey, pk: *mut PublicKey,
tweak: *const c_uchar) tweak: *const c_uchar)
-> c_int; -> c_int;
pub fn secp256k1_ec_pubkey_combine(cx: *const Context, pub fn secp256k1_ec_pubkey_combine(cx: *const Context,
out: *mut PublicKey, out: *mut PublicKey,
ins: *const *const PublicKey, ins: *const *const PublicKey,
n: c_int) n: c_int)
-> c_int; -> c_int;
pub fn secp256k1_ecdh(cx: *const Context, pub fn secp256k1_ecdh(cx: *const Context,
out: *mut SharedSecret, out: *mut SharedSecret,
point: *const PublicKey, point: *const PublicKey,
scalar: *const c_uchar) scalar: *const c_uchar)
-> c_int; -> c_int;
// Generates a pedersen commitment: *commit = blind * G + value * G2. // Generates a pedersen commitment: *commit = blind * G + value * G2.
// The commitment is 33 bytes, the blinding factor is 32 bytes. // The commitment is 33 bytes, the blinding factor is 32 bytes.
pub fn secp256k1_pedersen_commit(ctx: *const Context, pub fn secp256k1_pedersen_commit(ctx: *const Context,
commit: *mut c_uchar, commit: *mut c_uchar,
blind: *const c_uchar, blind: *const c_uchar,
value: uint64_t) value: uint64_t)
-> c_int; -> c_int;
// Takes a list of n pointers to 32 byte blinding values, the first negs // Takes a list of n pointers to 32 byte blinding values, the first negs
// of which are treated with positive sign and the rest negative, then // of which are treated with positive sign and the rest negative, then
// calculates an additional blinding value that adds to zero. // calculates an additional blinding value that adds to zero.
pub fn secp256k1_pedersen_blind_sum(ctx: *const Context, pub fn secp256k1_pedersen_blind_sum(ctx: *const Context,
blind_out: *const c_uchar, blind_out: *const c_uchar,
blinds: *const *const c_uchar, blinds: *const *const c_uchar,
n: c_int, n: c_int,
npositive: c_int) npositive: c_int)
-> c_int; -> c_int;
// Takes two list of 33-byte commitments and sums the first set, subtracts // Takes two list of 33-byte commitments and sums the first set, subtracts
// the second and returns the resulting commitment. // the second and returns the resulting commitment.
pub fn secp256k1_pedersen_commit_sum(ctx: *const Context, pub fn secp256k1_pedersen_commit_sum(ctx: *const Context,
commit_out: *const c_uchar, commit_out: *const c_uchar,
commits: *const *const c_uchar, commits: *const *const c_uchar,
pcnt: c_int, pcnt: c_int,
ncommits: *const *const c_uchar, ncommits: *const *const c_uchar,
ncnt: c_int) ncnt: c_int)
-> c_int; -> c_int;
// Takes two list of 33-byte commitments and sums the first set and // Takes two list of 33-byte commitments and sums the first set and
// subtracts the second and verifies that they sum to excess. // subtracts the second and verifies that they sum to excess.
pub fn secp256k1_pedersen_verify_tally(ctx: *const Context, pub fn secp256k1_pedersen_verify_tally(ctx: *const Context,
commits: *const *const c_uchar, commits: *const *const c_uchar,
pcnt: c_int, pcnt: c_int,
ncommits: *const *const c_uchar, ncommits: *const *const c_uchar,
ncnt: c_int, ncnt: c_int,
excess: int64_t) excess: int64_t)
-> c_int; -> c_int;
pub fn secp256k1_rangeproof_info(ctx: *const Context, pub fn secp256k1_rangeproof_info(ctx: *const Context,
exp: *mut c_int, exp: *mut c_int,
mantissa: *mut c_int, mantissa: *mut c_int,
min_value: *mut uint64_t, min_value: *mut uint64_t,
max_value: *mut uint64_t, max_value: *mut uint64_t,
proof: *const c_uchar, proof: *const c_uchar,
plen: c_int) plen: c_int)
-> c_int; -> c_int;
pub fn secp256k1_rangeproof_rewind(ctx: *const Context, pub fn secp256k1_rangeproof_rewind(ctx: *const Context,
blind_out: *mut c_uchar, blind_out: *mut c_uchar,
value_out: *mut uint64_t, value_out: *mut uint64_t,
message_out: *mut c_uchar, message_out: *mut c_uchar,
outlen: *mut c_int, outlen: *mut c_int,
nonce: *const c_uchar, nonce: *const c_uchar,
min_value: *mut uint64_t, min_value: *mut uint64_t,
max_value: *mut uint64_t, max_value: *mut uint64_t,
commit: *const c_uchar, commit: *const c_uchar,
proof: *const c_uchar, proof: *const c_uchar,
plen: c_int) plen: c_int)
-> c_int; -> c_int;
pub fn secp256k1_rangeproof_verify(ctx: *const Context, pub fn secp256k1_rangeproof_verify(ctx: *const Context,
min_value: &mut uint64_t, min_value: &mut uint64_t,
max_value: &mut uint64_t, max_value: &mut uint64_t,
commit: *const c_uchar, commit: *const c_uchar,
proof: *const c_uchar, proof: *const c_uchar,
plen: c_int) plen: c_int)
-> c_int; -> c_int;
pub fn secp256k1_rangeproof_sign(ctx: *const Context, pub fn secp256k1_rangeproof_sign(ctx: *const Context,
proof: *mut c_uchar, proof: *mut c_uchar,
plen: *mut c_int, plen: *mut c_int,
min_value: uint64_t, min_value: uint64_t,
commit: *const c_uchar, commit: *const c_uchar,
blind: *const c_uchar, blind: *const c_uchar,
nonce: *const c_uchar, nonce: *const c_uchar,
exp: c_int, exp: c_int,
min_bits: c_int, min_bits: c_int,
value: uint64_t) value: uint64_t)
-> c_int; -> c_int;
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -20,25 +20,25 @@ macro_rules! impl_array_newtype {
impl $thing { impl $thing {
#[inline] #[inline]
/// Converts the object to a raw pointer for FFI interfacing /// Converts the object to a raw pointer for FFI interfacing
pub fn as_ptr(&self) -> *const $ty { pub fn as_ptr(&self) -> *const $ty {
let &$thing(ref dat) = self; let &$thing(ref dat) = self;
dat.as_ptr() dat.as_ptr()
} }
#[inline] #[inline]
/// Converts the object to a mutable raw pointer for FFI interfacing /// Converts the object to a mutable raw pointer for FFI interfacing
pub fn as_mut_ptr(&mut self) -> *mut $ty { pub fn as_mut_ptr(&mut self) -> *mut $ty {
let &mut $thing(ref mut dat) = self; let &mut $thing(ref mut dat) = self;
dat.as_mut_ptr() dat.as_mut_ptr()
} }
#[inline] #[inline]
/// Returns the length of the object as an array /// Returns the length of the object as an array
pub fn len(&self) -> usize { $len } pub fn len(&self) -> usize { $len }
#[inline] #[inline]
/// Returns whether the object as an array is empty /// Returns whether the object as an array is empty
pub fn is_empty(&self) -> bool { false } pub fn is_empty(&self) -> bool { false }
} }
@ -125,9 +125,9 @@ macro_rules! impl_array_newtype {
impl ::std::hash::Hash for $thing { impl ::std::hash::Hash for $thing {
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) { fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
state.write(&self.0) state.write(&self.0)
// for n in 0..self.len() { // for n in 0..self.len() {
// state.write_u8(self.0[n]); // state.write_u8(self.0[n]);
// } // }
} }
} }
@ -159,45 +159,48 @@ macro_rules! impl_array_newtype {
} }
} }
impl ::serde::Deserialize for $thing { impl<'de> ::serde::Deserialize<'de> for $thing {
fn deserialize<D>(d: &mut D) -> Result<$thing, D::Error> fn deserialize<D>(d: D) -> Result<$thing, D::Error>
where D: ::serde::Deserializer where D: ::serde::Deserializer<'de>
{ {
// We have to define the Visitor struct inside the function // We have to define the Visitor struct inside the function
// to make it local ... all we really need is that it's // to make it local ... all we really need is that it's
// local to the macro, but this works too :) // local to the macro, but this works too :)
struct Visitor { struct Visitor;
marker: ::std::marker::PhantomData<$thing>,
} impl<'di> ::serde::de::Visitor<'di> for Visitor {
impl ::serde::de::Visitor for Visitor {
type Value = $thing; type Value = $thing;
fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
formatter.write_str("an array of bytes")
}
#[inline] #[inline]
fn visit_seq<V>(&mut self, mut v: V) -> Result<$thing, V::Error> fn visit_seq<V>(self, mut v: V) -> Result<$thing, V::Error>
where V: ::serde::de::SeqVisitor where V: ::serde::de::SeqAccess<'di>
{ {
unsafe { unsafe {
use std::mem; use std::mem;
let mut ret: [$ty; $len] = mem::uninitialized(); let mut ret: [$ty; $len] = mem::uninitialized();
for i in 0..$len { for i in 0..$len {
ret[i] = match try!(v.visit()) { ret[i] = match try!(v.next_element()) {
Some(c) => c, Some(c) => c,
None => return Err(::serde::de::Error::end_of_stream()) None => return Err(::serde::de::Error::invalid_length(i, &self))
}; };
} }
try!(v.end());
Ok($thing(ret)) Ok($thing(ret))
} }
} }
} }
// Begin actual function // Begin actual function
d.visit(Visitor { marker: ::std::marker::PhantomData }) // d.visit(Visitor { marker: ::std::marker::PhantomData })
d.deserialize_seq(Visitor)
} }
} }
impl ::serde::Serialize for $thing { impl ::serde::Serialize for $thing {
fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where S: ::serde::Serializer where S: ::serde::Serializer
{ {
(&self.0[..]).serialize(s) (&self.0[..]).serialize(s)

View file

@ -15,6 +15,8 @@
//! # Pedersen commitments and related range proofs //! # Pedersen commitments and related range proofs
use std::cmp::min;
use std::fmt;
use std::mem; use std::mem;
use ContextFlag; use ContextFlag;
@ -26,6 +28,7 @@ use ffi;
use key; use key;
use key::SecretKey; use key::SecretKey;
use rand::{Rng, OsRng}; use rand::{Rng, OsRng};
use serde::{ser, de};
/// A Pedersen commitment /// A Pedersen commitment
pub struct Commitment(pub [u8; constants::PEDERSEN_COMMITMENT_SIZE]); pub struct Commitment(pub [u8; constants::PEDERSEN_COMMITMENT_SIZE]);
@ -34,327 +37,392 @@ impl_pretty_debug!(Commitment);
impl Commitment { impl Commitment {
/// Uninitialized commitment, use with caution /// Builds a Hash from a byte vector. If the vector is too short, it will be
unsafe fn blank() -> Commitment { /// completed by zeroes. If it's too long, it will be truncated.
mem::uninitialized() pub fn from_vec(v: Vec<u8>) -> Commitment {
} let mut h = [0; constants::PEDERSEN_COMMITMENT_SIZE];
/// Converts a commitment to a public key for i in 0..min(v.len(), constants::PEDERSEN_COMMITMENT_SIZE) {
pub fn to_pubkey(&self, secp: &Secp256k1) -> Result<key::PublicKey, Error> { h[i] = v[i];
key::PublicKey::from_slice(secp, &self.0)
} }
Commitment(h)
}
/// Uninitialized commitment, use with caution
unsafe fn blank() -> Commitment {
mem::uninitialized()
}
/// Converts a commitment to a public key
pub fn to_pubkey(&self, secp: &Secp256k1) -> Result<key::PublicKey, Error> {
key::PublicKey::from_slice(secp, &self.0)
}
} }
/// A range proof. Typically much larger in memory that the above (~5k). /// A range proof. Typically much larger in memory that the above (~5k).
#[derive(Copy)] #[derive(Copy)]
pub struct RangeProof { pub struct RangeProof {
/// The proof itself, at most 5134 bytes long /// The proof itself, at most 5134 bytes long
pub proof: [u8; constants::MAX_PROOF_SIZE], pub proof: [u8; constants::MAX_PROOF_SIZE],
/// The length of the proof /// The length of the proof
pub plen: usize, pub plen: usize,
} }
impl PartialEq for RangeProof { impl PartialEq for RangeProof {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.proof.as_ref() == other.proof.as_ref() self.proof.as_ref() == other.proof.as_ref()
} }
} }
impl Clone for RangeProof { impl Clone for RangeProof {
#[inline] #[inline]
fn clone(&self) -> RangeProof { fn clone(&self) -> RangeProof {
unsafe { unsafe {
use std::intrinsics::copy_nonoverlapping; use std::intrinsics::copy_nonoverlapping;
use std::mem; use std::mem;
let mut ret: [u8; constants::MAX_PROOF_SIZE] = mem::uninitialized(); let mut ret: [u8; constants::MAX_PROOF_SIZE] = mem::uninitialized();
copy_nonoverlapping(self.proof.as_ptr(), copy_nonoverlapping(self.proof.as_ptr(),
ret.as_mut_ptr(), ret.as_mut_ptr(),
mem::size_of::<RangeProof>()); mem::size_of::<RangeProof>());
RangeProof { RangeProof {
proof: ret, proof: ret,
plen: self.plen, plen: self.plen,
} }
} }
} }
}
impl ser::Serialize for RangeProof {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where S: ser::Serializer
{
(&self.proof[..self.plen]).serialize(s)
}
}
struct Visitor;
impl<'di> de::Visitor<'di> for Visitor {
type Value = RangeProof;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an array of bytes")
}
#[inline]
fn visit_seq<V>(self, mut v: V) -> Result<RangeProof, V::Error>
where V: de::SeqAccess<'di>
{
unsafe {
use std::mem;
let mut ret: [u8; constants::MAX_PROOF_SIZE] = mem::uninitialized();
let mut i = 0;
while let Some(val) = v.next_element()? {
ret[i] = val;
i += 1;
}
Ok(RangeProof {
proof: ret,
plen: i,
})
}
}
}
impl<'de> de::Deserialize<'de> for RangeProof {
fn deserialize<D>(d: D) -> Result<RangeProof, D::Error>
where D: de::Deserializer<'de>
{
// Begin actual function
d.deserialize_seq(Visitor)
}
} }
impl AsRef<[u8]> for RangeProof { impl AsRef<[u8]> for RangeProof {
fn as_ref(&self) -> &[u8] { fn as_ref(&self) -> &[u8] {
&self.proof[..self.plen as usize] &self.proof[..self.plen as usize]
} }
} }
impl RangeProof { impl RangeProof {
/// The range proof as a byte slice. pub fn zero() -> RangeProof {
pub fn bytes(&self) -> &[u8] { RangeProof {
&self.proof[..self.plen as usize] proof: [0; constants::MAX_PROOF_SIZE],
} plen: 0,
/// Length of the range proof in bytes. }
pub fn len(&self) -> usize { }
self.plen /// The range proof as a byte slice.
} pub fn bytes(&self) -> &[u8] {
&self.proof[..self.plen as usize]
}
/// Length of the range proof in bytes.
pub fn len(&self) -> usize {
self.plen
}
} }
/// The range that was proven /// The range that was proven
pub struct ProofRange { pub struct ProofRange {
/// Min value that was proven /// Min value that was proven
pub min: u64, pub min: u64,
/// Max value that was proven /// Max value that was proven
pub max: u64, pub max: u64,
} }
/// Information about a valid proof after rewinding it. /// Information about a valid proof after rewinding it.
pub struct ProofInfo { pub struct ProofInfo {
/// Whether the proof is valid or not /// Whether the proof is valid or not
pub success: bool, pub success: bool,
/// Value that was used by the commitment /// Value that was used by the commitment
pub value: u64, pub value: u64,
/// Message embedded in the proof /// Message embedded in the proof
pub message: [u8; constants::PROOF_MSG_SIZE], pub message: [u8; constants::PROOF_MSG_SIZE],
/// Length of the embedded message /// Length of the embedded message
pub mlen: i32, pub mlen: i32,
/// Min value that was proven /// Min value that was proven
pub min: u64, pub min: u64,
/// Max value that was proven /// Max value that was proven
pub max: u64, pub max: u64,
/// Exponent used by the proof /// Exponent used by the proof
pub exp: i32, pub exp: i32,
/// Mantissa used by the proof /// Mantissa used by the proof
pub mantissa: i32, pub mantissa: i32,
} }
impl ::std::fmt::Debug for RangeProof { impl ::std::fmt::Debug for RangeProof {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
try!(write!(f, "{}(", stringify!(RangeProof))); try!(write!(f, "{}(", stringify!(RangeProof)));
for i in self.proof[..self.plen].iter().cloned() { for i in self.proof[..self.plen].iter().cloned() {
try!(write!(f, "{:02x}", i)); try!(write!(f, "{:02x}", i));
} }
write!(f, ")[{}]", self.plen) write!(f, ")[{}]", self.plen)
} }
} }
impl Secp256k1 { impl Secp256k1 {
/// Creates a pedersen commitment from a value and a blinding factor /// Creates a pedersen commitment from a value and a blinding factor
pub fn commit(&self, value: u64, blind: SecretKey) -> Result<Commitment, Error> { pub fn commit(&self, value: u64, blind: SecretKey) -> Result<Commitment, Error> {
if self.caps != ContextFlag::Commit { if self.caps != ContextFlag::Commit {
return Err(Error::IncapableContext); return Err(Error::IncapableContext);
} }
let mut commit = [0; 33]; let mut commit = [0; 33];
unsafe { unsafe {
ffi::secp256k1_pedersen_commit(self.ctx, commit.as_mut_ptr(), blind.as_ptr(), value) ffi::secp256k1_pedersen_commit(self.ctx, commit.as_mut_ptr(), blind.as_ptr(), value)
}; };
Ok(Commitment(commit)) Ok(Commitment(commit))
} }
/// Convenience method to Create a pedersen commitment only from a value, with a zero blinding factor /// Convenience method to Create a pedersen commitment only from a value,
pub fn commit_value(&self, value: u64) -> Result<Commitment, Error> { /// with a zero blinding factor
pub fn commit_value(&self, value: u64) -> Result<Commitment, Error> {
if self.caps != ContextFlag::Commit { if self.caps != ContextFlag::Commit {
return Err(Error::IncapableContext); return Err(Error::IncapableContext);
} }
let mut commit = [0; 33]; let mut commit = [0; 33];
let zblind = [0; 32]; let zblind = [0; 32];
unsafe { unsafe {
ffi::secp256k1_pedersen_commit(self.ctx, commit.as_mut_ptr(), zblind.as_ptr(), value) ffi::secp256k1_pedersen_commit(self.ctx, commit.as_mut_ptr(), zblind.as_ptr(), value)
}; };
Ok(Commitment(commit)) Ok(Commitment(commit))
} }
/// Taking vectors of positive and negative commitments as well as an /// Taking vectors of positive and negative commitments as well as an
/// expected excess, verifies that it all sums to zero. /// expected excess, verifies that it all sums to zero.
pub fn verify_commit_sum(&self, pub fn verify_commit_sum(&self,
positive: Vec<Commitment>, positive: Vec<Commitment>,
negative: Vec<Commitment>, negative: Vec<Commitment>,
excess: i64) excess: i64)
-> bool { -> bool {
let pos = map_vec!(positive, |p| p.0.as_ptr()); let pos = map_vec!(positive, |p| p.0.as_ptr());
let neg = map_vec!(negative, |n| n.0.as_ptr()); let neg = map_vec!(negative, |n| n.0.as_ptr());
unsafe { unsafe {
ffi::secp256k1_pedersen_verify_tally(self.ctx, ffi::secp256k1_pedersen_verify_tally(self.ctx,
pos.as_ptr(), pos.as_ptr(),
pos.len() as i32, pos.len() as i32,
neg.as_ptr(), neg.as_ptr(),
neg.len() as i32, neg.len() as i32,
excess) == 1 excess) == 1
} }
} }
/// Computes the sum of multiple positive and negative pedersen commitments. /// Computes the sum of multiple positive and negative pedersen commitments.
pub fn commit_sum(&self, pub fn commit_sum(&self,
positive: Vec<Commitment>, positive: Vec<Commitment>,
negative: Vec<Commitment>) negative: Vec<Commitment>)
-> Result<Commitment, Error> { -> Result<Commitment, Error> {
let pos = map_vec!(positive, |p| p.0.as_ptr()); let pos = map_vec!(positive, |p| p.0.as_ptr());
let neg = map_vec!(negative, |n| n.0.as_ptr()); let neg = map_vec!(negative, |n| n.0.as_ptr());
let mut ret = unsafe { Commitment::blank() }; let mut ret = unsafe { Commitment::blank() };
let err = unsafe { let err = unsafe {
ffi::secp256k1_pedersen_commit_sum(self.ctx, ffi::secp256k1_pedersen_commit_sum(self.ctx,
ret.as_mut_ptr(), ret.as_mut_ptr(),
pos.as_ptr(), pos.as_ptr(),
pos.len() as i32, pos.len() as i32,
neg.as_ptr(), neg.as_ptr(),
neg.len() as i32) neg.len() as i32)
}; };
if err == 1 { if err == 1 {
Ok(ret) Ok(ret)
} else { } else {
Err(Error::IncorrectCommitSum) Err(Error::IncorrectCommitSum)
} }
} }
/// Computes the sum of multiple positive and negative blinding factors. /// Computes the sum of multiple positive and negative blinding factors.
pub fn blind_sum(&self, pub fn blind_sum(&self,
positive: Vec<SecretKey>, positive: Vec<SecretKey>,
negative: Vec<SecretKey>) negative: Vec<SecretKey>)
-> Result<SecretKey, Error> { -> Result<SecretKey, Error> {
let mut neg = map_vec!(negative, |n| n.as_ptr()); let mut neg = map_vec!(negative, |n| n.as_ptr());
let mut all = map_vec!(positive, |p| p.as_ptr()); let mut all = map_vec!(positive, |p| p.as_ptr());
all.append(&mut neg); all.append(&mut neg);
let mut ret: [u8; 32] = unsafe { mem::uninitialized() }; let mut ret: [u8; 32] = unsafe { mem::uninitialized() };
unsafe { unsafe {
assert_eq!(ffi::secp256k1_pedersen_blind_sum(self.ctx, assert_eq!(ffi::secp256k1_pedersen_blind_sum(self.ctx,
ret.as_mut_ptr(), ret.as_mut_ptr(),
all.as_ptr(), all.as_ptr(),
all.len() as i32, all.len() as i32,
positive.len() as i32), positive.len() as i32),
1) 1)
} }
// secp256k1 should never return an invalid private // secp256k1 should never return an invalid private
SecretKey::from_slice(self, &ret) SecretKey::from_slice(self, &ret)
} }
/// Produces a range proof for the provided value, using min and max bounds, relying /// Produces a range proof for the provided value, using min and max
/// on the blinding factor and commitment. /// bounds, relying
pub fn range_proof(&self, /// on the blinding factor and commitment.
min: u64, pub fn range_proof(&self,
value: u64, min: u64,
blind: SecretKey, value: u64,
commit: Commitment) blind: SecretKey,
-> RangeProof { commit: Commitment)
-> RangeProof {
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng::new().unwrap();
let mut nonce = [0u8; 32]; let mut nonce = [0u8; 32];
rng.fill_bytes(&mut nonce); rng.fill_bytes(&mut nonce);
let mut retried = false; let mut retried = false;
let mut proof = [0; constants::MAX_PROOF_SIZE]; let mut proof = [0; constants::MAX_PROOF_SIZE];
let mut plen = constants::MAX_PROOF_SIZE as i32; let mut plen = constants::MAX_PROOF_SIZE as i32;
loop { loop {
let err = unsafe { let err = unsafe {
// because: "This can randomly fail with probability around one in 2^100. // because: "This can randomly fail with probability around one in 2^100.
// If this happens, buy a lottery ticket and retry." // If this happens, buy a lottery ticket and retry."
ffi::secp256k1_rangeproof_sign(self.ctx, ffi::secp256k1_rangeproof_sign(self.ctx,
proof.as_mut_ptr(), proof.as_mut_ptr(),
&mut plen, &mut plen,
min, min,
commit.as_ptr(), commit.as_ptr(),
blind.as_ptr(), blind.as_ptr(),
nonce.as_ptr(), nonce.as_ptr(),
0, 0,
64, 64,
value) value)
}; };
if retried { if retried {
break; break;
} }
if err == 1 { if err == 1 {
retried = true; retried = true;
} }
} }
RangeProof { RangeProof {
proof: proof, proof: proof,
plen: plen as usize, plen: plen as usize,
} }
} }
/// Verify a proof that a committed value is within a range. /// Verify a proof that a committed value is within a range.
pub fn verify_range_proof(&self, pub fn verify_range_proof(&self,
commit: Commitment, commit: Commitment,
proof: RangeProof) proof: RangeProof)
-> Result<ProofRange, Error> { -> Result<ProofRange, Error> {
let mut min: u64 = 0; let mut min: u64 = 0;
let mut max: u64 = 0; let mut max: u64 = 0;
let success = unsafe { let success = unsafe {
ffi::secp256k1_rangeproof_verify(self.ctx, ffi::secp256k1_rangeproof_verify(self.ctx,
&mut min, &mut min,
&mut max, &mut max,
commit.as_ptr(), commit.as_ptr(),
proof.proof.as_ptr(), proof.proof.as_ptr(),
proof.plen as i32) == 1 proof.plen as i32) == 1
}; };
if success { if success {
Ok(ProofRange { Ok(ProofRange {
min: min, min: min,
max: max, max: max,
}) })
} else { } else {
Err(Error::InvalidRangeProof) Err(Error::InvalidRangeProof)
} }
} }
/// Verify a range proof proof and rewind the proof to recover information sent by its author. /// Verify a range proof proof and rewind the proof to recover information
pub fn rewind_range_proof(&self, /// sent by its author.
commit: Commitment, pub fn rewind_range_proof(&self,
proof: RangeProof, commit: Commitment,
nonce: [u8; 32]) proof: RangeProof,
-> ProofInfo { nonce: [u8; 32])
let mut value: u64 = 0; -> ProofInfo {
let mut blind: [u8; 32] = unsafe { mem::uninitialized() }; let mut value: u64 = 0;
let mut message = [0u8; constants::PROOF_MSG_SIZE]; let mut blind: [u8; 32] = unsafe { mem::uninitialized() };
let mut mlen: i32 = 0; let mut message = [0u8; constants::PROOF_MSG_SIZE];
let mut min: u64 = 0; let mut mlen: i32 = 0;
let mut max: u64 = 0; let mut min: u64 = 0;
let success = unsafe { let mut max: u64 = 0;
ffi::secp256k1_rangeproof_rewind(self.ctx, let success = unsafe {
blind.as_mut_ptr(), ffi::secp256k1_rangeproof_rewind(self.ctx,
&mut value, blind.as_mut_ptr(),
message.as_mut_ptr(), &mut value,
&mut mlen, message.as_mut_ptr(),
nonce.as_ptr(), &mut mlen,
&mut min, nonce.as_ptr(),
&mut max, &mut min,
commit.as_ptr(), &mut max,
proof.proof.as_ptr(), commit.as_ptr(),
proof.plen as i32) == 1 proof.proof.as_ptr(),
}; proof.plen as i32) == 1
ProofInfo { };
success: success, ProofInfo {
value: value, success: success,
message: message, value: value,
mlen: mlen, message: message,
min: min, mlen: mlen,
max: max, min: min,
exp: 0, max: max,
mantissa: 0, exp: 0,
} mantissa: 0,
} }
}
/// General information extracted from a range proof. Does not provide any /// General information extracted from a range proof. Does not provide any
/// information about the value or the message (see rewind). /// information about the value or the message (see rewind).
pub fn range_proof_info(&self, proof: RangeProof) -> ProofInfo { pub fn range_proof_info(&self, proof: RangeProof) -> ProofInfo {
let mut exp: i32 = 0; let mut exp: i32 = 0;
let mut mantissa: i32 = 0; let mut mantissa: i32 = 0;
let mut min: u64 = 0; let mut min: u64 = 0;
let mut max: u64 = 0; let mut max: u64 = 0;
let success = unsafe { let success = unsafe {
ffi::secp256k1_rangeproof_info(self.ctx, ffi::secp256k1_rangeproof_info(self.ctx,
&mut exp, &mut exp,
&mut mantissa, &mut mantissa,
&mut min, &mut min,
&mut max, &mut max,
proof.proof.as_ptr(), proof.proof.as_ptr(),
proof.plen as i32) == 1 proof.plen as i32) == 1
}; };
ProofInfo { ProofInfo {
success: success, success: success,
value: 0, value: 0,
message: [0; 4096], message: [0; 4096],
mlen: 0, mlen: 0,
min: min, min: min,
max: max, max: max,
exp: exp, exp: exp,
mantissa: mantissa, mantissa: mantissa,
} }
} }
} }

View file

@ -32,166 +32,166 @@ impl_array_newtype!(Signature, u8, constants::SCHNORR_SIGNATURE_SIZE);
impl_pretty_debug!(Signature); impl_pretty_debug!(Signature);
impl Signature { impl Signature {
/// Deserializes a signature from a 64-byte vector /// Deserializes a signature from a 64-byte vector
pub fn deserialize(data: &[u8]) -> Signature { pub fn deserialize(data: &[u8]) -> Signature {
assert_eq!(data.len(), constants::SCHNORR_SIGNATURE_SIZE); assert_eq!(data.len(), constants::SCHNORR_SIGNATURE_SIZE);
unsafe { unsafe {
let mut ret: Signature = mem::uninitialized(); let mut ret: Signature = mem::uninitialized();
ptr::copy_nonoverlapping(data.as_ptr(), ptr::copy_nonoverlapping(data.as_ptr(),
ret.as_mut_ptr(), ret.as_mut_ptr(),
constants::SCHNORR_SIGNATURE_SIZE); constants::SCHNORR_SIGNATURE_SIZE);
ret ret
} }
} }
/// Serializes a signature to a 64-byte vector /// Serializes a signature to a 64-byte vector
pub fn serialize(&self) -> Vec<u8> { pub fn serialize(&self) -> Vec<u8> {
let mut ret = Vec::with_capacity(constants::SCHNORR_SIGNATURE_SIZE); let mut ret = Vec::with_capacity(constants::SCHNORR_SIGNATURE_SIZE);
unsafe { unsafe {
ptr::copy_nonoverlapping(self.as_ptr(), ptr::copy_nonoverlapping(self.as_ptr(),
ret.as_mut_ptr(), ret.as_mut_ptr(),
constants::SCHNORR_SIGNATURE_SIZE); constants::SCHNORR_SIGNATURE_SIZE);
ret.set_len(constants::SCHNORR_SIGNATURE_SIZE); ret.set_len(constants::SCHNORR_SIGNATURE_SIZE);
} }
ret ret
} }
} }
impl Secp256k1 { impl Secp256k1 {
/// Create a Schnorr signature /// Create a Schnorr signature
pub fn sign_schnorr(&self, msg: &Message, sk: &SecretKey) -> Result<Signature, Error> { pub fn sign_schnorr(&self, msg: &Message, sk: &SecretKey) -> Result<Signature, Error> {
if self.caps == ContextFlag::VerifyOnly || self.caps == ContextFlag::None { if self.caps == ContextFlag::VerifyOnly || self.caps == ContextFlag::None {
return Err(Error::IncapableContext); return Err(Error::IncapableContext);
} }
let mut ret: Signature = unsafe { mem::uninitialized() }; let mut ret: Signature = unsafe { mem::uninitialized() };
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 signature from a valid `Message` and `SecretKey` // an invalid signature from a valid `Message` and `SecretKey`
let err = ffi::secp256k1_schnorr_sign(self.ctx, let err = ffi::secp256k1_schnorr_sign(self.ctx,
ret.as_mut_ptr(), ret.as_mut_ptr(),
msg.as_ptr(), msg.as_ptr(),
sk.as_ptr(), sk.as_ptr(),
ffi::secp256k1_nonce_function_rfc6979, ffi::secp256k1_nonce_function_rfc6979,
ptr::null()); ptr::null());
debug_assert_eq!(err, 1); debug_assert_eq!(err, 1);
} }
Ok(ret) Ok(ret)
} }
/// Verify a Schnorr signature /// Verify a Schnorr signature
pub fn verify_schnorr(&self, pub fn verify_schnorr(&self,
msg: &Message, msg: &Message,
sig: &Signature, sig: &Signature,
pk: &PublicKey) pk: &PublicKey)
-> Result<(), Error> { -> Result<(), Error> {
if self.caps == ContextFlag::SignOnly || self.caps == ContextFlag::None { if self.caps == ContextFlag::SignOnly || self.caps == ContextFlag::None {
return Err(Error::IncapableContext); return Err(Error::IncapableContext);
} }
if !pk.is_valid() { if !pk.is_valid() {
Err(Error::InvalidPublicKey) Err(Error::InvalidPublicKey)
} else if unsafe { } else if unsafe {
ffi::secp256k1_schnorr_verify(self.ctx, sig.as_ptr(), msg.as_ptr(), pk.as_ptr()) ffi::secp256k1_schnorr_verify(self.ctx, sig.as_ptr(), msg.as_ptr(), pk.as_ptr())
} == 0 { } == 0 {
Err(Error::IncorrectSignature) Err(Error::IncorrectSignature)
} else { } else {
Ok(()) Ok(())
} }
} }
/// Retrieves the public key for which `sig` is a valid signature for `msg`. /// Retrieves the public key for which `sig` is a valid signature for `msg`.
/// Requires a verify-capable context. /// Requires a verify-capable context.
pub fn recover_schnorr(&self, msg: &Message, sig: &Signature) -> Result<PublicKey, Error> { pub fn recover_schnorr(&self, msg: &Message, sig: &Signature) -> Result<PublicKey, Error> {
if self.caps == ContextFlag::SignOnly || self.caps == ContextFlag::None { if self.caps == ContextFlag::SignOnly || self.caps == ContextFlag::None {
return Err(Error::IncapableContext); return Err(Error::IncapableContext);
} }
let mut pk = unsafe { ffi::PublicKey::blank() }; let mut pk = unsafe { ffi::PublicKey::blank() };
unsafe { unsafe {
if ffi::secp256k1_schnorr_recover(self.ctx, &mut pk, sig.as_ptr(), msg.as_ptr()) != 1 { if ffi::secp256k1_schnorr_recover(self.ctx, &mut pk, sig.as_ptr(), msg.as_ptr()) != 1 {
return Err(Error::InvalidSignature); return Err(Error::InvalidSignature);
} }
}; };
Ok(PublicKey::from(pk)) Ok(PublicKey::from(pk))
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use rand::{Rng, thread_rng}; use rand::{Rng, thread_rng};
use ContextFlag; use ContextFlag;
use Message; use Message;
use Secp256k1; use Secp256k1;
use Error::IncapableContext; use Error::IncapableContext;
use super::Signature; use super::Signature;
#[test] #[test]
fn capabilities() { fn capabilities() {
let none = Secp256k1::with_caps(ContextFlag::None); let none = Secp256k1::with_caps(ContextFlag::None);
let sign = Secp256k1::with_caps(ContextFlag::SignOnly); let sign = Secp256k1::with_caps(ContextFlag::SignOnly);
let vrfy = Secp256k1::with_caps(ContextFlag::VerifyOnly); let vrfy = Secp256k1::with_caps(ContextFlag::VerifyOnly);
let full = Secp256k1::with_caps(ContextFlag::Full); let full = Secp256k1::with_caps(ContextFlag::Full);
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();
let (sk, pk) = full.generate_keypair(&mut thread_rng()).unwrap(); let (sk, pk) = full.generate_keypair(&mut thread_rng()).unwrap();
// Try signing // Try signing
assert_eq!(none.sign_schnorr(&msg, &sk), Err(IncapableContext)); assert_eq!(none.sign_schnorr(&msg, &sk), Err(IncapableContext));
assert_eq!(vrfy.sign_schnorr(&msg, &sk), Err(IncapableContext)); assert_eq!(vrfy.sign_schnorr(&msg, &sk), Err(IncapableContext));
assert!(sign.sign_schnorr(&msg, &sk).is_ok()); assert!(sign.sign_schnorr(&msg, &sk).is_ok());
assert!(full.sign_schnorr(&msg, &sk).is_ok()); assert!(full.sign_schnorr(&msg, &sk).is_ok());
assert_eq!(sign.sign_schnorr(&msg, &sk), full.sign_schnorr(&msg, &sk)); assert_eq!(sign.sign_schnorr(&msg, &sk), full.sign_schnorr(&msg, &sk));
let sig = full.sign_schnorr(&msg, &sk).unwrap(); let sig = full.sign_schnorr(&msg, &sk).unwrap();
// Try verifying // Try verifying
assert_eq!(none.verify_schnorr(&msg, &sig, &pk), Err(IncapableContext)); assert_eq!(none.verify_schnorr(&msg, &sig, &pk), Err(IncapableContext));
assert_eq!(sign.verify_schnorr(&msg, &sig, &pk), Err(IncapableContext)); assert_eq!(sign.verify_schnorr(&msg, &sig, &pk), Err(IncapableContext));
assert!(vrfy.verify_schnorr(&msg, &sig, &pk).is_ok()); assert!(vrfy.verify_schnorr(&msg, &sig, &pk).is_ok());
assert!(full.verify_schnorr(&msg, &sig, &pk).is_ok()); assert!(full.verify_schnorr(&msg, &sig, &pk).is_ok());
// Try pk recovery // Try pk recovery
assert_eq!(none.recover_schnorr(&msg, &sig), Err(IncapableContext)); assert_eq!(none.recover_schnorr(&msg, &sig), Err(IncapableContext));
assert_eq!(sign.recover_schnorr(&msg, &sig), Err(IncapableContext)); assert_eq!(sign.recover_schnorr(&msg, &sig), Err(IncapableContext));
assert!(vrfy.recover_schnorr(&msg, &sig).is_ok()); assert!(vrfy.recover_schnorr(&msg, &sig).is_ok());
assert!(full.recover_schnorr(&msg, &sig).is_ok()); assert!(full.recover_schnorr(&msg, &sig).is_ok());
assert_eq!(vrfy.recover_schnorr(&msg, &sig), assert_eq!(vrfy.recover_schnorr(&msg, &sig),
full.recover_schnorr(&msg, &sig)); full.recover_schnorr(&msg, &sig));
assert_eq!(full.recover_schnorr(&msg, &sig), Ok(pk)); assert_eq!(full.recover_schnorr(&msg, &sig), Ok(pk));
} }
#[test] #[test]
fn sign_verify() { fn sign_verify() {
let mut s = Secp256k1::new(); let mut s = Secp256k1::new();
s.randomize(&mut thread_rng()); s.randomize(&mut thread_rng());
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();
let (sk, pk) = s.generate_keypair(&mut thread_rng()).unwrap(); let (sk, pk) = s.generate_keypair(&mut thread_rng()).unwrap();
let sig = s.sign_schnorr(&msg, &sk).unwrap(); let sig = s.sign_schnorr(&msg, &sk).unwrap();
assert!(s.verify_schnorr(&msg, &sig, &pk).is_ok()); assert!(s.verify_schnorr(&msg, &sig, &pk).is_ok());
} }
#[test] #[test]
fn deserialize() { fn deserialize() {
let mut s = Secp256k1::new(); let mut s = Secp256k1::new();
s.randomize(&mut thread_rng()); s.randomize(&mut thread_rng());
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();
let (sk, _) = s.generate_keypair(&mut thread_rng()).unwrap(); let (sk, _) = s.generate_keypair(&mut thread_rng()).unwrap();
let sig1 = s.sign_schnorr(&msg, &sk).unwrap(); let sig1 = s.sign_schnorr(&msg, &sk).unwrap();
let sig2 = Signature::deserialize(&sig1.serialize()); let sig2 = Signature::deserialize(&sig1.serialize());
assert_eq!(sig1, sig2); assert_eq!(sig1, sig2);
} }
} }