lez-fuzzing/fuzz/fuzz_targets/fuzz_signature_verification.rs

62 lines
2.7 KiB
Rust

#![cfg_attr(feature = "fuzzer-libfuzzer", no_main)]
//! Fuzz target: signature creation and verification.
//!
//! Invariants exercised:
//!
//! 1. **Correctness** — `Signature::new(key, msg).is_valid_for(msg, pub_key)` is always `true`
//! for the matching public key.
//! 2. **No panics** — random (possibly invalid) signatures and public keys must never cause a
//! panic in `is_valid_for`.
//! 3. **Cross-key soundness** — signing with key A and verifying against key B must not panic
//! (the result must be `false`; if it is `true` that is a security invariant violation).
use arbitrary::{Arbitrary, Unstructured};
use fuzz_props::arbitrary_types::{ArbPrivateKey, ArbPublicKey, ArbSignature};
use nssa::{PublicKey, Signature};
fuzz_props::fuzz_entry!(|data: &[u8]| {
let mut u = Unstructured::new(data);
// ── 1. Freshly signed message always verifies with the correct key ─────────
if let Ok(key_wrap) = ArbPrivateKey::arbitrary(&mut u) {
let private_key = key_wrap.0;
let public_key = PublicKey::new_from_private_key(&private_key);
let msg: [u8; 32] = u.arbitrary().unwrap_or_default();
let sig = Signature::new(&private_key, &msg);
assert!(
sig.is_valid_for(&msg, &public_key),
"INVARIANT VIOLATION: Signature::new + is_valid_for returned false for the signing key"
);
}
// ── 2. Random bytes as signature must never panic ──────────────────────────
if let (Ok(sig_wrap), Ok(pk_wrap)) = (
ArbSignature::arbitrary(&mut u),
ArbPublicKey::arbitrary(&mut u),
) {
let msg: [u8; 32] = u.arbitrary().unwrap_or_default();
// The result may be true or false — we only assert no panic.
let _ = sig_wrap.0.is_valid_for(&msg, &pk_wrap.0);
}
// ── 3. Cross-key soundness: different keys must never cross-verify ─────────
if let (Ok(key_a_wrap), Ok(key_b_wrap)) = (
ArbPrivateKey::arbitrary(&mut u),
ArbPrivateKey::arbitrary(&mut u),
) {
let public_a = PublicKey::new_from_private_key(&key_a_wrap.0);
let public_b = PublicKey::new_from_private_key(&key_b_wrap.0);
let msg: [u8; 32] = u.arbitrary().unwrap_or_default();
let sig_from_a = Signature::new(&key_a_wrap.0, &msg);
if public_a != public_b {
assert!(
!sig_from_a.is_valid_for(&msg, &public_b),
"INVARIANT VIOLATION: signature created with key_a verified successfully \
against key_b where key_a != key_b (cross-key forgery / broken verification)"
);
}
}
});