1use crate::{
4 api::CRYPTO_CIPHERTEXTBYTES,
5 macros::sub,
6 params::{PK_NROWS, PK_ROW_BYTES, SYND_BYTES, SYS_N, SYS_T},
7 util::load_gf,
8};
9use rand::{CryptoRng, RngCore};
10
11fn same_mask_u8(x: u16, y: u16) -> u8 {
13 let mut mask = (x ^ y) as u32;
14 mask = mask.wrapping_sub(1);
15 mask = mask.wrapping_shr(31);
16 mask = 0u32.wrapping_sub(mask);
17
18 (mask & 0xFF) as u8 }
20
21#[cfg(not(any(feature = "mceliece8192128", feature = "mceliece8192128f")))]
25fn gen_e<R: CryptoRng + RngCore>(e: &mut [u8; SYS_N / 8], rng: &mut R) {
26 let mut ind = [0u16; SYS_T];
27 let mut val = [0u8; SYS_T];
28
29 loop {
30 let mut bytes = [0u8; SYS_T * 4];
31 rng.fill_bytes(&mut bytes);
32
33 let mut nums = [0u16; SYS_T * 2];
34 for (i, chunk) in bytes.chunks(2).enumerate() {
35 nums[i] = load_gf(sub!(chunk, 0, 2));
36 }
37
38 let mut count = 0;
41 for itr_num in nums.iter() {
42 if count >= SYS_T {
43 break;
44 }
45 if *itr_num < SYS_N as u16 {
46 ind[count] = *itr_num;
47 count += 1;
48 }
49 }
50
51 if count < SYS_T {
52 continue;
53 }
54
55 let mut eq = 0;
58
59 for i in 1..SYS_T {
60 for j in 0..i {
61 if ind[i] == ind[j] {
62 eq = 1;
63 }
64 }
65 }
66
67 if eq == 0 {
68 break;
69 }
70 }
71
72 for j in 0..SYS_T {
73 val[j] = 1 << (ind[j] & 7);
74 }
75
76 for (i, itr_e) in e.iter_mut().enumerate() {
77 *itr_e = 0;
78
79 for j in 0..SYS_T {
80 let mask: u8 = same_mask_u8(i as u16, ind[j] >> 3);
81
82 *itr_e |= val[j] & mask;
83 }
84 }
85}
86
87#[cfg(any(feature = "mceliece8192128", feature = "mceliece8192128f"))]
91fn gen_e<R: CryptoRng + RngCore>(e: &mut [u8], rng: &mut R) {
92 let mut ind = [0u16; SYS_T];
93 let mut bytes = [0u8; SYS_T * 2];
94 let mut val = [0u8; SYS_T];
95
96 loop {
97 rng.fill_bytes(&mut bytes);
98
99 for (i, chunk) in bytes.chunks(2).enumerate() {
100 ind[i] = load_gf(sub!(chunk, 0, 2));
101 }
102
103 let mut eq = 0;
106
107 for i in 1..SYS_T {
108 for j in 0..i {
109 if ind[i] == ind[j] {
110 eq = 1;
111 }
112 }
113 }
114
115 if eq == 0 {
116 break;
117 }
118 }
119
120 for j in 0..SYS_T {
121 val[j] = 1 << (ind[j] & 7);
122 }
123
124 for i in 0..SYS_N / 8 {
125 e[i] = 0;
126
127 for j in 0..SYS_T {
128 let mask: u8 = same_mask_u8(i as u16, ind[j] >> 3);
129
130 e[i] |= val[j] & mask;
131 }
132 }
133}
134
135#[cfg(any(feature = "mceliece6960119", feature = "mceliece6960119f"))]
139fn syndrome(
140 s: &mut [u8; (PK_NROWS + 7) / 8],
141 pk: &[u8; PK_NROWS * PK_ROW_BYTES],
142 e: &[u8; SYS_N / 8],
143) {
144 let mut row = [0u8; SYS_N / 8];
145
146 let mut pk_segment = &pk[..];
147 let tail = PK_NROWS % 8;
148
149 s[0..SYND_BYTES].fill(0);
150
151 for i in 0..PK_NROWS {
152 row[0..SYS_N / 8].fill(0);
153
154 for j in 0..PK_ROW_BYTES {
155 row[SYS_N / 8 - PK_ROW_BYTES + j] = pk_segment[j];
156 }
157
158 for j in ((SYS_N / 8 - PK_ROW_BYTES)..SYS_N / 8).rev() {
159 row[j] = (row[j] << tail) | (row[j - 1] >> (8 - tail));
160 }
161
162 row[i / 8] |= 1 << (i % 8);
163
164 let mut b = 0u8;
165 for j in 0..SYS_N / 8 {
166 b ^= row[j] & e[j];
167 }
168
169 b ^= b >> 4;
170 b ^= b >> 2;
171 b ^= b >> 1;
172 b &= 1;
173
174 s[i / 8] |= b << (i % 8);
175
176 pk_segment = &pk_segment[PK_ROW_BYTES..];
177 }
178}
179
180#[cfg(not(any(feature = "mceliece6960119", feature = "mceliece6960119f")))]
184fn syndrome(
185 s: &mut [u8; PK_NROWS.div_ceil(8)],
186 pk: &[u8; PK_NROWS * PK_ROW_BYTES],
187 e: &[u8; SYS_N / 8],
188) {
189 let mut row = [0u8; SYS_N / 8];
190
191 let mut pk_segment = &pk[..];
192
193 s[0..SYND_BYTES].fill(0);
194
195 for i in 0..PK_NROWS {
196 row[0..SYS_N / 8].fill(0);
197
198 for j in 0..PK_ROW_BYTES {
199 row[SYS_N / 8 - PK_ROW_BYTES + j] = pk_segment[j];
200 }
201
202 row[i / 8] |= 1 << (i % 8);
203
204 let mut b = 0u8;
205 for j in 0..SYS_N / 8 {
206 b ^= row[j] & e[j];
207 }
208
209 b ^= b >> 4;
210 b ^= b >> 2;
211 b ^= b >> 1;
212 b &= 1;
213
214 s[i / 8] |= b << (i % 8);
215
216 pk_segment = &pk_segment[PK_ROW_BYTES..];
217 }
218}
219
220pub(crate) fn encrypt<R: CryptoRng + RngCore>(
223 s: &mut [u8; CRYPTO_CIPHERTEXTBYTES],
224 pk: &[u8; PK_NROWS * PK_ROW_BYTES],
225 e: &mut [u8; SYS_N / 8],
226 rng: &mut R,
227) {
228 gen_e(e, rng);
229 syndrome(sub!(mut s, 0, PK_NROWS.div_ceil(8)), pk, e);
230}
231
232#[cfg(test)]
233mod tests {
234 #[cfg(feature = "mceliece8192128f")]
235 use super::*;
236 #[cfg(feature = "mceliece8192128f")]
237 use crate::api::CRYPTO_CIPHERTEXTBYTES;
238 #[cfg(feature = "mceliece8192128f")]
239 use crate::api::CRYPTO_PUBLICKEYBYTES;
240 #[cfg(feature = "mceliece8192128f")]
241 use crate::nist_aes_rng::AesState;
242 #[cfg(feature = "mceliece8192128f")]
243 use crate::test_utils::TestData;
244
245 #[test]
246 #[cfg(feature = "mceliece8192128f")]
247 fn test_encrypt() {
248 let entropy_input = [
249 6, 21, 80, 35, 77, 21, 140, 94, 201, 85, 149, 254, 4, 239, 122, 37, 118, 127, 46, 36,
250 204, 43, 196, 121, 208, 157, 134, 220, 154, 188, 253, 231, 5, 106, 140, 38, 111, 158,
251 249, 126, 208, 133, 65, 219, 210, 225, 255, 161,
252 ];
253
254 let mut rng_state = AesState::new();
255 rng_state.randombytes_init(entropy_input);
256
257 let mut second_seed = [0u8; 33];
258 second_seed[0] = 64;
259
260 rng_state.fill_bytes(&mut second_seed[1..]);
261
262 let mut e = [0u8; SYS_N / 8];
263
264 let mut c = [0u8; CRYPTO_CIPHERTEXTBYTES];
265 let mut pk = TestData::new().u8vec("mceliece8192128f_pk1");
266
267 let compare_ct = TestData::new().u8vec("mceliece8192128f_encrypt_ct");
268 assert_eq!(compare_ct.len(), CRYPTO_CIPHERTEXTBYTES);
269
270 encrypt(
271 &mut c,
272 sub!(mut pk, 0, CRYPTO_PUBLICKEYBYTES),
273 sub!(mut e, 0, SYS_N / 8),
274 &mut rng_state,
275 );
276
277 assert_eq!(compare_ct, c);
278 }
279}