Skip to content

Commit 4b06f20

Browse files
committed
fix cfg(fuzzing) roundtrip of uncompressed keys
1 parent 05f4278 commit 4b06f20

File tree

3 files changed

+32
-30
lines changed

3 files changed

+32
-30
lines changed

secp256k1-sys/src/lib.rs

+18-26
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,15 @@ impl<T> CPtr for [T] {
680680

681681
#[cfg(fuzzing)]
682682
mod fuzz_dummy {
683+
/// Serialization logic:
684+
/// If pk is created from sk keypair:
685+
/// - It is serialized with prefix 0x02: sk || [0xaa;32]
686+
/// If pk is created from from slice:
687+
/// - 0x02||pk_bytes -> pk_bytes||[0xaa;32]
688+
/// - 0x03||pk_bytes -> pk_bytes||[0xbb;32]
689+
/// - 0x04||pk_bytes -> pk_bytes
690+
/// This leaves the room for collision between compressed and uncompressed pks,
691+
/// but as such collisions should be improbable. 2/2^128
683692
use super::*;
684693
use core::sync::atomic::{AtomicUsize, Ordering};
685694

@@ -770,26 +779,16 @@ mod fuzz_dummy {
770779
assert_eq!(cx_flags & required_flags, required_flags);
771780
}
772781

773-
/// Checks that pk != 0xffff...ffff and pk[1..32] == pk[33..64]
782+
/// Checks that pk is valid
774783
unsafe fn test_pk_validate(cx: *const Context,
775784
pk: *const PublicKey) -> c_int {
776785
check_context_flags(cx, 0);
777-
if (*pk).0[1..32] != (*pk).0[33..64] ||
778-
((*pk).0[32] != 0 && (*pk).0[32] != 0xff) ||
779-
secp256k1_ec_seckey_verify(cx, (*pk).0[0..32].as_ptr()) == 0 {
786+
if secp256k1_ec_seckey_verify(cx, (*pk).0[0..32].as_ptr()) == 0 {
780787
0
781788
} else {
782789
1
783790
}
784791
}
785-
unsafe fn test_cleanup_pk(pk: *mut PublicKey) {
786-
(*pk).0[32..].copy_from_slice(&(*pk).0[..32]);
787-
if (*pk).0[32] <= 0x7f {
788-
(*pk).0[32] = 0;
789-
} else {
790-
(*pk).0[32] = 0xff;
791-
}
792-
}
793792

794793
// Pubkeys
795794
pub unsafe fn secp256k1_ec_pubkey_parse(cx: *const Context, pk: *mut PublicKey,
@@ -802,11 +801,10 @@ mod fuzz_dummy {
802801
0
803802
} else {
804803
ptr::copy(input.offset(1), (*pk).0[0..32].as_mut_ptr(), 32);
805-
ptr::copy(input.offset(2), (*pk).0[33..64].as_mut_ptr(), 31);
806804
if *input == 3 {
807-
(*pk).0[32] = 0xff;
805+
ptr::write_bytes((*pk).0[32..64].as_mut_ptr(), 0xbb, 32);
808806
} else {
809-
(*pk).0[32] = 0;
807+
ptr::write_bytes((*pk).0[32..64].as_mut_ptr(), 0xaa, 32);
810808
}
811809
test_pk_validate(cx, pk)
812810
}
@@ -816,7 +814,6 @@ mod fuzz_dummy {
816814
0
817815
} else {
818816
ptr::copy(input.offset(1), (*pk).0.as_mut_ptr(), 64);
819-
test_cleanup_pk(pk);
820817
test_pk_validate(cx, pk)
821818
}
822819
},
@@ -833,10 +830,10 @@ mod fuzz_dummy {
833830
assert_eq!(test_pk_validate(cx, pk), 1);
834831
if compressed == SECP256K1_SER_COMPRESSED {
835832
assert_eq!(*out_len, 33);
836-
if (*pk).0[32] <= 0x7f {
837-
*output = 2;
838-
} else {
833+
if &(*pk).0[32..64] == &[0xbb; 32] {
839834
*output = 3;
835+
} else {
836+
*output = 2;
840837
}
841838
ptr::copy((*pk).0.as_ptr(), output.offset(1), 32);
842839
} else if compressed == SECP256K1_SER_UNCOMPRESSED {
@@ -856,7 +853,7 @@ mod fuzz_dummy {
856853
check_context_flags(cx, SECP256K1_START_SIGN);
857854
if secp256k1_ec_seckey_verify(cx, sk) != 1 { return 0; }
858855
ptr::copy(sk, (*pk).0[0..32].as_mut_ptr(), 32);
859-
test_cleanup_pk(pk);
856+
ptr::write_bytes((*pk).0[32..64].as_mut_ptr(), 0xaa, 32);
860857
assert_eq!(test_pk_validate(cx, pk), 1);
861858
1
862859
}
@@ -866,7 +863,6 @@ mod fuzz_dummy {
866863
check_context_flags(cx, 0);
867864
assert_eq!(test_pk_validate(cx, pk), 1);
868865
if secp256k1_ec_seckey_negate(cx, (*pk).0[..32].as_mut_ptr()) != 1 { return 0; }
869-
test_cleanup_pk(pk);
870866
assert_eq!(test_pk_validate(cx, pk), 1);
871867
1
872868
}
@@ -879,7 +875,6 @@ mod fuzz_dummy {
879875
check_context_flags(cx, SECP256K1_START_VERIFY);
880876
assert_eq!(test_pk_validate(cx, pk), 1);
881877
if secp256k1_ec_seckey_tweak_add(cx, (*pk).0[..32].as_mut_ptr(), tweak) != 1 { return 0; }
882-
test_cleanup_pk(pk);
883878
assert_eq!(test_pk_validate(cx, pk), 1);
884879
1
885880
}
@@ -892,7 +887,6 @@ mod fuzz_dummy {
892887
check_context_flags(cx, 0);
893888
assert_eq!(test_pk_validate(cx, pk), 1);
894889
if secp256k1_ec_seckey_tweak_mul(cx, (*pk).0[..32].as_mut_ptr(), tweak) != 1 { return 0; }
895-
test_cleanup_pk(pk);
896890
assert_eq!(test_pk_validate(cx, pk), 1);
897891
1
898892
}
@@ -911,7 +905,6 @@ mod fuzz_dummy {
911905
return 0;
912906
}
913907
}
914-
test_cleanup_pk(out);
915908
assert_eq!(test_pk_validate(cx, out), 1);
916909
1
917910
}
@@ -1059,8 +1052,7 @@ mod fuzz_dummy {
10591052
check_context_flags(cx, 0);
10601053
let inslice = slice::from_raw_parts(input32, 32);
10611054
(*pubkey).0[..32].copy_from_slice(inslice);
1062-
(*pubkey).0[32..].copy_from_slice(inslice);
1063-
test_cleanup_pk(pubkey as *mut PublicKey);
1055+
ptr::write_bytes((*pubkey).0[32..64].as_mut_ptr(), 0xaa, 32);
10641056
test_pk_validate(cx, pubkey as *mut PublicKey)
10651057
}
10661058

src/key.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -714,10 +714,20 @@ mod test {
714714
PublicKey::from_str("0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166").unwrap(),
715715
pk
716716
);
717+
#[cfg(fuzzing)]
718+
assert_eq!(
719+
PublicKey::from_str("04\
720+
18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166\
721+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
722+
).unwrap(),
723+
pk
724+
);
725+
println!("{:02x?}", pk.serialize_uncompressed());
726+
#[cfg(not(fuzzing))]
717727
assert_eq!(
718728
PublicKey::from_str("04\
719729
18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166\
720-
84B84DB303A340CD7D6823EE88174747D12A67D2F8F2F9BA40846EE5EE7A44F6"
730+
84b84db303a340cd7d6823ee88174747d12a67d2f8f2f9ba40846ee5ee7a44f6"
721731
).unwrap(),
722732
pk
723733
);

src/lib.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292
//! 0xd5, 0x44, 0x53, 0xcf, 0x6e, 0x82, 0xb4, 0x50,
9393
//! ]).expect("messages must be 32 bytes and are expected to be hashes");
9494
//!
95-
//! let sig = Signature::from_compact(&[
95+
//! let sig2 = Signature::from_compact(&[
9696
//! 0xdc, 0x4d, 0xc2, 0x64, 0xa9, 0xfe, 0xf1, 0x7a,
9797
//! 0x3f, 0x25, 0x34, 0x49, 0xcf, 0x8c, 0x39, 0x7a,
9898
//! 0xb6, 0xf1, 0x6f, 0xb3, 0xd6, 0x3d, 0x86, 0x94,
@@ -103,8 +103,8 @@
103103
//! 0xc9, 0x42, 0x8f, 0xca, 0x69, 0xc1, 0x32, 0xa2,
104104
//! ]).expect("compact signatures are 64 bytes; DER signatures are 68-72 bytes");
105105
//!
106-
//! # #[cfg(not(fuzzing))]
107-
//! assert!(secp.verify(&message, &sig, &public_key).is_ok());
106+
//! #[cfg(not(fuzzing))]
107+
//! assert!(secp.verify(&message, &sig2, &public_key).is_ok());
108108
//! ```
109109
//!
110110
//! Observe that the same code using, say [`signing_only`](struct.Secp256k1.html#method.signing_only)

0 commit comments

Comments
 (0)