1use rand::rngs::StdRng;
14use rand::{thread_rng, Rng, SeedableRng};
15
16const NUM_OF_BOXES: usize = 49; const BLOCK_SIZE: usize = 256; const KEY_SIZE: usize = 80; const ROUNDS: usize = 12; #[derive(Clone, Debug, PartialEq)]
24struct BitVec {
25 words: Vec<u32>,
26 bits: usize,
27}
28
29impl BitVec {
30 fn new(bits: usize) -> Self {
31 let words = bits.div_ceil(32);
32 BitVec {
33 words: vec![0u32; words],
34 bits,
35 }
36 }
37
38 fn get(&self, index: usize) -> bool {
39 if index >= self.bits {
40 return false;
41 }
42 let word_idx = index / 32;
43 let bit_idx = index % 32;
44 (self.words[word_idx] >> bit_idx) & 1 == 1
45 }
46
47 fn set(&mut self, index: usize, value: bool) {
48 if index >= self.bits {
49 return;
50 }
51 let word_idx = index / 32;
52 let bit_idx = index % 32;
53 if value {
54 self.words[word_idx] |= 1 << bit_idx;
55 } else {
56 self.words[word_idx] &= !(1 << bit_idx);
57 }
58 }
59
60 fn count_ones(&self) -> u32 {
61 self.words.iter().map(|w| w.count_ones()).sum()
62 }
63
64 fn xor_assign(&mut self, other: &BitVec) {
65 for (a, b) in self.words.iter_mut().zip(other.words.iter()) {
66 *a ^= b;
67 }
68 }
69
70 fn and(&self, other: &BitVec) -> BitVec {
71 let mut result = BitVec::new(self.bits);
72 for i in 0..self.words.len().min(other.words.len()) {
73 result.words[i] = self.words[i] & other.words[i];
74 }
75 result
76 }
77
78 fn from_u128(value: u128, bits: usize) -> BitVec {
79 let mut result = BitVec::new(bits);
80 let bytes = value.to_le_bytes();
81 for (i, &byte) in bytes.iter().enumerate() {
82 for j in 0..8 {
83 if i * 8 + j < bits {
84 result.set(i * 8 + j, (byte >> j) & 1 == 1);
85 }
86 }
87 }
88 result
89 }
90
91 fn to_u128(&self) -> u128 {
92 let mut bytes = [0u8; 16];
93 for (i, byte) in bytes.iter_mut().enumerate() {
94 for j in 0..8 {
95 if i * 8 + j < self.bits && self.get(i * 8 + j) {
96 *byte |= 1 << j;
97 }
98 }
99 }
100 u128::from_le_bytes(bytes)
101 }
102}
103
104pub struct LowMC {
106 sbox: [u8; 8],
108 inv_sbox: [u8; 8],
109
110 lin_matrices: Vec<Vec<BitVec>>,
112 inv_lin_matrices: Vec<Vec<BitVec>>,
113 round_constants: Vec<BitVec>,
114 key_matrices: Vec<Vec<BitVec>>,
115 round_keys: Vec<BitVec>,
116
117 key: BitVec,
119}
120
121impl LowMC {
122 pub fn new(key: u128) -> Self {
124 let mut cipher = LowMC {
125 sbox: [0x00, 0x01, 0x03, 0x06, 0x07, 0x04, 0x05, 0x02],
126 inv_sbox: [0x00, 0x01, 0x07, 0x02, 0x05, 0x06, 0x03, 0x04],
127 lin_matrices: Vec::new(),
128 inv_lin_matrices: Vec::new(),
129 round_constants: Vec::new(),
130 key_matrices: Vec::new(),
131 round_keys: Vec::new(),
132 key: BitVec::from_u128(key, KEY_SIZE),
133 };
134
135 cipher.instantiate_lowmc(key);
136 cipher.keyschedule();
137 cipher
138 }
139
140 pub fn generate_random_key() -> u128 {
142 let mut rng = thread_rng();
143 rng.gen()
144 }
145
146 pub fn encrypt_full(&self, low: u128, high: u128) -> (u128, u128) {
148 let mut state = BitVec::new(BLOCK_SIZE);
149
150 let low_bytes = low.to_le_bytes();
152 for (i, &byte) in low_bytes.iter().enumerate() {
153 for j in 0..8 {
154 if i * 8 + j < 128 {
155 state.set(i * 8 + j, (byte >> j) & 1 == 1);
156 }
157 }
158 }
159
160 let high_bytes = high.to_le_bytes();
162 for (i, &byte) in high_bytes.iter().enumerate() {
163 for j in 0..8 {
164 if 128 + i * 8 + j < BLOCK_SIZE {
165 state.set(128 + i * 8 + j, (byte >> j) & 1 == 1);
166 }
167 }
168 }
169
170 state.xor_assign(&self.round_keys[0]);
172
173 for round in 0..ROUNDS {
175 state = self.substitution(&state);
177
178 state = self.multiply_with_gf2_matrix(&self.lin_matrices[round], &state);
180
181 state.xor_assign(&self.round_constants[round]);
183
184 state.xor_assign(&self.round_keys[round + 1]);
186 }
187
188 let mut low_bytes = [0u8; 16];
190 let mut high_bytes = [0u8; 16];
191
192 for i in 0..16 {
193 for j in 0..8 {
194 if i * 8 + j < 128 && state.get(i * 8 + j) {
195 low_bytes[i] |= 1 << j;
196 }
197 if 128 + i * 8 + j < BLOCK_SIZE && state.get(128 + i * 8 + j) {
198 high_bytes[i] |= 1 << j;
199 }
200 }
201 }
202
203 (
204 u128::from_le_bytes(low_bytes),
205 u128::from_le_bytes(high_bytes),
206 )
207 }
208
209 pub fn decrypt_full(&self, low: u128, high: u128) -> (u128, u128) {
211 let mut state = BitVec::new(BLOCK_SIZE);
212
213 let low_bytes = low.to_le_bytes();
215 for (i, &byte) in low_bytes.iter().enumerate() {
216 for j in 0..8 {
217 if i * 8 + j < 128 {
218 state.set(i * 8 + j, (byte >> j) & 1 == 1);
219 }
220 }
221 }
222
223 let high_bytes = high.to_le_bytes();
225 for (i, &byte) in high_bytes.iter().enumerate() {
226 for j in 0..8 {
227 if 128 + i * 8 + j < BLOCK_SIZE {
228 state.set(128 + i * 8 + j, (byte >> j) & 1 == 1);
229 }
230 }
231 }
232
233 for round in (0..ROUNDS).rev() {
235 state.xor_assign(&self.round_keys[round + 1]);
237
238 state.xor_assign(&self.round_constants[round]);
240
241 state = self.multiply_with_gf2_matrix(&self.inv_lin_matrices[round], &state);
243
244 state = self.inv_substitution(&state);
246 }
247
248 state.xor_assign(&self.round_keys[0]);
250
251 let mut low_bytes = [0u8; 16];
253 let mut high_bytes = [0u8; 16];
254
255 for i in 0..16 {
256 for j in 0..8 {
257 if i * 8 + j < 128 && state.get(i * 8 + j) {
258 low_bytes[i] |= 1 << j;
259 }
260 if 128 + i * 8 + j < BLOCK_SIZE && state.get(128 + i * 8 + j) {
261 high_bytes[i] |= 1 << j;
262 }
263 }
264 }
265
266 (
267 u128::from_le_bytes(low_bytes),
268 u128::from_le_bytes(high_bytes),
269 )
270 }
271
272 pub fn encrypt(&self, message: u128) -> (u128, u128) {
276 self.encrypt_full(message, 0)
277 }
278
279 pub fn decrypt(&self, ciphertext_low: u128, ciphertext_high: u128) -> u128 {
283 let (plaintext_low, _plaintext_high) = self.decrypt_full(ciphertext_low, ciphertext_high);
284 plaintext_low
285 }
286
287 #[deprecated(
291 note = "Use encrypt() which returns the full result, or encrypt_full() for explicit 256-bit operation"
292 )]
293 pub fn encrypt_128_legacy(&self, message: u128) -> u128 {
294 let (low, _high) = self.encrypt_full(message, 0);
295 low
296 }
297
298 pub fn set_key(&mut self, key: u128) {
300 self.key = BitVec::from_u128(key, KEY_SIZE);
301 self.instantiate_lowmc(key);
303 self.keyschedule();
304 }
305
306 fn substitution(&self, message: &BitVec) -> BitVec {
307 let mut result = message.clone();
308
309 for sbox_idx in 0..NUM_OF_BOXES {
311 let bit_pos = sbox_idx * 3;
312
313 let input = (if result.get(bit_pos) { 1 } else { 0 })
315 | (if result.get(bit_pos + 1) { 2 } else { 0 })
316 | (if result.get(bit_pos + 2) { 4 } else { 0 });
317
318 let output = self.sbox[input as usize];
319
320 result.set(bit_pos, (output & 1) != 0);
322 result.set(bit_pos + 1, (output & 2) != 0);
323 result.set(bit_pos + 2, (output & 4) != 0);
324 }
325
326 result
327 }
328
329 fn inv_substitution(&self, message: &BitVec) -> BitVec {
330 let mut result = message.clone();
331
332 for sbox_idx in 0..NUM_OF_BOXES {
334 let bit_pos = sbox_idx * 3;
335
336 let input = (if result.get(bit_pos) { 1 } else { 0 })
338 | (if result.get(bit_pos + 1) { 2 } else { 0 })
339 | (if result.get(bit_pos + 2) { 4 } else { 0 });
340
341 let output = self.inv_sbox[input as usize];
342
343 result.set(bit_pos, (output & 1) != 0);
345 result.set(bit_pos + 1, (output & 2) != 0);
346 result.set(bit_pos + 2, (output & 4) != 0);
347 }
348
349 result
350 }
351
352 fn multiply_with_gf2_matrix(&self, matrix: &[BitVec], message: &BitVec) -> BitVec {
353 Self::multiply_with_gf2_matrix_static(matrix, message)
354 }
355
356 fn multiply_with_gf2_matrix_static(matrix: &[BitVec], message: &BitVec) -> BitVec {
357 let mut result = BitVec::new(matrix.len());
358
359 for (i, matrix_row) in matrix.iter().enumerate() {
360 let and_result = matrix_row.and(message);
361 let bit_result = and_result.count_ones() % 2 == 1;
362 result.set(i, bit_result);
363 }
364
365 result
366 }
367
368 fn keyschedule(&mut self) {
369 self.round_keys.clear();
370
371 for round in 0..=ROUNDS {
373 if round == 0 {
374 let mut round_key = BitVec::new(BLOCK_SIZE);
376 for i in 0..KEY_SIZE.min(BLOCK_SIZE) {
377 round_key.set(i, self.key.get(i));
378 }
379 self.round_keys.push(round_key);
380 } else {
381 let round_key =
383 self.multiply_with_gf2_matrix(&self.key_matrices[round - 1], &self.key);
384 self.round_keys.push(round_key);
386 }
387 }
388 }
389
390 fn instantiate_lowmc(&mut self, key_seed: u128) {
391 let seed = key_seed as u64 ^ (key_seed >> 64) as u64;
393 let mut rng = StdRng::seed_from_u64(seed);
394
395 self.lin_matrices.clear();
396 self.inv_lin_matrices.clear();
397 self.round_constants.clear();
398 self.key_matrices.clear();
399
400 for _ in 0..ROUNDS {
402 let matrix = Self::generate_matrix_with_rng(&mut rng, BLOCK_SIZE);
403 let inv_matrix = Self::invert_matrix(&matrix);
404 self.lin_matrices.push(matrix);
405 self.inv_lin_matrices.push(inv_matrix);
406 }
407
408 for _ in 0..ROUNDS {
410 self.round_constants
411 .push(Self::generate_block_with_rng(&mut rng, BLOCK_SIZE));
412 }
413
414 for _ in 0..ROUNDS {
416 let mut key_matrix = Vec::new();
417 for _ in 0..BLOCK_SIZE {
418 key_matrix.push(Self::generate_block_with_rng(&mut rng, KEY_SIZE));
419 }
420 self.key_matrices.push(key_matrix);
421 }
422 }
423
424 fn generate_matrix_with_rng<R: Rng>(rng: &mut R, size: usize) -> Vec<BitVec> {
425 let mut matrix = Vec::new();
430
431 for i in 0..size {
432 let mut row = BitVec::new(size);
433 row.set(i, true);
435 for j in (i + 1)..size {
437 row.set(j, rng.gen::<bool>());
438 }
439 matrix.push(row);
440 }
441
442 matrix
443 }
444
445 fn generate_block_with_rng<R: Rng>(rng: &mut R, bits: usize) -> BitVec {
446 let mut block = BitVec::new(bits);
447 for i in 0..bits {
448 block.set(i, rng.gen::<bool>());
449 }
450 block
451 }
452
453 fn invert_matrix(matrix: &[BitVec]) -> Vec<BitVec> {
454 let n = matrix.len();
455 let mut augmented = Vec::new();
456
457 for (i, row) in matrix.iter().enumerate() {
459 let mut aug_row = BitVec::new(2 * n);
460 for j in 0..n {
462 aug_row.set(j, row.get(j));
463 }
464 aug_row.set(n + i, true);
466 augmented.push(aug_row);
467 }
468
469 for i in 0..n {
471 let mut pivot_row = i;
473 for (k, row) in augmented.iter().enumerate().skip(i + 1) {
474 if row.get(i) {
475 pivot_row = k;
476 break;
477 }
478 }
479
480 if pivot_row != i {
482 augmented.swap(i, pivot_row);
483 }
484
485 let pivot_row = augmented[i].clone();
487 for (j, row) in augmented.iter_mut().enumerate() {
488 if i != j && row.get(i) {
489 row.xor_assign(&pivot_row);
490 }
491 }
492 }
493
494 let mut inverse = Vec::new();
496 for row in augmented.iter().take(n) {
497 let mut inv_row = BitVec::new(n);
498 for j in 0..n {
499 inv_row.set(j, row.get(n + j));
500 }
501 inverse.push(inv_row);
502 }
503
504 inverse
505 }
506
507 pub fn new_simple_test(key: u128) -> Self {
509 let mut cipher = LowMC {
510 sbox: [0x00, 0x01, 0x03, 0x06, 0x07, 0x04, 0x05, 0x02],
511 inv_sbox: [0x00, 0x01, 0x07, 0x02, 0x05, 0x06, 0x03, 0x04],
512 lin_matrices: Vec::new(),
513 inv_lin_matrices: Vec::new(),
514 round_constants: Vec::new(),
515 key_matrices: Vec::new(),
516 round_keys: Vec::new(),
517 key: BitVec::from_u128(key, KEY_SIZE),
518 };
519
520 for _ in 0..ROUNDS {
522 let mut identity = Vec::new();
523 for i in 0..BLOCK_SIZE {
524 let mut row = BitVec::new(BLOCK_SIZE);
525 row.set(i, true);
526 identity.push(row);
527 }
528 cipher.lin_matrices.push(identity.clone());
529 cipher.inv_lin_matrices.push(identity);
530
531 cipher.round_constants.push(BitVec::new(BLOCK_SIZE));
532 }
533
534 for _ in 0..ROUNDS {
536 let mut key_matrix = Vec::new();
537 for _ in 0..BLOCK_SIZE {
538 key_matrix.push(BitVec::new(KEY_SIZE));
539 }
540 cipher.key_matrices.push(key_matrix);
541 }
542
543 cipher.keyschedule();
544 cipher
545 }
546
547 pub fn new_single_round_test(key: u128) -> Self {
549 let mut cipher = LowMC {
550 sbox: [0x00, 0x01, 0x03, 0x06, 0x07, 0x04, 0x05, 0x02],
551 inv_sbox: [0x00, 0x01, 0x07, 0x02, 0x05, 0x06, 0x03, 0x04],
552 lin_matrices: Vec::new(),
553 inv_lin_matrices: Vec::new(),
554 round_constants: Vec::new(),
555 key_matrices: Vec::new(),
556 round_keys: Vec::new(),
557 key: BitVec::from_u128(key, KEY_SIZE),
558 };
559
560 let seed = key as u64;
562 let mut rng = StdRng::seed_from_u64(seed);
563
564 let matrix = Self::generate_matrix_with_rng(&mut rng, BLOCK_SIZE);
566 let inv_matrix = Self::invert_matrix(&matrix);
567 cipher.lin_matrices.push(matrix);
568 cipher.inv_lin_matrices.push(inv_matrix);
569 cipher
570 .round_constants
571 .push(Self::generate_block_with_rng(&mut rng, BLOCK_SIZE));
572
573 let mut key_matrix = Vec::new();
575 for _ in 0..BLOCK_SIZE {
576 key_matrix.push(Self::generate_block_with_rng(&mut rng, KEY_SIZE));
577 }
578 cipher.key_matrices.push(key_matrix);
579
580 cipher.keyschedule();
581 cipher
582 }
583
584 pub fn encrypt_single_round(&self, message: u128) -> u128 {
586 let mut state = BitVec::from_u128(message, BLOCK_SIZE);
587 state.xor_assign(&self.round_keys[0]);
588 state = self.substitution(&state);
589 state = self.multiply_with_gf2_matrix(&self.lin_matrices[0], &state);
590 state.xor_assign(&self.round_constants[0]);
591 state.xor_assign(&self.round_keys[1]);
592 state.to_u128()
593 }
594
595 pub fn decrypt_single_round(&self, message: u128) -> u128 {
597 let mut state = BitVec::from_u128(message, BLOCK_SIZE);
598 state.xor_assign(&self.round_keys[1]);
599 state.xor_assign(&self.round_constants[0]);
600 state = self.multiply_with_gf2_matrix(&self.inv_lin_matrices[0], &state);
601 state = self.inv_substitution(&state);
602 state.xor_assign(&self.round_keys[0]);
603 state.to_u128()
604 }
605}
606
607#[cfg(test)]
608mod tests {
609 use super::*;
610
611 #[test]
612 fn test_sbox_inversion() {
613 let sbox = [0x00, 0x01, 0x03, 0x06, 0x07, 0x04, 0x05, 0x02];
614 let inv_sbox = [0x00, 0x01, 0x07, 0x02, 0x05, 0x06, 0x03, 0x04];
615
616 for i in 0..8 {
617 let forward = sbox[i] as usize;
618 let backward = inv_sbox[forward] as usize;
619 assert_eq!(backward, i, "S-box inversion failed for input {}", i);
620 }
621 }
622
623 #[test]
624 fn test_substitution_layer() {
625 let cipher = LowMC::new(1);
626 let test_values = [0x0u128, 0x1u128, 0x7u128, 0xFFu128, 0xFFD5u128];
627
628 for &test_val in &test_values {
629 let test_bits = BitVec::from_u128(test_val, BLOCK_SIZE);
630 let substituted = cipher.substitution(&test_bits);
631 let recovered = cipher.inv_substitution(&substituted);
632
633 assert_eq!(
634 test_bits.to_u128(),
635 recovered.to_u128(),
636 "Substitution layer inversion failed for {:#x}",
637 test_val
638 );
639 }
640 }
641
642 #[test]
643 fn test_matrix_inversion() {
644 let mut rng = thread_rng();
645 let matrix = LowMC::generate_matrix_with_rng(&mut rng, BLOCK_SIZE);
646 let inv_matrix = LowMC::invert_matrix(&matrix);
647 let test_values = [0x0u128, 0x1u128, 0xFFD5u128];
648
649 for &test_val in &test_values {
650 let test_bits = BitVec::from_u128(test_val, BLOCK_SIZE);
651 let transformed = LowMC::multiply_with_gf2_matrix_static(&matrix, &test_bits);
652 let recovered = LowMC::multiply_with_gf2_matrix_static(&inv_matrix, &transformed);
653
654 assert_eq!(
655 test_bits.to_u128(),
656 recovered.to_u128(),
657 "Matrix inversion failed for {:#x}",
658 test_val
659 );
660 }
661 }
662
663 #[test]
664 fn test_single_round() {
665 let cipher = LowMC::new(1);
666 let test_values = [0x0u128, 0x1u128, 0xFFD5u128];
667
668 for &plaintext in &test_values {
669 let mut state = BitVec::from_u128(plaintext, BLOCK_SIZE);
670
671 state.xor_assign(&cipher.round_keys[0]);
673 state = cipher.substitution(&state);
674 state = cipher.multiply_with_gf2_matrix(&cipher.lin_matrices[0], &state);
675 state.xor_assign(&cipher.round_constants[0]);
676 state.xor_assign(&cipher.round_keys[1]);
677
678 let mut reverse_state = state.clone();
680 reverse_state.xor_assign(&cipher.round_keys[1]);
681 reverse_state.xor_assign(&cipher.round_constants[0]);
682 reverse_state =
683 cipher.multiply_with_gf2_matrix(&cipher.inv_lin_matrices[0], &reverse_state);
684 reverse_state = cipher.inv_substitution(&reverse_state);
685 reverse_state.xor_assign(&cipher.round_keys[0]);
686
687 let recovered = reverse_state.to_u128();
688 assert_eq!(
689 plaintext, recovered,
690 "Single round inversion failed for {:#x}",
691 plaintext
692 );
693 }
694 }
695
696 #[test]
697 fn test_bit_vector_operations() {
698 let mut bv = BitVec::new(32);
699
700 bv.set(0, true);
702 bv.set(31, true);
703 assert!(bv.get(0));
704 assert!(bv.get(31));
705 assert!(!bv.get(15));
706
707 let mut bv2 = BitVec::new(32);
709 bv2.set(0, true);
710 bv2.set(15, true);
711
712 bv.xor_assign(&bv2);
713 assert!(!bv.get(0)); assert!(bv.get(15)); assert!(bv.get(31)); assert_eq!(bv.count_ones(), 2);
719 }
720
721 #[test]
722 fn test_lowmc_parameters() {
723 assert_eq!(BLOCK_SIZE, 256);
724 assert_eq!(KEY_SIZE, 80);
725 assert_eq!(ROUNDS, 12);
726 assert_eq!(NUM_OF_BOXES, 49);
727 assert_eq!(BLOCK_SIZE - 3 * NUM_OF_BOXES, 109); }
729
730 #[test]
731 fn test_encryption_decryption_deterministic() {
732 let cipher = LowMC::new(1);
733
734 let plaintext = 0x123456789ABCDEFu128;
736 let (ciphertext_low, ciphertext_high) = cipher.encrypt(plaintext);
737 let recovered = cipher.decrypt(ciphertext_low, ciphertext_high);
738
739 assert_ne!(
741 plaintext, ciphertext_low,
742 "Ciphertext should differ from plaintext"
743 );
744 assert_eq!(
745 plaintext, recovered,
746 "Decryption should recover original plaintext"
747 );
748 }
749
750 #[test]
751 fn test_multiple_values() {
752 let cipher = LowMC::new(42);
753 let test_values = [
754 0x0u128,
755 0x1u128,
756 0xDEADBEEFu128,
757 0x123456789ABCDEFu128,
758 0xFFFFFFFFFFFFFFFFu128,
759 ];
760
761 for &plaintext in &test_values {
762 let (ciphertext_low, ciphertext_high) = cipher.encrypt(plaintext);
763 let recovered = cipher.decrypt(ciphertext_low, ciphertext_high);
764
765 assert_ne!(
766 plaintext, ciphertext_low,
767 "Ciphertext should differ from plaintext for {:#x}",
768 plaintext
769 );
770 assert_eq!(
771 plaintext, recovered,
772 "Decryption should recover original plaintext for {:#x}",
773 plaintext
774 );
775 }
776 }
777
778 #[test]
779 fn test_128_bit_compatibility() {
780 let cipher = LowMC::new(1);
781 let plaintext = 0xDEADBEEFu128;
782
783 println!("=== Testing 128-bit API ===");
784 println!("Plaintext: {:#x}", plaintext);
785
786 let (ciphertext_low, ciphertext_high) = cipher.encrypt(plaintext);
787 println!(
788 "Ciphertext: low={:#x}, high={:#x}",
789 ciphertext_low, ciphertext_high
790 );
791
792 let recovered = cipher.decrypt(ciphertext_low, ciphertext_high);
793 println!("Recovered: {:#x}", recovered);
794
795 let success = plaintext == recovered;
796 println!("Success: {}", success);
797
798 assert_eq!(plaintext, recovered, "128-bit API should work correctly");
799 assert_ne!(
800 plaintext, ciphertext_low,
801 "Ciphertext should differ from plaintext"
802 );
803
804 println!("✅ 128-bit API works correctly!");
805 }
806}