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"
libc = "0.1"
rustc-serialize = "0.3"
serde = "0.6"
serde_json = "0.6"
serde = "~1.0.8"
serde_json = "~1.0.2"

View file

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

View file

@ -61,14 +61,14 @@ 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()
}
/// 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
@ -84,25 +84,25 @@ impl_array_newtype!(RecoverableSignature, c_uchar, 65);
impl_raw_debug!(RecoverableSignature);
impl Signature {
/// Create a new (zeroed) signature usable for the FFI interface
pub fn new() -> Signature {
Signature([0; 64])
}
/// Create a new (uninitialized) signature usable for the FFI interface
pub unsafe fn blank() -> Signature {
mem::uninitialized()
}
/// Create a new (zeroed) signature usable for the FFI interface
pub fn new() -> Signature {
Signature([0; 64])
}
/// Create a new (uninitialized) signature usable for the FFI interface
pub unsafe fn blank() -> Signature {
mem::uninitialized()
}
}
impl RecoverableSignature {
/// Create a new (zeroed) signature usable for the FFI interface
pub fn new() -> RecoverableSignature {
RecoverableSignature([0; 65])
}
/// Create a new (uninitialized) signature usable for the FFI interface
pub unsafe fn blank() -> RecoverableSignature {
mem::uninitialized()
}
/// Create a new (zeroed) signature usable for the FFI interface
pub fn new() -> RecoverableSignature {
RecoverableSignature([0; 65])
}
/// Create a new (uninitialized) signature usable for the FFI interface
pub unsafe fn blank() -> RecoverableSignature {
mem::uninitialized()
}
}
/// Library-internal representation of an ECDH shared secret
@ -112,263 +112,263 @@ impl_array_newtype!(SharedSecret, c_uchar, 32);
impl_raw_debug!(SharedSecret);
impl SharedSecret {
/// Create a new (zeroed) signature usable for the FFI interface
pub fn new() -> SharedSecret {
SharedSecret([0; 32])
}
/// Create a new (uninitialized) signature usable for the FFI interface
pub unsafe fn blank() -> SharedSecret {
mem::uninitialized()
}
/// Create a new (zeroed) signature usable for the FFI interface
pub fn new() -> SharedSecret {
SharedSecret([0; 32])
}
/// Create a new (uninitialized) signature usable for the FFI interface
pub unsafe fn blank() -> SharedSecret {
mem::uninitialized()
}
}
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
pub fn secp256k1_context_create(flags: c_uint) -> *mut Context;
// Contexts
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_rangeproof_context_initialize(ctx: *mut Context);
pub fn secp256k1_pedersen_context_initialize(ctx: *mut Context);
pub fn secp256k1_rangeproof_context_initialize(ctx: *mut Context);
// TODO secp256k1_context_set_illegal_callback
// TODO secp256k1_context_set_error_callback
// (Actually, I don't really want these exposed; if either of these
// are ever triggered it indicates a bug in rust-secp256k1, since
// one goal is to use Rust's type system to eliminate all possible
// bad inputs.)
// TODO secp256k1_context_set_illegal_callback
// TODO secp256k1_context_set_error_callback
// (Actually, I don't really want these exposed; if either of these
// are ever triggered it indicates a bug in rust-secp256k1, since
// one goal is to use Rust's type system to eliminate all possible
// bad inputs.)
// Pubkeys
pub fn secp256k1_ec_pubkey_parse(cx: *const Context,
pk: *mut PublicKey,
input: *const c_uchar,
in_len: size_t)
-> c_int;
// Pubkeys
pub fn secp256k1_ec_pubkey_parse(cx: *const Context,
pk: *mut PublicKey,
input: *const c_uchar,
in_len: size_t)
-> c_int;
pub fn secp256k1_ec_pubkey_serialize(cx: *const Context,
output: *const c_uchar,
out_len: *mut size_t,
pk: *const PublicKey,
compressed: c_uint)
-> c_int;
pub fn secp256k1_ec_pubkey_serialize(cx: *const Context,
output: *const c_uchar,
out_len: *mut size_t,
pk: *const PublicKey,
compressed: c_uint)
-> c_int;
// Signatures
pub fn secp256k1_ecdsa_signature_parse_der(cx: *const Context,
sig: *mut Signature,
input: *const c_uchar,
in_len: size_t)
-> c_int;
// Signatures
pub fn secp256k1_ecdsa_signature_parse_der(cx: *const Context,
sig: *mut Signature,
input: *const c_uchar,
in_len: size_t)
-> c_int;
pub fn ecdsa_signature_parse_der_lax(cx: *const Context,
sig: *mut Signature,
input: *const c_uchar,
in_len: size_t)
-> c_int;
pub fn ecdsa_signature_parse_der_lax(cx: *const Context,
sig: *mut Signature,
input: *const c_uchar,
in_len: size_t)
-> c_int;
pub fn secp256k1_ecdsa_signature_serialize_der(cx: *const Context,
output: *const c_uchar,
out_len: *mut size_t,
sig: *const Signature)
-> c_int;
pub fn secp256k1_ecdsa_signature_serialize_der(cx: *const Context,
output: *const c_uchar,
out_len: *mut size_t,
sig: *const Signature)
-> c_int;
pub fn secp256k1_ecdsa_recoverable_signature_parse_compact(cx: *const Context,
sig: *mut RecoverableSignature,
input64: *const c_uchar,
recid: c_int)
-> c_int;
pub fn secp256k1_ecdsa_recoverable_signature_parse_compact(cx: *const Context,
sig: *mut RecoverableSignature,
input64: *const c_uchar,
recid: 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)
-> c_int;
pub fn secp256k1_ecdsa_recoverable_signature_convert(cx: *const Context,
sig: *mut Signature,
input: *const RecoverableSignature)
-> c_int;
pub fn secp256k1_ecdsa_recoverable_signature_convert(cx: *const Context,
sig: *mut Signature,
input: *const RecoverableSignature)
-> c_int;
pub fn secp256k1_ecdsa_signature_normalize(cx: *const Context,
out_sig: *mut Signature,
in_sig: *const Signature)
-> c_int;
pub fn secp256k1_ecdsa_signature_normalize(cx: *const Context,
out_sig: *mut Signature,
in_sig: *const Signature)
-> c_int;
// ECDSA
pub fn secp256k1_ecdsa_verify(cx: *const Context,
sig: *const Signature,
msg32: *const c_uchar,
pk: *const PublicKey)
-> c_int;
// ECDSA
pub fn secp256k1_ecdsa_verify(cx: *const Context,
sig: *const Signature,
msg32: *const c_uchar,
pk: *const PublicKey)
-> c_int;
pub fn secp256k1_ecdsa_sign(cx: *const Context,
sig: *mut Signature,
msg32: *const c_uchar,
sk: *const c_uchar,
noncefn: NonceFn,
noncedata: *const c_void)
-> c_int;
pub fn secp256k1_ecdsa_sign(cx: *const Context,
sig: *mut Signature,
msg32: *const c_uchar,
sk: *const c_uchar,
noncefn: NonceFn,
noncedata: *const c_void)
-> c_int;
pub fn secp256k1_ecdsa_sign_recoverable(cx: *const Context,
sig: *mut RecoverableSignature,
msg32: *const c_uchar,
sk: *const c_uchar,
noncefn: NonceFn,
noncedata: *const c_void)
-> c_int;
pub fn secp256k1_ecdsa_sign_recoverable(cx: *const Context,
sig: *mut RecoverableSignature,
msg32: *const c_uchar,
sk: *const c_uchar,
noncefn: NonceFn,
noncedata: *const c_void)
-> c_int;
pub fn secp256k1_ecdsa_recover(cx: *const Context,
pk: *mut PublicKey,
sig: *const RecoverableSignature,
msg32: *const c_uchar)
-> c_int;
pub fn secp256k1_ecdsa_recover(cx: *const Context,
pk: *mut PublicKey,
sig: *const RecoverableSignature,
msg32: *const c_uchar)
-> c_int;
// Schnorr
pub fn secp256k1_schnorr_sign(cx: *const Context,
sig64: *mut c_uchar,
msg32: *const c_uchar,
sk: *const c_uchar,
noncefn: NonceFn,
noncedata: *const c_void)
-> c_int;
// Schnorr
pub fn secp256k1_schnorr_sign(cx: *const Context,
sig64: *mut c_uchar,
msg32: *const c_uchar,
sk: *const c_uchar,
noncefn: NonceFn,
noncedata: *const c_void)
-> c_int;
pub fn secp256k1_schnorr_verify(cx: *const Context,
sig64: *const c_uchar,
msg32: *const c_uchar,
pk: *const PublicKey)
-> c_int;
pub fn secp256k1_schnorr_verify(cx: *const Context,
sig64: *const c_uchar,
msg32: *const c_uchar,
pk: *const PublicKey)
-> c_int;
pub fn secp256k1_schnorr_recover(cx: *const Context,
pk: *mut PublicKey,
sig64: *const c_uchar,
msg32: *const c_uchar)
-> c_int;
pub fn secp256k1_schnorr_recover(cx: *const Context,
pk: *mut PublicKey,
sig64: *const c_uchar,
msg32: *const c_uchar)
-> c_int;
// EC
pub fn secp256k1_ec_seckey_verify(cx: *const Context, sk: *const c_uchar) -> c_int;
// EC
pub fn secp256k1_ec_seckey_verify(cx: *const Context, sk: *const c_uchar) -> c_int;
pub fn secp256k1_ec_pubkey_create(cx: *const Context,
pk: *mut PublicKey,
sk: *const c_uchar)
-> c_int;
pub fn secp256k1_ec_pubkey_create(cx: *const Context,
pk: *mut PublicKey,
sk: *const c_uchar)
-> c_int;
// TODO secp256k1_ec_privkey_export
// TODO secp256k1_ec_privkey_import
// TODO secp256k1_ec_privkey_export
// TODO secp256k1_ec_privkey_import
pub fn secp256k1_ec_privkey_tweak_add(cx: *const Context,
sk: *mut c_uchar,
tweak: *const c_uchar)
-> c_int;
pub fn secp256k1_ec_privkey_tweak_add(cx: *const Context,
sk: *mut c_uchar,
tweak: *const c_uchar)
-> c_int;
pub fn secp256k1_ec_pubkey_tweak_add(cx: *const Context,
pk: *mut PublicKey,
tweak: *const c_uchar)
-> c_int;
pub fn secp256k1_ec_pubkey_tweak_add(cx: *const Context,
pk: *mut PublicKey,
tweak: *const c_uchar)
-> c_int;
pub fn secp256k1_ec_privkey_tweak_mul(cx: *const Context,
sk: *mut c_uchar,
tweak: *const c_uchar)
-> c_int;
pub fn secp256k1_ec_privkey_tweak_mul(cx: *const Context,
sk: *mut c_uchar,
tweak: *const c_uchar)
-> c_int;
pub fn secp256k1_ec_pubkey_tweak_mul(cx: *const Context,
pk: *mut PublicKey,
tweak: *const c_uchar)
-> c_int;
pub fn secp256k1_ec_pubkey_tweak_mul(cx: *const Context,
pk: *mut PublicKey,
tweak: *const c_uchar)
-> c_int;
pub fn secp256k1_ec_pubkey_combine(cx: *const Context,
out: *mut PublicKey,
ins: *const *const PublicKey,
n: c_int)
-> c_int;
pub fn secp256k1_ec_pubkey_combine(cx: *const Context,
out: *mut PublicKey,
ins: *const *const PublicKey,
n: c_int)
-> c_int;
pub fn secp256k1_ecdh(cx: *const Context,
out: *mut SharedSecret,
point: *const PublicKey,
scalar: *const c_uchar)
-> c_int;
pub fn secp256k1_ecdh(cx: *const Context,
out: *mut SharedSecret,
point: *const PublicKey,
scalar: *const c_uchar)
-> c_int;
// Generates a pedersen commitment: *commit = blind * G + value * G2.
// The commitment is 33 bytes, the blinding factor is 32 bytes.
pub fn secp256k1_pedersen_commit(ctx: *const Context,
commit: *mut c_uchar,
blind: *const c_uchar,
value: uint64_t)
-> c_int;
// Generates a pedersen commitment: *commit = blind * G + value * G2.
// The commitment is 33 bytes, the blinding factor is 32 bytes.
pub fn secp256k1_pedersen_commit(ctx: *const Context,
commit: *mut c_uchar,
blind: *const c_uchar,
value: uint64_t)
-> c_int;
// 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
// calculates an additional blinding value that adds to zero.
pub fn secp256k1_pedersen_blind_sum(ctx: *const Context,
blind_out: *const c_uchar,
blinds: *const *const c_uchar,
n: c_int,
npositive: c_int)
-> c_int;
// 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
// calculates an additional blinding value that adds to zero.
pub fn secp256k1_pedersen_blind_sum(ctx: *const Context,
blind_out: *const c_uchar,
blinds: *const *const c_uchar,
n: c_int,
npositive: c_int)
-> c_int;
// Takes two list of 33-byte commitments and sums the first set, subtracts
// the second and returns the resulting commitment.
pub fn secp256k1_pedersen_commit_sum(ctx: *const Context,
commit_out: *const c_uchar,
commits: *const *const c_uchar,
pcnt: c_int,
ncommits: *const *const c_uchar,
ncnt: c_int)
-> c_int;
// Takes two list of 33-byte commitments and sums the first set, subtracts
// the second and returns the resulting commitment.
pub fn secp256k1_pedersen_commit_sum(ctx: *const Context,
commit_out: *const c_uchar,
commits: *const *const c_uchar,
pcnt: c_int,
ncommits: *const *const c_uchar,
ncnt: c_int)
-> c_int;
// Takes two list of 33-byte commitments and sums the first set and
// subtracts the second and verifies that they sum to excess.
pub fn secp256k1_pedersen_verify_tally(ctx: *const Context,
commits: *const *const c_uchar,
pcnt: c_int,
ncommits: *const *const c_uchar,
ncnt: c_int,
excess: int64_t)
-> c_int;
// Takes two list of 33-byte commitments and sums the first set and
// subtracts the second and verifies that they sum to excess.
pub fn secp256k1_pedersen_verify_tally(ctx: *const Context,
commits: *const *const c_uchar,
pcnt: c_int,
ncommits: *const *const c_uchar,
ncnt: c_int,
excess: int64_t)
-> c_int;
pub fn secp256k1_rangeproof_info(ctx: *const Context,
exp: *mut c_int,
mantissa: *mut c_int,
min_value: *mut uint64_t,
max_value: *mut uint64_t,
proof: *const c_uchar,
plen: c_int)
-> c_int;
pub fn secp256k1_rangeproof_info(ctx: *const Context,
exp: *mut c_int,
mantissa: *mut c_int,
min_value: *mut uint64_t,
max_value: *mut uint64_t,
proof: *const c_uchar,
plen: c_int)
-> c_int;
pub fn secp256k1_rangeproof_rewind(ctx: *const Context,
blind_out: *mut c_uchar,
value_out: *mut uint64_t,
message_out: *mut c_uchar,
outlen: *mut c_int,
nonce: *const c_uchar,
min_value: *mut uint64_t,
max_value: *mut uint64_t,
commit: *const c_uchar,
proof: *const c_uchar,
plen: c_int)
-> c_int;
pub fn secp256k1_rangeproof_rewind(ctx: *const Context,
blind_out: *mut c_uchar,
value_out: *mut uint64_t,
message_out: *mut c_uchar,
outlen: *mut c_int,
nonce: *const c_uchar,
min_value: *mut uint64_t,
max_value: *mut uint64_t,
commit: *const c_uchar,
proof: *const c_uchar,
plen: c_int)
-> c_int;
pub fn secp256k1_rangeproof_verify(ctx: *const Context,
min_value: &mut uint64_t,
max_value: &mut uint64_t,
commit: *const c_uchar,
proof: *const c_uchar,
plen: c_int)
-> c_int;
pub fn secp256k1_rangeproof_verify(ctx: *const Context,
min_value: &mut uint64_t,
max_value: &mut uint64_t,
commit: *const c_uchar,
proof: *const c_uchar,
plen: c_int)
-> c_int;
pub fn secp256k1_rangeproof_sign(ctx: *const Context,
proof: *mut c_uchar,
plen: *mut c_int,
min_value: uint64_t,
commit: *const c_uchar,
blind: *const c_uchar,
nonce: *const c_uchar,
exp: c_int,
min_bits: c_int,
value: uint64_t)
-> c_int;
pub fn secp256k1_rangeproof_sign(ctx: *const Context,
proof: *mut c_uchar,
plen: *mut c_int,
min_value: uint64_t,
commit: *const c_uchar,
blind: *const c_uchar,
nonce: *const c_uchar,
exp: c_int,
min_bits: c_int,
value: uint64_t)
-> 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 {
#[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 {
let &$thing(ref dat) = self;
dat.as_ptr()
}
#[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 {
let &mut $thing(ref mut dat) = self;
dat.as_mut_ptr()
}
#[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 }
#[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 }
}
@ -125,9 +125,9 @@ macro_rules! impl_array_newtype {
impl ::std::hash::Hash for $thing {
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
state.write(&self.0)
// for n in 0..self.len() {
// state.write_u8(self.0[n]);
// }
// for n in 0..self.len() {
// state.write_u8(self.0[n]);
// }
}
}
@ -159,45 +159,48 @@ macro_rules! impl_array_newtype {
}
}
impl ::serde::Deserialize for $thing {
fn deserialize<D>(d: &mut D) -> Result<$thing, D::Error>
where D: ::serde::Deserializer
impl<'de> ::serde::Deserialize<'de> for $thing {
fn deserialize<D>(d: D) -> Result<$thing, D::Error>
where D: ::serde::Deserializer<'de>
{
// We have to define the Visitor struct inside the function
// to make it local ... all we really need is that it's
// local to the macro, but this works too :)
struct Visitor {
marker: ::std::marker::PhantomData<$thing>,
}
impl ::serde::de::Visitor for Visitor {
struct Visitor;
impl<'di> ::serde::de::Visitor<'di> for Visitor {
type Value = $thing;
fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
formatter.write_str("an array of bytes")
}
#[inline]
fn visit_seq<V>(&mut self, mut v: V) -> Result<$thing, V::Error>
where V: ::serde::de::SeqVisitor
fn visit_seq<V>(self, mut v: V) -> Result<$thing, V::Error>
where V: ::serde::de::SeqAccess<'di>
{
unsafe {
use std::mem;
let mut ret: [$ty; $len] = mem::uninitialized();
for i in 0..$len {
ret[i] = match try!(v.visit()) {
ret[i] = match try!(v.next_element()) {
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))
}
}
}
// 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 {
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
{
(&self.0[..]).serialize(s)

View file

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

View file

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