Merge pull request #21 from TheBlueMatt/master
Add fuzztarget feature that replaces crypto with memcpys
This commit is contained in:
commit
3b0fcbd05f
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
|
|
||||||
name = "secp256k1"
|
name = "secp256k1"
|
||||||
version = "0.8.4"
|
version = "0.8.5"
|
||||||
authors = [ "Dawid Ciężarkiewicz <dpc@ucore.info>",
|
authors = [ "Dawid Ciężarkiewicz <dpc@ucore.info>",
|
||||||
"Andrew Poelstra <apoelstra@wpsoftware.net>" ]
|
"Andrew Poelstra <apoelstra@wpsoftware.net>" ]
|
||||||
license = "CC0-1.0"
|
license = "CC0-1.0"
|
||||||
|
@ -23,6 +23,7 @@ path = "src/lib.rs"
|
||||||
[features]
|
[features]
|
||||||
unstable = []
|
unstable = []
|
||||||
default = []
|
default = []
|
||||||
|
fuzztarget = []
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
[![Build Status](https://travis-ci.org/apoelstra/rust-secp256k1.png?branch=master)](https://travis-ci.org/apoelstra/rust-secp256k1)
|
[![Build Status](https://travis-ci.org/rust-bitcoin/rust-secp256k1.png?branch=master)](https://travis-ci.org/rust-bitcoin/rust-secp256k1)
|
||||||
|
|
||||||
### rust-secp256k1
|
### rust-secp256k1
|
||||||
|
|
||||||
`rust-secp256k1` is a wrapper around ![libsecp256k1](https://github.com/bitcoin/secp256k1),
|
`rust-secp256k1` is a wrapper around ![libsecp256k1](https://github.com/bitcoin-core/secp256k1),
|
||||||
a C library by Peter Wuille for producing ECDSA signatures using the SECG curve
|
a C library by Peter Wuille for producing ECDSA signatures using the SECG curve
|
||||||
`secp256k1`. This library
|
`secp256k1`. This library
|
||||||
* exposes type-safe Rust bindings for all `libsecp256k1` functions
|
* exposes type-safe Rust bindings for all `libsecp256k1` functions
|
||||||
|
|
383
src/ffi.rs
383
src/ffi.rs
|
@ -112,6 +112,7 @@ impl SharedSecret {
|
||||||
pub unsafe fn blank() -> SharedSecret { mem::uninitialized() }
|
pub unsafe fn blank() -> SharedSecret { mem::uninitialized() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "fuzztarget"))]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub static secp256k1_nonce_function_rfc6979: NonceFn;
|
pub static secp256k1_nonce_function_rfc6979: NonceFn;
|
||||||
|
|
||||||
|
@ -141,8 +142,8 @@ extern "C" {
|
||||||
-> c_int;
|
-> c_int;
|
||||||
|
|
||||||
pub fn secp256k1_ec_pubkey_serialize(cx: *const Context, output: *mut c_uchar,
|
pub fn secp256k1_ec_pubkey_serialize(cx: *const Context, output: *mut c_uchar,
|
||||||
out_len: *mut size_t, pk: *const PublicKey
|
out_len: *mut size_t, pk: *const PublicKey,
|
||||||
, compressed: c_uint)
|
compressed: c_uint)
|
||||||
-> c_int;
|
-> c_int;
|
||||||
|
|
||||||
// Signatures
|
// Signatures
|
||||||
|
@ -158,7 +159,7 @@ extern "C" {
|
||||||
input: *const c_uchar, in_len: size_t)
|
input: *const c_uchar, in_len: size_t)
|
||||||
-> c_int;
|
-> c_int;
|
||||||
|
|
||||||
pub fn secp256k1_ecdsa_signature_serialize_der(cx: *const Context, output: *const c_uchar,
|
pub fn secp256k1_ecdsa_signature_serialize_der(cx: *const Context, output: *mut c_uchar,
|
||||||
out_len: *mut size_t, sig: *const Signature)
|
out_len: *mut size_t, sig: *const Signature)
|
||||||
-> c_int;
|
-> c_int;
|
||||||
|
|
||||||
|
@ -175,7 +176,7 @@ extern "C" {
|
||||||
-> c_int;
|
-> c_int;
|
||||||
|
|
||||||
pub fn secp256k1_ecdsa_recoverable_signature_convert(cx: *const Context, sig: *mut Signature,
|
pub fn secp256k1_ecdsa_recoverable_signature_convert(cx: *const Context, sig: *mut Signature,
|
||||||
input: *const RecoverableSignature)
|
input: *const RecoverableSignature)
|
||||||
-> c_int;
|
-> c_int;
|
||||||
|
|
||||||
pub fn secp256k1_ecdsa_signature_normalize(cx: *const Context, out_sig: *mut Signature,
|
pub fn secp256k1_ecdsa_signature_normalize(cx: *const Context, out_sig: *mut Signature,
|
||||||
|
@ -275,3 +276,377 @@ extern "C" {
|
||||||
-> c_int;
|
-> c_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "fuzztarget")]
|
||||||
|
mod fuzz_dummy {
|
||||||
|
use libc::{c_int, c_uchar, c_uint, c_void};
|
||||||
|
use ffi::*;
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub static secp256k1_nonce_function_rfc6979: NonceFn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contexts
|
||||||
|
/// Creates a dummy context, tracking flags to ensure proper calling semantics
|
||||||
|
pub unsafe fn secp256k1_context_create(flags: c_uint) -> *mut Context {
|
||||||
|
let b = Box::new(Context(flags as i32));
|
||||||
|
Box::into_raw(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copies a dummy context
|
||||||
|
pub unsafe fn secp256k1_context_clone(cx: *mut Context) -> *mut Context {
|
||||||
|
let b = Box::new(Context((*cx).0));
|
||||||
|
Box::into_raw(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Frees a dummy context
|
||||||
|
pub unsafe fn secp256k1_context_destroy(cx: *mut Context) {
|
||||||
|
Box::from_raw(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Asserts that cx is properly initialized
|
||||||
|
pub unsafe fn secp256k1_context_randomize(cx: *mut Context,
|
||||||
|
_seed32: *const c_uchar)
|
||||||
|
-> c_int {
|
||||||
|
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
/// Parse 33/65 byte pubkey into PublicKey, losing compressed information
|
||||||
|
pub unsafe fn secp256k1_ec_pubkey_parse(cx: *const Context, pk: *mut PublicKey,
|
||||||
|
input: *const c_uchar, in_len: size_t)
|
||||||
|
-> c_int {
|
||||||
|
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
|
||||||
|
match in_len {
|
||||||
|
33 => {
|
||||||
|
if *input != 2 && *input != 3 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
ptr::copy(input.offset(1), (*pk).0[0..32].as_mut_ptr(), 32);
|
||||||
|
ptr::copy(input.offset(1), (*pk).0[32..64].as_mut_ptr(), 32);
|
||||||
|
test_pk_validate(cx, pk)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
65 => {
|
||||||
|
if *input != 4 && *input != 6 && *input != 7 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
ptr::copy(input.offset(1), (*pk).0.as_mut_ptr(), 64);
|
||||||
|
test_pk_validate(cx, pk)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serialize PublicKey back to 33/65 byte pubkey
|
||||||
|
pub unsafe fn secp256k1_ec_pubkey_serialize(cx: *const Context, output: *mut c_uchar,
|
||||||
|
out_len: *mut size_t, pk: *const PublicKey,
|
||||||
|
compressed: c_uint)
|
||||||
|
-> c_int {
|
||||||
|
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
|
||||||
|
if test_pk_validate(cx, pk) != 1 { return 0; }
|
||||||
|
if compressed == SECP256K1_SER_COMPRESSED {
|
||||||
|
assert_eq!(*out_len, 33);
|
||||||
|
if (*pk).0[0] > 0x7f {
|
||||||
|
*output = 2;
|
||||||
|
} else {
|
||||||
|
*output = 3;
|
||||||
|
}
|
||||||
|
ptr::copy((*pk).0.as_ptr(), output.offset(1), 32);
|
||||||
|
} else if compressed == SECP256K1_SER_UNCOMPRESSED {
|
||||||
|
assert_eq!(*out_len, 65);
|
||||||
|
*output = 4;
|
||||||
|
ptr::copy((*pk).0.as_ptr(), output.offset(1), 64);
|
||||||
|
} else {
|
||||||
|
panic!("Bad flags");
|
||||||
|
}
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signatures
|
||||||
|
pub unsafe fn secp256k1_ecdsa_signature_parse_der(cx: *const Context, sig: *mut Signature,
|
||||||
|
input: *const c_uchar, in_len: size_t)
|
||||||
|
-> c_int {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copies input64 to sig, checking the pubkey part is valid
|
||||||
|
pub unsafe fn secp256k1_ecdsa_signature_parse_compact(cx: *const Context, sig: *mut Signature,
|
||||||
|
input64: *const c_uchar)
|
||||||
|
-> c_int {
|
||||||
|
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
|
||||||
|
if secp256k1_ec_seckey_verify(cx, input64.offset(32)) != 1 { return 0; } // sig should be msg32||sk
|
||||||
|
ptr::copy(input64, (*sig).0[..].as_mut_ptr(), 64);
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn ecdsa_signature_parse_der_lax(cx: *const Context, sig: *mut Signature,
|
||||||
|
input: *const c_uchar, in_len: size_t)
|
||||||
|
-> c_int {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn secp256k1_ecdsa_signature_serialize_der(cx: *const Context, output: *mut c_uchar,
|
||||||
|
out_len: *mut size_t, sig: *const Signature)
|
||||||
|
-> c_int {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copies sig to output64
|
||||||
|
pub unsafe fn secp256k1_ecdsa_signature_serialize_compact(cx: *const Context, output64: *mut c_uchar,
|
||||||
|
sig: *const Signature)
|
||||||
|
-> c_int {
|
||||||
|
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
|
||||||
|
ptr::copy((*sig).0[..].as_ptr(), output64, 64);
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn secp256k1_ecdsa_recoverable_signature_parse_compact(cx: *const Context, sig: *mut RecoverableSignature,
|
||||||
|
input64: *const c_uchar, recid: c_int)
|
||||||
|
-> c_int {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn secp256k1_ecdsa_recoverable_signature_serialize_compact(cx: *const Context, output64: *const c_uchar,
|
||||||
|
recid: *mut c_int, sig: *const RecoverableSignature)
|
||||||
|
-> c_int {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn secp256k1_ecdsa_recoverable_signature_convert(cx: *const Context, sig: *mut Signature,
|
||||||
|
input: *const RecoverableSignature)
|
||||||
|
-> c_int {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn secp256k1_ecdsa_signature_normalize(cx: *const Context, out_sig: *mut Signature,
|
||||||
|
in_sig: *const Signature)
|
||||||
|
-> c_int {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ECDSA
|
||||||
|
/// Verifies that sig is msg32||pk[0..32]
|
||||||
|
pub unsafe fn secp256k1_ecdsa_verify(cx: *const Context,
|
||||||
|
sig: *const Signature,
|
||||||
|
msg32: *const c_uchar,
|
||||||
|
pk: *const PublicKey)
|
||||||
|
-> c_int {
|
||||||
|
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
|
||||||
|
assert!((*cx).0 as u32 & SECP256K1_START_VERIFY == SECP256K1_START_VERIFY);
|
||||||
|
if test_pk_validate(cx, pk) != 1 { return 0; }
|
||||||
|
for i in 0..32 {
|
||||||
|
if (*sig).0[i] != *msg32.offset(i as isize) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*sig).0[32..64] != (*pk).0[0..32] {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets sig to msg32||sk
|
||||||
|
pub unsafe 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 {
|
||||||
|
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
|
||||||
|
assert!((*cx).0 as u32 & SECP256K1_START_SIGN == SECP256K1_START_SIGN);
|
||||||
|
if secp256k1_ec_seckey_verify(cx, sk) != 1 { return 0; }
|
||||||
|
ptr::copy(msg32, (*sig).0[0..32].as_mut_ptr(), 32);
|
||||||
|
ptr::copy(sk, (*sig).0[32..64].as_mut_ptr(), 32);
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets sig to (2|3)||msg32||sk
|
||||||
|
pub unsafe 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 {
|
||||||
|
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
|
||||||
|
assert!((*cx).0 as u32 & SECP256K1_START_SIGN == SECP256K1_START_SIGN);
|
||||||
|
if secp256k1_ec_seckey_verify(cx, sk) != 1 { return 0; }
|
||||||
|
if *sk.offset(0) > 0x7f {
|
||||||
|
(*sig).0[0] = 2;
|
||||||
|
} else {
|
||||||
|
(*sig).0[0] = 3;
|
||||||
|
}
|
||||||
|
ptr::copy(msg32, (*sig).0[1..33].as_mut_ptr(), 32);
|
||||||
|
ptr::copy(sk, (*sig).0[33..65].as_mut_ptr(), 32);
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn secp256k1_ecdsa_recover(cx: *const Context,
|
||||||
|
pk: *mut PublicKey,
|
||||||
|
sig: *const RecoverableSignature,
|
||||||
|
msg32: *const c_uchar)
|
||||||
|
-> c_int {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schnorr
|
||||||
|
pub unsafe 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 {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn secp256k1_schnorr_verify(cx: *const Context,
|
||||||
|
sig64: *const c_uchar,
|
||||||
|
msg32: *const c_uchar,
|
||||||
|
pk: *const PublicKey)
|
||||||
|
-> c_int {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn secp256k1_schnorr_recover(cx: *const Context,
|
||||||
|
pk: *mut PublicKey,
|
||||||
|
sig64: *const c_uchar,
|
||||||
|
msg32: *const c_uchar)
|
||||||
|
-> c_int {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
// EC
|
||||||
|
/// Checks that pk != 0xffff...ffff and pk[0..32] == pk[32..64]
|
||||||
|
pub unsafe fn test_pk_validate(cx: *const Context,
|
||||||
|
pk: *const PublicKey) -> c_int {
|
||||||
|
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
|
||||||
|
if (*pk).0[0..32] != (*pk).0[32..64] || secp256k1_ec_seckey_verify(cx, (*pk).0[0..32].as_ptr()) == 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that sk != 0xffff...ffff
|
||||||
|
pub unsafe fn secp256k1_ec_seckey_verify(cx: *const Context,
|
||||||
|
sk: *const c_uchar) -> c_int {
|
||||||
|
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
|
||||||
|
let mut res = 0;
|
||||||
|
for i in 0..32 {
|
||||||
|
if *sk.offset(i as isize) != 0xff { res = 1 };
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets pk to sk||sk
|
||||||
|
pub unsafe fn secp256k1_ec_pubkey_create(cx: *const Context, pk: *mut PublicKey,
|
||||||
|
sk: *const c_uchar) -> c_int {
|
||||||
|
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
|
||||||
|
if secp256k1_ec_seckey_verify(cx, sk) != 1 { return 0; }
|
||||||
|
ptr::copy(sk, (*pk).0[0..32].as_mut_ptr(), 32);
|
||||||
|
ptr::copy(sk, (*pk).0[32..64].as_mut_ptr(), 32);
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO secp256k1_ec_privkey_export
|
||||||
|
//TODO secp256k1_ec_privkey_import
|
||||||
|
|
||||||
|
/// Copies the first 16 bytes of tweak into the last 16 bytes of sk
|
||||||
|
pub unsafe fn secp256k1_ec_privkey_tweak_add(cx: *const Context,
|
||||||
|
sk: *mut c_uchar,
|
||||||
|
tweak: *const c_uchar)
|
||||||
|
-> c_int {
|
||||||
|
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
|
||||||
|
if secp256k1_ec_seckey_verify(cx, sk) != 1 { return 0; }
|
||||||
|
ptr::copy(tweak, sk.offset(16), 16);
|
||||||
|
*sk.offset(24) = 0x7f; // Ensure sk remains valid no matter what tweak was
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The PublicKey equivalent of secp256k1_ec_privkey_tweak_add
|
||||||
|
pub unsafe fn secp256k1_ec_pubkey_tweak_add(cx: *const Context,
|
||||||
|
pk: *mut PublicKey,
|
||||||
|
tweak: *const c_uchar)
|
||||||
|
-> c_int {
|
||||||
|
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
|
||||||
|
if test_pk_validate(cx, pk) != 1 { return 0; }
|
||||||
|
ptr::copy(tweak, (*pk).0[16..32].as_mut_ptr(), 16);
|
||||||
|
ptr::copy(tweak, (*pk).0[16+32..64].as_mut_ptr(), 16);
|
||||||
|
(*pk).0[24] = 0x7f; // Ensure pk remains valid no matter what tweak was
|
||||||
|
(*pk).0[24+32] = 0x7f; // Ensure pk remains valid no matter what tweak was
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copies the last 16 bytes of tweak into the last 16 bytes of sk
|
||||||
|
pub unsafe fn secp256k1_ec_privkey_tweak_mul(cx: *const Context,
|
||||||
|
sk: *mut c_uchar,
|
||||||
|
tweak: *const c_uchar)
|
||||||
|
-> c_int {
|
||||||
|
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
|
||||||
|
if secp256k1_ec_seckey_verify(cx, sk) != 1 { return 0; }
|
||||||
|
ptr::copy(tweak.offset(16), sk.offset(16), 16);
|
||||||
|
*sk.offset(24) = 0x00; // Ensure sk remains valid no matter what tweak was
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The PublicKey equivalent of secp256k1_ec_privkey_tweak_mul
|
||||||
|
pub unsafe fn secp256k1_ec_pubkey_tweak_mul(cx: *const Context,
|
||||||
|
pk: *mut PublicKey,
|
||||||
|
tweak: *const c_uchar)
|
||||||
|
-> c_int {
|
||||||
|
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
|
||||||
|
if test_pk_validate(cx, pk) != 1 { return 0; }
|
||||||
|
ptr::copy(tweak.offset(16), (*pk).0[16..32].as_mut_ptr(), 16);
|
||||||
|
ptr::copy(tweak.offset(16), (*pk).0[16+32..64].as_mut_ptr(), 16);
|
||||||
|
(*pk).0[24] = 0x00; // Ensure pk remains valid no matter what tweak was
|
||||||
|
(*pk).0[24+32] = 0x00; // Ensure pk remains valid no matter what tweak was
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn secp256k1_ec_pubkey_combine(cx: *const Context,
|
||||||
|
out: *mut PublicKey,
|
||||||
|
ins: *const *const PublicKey,
|
||||||
|
n: c_int)
|
||||||
|
-> c_int {
|
||||||
|
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
|
||||||
|
assert!(n <= 32 && n >= 0); //TODO: Remove this restriction?
|
||||||
|
for i in 0..n {
|
||||||
|
if test_pk_validate(cx, *ins.offset(i as isize)) != 1 { return 0; }
|
||||||
|
(*out).0[(i*32/n) as usize..((i+1)*32/n) as usize].copy_from_slice(&(**ins.offset(i as isize)).0[(i*32/n) as usize..((i+1)*32/n) as usize]);
|
||||||
|
}
|
||||||
|
ptr::copy((*out).0[0..32].as_ptr(), (*out).0[32..64].as_mut_ptr(), 32);
|
||||||
|
(*out).0[24] = 0x0d; // pk should always be valid
|
||||||
|
(*out).0[24+32] = 0x0d; // pk should always be valid
|
||||||
|
test_pk_validate(cx, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets out to point[0..16]||scalar[0..16]
|
||||||
|
pub unsafe fn secp256k1_ecdh(cx: *const Context,
|
||||||
|
out: *mut SharedSecret,
|
||||||
|
point: *const PublicKey,
|
||||||
|
scalar: *const c_uchar)
|
||||||
|
-> c_int {
|
||||||
|
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
|
||||||
|
assert!((*cx).0 as u32 & SECP256K1_START_SIGN == SECP256K1_START_SIGN);
|
||||||
|
if secp256k1_ec_seckey_verify(cx, scalar) != 1 { return 0; }
|
||||||
|
(*out).0[0..16].copy_from_slice(&(*point).0[0..16]);
|
||||||
|
ptr::copy(scalar, (*out).0[16..32].as_mut_ptr(), 16);
|
||||||
|
(*out).0[16] = 0x00; // result should always be a valid secret key
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(feature = "fuzztarget")]
|
||||||
|
pub use self::fuzz_dummy::*;
|
||||||
|
|
Loading…
Reference in New Issue