From b811ec133a0628f9db0e452abf84b8e302737f58 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Tue, 22 Dec 2020 20:16:10 +0000 Subject: [PATCH] fuzz: only replace signing and verification, leave everything else alone We can now run unit tests with the fuzz feature on, and they'll pass, which is some assurance that fuzzing with the feature on won't lead to spurious failures due to the fuzz harness inadequately simulating message signing. --- secp256k1-sys/src/lib.rs | 631 +++++++-------------------------------- src/lib.rs | 1 + src/schnorrsig.rs | 2 + 3 files changed, 119 insertions(+), 515 deletions(-) diff --git a/secp256k1-sys/src/lib.rs b/secp256k1-sys/src/lib.rs index d0f95fa..7a8d666 100644 --- a/secp256k1-sys/src/lib.rs +++ b/secp256k1-sys/src/lib.rs @@ -264,7 +264,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")] @@ -276,6 +275,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; @@ -343,35 +345,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, @@ -381,10 +358,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, @@ -398,12 +371,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, @@ -417,6 +384,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, @@ -440,31 +424,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, @@ -527,6 +487,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. /// @@ -675,221 +674,31 @@ impl 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::() - } - - /// Return dummy size of context struct. - pub unsafe fn secp256k1_context_preallocated_clone_size(_cx: *mut Context) -> size_t { - mem::size_of::() - } - - /// 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, @@ -897,274 +706,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] diff --git a/src/lib.rs b/src/lib.rs index 9016d0b..b4eddd7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1172,6 +1172,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 diff --git a/src/schnorrsig.rs b/src/schnorrsig.rs index c55fca1..f637456 100644 --- a/src/schnorrsig.rs +++ b/src/schnorrsig.rs @@ -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();