-
Notifications
You must be signed in to change notification settings - Fork 272
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix fuzzing cfg rtt bug for uncompressed keys #322
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -680,6 +680,15 @@ impl<T> CPtr for [T] { | |
|
||
#[cfg(fuzzing)] | ||
mod fuzz_dummy { | ||
/// Serialization logic: | ||
/// If pk is created from sk keypair: | ||
/// - It is serialized with prefix 0x02: sk || [0xaa;32] | ||
/// If pk is created from from slice: | ||
/// - 0x02||pk_bytes -> pk_bytes||[0xaa;32] | ||
/// - 0x03||pk_bytes -> pk_bytes||[0xbb;32] | ||
/// - 0x04||pk_bytes -> pk_bytes | ||
/// This leaves the room for collision between compressed and uncompressed pks, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wait, maybe I'm confused by this. What is the collision here and why would it ever be an issue? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Never mind, this is not an issue. But what I meant by collision is the following
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Public keys don't, themselves, have any concept of "compressed" or not? That's purely a serialization-time difference, no? |
||
/// but as such collisions should be improbable. 2/2^128 | ||
use super::*; | ||
use core::sync::atomic::{AtomicUsize, Ordering}; | ||
|
||
|
@@ -770,26 +779,16 @@ mod fuzz_dummy { | |
assert_eq!(cx_flags & required_flags, required_flags); | ||
} | ||
|
||
/// Checks that pk != 0xffff...ffff and pk[1..32] == pk[33..64] | ||
/// Checks that pk is valid | ||
unsafe fn test_pk_validate(cx: *const Context, | ||
pk: *const PublicKey) -> c_int { | ||
check_context_flags(cx, 0); | ||
if (*pk).0[1..32] != (*pk).0[33..64] || | ||
((*pk).0[32] != 0 && (*pk).0[32] != 0xff) || | ||
secp256k1_ec_seckey_verify(cx, (*pk).0[0..32].as_ptr()) == 0 { | ||
if secp256k1_ec_seckey_verify(cx, (*pk).0[0..32].as_ptr()) == 0 { | ||
0 | ||
} else { | ||
1 | ||
} | ||
} | ||
unsafe fn test_cleanup_pk(pk: *mut PublicKey) { | ||
(*pk).0[32..].copy_from_slice(&(*pk).0[..32]); | ||
if (*pk).0[32] <= 0x7f { | ||
(*pk).0[32] = 0; | ||
} else { | ||
(*pk).0[32] = 0xff; | ||
} | ||
} | ||
|
||
// Pubkeys | ||
pub unsafe fn secp256k1_ec_pubkey_parse(cx: *const Context, pk: *mut PublicKey, | ||
|
@@ -802,11 +801,10 @@ mod fuzz_dummy { | |
0 | ||
} else { | ||
ptr::copy(input.offset(1), (*pk).0[0..32].as_mut_ptr(), 32); | ||
ptr::copy(input.offset(2), (*pk).0[33..64].as_mut_ptr(), 31); | ||
if *input == 3 { | ||
(*pk).0[32] = 0xff; | ||
ptr::write_bytes((*pk).0[32..64].as_mut_ptr(), 0xbb, 32); | ||
} else { | ||
(*pk).0[32] = 0; | ||
ptr::write_bytes((*pk).0[32..64].as_mut_ptr(), 0xaa, 32); | ||
} | ||
test_pk_validate(cx, pk) | ||
} | ||
|
@@ -816,7 +814,6 @@ mod fuzz_dummy { | |
0 | ||
} else { | ||
ptr::copy(input.offset(1), (*pk).0.as_mut_ptr(), 64); | ||
test_cleanup_pk(pk); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we instead just drop this line and keep the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had to change how keys are stored and the function |
||
test_pk_validate(cx, pk) | ||
} | ||
}, | ||
|
@@ -833,10 +830,10 @@ mod fuzz_dummy { | |
assert_eq!(test_pk_validate(cx, pk), 1); | ||
if compressed == SECP256K1_SER_COMPRESSED { | ||
assert_eq!(*out_len, 33); | ||
if (*pk).0[32] <= 0x7f { | ||
*output = 2; | ||
} else { | ||
if &(*pk).0[32..64] == &[0xbb; 32] { | ||
*output = 3; | ||
} else { | ||
*output = 2; | ||
} | ||
ptr::copy((*pk).0.as_ptr(), output.offset(1), 32); | ||
} else if compressed == SECP256K1_SER_UNCOMPRESSED { | ||
|
@@ -856,7 +853,7 @@ mod fuzz_dummy { | |
check_context_flags(cx, SECP256K1_START_SIGN); | ||
if secp256k1_ec_seckey_verify(cx, sk) != 1 { return 0; } | ||
ptr::copy(sk, (*pk).0[0..32].as_mut_ptr(), 32); | ||
test_cleanup_pk(pk); | ||
ptr::write_bytes((*pk).0[32..64].as_mut_ptr(), 0xaa, 32); | ||
assert_eq!(test_pk_validate(cx, pk), 1); | ||
1 | ||
} | ||
|
@@ -866,7 +863,6 @@ mod fuzz_dummy { | |
check_context_flags(cx, 0); | ||
assert_eq!(test_pk_validate(cx, pk), 1); | ||
if secp256k1_ec_seckey_negate(cx, (*pk).0[..32].as_mut_ptr()) != 1 { return 0; } | ||
test_cleanup_pk(pk); | ||
assert_eq!(test_pk_validate(cx, pk), 1); | ||
1 | ||
} | ||
|
@@ -879,7 +875,6 @@ mod fuzz_dummy { | |
check_context_flags(cx, SECP256K1_START_VERIFY); | ||
assert_eq!(test_pk_validate(cx, pk), 1); | ||
if secp256k1_ec_seckey_tweak_add(cx, (*pk).0[..32].as_mut_ptr(), tweak) != 1 { return 0; } | ||
test_cleanup_pk(pk); | ||
assert_eq!(test_pk_validate(cx, pk), 1); | ||
1 | ||
} | ||
|
@@ -892,7 +887,6 @@ mod fuzz_dummy { | |
check_context_flags(cx, 0); | ||
assert_eq!(test_pk_validate(cx, pk), 1); | ||
if secp256k1_ec_seckey_tweak_mul(cx, (*pk).0[..32].as_mut_ptr(), tweak) != 1 { return 0; } | ||
test_cleanup_pk(pk); | ||
assert_eq!(test_pk_validate(cx, pk), 1); | ||
1 | ||
} | ||
|
@@ -911,7 +905,6 @@ mod fuzz_dummy { | |
return 0; | ||
} | ||
} | ||
test_cleanup_pk(out); | ||
assert_eq!(test_pk_validate(cx, out), 1); | ||
1 | ||
} | ||
|
@@ -1059,8 +1052,7 @@ mod fuzz_dummy { | |
check_context_flags(cx, 0); | ||
let inslice = slice::from_raw_parts(input32, 32); | ||
(*pubkey).0[..32].copy_from_slice(inslice); | ||
(*pubkey).0[32..].copy_from_slice(inslice); | ||
test_cleanup_pk(pubkey as *mut PublicKey); | ||
ptr::write_bytes((*pubkey).0[32..64].as_mut_ptr(), 0xaa, 32); | ||
test_pk_validate(cx, pubkey as *mut PublicKey) | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These types of patterns are exactly the kind of things fuzzers are good at finding. Why not just store an extra byte in memory?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is exceeding the 64 bytes and using space beyond the 64 bytes a good idea?
Because we need all of 64 bytes to support full roundtrip of uncompressed keys.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had another related question, why do you need to serialize/parse functions for fuzzing anyway? Can we just not use regular logic for it.
For forging signatures, the keys are anyways created by
secp256k1_ec_pubkey_create
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, we cannot switch to requiring public keys be valid according to standard rules. Not only does it break the RL fuzzers (see #271) but its also really slow, which can make fuzzers untenable.