mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 17:01:09 +03:00
Update secp256k1zlp to serde 1.0
This commit is contained in:
parent
1ae2e905d8
commit
da41120293
8 changed files with 2067 additions and 1999 deletions
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue