fix: add canonical encoding check

This commit is contained in:
Roman 2026-05-13 10:34:57 +08:00
parent 24e912636a
commit 3370a39417
No known key found for this signature in database
GPG Key ID: 583BDF43C238B83E

View File

@ -1,8 +1,12 @@
#![no_main]
//! Fuzz target: encoding round-trip for all transaction types.
//!
//! Invariant: `decode(encode(tx)) == Ok(tx)` and `encode(decode(encode(tx))) == encode(tx)`
//! for every `PublicTransaction` and `ProgramDeploymentTransaction`.
//! Invariants exercised:
//!
//! 1. **Encode/decode stability** — `encode(decode(encode(tx))) == encode(tx)`.
//! 2. **Canonical encoding** — if raw fuzzer bytes decode successfully, re-encoding must
//! reproduce those exact bytes (`encode(decode(data)) == data`). This catches non-canonical
//! encodings that are accepted by the decoder but silently normalised on the way out.
//!
//! `PrivacyPreservingTransaction` is excluded because its ZK receipt cannot be
//! reconstructed in a fuzzing loop.
@ -42,4 +46,26 @@ fuzz_target!(|data: &[u8]| {
"INVARIANT VIOLATION: encode(decode(encode(tx))) != encode(tx) for ProgramDeploymentTransaction"
);
}
// ── Test 3: Canonical encoding — raw bytes that decode must re-encode identically ──
if let Ok(tx) = PublicTransaction::from_bytes(data) {
let re_encoded = tx.to_bytes();
assert_eq!(
data,
re_encoded.as_slice(),
"INVARIANT VIOLATION: PublicTransaction decoded from raw fuzzer bytes but \
re-encoding differs from the original input (non-canonical encoding accepted)"
);
}
// ── Test 4: Canonical encoding for ProgramDeploymentTransaction ──────────────────
if let Ok(tx) = ProgramDeploymentTransaction::from_bytes(data) {
let re_encoded = tx.to_bytes();
assert_eq!(
data,
re_encoded.as_slice(),
"INVARIANT VIOLATION: ProgramDeploymentTransaction decoded from raw fuzzer bytes \
but re-encoding differs from the original input (non-canonical encoding accepted)"
);
}
});