elara_fuzz/lib.rs
1//! Fuzzing infrastructure for ELARA Protocol
2//!
3//! This crate provides a trait-based framework for creating fuzz targets
4//! that can discover edge cases, panics, and security vulnerabilities in
5//! parsing and cryptographic code.
6//!
7//! # Architecture
8//!
9//! The fuzzing infrastructure consists of:
10//! - **FuzzTarget trait**: Core abstraction for fuzz targets
11//! - **FuzzResult enum**: Classification of fuzz outcomes
12//! - **Concrete fuzzers**: Pre-built fuzzers for wire protocol, crypto, and state
13//!
14//! # Example
15//!
16//! ```rust
17//! use elara_fuzz::{FuzzTarget, FuzzResult};
18//! use arbitrary::Arbitrary;
19//!
20//! #[derive(Arbitrary, Debug)]
21//! struct MyInput {
22//! data: Vec<u8>,
23//! }
24//!
25//! struct MyFuzzer;
26//!
27//! impl FuzzTarget for MyFuzzer {
28//! type Input = MyInput;
29//!
30//! fn fuzz_once(&mut self, input: Self::Input) -> FuzzResult {
31//! // Test your code with arbitrary input
32//! match process_data(&input.data) {
33//! Ok(_) => FuzzResult::Ok,
34//! Err(e) if e.is_expected() => FuzzResult::Invalid,
35//! Err(e) => FuzzResult::Bug(format!("Unexpected error: {}", e)),
36//! }
37//! }
38//! }
39//! # fn process_data(_data: &[u8]) -> Result<(), std::io::Error> { Ok(()) }
40//! # trait ErrorExt { fn is_expected(&self) -> bool; }
41//! # impl ErrorExt for std::io::Error { fn is_expected(&self) -> bool { true } }
42//! ```
43//!
44//! # Integration with cargo-fuzz
45//!
46//! To use with cargo-fuzz, create fuzz targets in `fuzz/fuzz_targets/`:
47//!
48//! ```rust,no_run
49//! #![no_main]
50//! use libfuzzer_sys::fuzz_target;
51//! use elara_fuzz::FuzzTarget;
52//!
53//! # struct MyFuzzer;
54//! # impl elara_fuzz::FuzzTarget for MyFuzzer {
55//! # type Input = Vec<u8>;
56//! # fn fuzz_once(&mut self, _input: Self::Input) -> elara_fuzz::FuzzResult {
57//! # elara_fuzz::FuzzResult::Ok
58//! # }
59//! # }
60//! fuzz_target!(|data: <MyFuzzer as FuzzTarget>::Input| {
61//! let mut fuzzer = MyFuzzer;
62//! let _ = fuzzer.fuzz_once(data);
63//! });
64//! ```
65
66use arbitrary::Arbitrary;
67
68/// Result of a single fuzz iteration
69#[derive(Debug, Clone, PartialEq, Eq)]
70pub enum FuzzResult {
71 /// Test passed - input was processed successfully
72 Ok,
73
74 /// Found a bug - panic, assertion failure, or unexpected error
75 Bug(String),
76
77 /// Invalid input - expected rejection, not a bug
78 Invalid,
79}
80
81/// Trait for implementing fuzz targets
82///
83/// Implementors define an `Input` type that can be generated arbitrarily
84/// and a `fuzz_once` method that tests the code with that input.
85pub trait FuzzTarget {
86 /// Input type for fuzzing - must implement `arbitrary::Arbitrary`
87 /// so the fuzzer can generate random instances
88 type Input: Arbitrary<'static>;
89
90 /// Execute one fuzz iteration with the given input
91 ///
92 /// This method should:
93 /// - Test the target code with the input
94 /// - Return `FuzzResult::Ok` if processing succeeds
95 /// - Return `FuzzResult::Invalid` if input is malformed (expected)
96 /// - Return `FuzzResult::Bug` if an unexpected error occurs
97 ///
98 /// The method should catch panics and convert them to `FuzzResult::Bug`.
99 fn fuzz_once(&mut self, input: Self::Input) -> FuzzResult;
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[derive(Arbitrary, Debug)]
107 struct TestInput {
108 value: u8,
109 }
110
111 struct TestFuzzer;
112
113 impl FuzzTarget for TestFuzzer {
114 type Input = TestInput;
115
116 fn fuzz_once(&mut self, input: Self::Input) -> FuzzResult {
117 if input.value == 0 {
118 FuzzResult::Invalid
119 } else if input.value == 255 {
120 FuzzResult::Bug("Found edge case".to_string())
121 } else {
122 FuzzResult::Ok
123 }
124 }
125 }
126
127 #[test]
128 fn test_fuzz_result_ok() {
129 let mut fuzzer = TestFuzzer;
130 let result = fuzzer.fuzz_once(TestInput { value: 42 });
131 assert_eq!(result, FuzzResult::Ok);
132 }
133
134 #[test]
135 fn test_fuzz_result_invalid() {
136 let mut fuzzer = TestFuzzer;
137 let result = fuzzer.fuzz_once(TestInput { value: 0 });
138 assert_eq!(result, FuzzResult::Invalid);
139 }
140
141 #[test]
142 fn test_fuzz_result_bug() {
143 let mut fuzzer = TestFuzzer;
144 let result = fuzzer.fuzz_once(TestInput { value: 255 });
145 assert_eq!(result, FuzzResult::Bug("Found edge case".to_string()));
146 }
147}