1use crate::{
24 ff::FiniteField,
25 isogeny::{PublicKey, PublicParameters, SecretKey},
26 pke::{Ciphertext, Message, PKE},
27 utils::{conversion, shake},
28};
29
30use std::fmt::Debug;
31
32pub struct KEM<K> {
34 params: PublicParameters<K>,
35 pke: PKE<K>,
36 n: usize,
37}
38
39impl<K: FiniteField + Clone + Debug> KEM<K> {
40 #[inline]
42 pub fn setup(params: PublicParameters<K>) -> Self {
43 Self {
44 pke: PKE::setup(params.clone()),
45 n: params.secparam,
46 params,
47 }
48 }
49
50 #[inline]
52 pub fn keygen(&self) -> Result<(Vec<u8>, SecretKey, PublicKey<K>), String> {
53 let sk3 = SecretKey::get_random_secret_key(self.params.keyspace3 as usize)?;
54 let pk3 = self.pke.isogenies.isogen3(&sk3)?;
55 let s = Self::random_string(self.n);
56
57 Ok((s, sk3, pk3))
58 }
59
60 #[inline]
62 pub fn encaps(&self, pk: &PublicKey<K>) -> Result<(Ciphertext, Vec<u8>), String> {
63 let message = Message::from_bytes(Self::random_string(self.n / 8));
64 let r = self.hash_function_g(&message.clone(), &pk);
65 let det_sk = SecretKey::from_bytes(&r);
66
67 let c0: PublicKey<K> = self.pke.isogenies.isogen2(&det_sk)?;
68
69 let j_inv = self.pke.isogenies.isoex2(&det_sk, &pk)?;
70 let h = self.pke.hash_function_f(j_inv);
71
72 if h.len() != message.bytes.len() {
73 return Err(String::from("Incorrect Hash"));
74 }
75
76 let c1_bytes = PKE::<K>::xor(&message.bytes, &h);
77
78 let (part1, part2, part3) = c0.into_bytes();
79 let cipher = Ciphertext {
80 bytes00: part1,
81 bytes01: part2,
82 bytes02: part3,
83 bytes1: c1_bytes,
84 };
85
86 let k = self.hash_function_h(&message, &cipher);
87 Ok((cipher, k))
88 }
89
90 #[inline]
92 pub fn decaps(
93 &self,
94 s: &[u8],
95 sk: &SecretKey,
96 pk: &PublicKey<K>,
97 c: Ciphertext,
98 ) -> Result<Vec<u8>, String> {
99 let m = self.pke.dec(&sk, c.clone())?;
100 let s = Message::from_bytes(s.to_vec());
101 let r = self.hash_function_g(&m.clone(), &pk);
102
103 let c0 = PublicKey::from_bytes(&c.bytes00, &c.bytes01, &c.bytes02)?;
104 let rsk = SecretKey::from_bytes(&r);
105
106 let c0p = self.pke.isogenies.isogen2(&rsk)?;
107
108 if c0p == c0 {
109 Ok(self.hash_function_h(&m, &c))
110 } else {
111 Ok(self.hash_function_h(&s, &c))
112 }
113 }
114
115 fn random_string(size: usize) -> Vec<u8> {
116 let mut result = vec![0; size];
117 getrandom::getrandom(&mut result).unwrap();
118 result
119 }
120
121 fn hash_function_g(&self, m: &Message, pk: &PublicKey<K>) -> Vec<u8> {
122 let (part1, part2, part3) = pk.clone().into_bytes();
123 let msg_bytes = m.clone().into_bytes();
124 let input = conversion::concatenate(&[&msg_bytes, &part1, &part2, &part3]);
125
126 let n: usize = self.params.secparam;
127
128 shake::shake256(&input, n / 8)
129 }
130
131 fn hash_function_h(&self, m: &Message, c: &Ciphertext) -> Vec<u8> {
132 let input = conversion::concatenate(&[
133 &m.clone().into_bytes(),
134 &c.bytes00,
135 &c.bytes01,
136 &c.bytes02,
137 &c.bytes1,
138 ]);
139
140 let n = self.params.secparam;
141
142 shake::shake256(&input, n / 8)
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149 use crate::{
150 isogeny::{sike_p434_params, sike_p503_params, sike_p610_params, sike_p751_params},
151 utils::strategy::*,
152 };
153
154 #[test]
155 fn test_kem_p434() {
156 let params = sike_p434_params(None, None).unwrap();
157
158 let kem = KEM::setup(params);
159
160 let (s, sk3, pk3) = kem.keygen().unwrap();
162
163 let (c, k) = kem.encaps(&pk3).unwrap();
165
166 let k_recovered = kem.decaps(&s, &sk3, &pk3, c).unwrap();
169
170 assert_eq!(k, k_recovered);
171 }
172
173 #[test]
174 fn test_kem_p503() {
175 let params = sike_p503_params(None, None).unwrap();
176
177 let kem = KEM::setup(params);
178
179 let (s, sk3, pk3) = kem.keygen().unwrap();
181
182 let (c, k) = kem.encaps(&pk3).unwrap();
184
185 let k_recovered = kem.decaps(&s, &sk3, &pk3, c).unwrap();
188
189 assert_eq!(k, k_recovered);
190 }
191
192 #[test]
193 fn test_kem_p610() {
194 let params = sike_p610_params(None, None).unwrap();
195
196 let kem = KEM::setup(params);
197
198 let (s, sk3, pk3) = kem.keygen().unwrap();
200
201 let (c, k) = kem.encaps(&pk3).unwrap();
203
204 let k_recovered = kem.decaps(&s, &sk3, &pk3, c).unwrap();
207
208 assert_eq!(k, k_recovered);
209 }
210
211 #[test]
212 fn test_kem_p751() {
213 let params = sike_p751_params(None, None).unwrap();
214
215 let kem = KEM::setup(params);
216
217 let (s, sk3, pk3) = kem.keygen().unwrap();
219
220 let (c, k) = kem.encaps(&pk3).unwrap();
222
223 let k_recovered = kem.decaps(&s, &sk3, &pk3, c).unwrap();
226
227 assert_eq!(k, k_recovered);
228 }
229
230 #[test]
231 fn test_kem_optim_p434() {
232 let params = sike_p434_params(
233 Some(P434_TWO_TORSION_STRATEGY.to_vec()),
234 Some(P434_THREE_TORSION_STRATEGY.to_vec()),
235 )
236 .unwrap();
237
238 let kem = KEM::setup(params);
239
240 let (s, sk3, pk3) = kem.keygen().unwrap();
242
243 let (c, k) = kem.encaps(&pk3).unwrap();
245
246 let k_recovered = kem.decaps(&s, &sk3, &pk3, c).unwrap();
249
250 assert_eq!(k, k_recovered);
251 }
252
253 #[test]
254 fn test_kem_optim_p503() {
255 let params = sike_p503_params(
256 Some(P503_TWO_TORSION_STRATEGY.to_vec()),
257 Some(P503_THREE_TORSION_STRATEGY.to_vec()),
258 )
259 .unwrap();
260
261 let kem = KEM::setup(params);
262
263 let (s, sk3, pk3) = kem.keygen().unwrap();
265
266 let (c, k) = kem.encaps(&pk3).unwrap();
268
269 let k_recovered = kem.decaps(&s, &sk3, &pk3, c).unwrap();
272
273 assert_eq!(k, k_recovered);
274 }
275
276 #[test]
277 fn test_kem_optim_p610() {
278 let params = sike_p610_params(
279 Some(P610_TWO_TORSION_STRATEGY.to_vec()),
280 Some(P610_THREE_TORSION_STRATEGY.to_vec()),
281 )
282 .unwrap();
283
284 let kem = KEM::setup(params);
285
286 let (s, sk3, pk3) = kem.keygen().unwrap();
288
289 let (c, k) = kem.encaps(&pk3).unwrap();
291
292 let k_recovered = kem.decaps(&s, &sk3, &pk3, c).unwrap();
295
296 assert_eq!(k, k_recovered);
297 }
298
299 #[test]
300 fn test_kem_optim_p751() {
301 let params = sike_p751_params(
302 Some(P751_TWO_TORSION_STRATEGY.to_vec()),
303 Some(P751_THREE_TORSION_STRATEGY.to_vec()),
304 )
305 .unwrap();
306
307 let kem = KEM::setup(params);
308
309 let (s, sk3, pk3) = kem.keygen().unwrap();
311
312 let (c, k) = kem.encaps(&pk3).unwrap();
314
315 let k_recovered = kem.decaps(&s, &sk3, &pk3, c).unwrap();
318
319 assert_eq!(k, k_recovered);
320 }
321}