1pub struct CodeFuzzer {
6 pub seed: u64,
7 state: u64,
8}
9
10impl CodeFuzzer {
11 pub fn new(seed: Option<u64>) -> Self {
13 let s = seed.unwrap_or_else(|| {
14 std::time::SystemTime::now()
15 .duration_since(std::time::UNIX_EPOCH)
16 .unwrap()
17 .as_secs()
18 });
19 Self { seed: s, state: s }
20 }
21
22 fn next_u64(&mut self) -> u64 {
24 self.state ^= self.state << 13;
25 self.state ^= self.state >> 7;
26 self.state ^= self.state << 17;
27 self.state
28 }
29
30 fn gen_range(&mut self, max: usize) -> usize {
32 (self.next_u64() as usize) % max
33 }
34
35 fn gen_bool(&mut self, numerator: usize, denominator: usize) -> bool {
37 (self.next_u64() as usize) % denominator < numerator
38 }
39
40 pub fn random_function_name(&mut self) -> String {
42 const PREFIXES: &[&str] = &["process_", "execute_", "handle_", "check_", "validate_"];
43 const SUFFIXES: &[&str] = &[
44 "transaction",
45 "deposit",
46 "withdraw",
47 "transfer",
48 "swap",
49 "mint",
50 "burn",
51 ];
52 let prefix = PREFIXES[self.gen_range(PREFIXES.len())];
53 let suffix = SUFFIXES[self.gen_range(SUFFIXES.len())];
54 format!("{}{}_{}", prefix, suffix, self.next_u64() % 1000)
55 }
56
57 pub fn random_variable_name(&mut self) -> String {
59 const NAMES: &[&str] = &[
60 "amount",
61 "balance",
62 "reserve",
63 "collateral",
64 "debt",
65 "price",
66 "rate",
67 "value",
68 "token",
69 "user",
70 ];
71 let name = NAMES[self.gen_range(NAMES.len())];
72 format!("{}_{}", name, self.next_u64() % 100)
73 }
74
75 pub fn generate_solidity_function(&mut self, include_vulnerable_pattern: bool) -> String {
77 let func_name = self.random_function_name();
78 let var1 = self.random_variable_name();
79 let var2 = self.random_variable_name();
80
81 let health_check = if include_vulnerable_pattern {
82 "// Missing health check".to_string()
83 } else {
84 "require(isHealthy(), \"Not healthy\");".to_string()
85 };
86
87 format!(
88 r#" function {}(uint256 {} ) public {{
89 {} = {} + 100;
90 {} = {} - 50;
91 {}
92 emit Transfer({}, {});
93 }}"#,
94 func_name, var1, var1, var1, var2, var2, health_check, var1, var2
95 )
96 }
97
98 pub fn generate_merkle_pattern(&mut self, vulnerable: bool) -> String {
100 let init_value = if vulnerable {
101 "bytes32 root = bytes32(0);"
102 } else {
103 "bytes32 root = keccak256(abi.encodePacked(leaves));"
104 };
105
106 format!(
107 r#" function setupMerkleRoot() public {{
108 {}
109 merkleRoot = root;
110 }}"#,
111 init_value
112 )
113 }
114
115 pub fn generate_oracle_pattern(&mut self, vulnerable: bool) -> String {
117 let price_source = if vulnerable {
118 "uint256 price = token.balanceOf(address(this));"
119 } else {
120 "uint256 price = priceOracle.getPrice(token); require(price > 0, \"Invalid price\");"
121 };
122
123 let state_modification = self.random_variable_name();
124
125 format!(
126 r#" function updatePrice() public {{
127 {}
128 {} = price;
129 emit PriceUpdated(price);
130 }}"#,
131 price_source, state_modification
132 )
133 }
134
135 pub fn generate_collateral_pattern(&mut self, vulnerable: bool) -> String {
137 let check = if vulnerable {
138 "// No collateral validation"
139 } else {
140 "require(collateral >= amount * RATIO, \"Insufficient collateral\");"
141 };
142
143 format!(
144 r#" function mintSynthetic(uint256 amount) public {{
145 {}
146 totalMinted += amount;
147 }}"#,
148 check
149 )
150 }
151
152 pub fn generate_contract(&mut self, function_count: usize) -> String {
154 let mut contract = "contract TestContract {\n".to_string();
155
156 for _ in 0..function_count {
157 let vulnerable = self.gen_bool(3, 10);
158 let func = self.generate_solidity_function(vulnerable);
159 contract.push_str(&func);
160 contract.push('\n');
161 }
162
163 contract.push('}');
164 contract
165 }
166
167 pub fn generate_rust_pattern(&mut self, vulnerable: bool) -> String {
169 let check = if vulnerable {
170 "// Missing validation"
171 } else {
172 "if !self.validate_state() { return Err(InvalidState); }"
173 };
174
175 format!(
176 r#"impl Handler {{
177 pub fn process(&mut self) -> Result<()> {{
178 self.update_state();
179 {}
180 Ok(())
181 }}
182}}"#,
183 check
184 )
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191
192 #[test]
193 fn fuzzer_generates_valid_solidity() {
194 let mut fuzzer = CodeFuzzer::new(Some(42));
195 let contract = fuzzer.generate_contract(5);
196 assert!(contract.contains("contract TestContract"));
197 assert!(contract.contains("function"));
198 }
199
200 #[test]
201 fn fuzzer_generates_different_outputs() {
202 let mut fuzzer1 = CodeFuzzer::new(Some(100));
203 let mut fuzzer2 = CodeFuzzer::new(Some(200));
204
205 let func1 = fuzzer1.generate_solidity_function(true);
206 let func2 = fuzzer2.generate_solidity_function(true);
207 assert_ne!(func1, func2);
208 }
209
210 #[test]
211 fn fuzzer_deterministic_with_seed() {
212 let mut f1 = CodeFuzzer::new(Some(999));
213 let mut f2 = CodeFuzzer::new(Some(999));
214
215 assert_eq!(
216 f1.generate_solidity_function(true),
217 f2.generate_solidity_function(true)
218 );
219 }
220
221 #[test]
222 fn fuzzer_generates_merkle_patterns() {
223 let mut fuzzer = CodeFuzzer::new(Some(123));
224 let vuln = fuzzer.generate_merkle_pattern(true);
225 let safe = fuzzer.generate_merkle_pattern(false);
226
227 assert!(vuln.contains("bytes32(0)"));
228 assert!(safe.contains("keccak256"));
229 }
230}