/src/fips203/fuzz/fuzz_targets/ml_kem_fuzz.rs
Line | Count | Source (jump to first uncovered line) |
1 | | #![no_main] |
2 | | use fips203::{ |
3 | | ml_kem_1024, ml_kem_512, ml_kem_768, |
4 | | traits::{Decaps, Encaps, KeyGen, SerDes}, |
5 | | RngCore, CryptoRng |
6 | | }; |
7 | | use libfuzzer_sys::fuzz_target; |
8 | | |
9 | | // Wrapper struct to help organize the fuzz input |
10 | 1.00k | #[derive(arbitrary::Arbitrary, Debug)] Unexecuted instantiation: <ml_kem_fuzz::FuzzInput as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#0} <ml_kem_fuzz::FuzzInput as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#1} Line | Count | Source | 10 | 480 | #[derive(arbitrary::Arbitrary, Debug)] |
Unexecuted instantiation: <ml_kem_fuzz::FuzzInput as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#2} <ml_kem_fuzz::FuzzInput as arbitrary::Arbitrary>::try_size_hint::{closure#0} Line | Count | Source | 10 | 526 | #[derive(arbitrary::Arbitrary, Debug)] |
Unexecuted instantiation: <ml_kem_fuzz::FuzzInput as arbitrary::Arbitrary>::arbitrary::{closure#0} Unexecuted instantiation: <ml_kem_fuzz::FuzzInput as arbitrary::Arbitrary>::arbitrary::{closure#1} Unexecuted instantiation: <ml_kem_fuzz::FuzzInput as arbitrary::Arbitrary>::arbitrary::{closure#2} |
11 | | struct FuzzInput { |
12 | | d: [u8; 32], |
13 | | z: [u8; 32], |
14 | | e: [u8; 32], |
15 | | ek_xor: [u8; ml_kem_1024::EK_LEN], |
16 | | dk_xor: [u8; ml_kem_1024::DK_LEN], |
17 | | ct_xor: [u8; ml_kem_1024::CT_LEN], |
18 | | sk_xor: [u8; fips203::SSK_LEN], |
19 | | } |
20 | | |
21 | | fuzz_target!(|input: FuzzInput| { |
22 | | // Generate keypair deterministically from fuzzer input |
23 | | let (ek1a, dk1a) = ml_kem_512::KG::keygen_from_seed(input.d, input.z); |
24 | | let (ek2a, dk2a) = ml_kem_768::KG::keygen_from_seed(input.d, input.z); |
25 | | let (ek3a, dk3a) = ml_kem_1024::KG::keygen_from_seed(input.d, input.z); |
26 | | |
27 | | // Serialize and deserialize encapsulation key; XOR |
28 | | let mut ek1a_bytes = ek1a.into_bytes(); |
29 | 384k | ek1a_bytes.iter_mut().zip(input.ek_xor.iter()).for_each(|(x1, x2)| *x1 ^= x2); |
30 | | let ek1b = match ml_kem_512::EncapsKey::try_from_bytes(ek1a_bytes) { |
31 | | Ok(k) => k, |
32 | | Err(_) => return, |
33 | | }; |
34 | | |
35 | | let mut ek2a_bytes = ek2a.into_bytes(); |
36 | 539k | ek2a_bytes.iter_mut().zip(input.ek_xor.iter()).for_each(|(x1, x2)| *x1 ^= x2); |
37 | | let ek2b = match ml_kem_768::EncapsKey::try_from_bytes(ek2a_bytes) { |
38 | | Ok(k) => k, |
39 | | Err(_) => return, |
40 | | }; |
41 | | |
42 | | let mut ek3a_bytes = ek3a.into_bytes(); |
43 | 699k | ek3a_bytes.iter_mut().zip(input.ek_xor.iter()).for_each(|(x1, x2)| *x1 ^= x2); |
44 | | let ek3b = match ml_kem_1024::EncapsKey::try_from_bytes(ek3a_bytes) { |
45 | | Ok(k) => k, |
46 | | Err(_) => return, |
47 | | }; |
48 | | |
49 | | // Serialize and deserialize decapsulation key |
50 | | let mut dk1a_bytes = dk1a.into_bytes(); |
51 | 713k | dk1a_bytes.iter_mut().zip(input.dk_xor.iter()).for_each(|(x1, x2)| *x1 ^= x2); |
52 | | let dk1b = match ml_kem_512::DecapsKey::try_from_bytes(dk1a_bytes) { |
53 | | Ok(k) => k, |
54 | | Err(_) => return, |
55 | | }; |
56 | | |
57 | | let mut dk2a_bytes = dk2a.into_bytes(); |
58 | 928k | dk2a_bytes.iter_mut().zip(input.dk_xor.iter()).for_each(|(x1, x2)| *x1 ^= x2); |
59 | | let dk2b = match ml_kem_768::DecapsKey::try_from_bytes(dk2a_bytes) { |
60 | | Ok(k) => k, |
61 | | Err(_) => return, |
62 | | }; |
63 | | |
64 | | let mut dk3a_bytes = dk3a.into_bytes(); |
65 | 1.07M | dk3a_bytes.iter_mut().zip(input.dk_xor.iter()).for_each(|(x1, x2)| *x1 ^= x2); |
66 | | let dk3b = match ml_kem_1024::DecapsKey::try_from_bytes(dk3a_bytes) { |
67 | | Ok(k) => k, |
68 | | Err(_) => return, |
69 | | }; |
70 | | |
71 | | |
72 | | let (ss1, ct1) = ek1b.encaps_from_seed(&input.e); |
73 | | let (ss2, ct2) = ek2b.encaps_from_seed(&input.e); |
74 | | let (ss3, ct3) = ek3b.encaps_from_seed(&input.e); |
75 | | |
76 | | // Serialize and deserialize ciphertext |
77 | | let mut ct1a_bytes = ct1.into_bytes(); |
78 | 238k | ct1a_bytes.iter_mut().zip(input.ct_xor.iter()).for_each(|(x1, x2)| *x1 ^= x2); |
79 | | let ct1b = match ml_kem_512::CipherText::try_from_bytes(ct1a_bytes) { |
80 | | Ok(c) => c, |
81 | | Err(_) => return, |
82 | | }; |
83 | | |
84 | | let mut ct2a_bytes = ct2.into_bytes(); |
85 | 337k | ct2a_bytes.iter_mut().zip(input.ct_xor.iter()).for_each(|(x1, x2)| *x1 ^= x2); |
86 | | let ct2b = match ml_kem_768::CipherText::try_from_bytes(ct2a_bytes) { |
87 | | Ok(c) => c, |
88 | | Err(_) => return, |
89 | | }; |
90 | | |
91 | | let mut ct3a_bytes = ct3.into_bytes(); |
92 | 486k | ct3a_bytes.iter_mut().zip(input.ct_xor.iter()).for_each(|(x1, x2)| *x1 ^= x2); |
93 | | let ct3b = match ml_kem_1024::CipherText::try_from_bytes(ct3a_bytes) { |
94 | | Ok(c) => c, |
95 | | Err(_) => return, |
96 | | }; |
97 | | |
98 | | // Serialize and deserialize shared secret |
99 | | let mut sk1a_bytes = ss1.into_bytes(); |
100 | 9.92k | sk1a_bytes.iter_mut().zip(input.sk_xor.iter()).for_each(|(x1, x2)| *x1 ^= x2); |
101 | | let _sk1b = match fips203::SharedSecretKey::try_from_bytes(sk1a_bytes) { |
102 | | Ok(s) => s, |
103 | | Err(_) => return, |
104 | | }; |
105 | | |
106 | | let mut sk2a_bytes = ss2.into_bytes(); |
107 | 9.92k | sk2a_bytes.iter_mut().zip(input.sk_xor.iter()).for_each(|(x1, x2)| *x1 ^= x2); |
108 | | let _sk2b = match fips203::SharedSecretKey::try_from_bytes(sk2a_bytes) { |
109 | | Ok(s) => s, |
110 | | Err(_) => return, |
111 | | }; |
112 | | |
113 | | let mut sk3a_bytes = ss3.into_bytes(); |
114 | 9.92k | sk3a_bytes.iter_mut().zip(input.sk_xor.iter()).for_each(|(x1, x2)| *x1 ^= x2); |
115 | | let _sk3b = match fips203::SharedSecretKey::try_from_bytes(sk3a_bytes) { |
116 | | Ok(s) => s, |
117 | | Err(_) => return, |
118 | | }; |
119 | | |
120 | | // Test decapsulation |
121 | | let _ss2a = match dk1b.try_decaps(&ct1b) { |
122 | | Ok(s) => s, |
123 | | Err(_) => return, |
124 | | }; |
125 | | let _ss2b = match dk2b.try_decaps(&ct2b) { |
126 | | Ok(s) => s, |
127 | | Err(_) => return, |
128 | | }; |
129 | | let _ss2c = match dk3b.try_decaps(&ct3b) { |
130 | | Ok(s) => s, |
131 | | Err(_) => return, |
132 | | }; |
133 | | |
134 | | // Verify shared secrets match |
135 | | //assert_eq!(ss1, ss2); |
136 | | |
137 | | // Test keypair validation |
138 | | |
139 | | // ----- CUSTOM RNG TO REPLAY VALUES ----- |
140 | | struct TestRng { |
141 | | data: Vec<Vec<u8>>, |
142 | | } |
143 | | |
144 | | impl RngCore for TestRng { |
145 | 0 | fn next_u32(&mut self) -> u32 { unimplemented!() } |
146 | | |
147 | 0 | fn next_u64(&mut self) -> u64 { unimplemented!() } |
148 | | |
149 | 1.89k | fn fill_bytes(&mut self, out: &mut [u8]) { |
150 | 1.89k | let x = self.data.pop().expect("test rng problem"); |
151 | 1.89k | out.copy_from_slice(&x) |
152 | 1.89k | } |
153 | | |
154 | 1.89k | fn try_fill_bytes(&mut self, out: &mut [u8]) -> Result<(), rand_core::Error> { |
155 | 1.89k | self.fill_bytes(out); |
156 | 1.89k | Ok(()) |
157 | 1.89k | } |
158 | | } |
159 | | |
160 | | impl CryptoRng for TestRng {} |
161 | | |
162 | | impl TestRng { |
163 | 270 | fn new() -> Self { TestRng { data: Vec::new() } } |
164 | | |
165 | 2.70k | fn push(&mut self, new_data: &[u8]) { |
166 | 2.70k | let x = new_data.to_vec(); |
167 | 2.70k | self.data.push(x); |
168 | 2.70k | } |
169 | | } |
170 | | |
171 | | |
172 | | let mut rng = TestRng::new(); |
173 | | rng.push(&input.d); |
174 | | let mut z = input.z; |
175 | 270 | z.iter_mut().zip(input.ct_xor[0..1].iter()).for_each(|(x1, x2)| *x1 ^= x2); |
176 | | rng.push(&z); |
177 | | let (ek1a, dk1a) = match ml_kem_512::KG::try_keygen_with_rng(&mut rng) { |
178 | | Ok(k) => k, |
179 | | Err(_) => return, |
180 | | }; |
181 | | rng.push(&input.d); |
182 | | rng.push(&z); |
183 | | ml_kem_512::KG::validate_keypair_with_rng_vartime( |
184 | | &mut rng, |
185 | | &ek1a.into_bytes(), |
186 | | &dk1a.into_bytes(), |
187 | | ); |
188 | | |
189 | | rng.push(&input.d); |
190 | | rng.push(&z); |
191 | | let (ek2a, dk2a) = match ml_kem_768::KG::try_keygen_with_rng(&mut rng) { |
192 | | Ok(k) => k, |
193 | | Err(_) => return, |
194 | | }; |
195 | | rng.push(&input.d); |
196 | | rng.push(&z); |
197 | | ml_kem_768::KG::validate_keypair_with_rng_vartime( |
198 | | &mut rng, |
199 | | &ek2a.into_bytes(), |
200 | | &dk2a.into_bytes(), |
201 | | ); |
202 | | |
203 | | let (ek3a, dk3a) = match ml_kem_1024::KG::try_keygen() { |
204 | | Ok(k) => k, |
205 | | Err(_) => return, |
206 | | }; |
207 | | let _ = ek3a.try_encaps(); |
208 | | rng.push(&input.d); |
209 | | rng.push(&z); |
210 | | ml_kem_1024::KG::validate_keypair_with_rng_vartime( |
211 | | &mut rng, |
212 | | &ek3a.into_bytes(), |
213 | | &dk3a.into_bytes(), |
214 | | ); |
215 | | }); |