1use aes::Aes256;
5use cipher::{BlockEncryptMut, KeyInit};
6use cipher::generic_array::GenericArray;
7use hmac::{Hmac, Mac};
8use num_bigint::BigUint;
9use pbkdf2::pbkdf2_hmac;
10use sha1::Sha1;
11use sha2::Sha256;
12use std::convert::TryInto;
13
14type HmacSha256 = Hmac<Sha256>;
15
16const PAD_IDENTIFIER: &str = "QPP_";
17const PM_SELECTOR_IDENTIFIER: &[u8] = b"PERMUTATION_MATRIX_SELECTOR";
18const SHUFFLE_SALT: &[u8] = b"___QUANTUM_PERMUTATION_PAD_SHUFFLE_SALT___";
19const PRNG_SALT: &[u8] = b"___QUANTUM_PERMUTATION_PAD_PRNG_SALT___";
20const CHUNK_DERIVE_SALT: &[u8] = b"___QUANTUM_PERMUTATION_PAD_SEED_DERIVE___";
21const PBKDF2_LOOPS: u32 = 128;
22const CHUNK_DERIVE_LOOPS: u32 = 1024;
23const PAD_SWITCH: u8 = 8;
24const QUBITS: u8 = 8;
25const MATRIX_BYTES: usize = 1 << QUBITS; #[derive(Clone)]
29pub struct Rand {
30 pub xoshiro: [u64; 4],
31 pub seed64: u64,
32 pub count: u8,
33}
34
35fn rol64(x: u64, k: i32) -> u64 {
36 (x << k) | (x >> (64 - k))
37}
38
39fn xoshiro256ss(s: &mut [u64; 4]) -> u64 {
41 let result = rol64(s[1].wrapping_mul(5), 7).wrapping_mul(9);
42 let t = s[1] << 17;
43 s[2] ^= s[0];
44 s[3] ^= s[1];
45 s[1] ^= s[2];
46 s[0] ^= s[3];
47 s[2] ^= t;
48 s[3] = rol64(s[3], 45);
49 result
50}
51
52pub fn create_prng(seed: &[u8]) -> Rand {
54 let mut mac = <HmacSha256 as Mac>::new_from_slice(seed).expect("HMAC key");
55 Mac::update(&mut mac, PM_SELECTOR_IDENTIFIER);
56 let sum = mac.finalize().into_bytes();
57
58 let mut xoshiro = [0u8; 32];
59 pbkdf2_hmac::<Sha1>(&sum, PRNG_SALT, PBKDF2_LOOPS, &mut xoshiro);
60
61 let mut state = [
62 u64::from_le_bytes(xoshiro[0..8].try_into().unwrap()),
63 u64::from_le_bytes(xoshiro[8..16].try_into().unwrap()),
64 u64::from_le_bytes(xoshiro[16..24].try_into().unwrap()),
65 u64::from_le_bytes(xoshiro[24..32].try_into().unwrap()),
66 ];
67 let seed64 = xoshiro256ss(&mut state);
68
69 Rand {
70 xoshiro: state,
71 seed64,
72 count: 0,
73 }
74}
75
76pub struct QuantumPermutationPad {
78 pads: Vec<u8>,
79 rpads: Vec<u8>,
80 num_pads: u16,
81}
82
83fn qpp_minimum_seed_length(qubits: u8) -> usize {
84 let n: usize = 1 << qubits;
86 let mut log2_fact = 0f64;
87 for i in 2..=n {
88 log2_fact += (i as f64).log2();
89 }
90 let bit_len = log2_fact.ceil() as usize;
91 let byte_len = (bit_len + 7) / 8;
92 byte_len.max(1)
93}
94
95fn fill(pad: &mut [u8]) {
96 for (i, b) in pad.iter_mut().enumerate() {
97 *b = i as u8;
98 }
99}
100
101fn reverse(pad: &[u8], rpad: &mut [u8]) {
102 for (i, &p) in pad.iter().enumerate() {
103 rpad[p as usize] = i as u8;
104 }
105}
106
107fn seed_to_chunks(seed: &[u8], qubits: u8) -> Vec<Vec<u8>> {
108 let min_len = qpp_minimum_seed_length(qubits);
109 let seed = if seed.len() < 32 {
110 let mut derived = vec![0u8; 32];
111 pbkdf2_hmac::<Sha1>(seed, CHUNK_DERIVE_SALT, PBKDF2_LOOPS, &mut derived);
112 derived
113 } else {
114 seed.to_vec()
115 };
116
117 let chunk_count = ((min_len + 31) / 32).max(1);
118 let mut chunks = Vec::with_capacity(chunk_count);
119 let mut seed_idx = 0;
120 for _ in 0..chunk_count {
121 let mut chunk = vec![0u8; 32];
122 for j in 0..32 {
123 chunk[j] = seed[seed_idx % seed.len()];
124 seed_idx += 1;
125 }
126 let mut derived = vec![0u8; chunk.len()];
127 pbkdf2_hmac::<Sha1>(&chunk, CHUNK_DERIVE_SALT, CHUNK_DERIVE_LOOPS, &mut derived);
128 chunks.push(derived);
129 }
130 chunks
131}
132
133fn shuffle(chunk: &[u8], pad: &mut [u8], pad_id: u16, blocks: &mut [Aes256]) {
134 let mut mac = <HmacSha256 as Mac>::new_from_slice(chunk).expect("HMAC key");
135 let msg = format!("{}{:b}", PAD_IDENTIFIER, pad_id);
136 Mac::update(&mut mac, msg.as_bytes());
137 let sum = mac.finalize().into_bytes();
138 let mut sum = sum.to_vec();
139
140 for i in (1..pad.len()).rev() {
141 for block in blocks.iter_mut() {
142 for off in (0..sum.len()).step_by(16) {
143 if off + 16 <= sum.len() {
144 let mut block_data: GenericArray<u8, _> =
145 GenericArray::clone_from_slice(&sum[off..off + 16]);
146 block.encrypt_block_mut(&mut block_data);
147 sum[off..off + 16].copy_from_slice(block_data.as_slice());
148 }
149 }
150 }
151 let bigrand = BigUint::from_bytes_be(&sum);
152 let modulus = BigUint::from(i + 1);
153 let rem = &bigrand % &modulus;
154 let digits = rem.to_u64_digits();
155 let j = digits.first().copied().unwrap_or(0) as usize;
156 pad.swap(i, j);
157 }
158}
159
160impl QuantumPermutationPad {
161 pub fn new(seed: &[u8], num_pads: u16) -> Self {
163 let chunks = seed_to_chunks(seed, QUBITS);
164 let mut blocks: Vec<Aes256> = Vec::with_capacity(chunks.len());
165 for chunk in &chunks {
166 let mut aeskey = [0u8; 32];
167 pbkdf2_hmac::<Sha1>(chunk, SHUFFLE_SALT, PBKDF2_LOOPS, &mut aeskey);
168 blocks.push(Aes256::new_from_slice(&aeskey).expect("AES256"));
169 }
170
171 let mut pads = vec![0u8; num_pads as usize * MATRIX_BYTES];
172 let mut rpads = vec![0u8; num_pads as usize * MATRIX_BYTES];
173
174 for i in 0..num_pads {
175 let pad_start = (i as usize) * MATRIX_BYTES;
176 let pad_end = pad_start + MATRIX_BYTES;
177 let (pad, rpad) = (
178 &mut pads[pad_start..pad_end],
179 &mut rpads[pad_start..pad_end],
180 );
181 fill(pad);
182 shuffle(&chunks[i as usize % chunks.len()], pad, i, &mut blocks);
183 reverse(pad, rpad);
184 }
185
186 QuantumPermutationPad {
187 pads,
188 rpads,
189 num_pads,
190 }
191 }
192
193 pub fn encrypt_with_prng(&self, data: &mut [u8], rand: &mut Rand) {
195 if data.is_empty() {
196 return;
197 }
198 let size = data.len();
199 let num_pads = self.num_pads;
200 let mut r = rand.seed64;
201 let mut count = rand.count;
202 let [mut s0, mut s1, mut s2, mut s3] = rand.xoshiro;
203
204 let mut offset = 0;
205
206 if count != 0 {
208 while offset < data.len() {
209 let rr = (r >> (count << 3)) as u8;
210 let base = (r as u16 % num_pads) as usize * MATRIX_BYTES;
211 data[offset] = self.pads[base + (data[offset] ^ rr) as usize];
212 count += 1;
213 if count == PAD_SWITCH {
214 r = rol64(s1.wrapping_mul(5), 7).wrapping_mul(9);
215 let t = s1 << 17;
216 s2 ^= s0;
217 s3 ^= s1;
218 s1 ^= s2;
219 s0 ^= s3;
220 s2 ^= t;
221 s3 = rol64(s3, 45);
222 count = 0;
223 offset += 1;
224 break;
225 }
226 offset += 1;
227 }
228 }
229
230 let mut idx = offset;
232 let repeat = (data.len() - idx) >> 4;
233 for _ in 0..repeat {
234 {
235 let d = &mut data[idx..idx + 16];
236 let base = (r as u16 % num_pads) as usize * MATRIX_BYTES;
237 d[0] = self.pads[base + (d[0] ^ r as u8) as usize];
238 d[1] = self.pads[base + (d[1] ^ (r >> 8) as u8) as usize];
239 d[2] = self.pads[base + (d[2] ^ (r >> 16) as u8) as usize];
240 d[3] = self.pads[base + (d[3] ^ (r >> 24) as u8) as usize];
241 d[4] = self.pads[base + (d[4] ^ (r >> 32) as u8) as usize];
242 d[5] = self.pads[base + (d[5] ^ (r >> 40) as u8) as usize];
243 d[6] = self.pads[base + (d[6] ^ (r >> 48) as u8) as usize];
244 d[7] = self.pads[base + (d[7] ^ (r >> 56) as u8) as usize];
245 }
246 r = rol64(s1.wrapping_mul(5), 7).wrapping_mul(9);
247 let t = s1 << 17;
248 s2 ^= s0;
249 s3 ^= s1;
250 s1 ^= s2;
251 s0 ^= s3;
252 s2 ^= t;
253 s3 = rol64(s3, 45);
254 let base = (r as u16 % num_pads) as usize * MATRIX_BYTES;
255 {
256 let d = &mut data[idx + 8..idx + 16];
257 d[0] = self.pads[base + (d[0] ^ r as u8) as usize];
258 d[1] = self.pads[base + (d[1] ^ (r >> 8) as u8) as usize];
259 d[2] = self.pads[base + (d[2] ^ (r >> 16) as u8) as usize];
260 d[3] = self.pads[base + (d[3] ^ (r >> 24) as u8) as usize];
261 d[4] = self.pads[base + (d[4] ^ (r >> 32) as u8) as usize];
262 d[5] = self.pads[base + (d[5] ^ (r >> 40) as u8) as usize];
263 d[6] = self.pads[base + (d[6] ^ (r >> 48) as u8) as usize];
264 d[7] = self.pads[base + (d[7] ^ (r >> 56) as u8) as usize];
265 }
266 r = rol64(s1.wrapping_mul(5), 7).wrapping_mul(9);
267 let t = s1 << 17;
268 s2 ^= s0;
269 s3 ^= s1;
270 s1 ^= s2;
271 s0 ^= s3;
272 s2 ^= t;
273 s3 = rol64(s3, 45);
274 idx += 16;
275 }
276
277 if idx + 8 <= data.len() {
279 let d = &mut data[idx..idx + 8];
280 let base = (r as u16 % num_pads) as usize * MATRIX_BYTES;
281 d[0] = self.pads[base + (d[0] ^ r as u8) as usize];
282 d[1] = self.pads[base + (d[1] ^ (r >> 8) as u8) as usize];
283 d[2] = self.pads[base + (d[2] ^ (r >> 16) as u8) as usize];
284 d[3] = self.pads[base + (d[3] ^ (r >> 24) as u8) as usize];
285 d[4] = self.pads[base + (d[4] ^ (r >> 32) as u8) as usize];
286 d[5] = self.pads[base + (d[5] ^ (r >> 40) as u8) as usize];
287 d[6] = self.pads[base + (d[6] ^ (r >> 48) as u8) as usize];
288 d[7] = self.pads[base + (d[7] ^ (r >> 56) as u8) as usize];
289 r = rol64(s1.wrapping_mul(5), 7).wrapping_mul(9);
290 let t = s1 << 17;
291 s2 ^= s0;
292 s3 ^= s1;
293 s1 ^= s2;
294 s0 ^= s3;
295 s2 ^= t;
296 s3 = rol64(s3, 45);
297 idx += 8;
298 }
299
300 for i in idx..data.len() {
302 let rr = (r >> (count << 3)) as u8;
303 let base = (r as u16 % num_pads) as usize * MATRIX_BYTES;
304 data[i] = self.pads[base + (data[i] ^ rr) as usize];
305 count += 1;
306 }
307
308 rand.xoshiro = [s0, s1, s2, s3];
309 rand.seed64 = r;
310 rand.count = ((rand.count as usize + size) & (PAD_SWITCH as usize - 1)) as u8;
311 }
312
313 pub fn decrypt_with_prng(&self, data: &mut [u8], rand: &mut Rand) {
315 if data.is_empty() {
316 return;
317 }
318 let size = data.len();
319 let num_pads = self.num_pads;
320 let mut r = rand.seed64;
321 let mut count = rand.count;
322 let [mut s0, mut s1, mut s2, mut s3] = rand.xoshiro;
323
324 let mut offset = 0;
325
326 if count != 0 {
327 while offset < data.len() {
328 let rr = (r >> (count << 3)) as u8;
329 let base = (r as u16 % num_pads) as usize * MATRIX_BYTES;
330 data[offset] = self.rpads[base + data[offset] as usize] ^ rr;
331 count += 1;
332 if count == PAD_SWITCH {
333 r = rol64(s1.wrapping_mul(5), 7).wrapping_mul(9);
334 let t = s1 << 17;
335 s2 ^= s0;
336 s3 ^= s1;
337 s1 ^= s2;
338 s0 ^= s3;
339 s2 ^= t;
340 s3 = rol64(s3, 45);
341 count = 0;
342 offset += 1;
343 break;
344 }
345 offset += 1;
346 }
347 }
348
349 let mut idx = offset;
350 let repeat = (data.len() - idx) >> 4;
351 for _ in 0..repeat {
352 {
353 let d = &mut data[idx..idx + 8];
354 let base = (r as u16 % num_pads) as usize * MATRIX_BYTES;
355 let (rr0, rr1, rr2, rr3) = (r as u8, (r >> 8) as u8, (r >> 16) as u8, (r >> 24) as u8);
356 let (rr4, rr5, rr6, rr7) =
357 ((r >> 32) as u8, (r >> 40) as u8, (r >> 48) as u8, (r >> 56) as u8);
358 d[0] = self.rpads[base + d[0] as usize] ^ rr0;
359 d[1] = self.rpads[base + d[1] as usize] ^ rr1;
360 d[2] = self.rpads[base + d[2] as usize] ^ rr2;
361 d[3] = self.rpads[base + d[3] as usize] ^ rr3;
362 d[4] = self.rpads[base + d[4] as usize] ^ rr4;
363 d[5] = self.rpads[base + d[5] as usize] ^ rr5;
364 d[6] = self.rpads[base + d[6] as usize] ^ rr6;
365 d[7] = self.rpads[base + d[7] as usize] ^ rr7;
366 }
367 r = rol64(s1.wrapping_mul(5), 7).wrapping_mul(9);
368 let t = s1 << 17;
369 s2 ^= s0;
370 s3 ^= s1;
371 s1 ^= s2;
372 s0 ^= s3;
373 s2 ^= t;
374 s3 = rol64(s3, 45);
375 let base = (r as u16 % num_pads) as usize * MATRIX_BYTES;
376 {
377 let d = &mut data[idx + 8..idx + 16];
378 let (rr0, rr1, rr2, rr3) = (r as u8, (r >> 8) as u8, (r >> 16) as u8, (r >> 24) as u8);
379 let (rr4, rr5, rr6, rr7) =
380 ((r >> 32) as u8, (r >> 40) as u8, (r >> 48) as u8, (r >> 56) as u8);
381 d[0] = self.rpads[base + d[0] as usize] ^ rr0;
382 d[1] = self.rpads[base + d[1] as usize] ^ rr1;
383 d[2] = self.rpads[base + d[2] as usize] ^ rr2;
384 d[3] = self.rpads[base + d[3] as usize] ^ rr3;
385 d[4] = self.rpads[base + d[4] as usize] ^ rr4;
386 d[5] = self.rpads[base + d[5] as usize] ^ rr5;
387 d[6] = self.rpads[base + d[6] as usize] ^ rr6;
388 d[7] = self.rpads[base + d[7] as usize] ^ rr7;
389 }
390 r = rol64(s1.wrapping_mul(5), 7).wrapping_mul(9);
391 let t = s1 << 17;
392 s2 ^= s0;
393 s3 ^= s1;
394 s1 ^= s2;
395 s0 ^= s3;
396 s2 ^= t;
397 s3 = rol64(s3, 45);
398 idx += 16;
399 }
400
401 if idx + 8 <= data.len() {
402 let d = &mut data[idx..idx + 8];
403 let base = (r as u16 % num_pads) as usize * MATRIX_BYTES;
404 let (rr0, rr1, rr2, rr3) = (r as u8, (r >> 8) as u8, (r >> 16) as u8, (r >> 24) as u8);
405 let (rr4, rr5, rr6, rr7) =
406 ((r >> 32) as u8, (r >> 40) as u8, (r >> 48) as u8, (r >> 56) as u8);
407 d[0] = self.rpads[base + d[0] as usize] ^ rr0;
408 d[1] = self.rpads[base + d[1] as usize] ^ rr1;
409 d[2] = self.rpads[base + d[2] as usize] ^ rr2;
410 d[3] = self.rpads[base + d[3] as usize] ^ rr3;
411 d[4] = self.rpads[base + d[4] as usize] ^ rr4;
412 d[5] = self.rpads[base + d[5] as usize] ^ rr5;
413 d[6] = self.rpads[base + d[6] as usize] ^ rr6;
414 d[7] = self.rpads[base + d[7] as usize] ^ rr7;
415 r = rol64(s1.wrapping_mul(5), 7).wrapping_mul(9);
416 let t = s1 << 17;
417 s2 ^= s0;
418 s3 ^= s1;
419 s1 ^= s2;
420 s0 ^= s3;
421 s2 ^= t;
422 s3 = rol64(s3, 45);
423 idx += 8;
424 }
425
426 for i in idx..data.len() {
427 let rr = (r >> (count << 3)) as u8;
428 let base = (r as u16 % num_pads) as usize * MATRIX_BYTES;
429 data[i] = self.rpads[base + data[i] as usize] ^ rr;
430 count += 1;
431 }
432
433 rand.xoshiro = [s0, s1, s2, s3];
434 rand.seed64 = r;
435 rand.count = ((rand.count as usize + size) & (PAD_SWITCH as usize - 1)) as u8;
436 }
437}