Skip to main content

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}