Merge pull request #264 from rust-bitcoin/2020-12--no-extsymb2

redo fuzz target
This commit is contained in:
Andrew Poelstra 2020-12-28 19:48:11 +00:00 committed by GitHub
commit 867b920aac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 222 additions and 586 deletions

View File

@ -34,11 +34,16 @@ if [ "$DO_FEATURE_MATRIX" = true ]; then
done
# Other combos
RUSTFLAGS='--cfg=rust_secp_fuzz' cargo test --no-run --all
RUSTFLAGS='--cfg=rust_secp_fuzz' cargo test --no-run --all --features="recovery"
RUSTFLAGS='--cfg=rust_secp_fuzz' RUSTDOCFLAGS=$RUSTFLAGS cargo test --all
RUSTFLAGS='--cfg=rust_secp_fuzz' RUSTDOCFLAGS=$RUSTFLAGS cargo test --all --features="$FEATURES"
cargo test --all --features="rand rand-std"
cargo test --all --features="rand serde"
if [ "$DO_BENCH" = true ]; then # proxy for us having a nightly compiler
cargo test --all --all-features
RUSTFLAGS='--cfg=rust_secp_fuzz' RUSTDOCFLAGS='--cfg=rust_secp_fuzz' cargo test --all --all-features
fi
# Examples
cargo run --example sign_verify
cargo run --example sign_verify_recovery --features=recovery

View File

