lez-fuzzing/fuzz/fuzz_targets/fuzz_block_verification.rs

41 lines
1.6 KiB
Rust
Raw Normal View History

2026-04-13 16:03:20 +08:00
#![no_main]
use common::block::{Block, HashableBlockData};
use libfuzzer_sys::fuzz_target;
2026-05-07 14:27:44 +08:00
use nssa::PrivateKey;
// A fixed, valid signing key used only to exercise the hash-computation path.
// The specific key value is irrelevant to hash correctness.
const DUMMY_KEY_BYTES: [u8; 32] = [1u8; 32];
2026-04-13 16:03:20 +08:00
fuzz_target!(|data: &[u8]| {
let Ok(block) = borsh::from_slice::<Block>(data) else {
return;
};
2026-05-07 14:27:44 +08:00
let signing_key = PrivateKey::try_new(DUMMY_KEY_BYTES).expect("constant key is valid");
let bedrock_parent_id = [0u8; 32];
// Convert to hashable form twice so we can check determinism without
// moving the value into the first call.
let hashable1 = HashableBlockData::from(block.clone());
let hashable2 = HashableBlockData::from(block.clone());
// INVARIANT: into_pending_block() must never panic regardless of fuzz input
let recomputed1 = hashable1.into_pending_block(&signing_key, bedrock_parent_id);
let hash1 = recomputed1.header.hash;
2026-04-13 16:03:20 +08:00
2026-05-07 14:27:44 +08:00
// INVARIANT: hash derivation must be deterministic
let recomputed2 = hashable2.into_pending_block(&signing_key, bedrock_parent_id);
let hash2 = recomputed2.header.hash;
2026-04-13 16:03:20 +08:00
2026-05-07 14:27:44 +08:00
assert_eq!(hash1, hash2, "block hash is not deterministic");
2026-04-13 16:03:20 +08:00
2026-04-24 12:04:20 +08:00
// We intentionally do NOT assert that the stored header hash equals the
// recomputed one: adversarially-crafted fuzz inputs can store an arbitrary
// hash field that does not match the body content, and that is a valid input
// for the purpose of this target (which only tests hash stability, not
// block validity).
2026-05-07 14:27:44 +08:00
let _ = block.header.hash;
2026-04-13 16:03:20 +08:00
});