#![no_main] #![allow(deprecated)] // Fuzz targets exercise from_bytes directly. use libfuzzer_sys::fuzz_target; use soliton::ratchet::RatchetState; fuzz_target!(|data: &[u8]| { // from_bytes → to_bytes → from_bytes round-trip: // any serializable state must re-serialize to identical bytes // (except the epoch field at bytes 1..9, which increments on each to_bytes). // // States near the epoch ceiling are legitimately non-serializable // (can_serialize() returns false). These are usable for encrypt/decrypt // but not persistable — skip them. let Ok(state1) = RatchetState::from_bytes(data) else { return; }; if !state1.can_serialize() { return; } let Ok((bytes1, epoch1)) = state1.to_bytes() else { panic!("to_bytes failed on a state where can_serialize() returned true"); }; let Ok(state2) = RatchetState::from_bytes(&bytes1) else { panic!("from_bytes rejected bytes produced by to_bytes"); }; if !state2.can_serialize() { return; } let Ok((bytes2, epoch2)) = state2.to_bytes() else { panic!("second to_bytes failed on a serializable round-tripped state"); }; // Version byte must match. assert_eq!(bytes1[0], bytes2[0], "version byte mismatch after round-trip"); // All fields after epoch must match. assert_eq!(bytes1[9..], bytes2[9..], "fields after epoch diverged after round-trip"); // Epoch must advance by exactly 1 per to_bytes call. assert_eq!(epoch2, epoch1 + 1, "epoch did not advance by 1"); });