@ -58,36 +58,37 @@ pub const SECP256K1_SER_COMPRESSED: c_uint = (1 << 1) | (1 << 8);
/// around the FFI functions to use it. And it's an unsafe type.
/// Nonces are generated deterministically by RFC6979 by
/// default; there should be no need to ever change this.
pub type NonceFn = unsafe extern "C" fn(nonce32: *mut c_uchar,
msg32: *const c_uchar,
key32: *const c_uchar,
algo16: *const c_uchar,
data: *mut c_void,
attempt: c_uint,
) -> c_int;
pub type NonceFn = Option<unsafe extern "C" fn(
nonce32: *mut c_uchar,
msg32: *const c_uchar,
key32: *const c_uchar,
algo16: *const c_uchar,
data: *mut c_void,
attempt: c_uint,
) -> c_int>;
/// Hash function to use to post-process an ECDH point to get
/// a shared secret.
pub type EcdhHashFn = unsafe extern "C" fn(
pub type EcdhHashFn = Option<unsafe extern "C" fn(
output: *mut c_uchar,
x: *const c_uchar,
y: *const c_uchar,
data: *mut c_void,
) -> c_int;
) -> c_int>;
/// Same as secp256k1_nonce function with the exception of accepting an
/// additional pubkey argument and not requiring an attempt argument. The pubkey
/// argument can protect signature schemes with key-prefixed challenge hash
/// inputs against reusing the nonce when signing with the wrong precomputed
/// pubkey.
pub type SchnorrNonceFn = unsafe extern "C" fn(
pub type SchnorrNonceFn = Option<unsafe extern "C" fn(
nonce32: *mut c_uchar,
msg32: *const c_uchar,
key32: *const c_uchar,
xonly_pk32: *const c_uchar,
algo16: *const c_uchar,
data: *mut c_void,
) -> c_int;
) -> c_int>;
/// A Secp256k1 context, containing various precomputed values and such
/// needed to do elliptic curve computations. If you create one of these
@ -96,13 +97,6 @@ pub type SchnorrNonceFn = unsafe extern "C" fn(
#[derive(Clone, Debug)]
#[repr(C)] pub struct Context(c_int);
#[cfg(rust_secp_fuzz)]
impl Context {
pub fn flags(&self) -> u32 {
self.0 as u32
}
}
/// Library-internal representation of a Secp256k1 public key
#[repr(C)]
pub struct PublicKey([c_uchar; 64]);
@ -263,7 +257,6 @@ impl hash::Hash for KeyPair {
}
}
#[cfg(not(rust_secp_fuzz))]
extern "C" {
/// Default ECDH hash function
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_ecdh_hash_function_default")]
@ -275,6 +268,9 @@ extern "C" {
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_nonce_function_default")]
pub static secp256k1_nonce_function_default: NonceFn;
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_nonce_function_bip340")]
pub static secp256k1_nonce_function_bip340: SchnorrNonceFn;
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_context_no_precomp")]
pub static secp256k1_context_no_precomp: *const Context;
@ -342,35 +338,10 @@ extern "C" {
in_sig: *const Signature)
-> c_int;
// ECDSA
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_ecdsa_verify")]
pub fn secp256k1_ecdsa_verify(cx: *const Context,
sig: *const Signature,
msg32: *const c_uchar,
pk: *const PublicKey)
-> c_int;
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_ecdsa_sign")]
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;
// EC
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_ec_seckey_verify")]
pub fn secp256k1_ec_seckey_verify(cx: *const Context,
sk: *const c_uchar) -> c_int;
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_ec_pubkey_create")]
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
#[deprecated(since = "0.2.0",note = "Please use the secp256k1_ec_seckey_tweak_add function instead")]
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_ec_privkey_negate")]
pub fn secp256k1_ec_privkey_negate(cx: *const Context,
@ -380,10 +351,6 @@ extern "C" {
pub fn secp256k1_ec_seckey_negate(cx: *const Context,
sk: *mut c_uchar) -> c_int;
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_ec_pubkey_negate")]
pub fn secp256k1_ec_pubkey_negate(cx: *const Context,
pk: *mut PublicKey) -> c_int;
#[deprecated(since = "0.2.0",note = "Please use the secp256k1_ec_seckey_tweak_add function instead")]
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_ec_privkey_tweak_add")]
pub fn secp256k1_ec_privkey_tweak_add(cx: *const Context,
@ -397,12 +364,6 @@ extern "C" {
tweak: *const c_uchar)
-> c_int;
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_ec_pubkey_tweak_add")]
pub fn secp256k1_ec_pubkey_tweak_add(cx: *const Context,
pk: *mut PublicKey,
tweak: *const c_uchar)
-> c_int;
#[deprecated(since = "0.2.0",note = "Please use the secp256k1_ec_seckey_tweak_mul function instead")]
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_ec_privkey_tweak_mul")]
pub fn secp256k1_ec_privkey_tweak_mul(cx: *const Context,
@ -416,6 +377,23 @@ extern "C" {
tweak: *const c_uchar)
-> c_int;
// EC
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_ec_pubkey_create")]
pub fn secp256k1_ec_pubkey_create(cx: *const Context, pk: *mut PublicKey,
sk: *const c_uchar) -> c_int;
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_ec_pubkey_negate")]
pub fn secp256k1_ec_pubkey_negate(cx: *const Context,
pk: *mut PublicKey) -> c_int;
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_ec_pubkey_tweak_add")]
pub fn secp256k1_ec_pubkey_tweak_add(cx: *const Context,
pk: *mut PublicKey,
tweak: *const c_uchar)
-> c_int;
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_ec_pubkey_tweak_mul")]
pub fn secp256k1_ec_pubkey_tweak_mul(cx: *const Context,
pk: *mut PublicKey,
@ -439,31 +417,7 @@ extern "C" {
data: *mut c_void,
) -> c_int;
// Schnorr Signatures
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_nonce_function_bip340")]
pub static secp256k1_nonce_function_bip340: SchnorrNonceFn;
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_schnorrsig_sign")]
pub fn secp256k1_schnorrsig_sign(
cx: *const Context,
sig: *mut c_uchar,
msg32: *const c_uchar,
keypair: *const KeyPair,
noncefp: SchnorrNonceFn,
noncedata: *const c_void
) -> c_int;
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_schnorrsig_verify")]
pub fn secp256k1_schnorrsig_verify(
cx: *const Context,
sig64: *const c_uchar,
msg32: *const c_uchar,
pubkey: *const XOnlyPublicKey,
) -> c_int;
// Extra keys
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_keypair_create")]
pub fn secp256k1_keypair_create(
cx: *const Context,
@ -526,6 +480,45 @@ extern "C" {
) -> c_int;
}
#[cfg(not(rust_secp_fuzz))]
extern "C" {
// ECDSA
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_ecdsa_verify")]
pub fn secp256k1_ecdsa_verify(cx: *const Context,
sig: *const Signature,
msg32: *const c_uchar,
pk: *const PublicKey)
-> c_int;
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_ecdsa_sign")]
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;
// Schnorr Signatures
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_schnorrsig_sign")]
pub fn secp256k1_schnorrsig_sign(
cx: *const Context,
sig: *mut c_uchar,
msg32: *const c_uchar,
keypair: *const KeyPair,
noncefp: SchnorrNonceFn,
noncedata: *const c_void
) -> c_int;
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_schnorrsig_verify")]
pub fn secp256k1_schnorrsig_verify(
cx: *const Context,
sig64: *const c_uchar,
msg32: *const c_uchar,
pubkey: *const XOnlyPublicKey,
) -> c_int;
}
/// A reimplementation of the C function `secp256k1_context_create` in rust.
///
@ -674,221 +667,31 @@ impl<T> CPtr for [T] {
}
}
#[cfg(rust_secp_fuzz)]
mod fuzz_dummy {
extern crate std;
use self::std::{ptr, mem};
use self::std::boxed::Box;
use types::*;
use {Signature, Context, NonceFn, EcdhHashFn, PublicKey,
SchnorrNonceFn, XOnlyPublicKey, KeyPair,
SECP256K1_START_NONE, SECP256K1_START_VERIFY, SECP256K1_START_SIGN,
SECP256K1_SER_COMPRESSED, SECP256K1_SER_UNCOMPRESSED};
#[allow(non_upper_case_globals)]
pub static secp256k1_context_no_precomp: &Context = &Context(0);
extern "C" {
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_ecdh_hash_function_default")]
pub static secp256k1_ecdh_hash_function_default: EcdhHashFn;
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_nonce_function_rfc6979")]
pub static secp256k1_nonce_function_rfc6979: NonceFn;
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_nonce_function_bip340")]
pub static secp256k1_nonce_function_bip340: SchnorrNonceFn;
}
// Contexts
/// Creates a dummy context, tracking flags to ensure proper calling semantics
pub unsafe fn secp256k1_context_preallocated_create(_ptr: *mut c_void, flags: c_uint) -> *mut Context {
let b = Box::new(Context(flags as i32));
Box::into_raw(b)
}
/// Return dummy size of context struct.
pub unsafe fn secp256k1_context_preallocated_size(_flags: c_uint) -> size_t {
mem::size_of::<Context>()
}
/// Return dummy size of context struct.
pub unsafe fn secp256k1_context_preallocated_clone_size(_cx: *mut Context) -> size_t {
mem::size_of::<Context>()
}
/// Copies a dummy context
pub unsafe fn secp256k1_context_preallocated_clone(cx: *const Context, prealloc: *mut c_void) -> *mut Context {
let ret = prealloc as *mut Context;
*ret = (*cx).clone();
ret
}
/// "Destroys" a dummy context
pub unsafe fn secp256k1_context_preallocated_destroy(cx: *mut Context) {
(*cx).0 = 0;
}
/// 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
}
// 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.offset(1) > 0x7f && *input != 2) || (*input.offset(1) <= 0x7f && *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!();
}
/// Copies up to 72 bytes into output from sig
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 {
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
let mut len_r = 33;
if *(*sig).0.as_ptr().offset(0) < 0x80 {
len_r -= 1;
}
let mut len_s = 33;
if *(*sig).0.as_ptr().offset(32) < 0x80 {
len_s -= 1;
}
assert!(*out_len >= (6 + len_s + len_r) as usize);
*output.offset(0) = 0x30;
*output.offset(1) = 4 + len_r + len_s;
*output.offset(2) = 0x02;
*output.offset(3) = len_r;
if len_r == 33 {
*output.offset(4) = 0;
ptr::copy((*sig).0[..].as_ptr(), output.offset(5), 32);
} else {
ptr::copy((*sig).0[..].as_ptr(), output.offset(4), 32);
}
*output.offset(4 + len_r as isize) = 0x02;
*output.offset(5 + len_r as isize) = len_s;
if len_s == 33 {
*output.offset(6 + len_r as isize) = 0;
ptr::copy((*sig).0[..].as_ptr().offset(32), output.offset(7 + len_r as isize), 32);
} else {
ptr::copy((*sig).0[..].as_ptr().offset(32), output.offset(6 + len_r as isize), 32);
}
1
}
/// 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_signature_normalize(_cx: *const Context, _out_sig: *mut Signature,
_in_sig: *const Signature)
-> c_int {
unimplemented!();
}
use super::*;
// ECDSA
/// Verifies that sig is msg32||pk[0..32]
/// Verifies that sig is msg32||pk[..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 {
// Check context is built for verification
let mut new_pk = (*pk).clone();
let _ = secp256k1_ec_pubkey_tweak_add(cx, &mut new_pk, msg32);
// Actually verify
let sig_sl = slice::from_raw_parts(sig as *const u8, 64);
let msg_sl = slice::from_raw_parts(msg32 as *const u8, 32);
if &sig_sl[..32] == msg_sl && sig_sl[32..] == (*pk).0[0..32] {
1
} else {
0
}
}
/// Sets sig to msg32||sk
/// Sets sig to msg32||pk[..32]
pub unsafe fn secp256k1_ecdsa_sign(cx: *const Context,
sig: *mut Signature,
msg32: *const c_uchar,
@ -896,274 +699,66 @@ mod fuzz_dummy {
_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
}
// 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
// Check context is built for signing (and compute pk)
let mut new_pk = PublicKey::new();
if secp256k1_ec_pubkey_create(cx, &mut new_pk, sk) != 1 {
return 0;
}
}
/// 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);
// Sign
let sig_sl = slice::from_raw_parts_mut(sig as *mut u8, 64);
let msg_sl = slice::from_raw_parts(msg32 as *const u8, 32);
sig_sl[..32].copy_from_slice(msg_sl);
sig_sl[32..].copy_from_slice(&new_pk.0[..32]);
1
}
//TODO secp256k1_ec_privkey_export
//TODO secp256k1_ec_privkey_import
#[deprecated(since = "0.2.0",note = "Please use the secp256k1_ec_seckey_negate function instead")]
pub unsafe fn secp256k1_ec_privkey_negate(cx: *const Context,
sk: *mut c_uchar) -> c_int {
secp256k1_ec_seckey_negate(cx, sk)
}
pub unsafe fn secp256k1_ec_seckey_negate(cx: *const Context,
sk: *mut 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; }
1
}
pub unsafe fn secp256k1_ec_pubkey_negate(cx: *const Context,
pk: *mut PublicKey) -> 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; }
1
}
/// 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 {
secp256k1_ec_seckey_tweak_add(cx, sk, tweak)
}
pub unsafe fn secp256k1_ec_seckey_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.offset(16), 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.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] = 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 {
secp256k1_ec_seckey_tweak_mul(cx, sk, tweak)
}
/// Copies the last 16 bytes of tweak into the last 16 bytes of sk
pub unsafe fn secp256k1_ec_seckey_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] = 0x7f; // pk should always be valid
(*out).0[24+32] = 0x7f; // 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 c_uchar,
point: *const PublicKey,
scalar: *const c_uchar,
_hashfp: EcdhHashFn,
_data: *mut c_void,
) -> 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, scalar) != 1 { return 0; }
let mut scalar_prefix = [0; 16];
ptr::copy(scalar, scalar_prefix[..].as_mut_ptr(), 16);
if (*point).0[0..16] > scalar_prefix[0..16] {
ptr::copy((*point).as_ptr(), out, 16);
ptr::copy(scalar, out.offset(16), 16);
} else {
ptr::copy(scalar, out, 16);
ptr::copy((*point).as_ptr(), out.offset(16), 16);
}
(*out.offset(16)) = 0x00; // result should always be a valid secret key
1
}
pub unsafe fn secp256k1_schnorrsig_sign(
_cx: *const Context,
_sig: *mut c_uchar,
_msg32: *const c_uchar,
_keypair: *const KeyPair,
_noncefp: SchnorrNonceFn,
_noncedata: *const c_void
) -> c_int {
unimplemented!();
}
/// Verifies that sig is msg32||pk[32..]
pub unsafe fn secp256k1_schnorrsig_verify(
_cx: *const Context,
_sig64: *const c_uchar,
_msg32: *const c_uchar,
_pubkey: *const XOnlyPublicKey,
cx: *const Context,
sig64: *const c_uchar,
msg32: *const c_uchar,
pubkey: *const XOnlyPublicKey,
) -> c_int {
unimplemented!();
// Check context is built for verification
let mut new_pk = PublicKey::new();
let _ = secp256k1_xonly_pubkey_tweak_add(cx, &mut new_pk, pubkey, msg32);
// Actually verify
let sig_sl = slice::from_raw_parts(sig64 as *const u8, 64);
let msg_sl = slice::from_raw_parts(msg32 as *const u8, 32);
if &sig_sl[..32] == msg_sl && sig_sl[32..] == (*pubkey).0[..32] {
1
} else {
0
}
}
pub fn secp256k1_xonly_pubkey_parse(
_cx: *const Context,
_pubkey: *mut XOnlyPublicKey,
_input32: *const c_uchar,
/// Sets sig to msg32||pk[..32]
pub unsafe fn secp256k1_schnorrsig_sign(
cx: *const Context,
sig64: *mut c_uchar,
msg32: *const c_uchar,
keypair: *const KeyPair,
noncefp: SchnorrNonceFn,
noncedata: *const c_void
) -> c_int {
unimplemented!();
}
pub fn secp256k1_xonly_pubkey_serialize(
_cx: *const Context,
_output32: *mut c_uchar,
_pubkey: *const XOnlyPublicKey,
) -> c_int {
unimplemented!();
}
pub unsafe fn secp256k1_xonly_pubkey_from_pubkey(
_cx: *const Context,
_xonly_pubkey: *mut XOnlyPublicKey,
_pk_parity: *mut c_int,
_pubkey: *const PublicKey,
) -> c_int {
unimplemented!();
}
pub unsafe fn secp256k1_keypair_create(
_cx: *const Context,
_keypair: *mut KeyPair,
_seckey: *const c_uchar,
) -> c_int {
unimplemented!();
}
pub unsafe fn secp256k1_xonly_pubkey_tweak_add(
_cx: *const Context,
_output_pubkey: *mut PublicKey,
_internal_pubkey: *const XOnlyPublicKey,
_tweak32: *const c_uchar,
) -> c_int {
unimplemented!();
}
pub unsafe fn secp256k1_keypair_xonly_pub(
_cx: *const Context,
_pubkey: *mut XOnlyPublicKey,
_pk_parity: *mut c_int,
_keypair: *const KeyPair
) -> c_int {
unimplemented!();
}
pub unsafe fn secp256k1_keypair_xonly_tweak_add(
_cx: *const Context,
_keypair: *mut KeyPair,
_tweak32: *const c_uchar,
) -> c_int {
unimplemented!();
}
pub unsafe fn secp256k1_xonly_pubkey_tweak_add_check(
_cx: *const Context,
_tweaked_pubkey32: *const c_uchar,
_tweaked_pubkey_parity: c_int,
_internal_pubkey: *const XOnlyPublicKey,
_tweak32: *const c_uchar,
) -> c_int {
unimplemented!();
// Check context is built for signing
let mut new_kp = KeyPair::new();
if secp256k1_keypair_create(cx, &mut new_kp, (*keypair).0.as_ptr()) != 1 {
return 0;
}
assert_eq!(new_kp, *keypair);
// Sign
let sig_sl = slice::from_raw_parts_mut(sig64 as *mut u8, 64);
let msg_sl = slice::from_raw_parts(msg32 as *const u8, 32);
sig_sl[..32].copy_from_slice(msg_sl);
sig_sl[32..].copy_from_slice(&new_kp.0[32..64]);
1
}
}
#[cfg(rust_secp_fuzz)]
pub use self::fuzz_dummy::*;
#[cfg(test)]
mod tests {
#[no_mangle]

View File

@ -16,8 +16,7 @@
//! # FFI of the recovery module
use ::types::*;
#[cfg(not(rust_secp_fuzz))]
use ::{Context, Signature, NonceFn, PublicKey};
use {Context, Signature, NonceFn, PublicKey};
/// Library-internal representation of a Secp256k1 signature + recovery ID
#[repr(C)]
@ -36,7 +35,6 @@ impl Default for RecoverableSignature {
}
}
#[cfg(not(rust_secp_fuzz))]
extern "C" {
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_ecdsa_recoverable_signature_parse_compact")]
pub fn secp256k1_ecdsa_recoverable_signature_parse_compact(cx: *const Context, sig: *mut RecoverableSignature,
@ -52,6 +50,10 @@ extern "C" {
pub fn secp256k1_ecdsa_recoverable_signature_convert(cx: *const Context, sig: *mut Signature,
input: *const RecoverableSignature)
-> c_int;
}
#[cfg(not(rust_secp_fuzz))]
extern "C" {
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_3_1_ecdsa_sign_recoverable")]
pub fn secp256k1_ecdsa_sign_recoverable(cx: *const Context,
sig: *mut RecoverableSignature,
@ -72,58 +74,76 @@ extern "C" {
#[cfg(rust_secp_fuzz)]
mod fuzz_dummy {
extern crate std;
use self::std::ptr;
use super::RecoverableSignature;
use types::*;
use ::{Signature, Context, PublicKey, NonceFn, secp256k1_ec_seckey_verify,
SECP256K1_START_NONE, SECP256K1_START_VERIFY, SECP256K1_START_SIGN};
use super::*;
use std::slice;
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!();
}
use secp256k1_ec_pubkey_create;
use secp256k1_ec_pubkey_parse;
use secp256k1_ec_pubkey_serialize;
use SECP256K1_SER_COMPRESSED;
pub unsafe fn secp256k1_ecdsa_recoverable_signature_serialize_compact(_cx: *const Context, _output64: *mut 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!();
}
/// 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).flags() & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
assert!((*cx).flags() & 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;
/// Sets sig to msg32||full pk
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 {
// Check context is built for signing (and compute pk)
let mut new_pk = PublicKey::new();
if secp256k1_ec_pubkey_create(cx, &mut new_pk, sk) != 1 {
return 0;
}
ptr::copy(msg32, (*sig).0[1..33].as_mut_ptr(), 32);
ptr::copy(sk, (*sig).0[33..65].as_mut_ptr(), 32);
// Sign
let sig_sl = slice::from_raw_parts_mut(sig as *mut u8, 65);
let msg_sl = slice::from_raw_parts(msg32 as *const u8, 32);
sig_sl[..32].copy_from_slice(msg_sl);
let mut out_len: size_t = 33;
secp256k1_ec_pubkey_serialize(cx, sig_sl[32..].as_mut_ptr(), &mut out_len, &new_pk, SECP256K1_SER_COMPRESSED);
// Encode the parity of the pubkey in the final byte as 0/1,
// which is the same encoding (though the parity is computed
// differently) as real recoverable signatures.
sig_sl.swap(32, 64);
sig_sl[64] -= 2;
1
}
pub unsafe fn secp256k1_ecdsa_recover(_cx: *const Context,
_pk: *mut PublicKey,
_sig: *const RecoverableSignature,
_msg32: *const c_uchar)
-> c_int {
unimplemented!();
pub unsafe fn secp256k1_ecdsa_recover(
cx: *const Context,
pk: *mut PublicKey,
sig: *const RecoverableSignature,
msg32: *const c_uchar
) -> c_int {
let sig_sl = slice::from_raw_parts(sig as *const u8, 65);
let msg_sl = slice::from_raw_parts(msg32 as *const u8, 32);
if sig_sl[64] >= 4 {
return 0;
}
// Pull the original pk out of the siganture
let mut pk_ser = [0; 33];
pk_ser.copy_from_slice(&sig_sl[32..]);
pk_ser.swap(0, 32);
pk_ser[0] += 2;
// Check that it parses (in a real sig, this would be the R value,
// so it is actually required to be a valid point)
if secp256k1_ec_pubkey_parse(cx, pk, pk_ser.as_ptr(), 33) == 0 {
return 0;
}
// Munge it up so that a different message will give a different pk
for i in 0..32 {
pk_ser[i + 1] ^= sig_sl[i] ^ msg_sl[i];
}
// If any munging happened, this will fail parsing half the time, so
// tweak-and-loop until we find a key that works.
let mut idx = 0;
while secp256k1_ec_pubkey_parse(cx, pk, pk_ser.as_ptr(), 33) == 0 {
pk_ser[1 + idx / 8] ^= 1 << (idx % 8);
idx += 1;
}
1
}
}
#[cfg(rust_secp_fuzz)]

View File

@ -151,7 +151,7 @@ impl SharedSecret {
xy.as_mut_ptr(),
point.as_ptr(),
scalar.as_ptr(),
c_callback,
Some(c_callback),
ptr::null_mut(),
)
};

View File

@ -103,6 +103,7 @@
//! 0xc9, 0x42, 0x8f, 0xca, 0x69, 0xc1, 0x32, 0xa2,
//! ]).expect("compact signatures are 64 bytes; DER signatures are 68-72 bytes");
//!
//! # #[cfg(not(rust_secp_fuzz))]
//! assert!(secp.verify(&message, &sig, &public_key).is_ok());
//! ```
//!
@ -735,6 +736,10 @@ impl<C: Signing> Secp256k1<C> {
}
entropy_p = extra_entropy.as_ptr() as *const ffi::types::c_void;
// When fuzzing, these checks will usually spinloop forever, so just short-circuit them.
#[cfg(rust_secp_fuzz)]
return Signature::from(ret);
}
}
}
@ -1097,9 +1102,12 @@ mod tests {
if compact[0] < 0x80 {
assert_eq!(sig, low_r_sig);
} else {
#[cfg(not(rust_secp_fuzz))] // mocked sig generation doesn't produce low-R sigs
assert_ne!(sig, low_r_sig);
}
#[cfg(not(rust_secp_fuzz))] // mocked sig generation doesn't produce low-R sigs
assert!(super::compact_sig_has_zero_first_bit(&low_r_sig.0));
#[cfg(not(rust_secp_fuzz))] // mocked sig generation doesn't produce low-R sigs
assert!(super::der_length_check(&grind_r_sig.0, 70));
}
}
@ -1172,6 +1180,7 @@ mod tests {
}
#[test]
#[cfg(not(rust_secp_fuzz))] // fixed sig vectors can't work with fuzz-sigs
fn test_low_s() {
// nb this is a transaction on testnet
// txid 8ccc87b72d766ab3128f03176bb1c98293f2d1f85ebfaf07b82cc81ea6891fa9
@ -1193,6 +1202,7 @@ mod tests {
}
#[test]
#[cfg(not(rust_secp_fuzz))] // fuzz-sigs have fixed size/format
fn test_low_r() {
let secp = Secp256k1::new();
let msg = hex!("887d04bb1cf1b1554f1b268dfe62d13064ca67ae45348d50d1392ce2d13418ac");
@ -1207,6 +1217,7 @@ mod tests {
}
#[test]
#[cfg(not(rust_secp_fuzz))] // fuzz-sigs have fixed size/format
fn test_grind_r() {
let secp = Secp256k1::new();
let msg = hex!("ef2d5b9a7c61865a95941d0f04285420560df7e9d76890ac1b8867b12ce43167");
@ -1220,6 +1231,7 @@ mod tests {
}
#[cfg(feature = "serde")]
#[cfg(not(rust_secp_fuzz))] // fixed sig vectors can't work with fuzz-sigs
#[test]
fn test_signature_serde() {
use serde_test::{Configure, Token, assert_tokens};

View File

@ -235,6 +235,7 @@ mod tests {
}
#[test]
#[cfg(not(rust_secp_fuzz))] // fixed sig vectors can't work with fuzz-sigs
fn sign() {
let mut s = Secp256k1::new();
s.randomize(&mut thread_rng());

View File

@ -561,6 +561,7 @@ mod tests {
}
#[test]
#[cfg(not(rust_secp_fuzz))] // fixed sig vectors can't work with fuzz-sigs
fn test_schnorrsig_sign() {
let secp = Secp256k1::new();
@ -582,6 +583,7 @@ mod tests {
}
#[test]
#[cfg(not(rust_secp_fuzz))] // fixed sig vectors can't work with fuzz-sigs
fn test_schnorrsig_verify() {
let secp = Secp256k1::new();
@ -720,6 +722,7 @@ mod tests {
}
#[cfg(feature = "serde")]
#[cfg(not(rust_secp_fuzz))] // fixed sig vectors can't work with fuzz-sigs
#[test]
fn test_signature_serde() {
use serde_test::{assert_tokens, Configure, Token};