Some checks failed
CI / lint (push) Successful in 1m37s
CI / test-python (push) Successful in 1m49s
CI / test-zig (push) Successful in 1m39s
CI / test-wasm (push) Successful in 1m54s
CI / test (push) Successful in 14m44s
CI / miri (push) Successful in 14m18s
CI / build (push) Successful in 1m9s
CI / fuzz-regression (push) Successful in 9m9s
CI / publish (push) Failing after 1m10s
CI / publish-python (push) Failing after 1m46s
CI / publish-wasm (push) Has been cancelled
Signed-off-by: Kamal Tufekcic <kamal@lo.sh>
44 lines
2.3 KiB
Rust
44 lines
2.3 KiB
Rust
#![no_main]
|
|
use libfuzzer_sys::fuzz_target;
|
|
use soliton::call::derive_call_keys;
|
|
|
|
// Fixed root key — exercises the HKDF-based key derivation without restricting
|
|
// the fuzz input space for the fields that drive branching (kem_ss, fp_a, fp_b).
|
|
const ROOT_KEY: [u8; 32] = [0x11; 32];
|
|
|
|
// Wire layout:
|
|
// kem_ss (32) | call_id (16) | fp_a (32) | fp_b (32)
|
|
// derive_call_keys returns Err(InvalidData) when kem_ss is all-zeros or
|
|
// fp_a == fp_b; those inputs exercise the guard paths without reaching advance().
|
|
const MIN: usize = 32 + 16 + 32 + 32; // 112 bytes
|
|
|
|
fuzz_target!(|data: &[u8]| {
|
|
if data.len() < MIN {
|
|
return;
|
|
}
|
|
let kem_ss: &[u8; 32] = data[0..32].try_into().unwrap();
|
|
let call_id: &[u8; 16] = data[32..48].try_into().unwrap();
|
|
let fp_a: &[u8; 32] = data[48..80].try_into().unwrap();
|
|
let fp_b: &[u8; 32] = data[80..112].try_into().unwrap();
|
|
|
|
// derive_call_keys and advance must never panic regardless of input.
|
|
// Exercises: kem_ss zero-check, fingerprint equality guard, HKDF key
|
|
// derivation, HMAC-SHA3-256 rekeying, and old-field zeroization in advance().
|
|
// Both role-assignment branches of advance() are covered by corpus seeds:
|
|
// fp_a < fp_b (lower_role=true) and fp_a > fp_b (lower_role=false).
|
|
if let Ok(mut keys_ab) = derive_call_keys(&ROOT_KEY, kem_ss, call_id, fp_a, fp_b) {
|
|
// Symmetry property: swapping fingerprints must swap send/recv keys.
|
|
// This catches edge cases near the fingerprint comparison boundary
|
|
// that the unit-level proptest may miss with different input distributions.
|
|
let keys_ba = derive_call_keys(&ROOT_KEY, kem_ss, call_id, fp_b, fp_a).unwrap();
|
|
assert_eq!(keys_ab.send_key(), keys_ba.recv_key(), "symmetry: send/recv mismatch");
|
|
assert_eq!(keys_ab.recv_key(), keys_ba.send_key(), "symmetry: recv/send mismatch");
|
|
|
|
// Verify advance() succeeds and produces different keys.
|
|
let pre_send = keys_ab.send_key().to_vec();
|
|
let pre_recv = keys_ab.recv_key().to_vec();
|
|
keys_ab.advance().expect("advance must succeed on valid call keys");
|
|
assert_ne!(&*keys_ab.send_key(), &pre_send[..], "advance must change send_key");
|
|
assert_ne!(&*keys_ab.recv_key(), &pre_recv[..], "advance must change recv_key");
|
|
}
|
|
});
|