1#![allow(deprecated)]
2#[allow(deprecated)]
20use aes::cipher::{Array, BlockCipherDecrypt, BlockCipherEncrypt, KeyInit};
21use aes::{Aes128, Aes256};
22use polyval::{Polyval, universal_hash::UniversalHash};
23
24use crate::common::{BLOCK_LENGTH, Direction, Error, absorb, xor_block, xor_blocks_3};
25use crate::hctr2::AesCipher;
26
27#[allow(non_camel_case_types)]
29#[deprecated(note = "Use common::Error instead")]
30pub type Hctr2FpError = Error;
31
32pub const fn is_power_of_two(n: u16) -> bool {
34 n > 0 && (n & (n - 1)) == 0
35}
36
37pub const fn bits_per_digit(radix: u16) -> u32 {
39 radix.trailing_zeros()
40}
41
42pub const fn first_block_length(radix: u16) -> usize {
45 assert!(radix >= 2 && radix <= 256);
46
47 if radix == 256 {
48 return 16;
49 }
50
51 if is_power_of_two(radix) {
52 let bpd = bits_per_digit(radix);
53 return 128_u32.div_ceil(bpd) as usize;
54 }
55
56 let mut k: usize = 1;
57 let mut capacity: u128 = radix as u128;
58
59 loop {
60 k += 1;
61 if let Some(next) = capacity.checked_mul(radix as u128) {
62 capacity = next;
63 } else {
64 return k;
65 }
66 }
67}
68
69pub fn encode_base_radix(value: u128, radix: u16, output: &mut [u8]) {
71 debug_assert!((2..=256).contains(&radix));
72 let min_len = first_block_length(radix);
73 debug_assert!(output.len() >= min_len);
74
75 if radix == 256 {
76 output[..16].copy_from_slice(&value.to_le_bytes());
77 return;
78 }
79
80 if is_power_of_two(radix) {
81 let bpd = bits_per_digit(radix);
82 let mask: u128 = ((1u128) << bpd) - 1;
83 let mut bits = value;
84
85 for digit in output.iter_mut() {
86 *digit = (bits & mask) as u8;
87 bits >>= bpd;
88 }
89 return;
90 }
91
92 let mut remaining = value;
93 for digit in output.iter_mut() {
94 *digit = (remaining % radix as u128) as u8;
95 remaining /= radix as u128;
96 }
97}
98
99pub fn decode_base_radix(digits: &[u8], radix: u16) -> Result<u128, Error> {
101 debug_assert!((2..=256).contains(&radix));
102
103 if radix == 256 {
104 if digits.len() < 16 {
105 return Err(Error::InputTooShort);
106 }
107 return Ok(u128::from_le_bytes(digits[..16].try_into().unwrap()));
108 }
109
110 for &d in digits {
111 if d >= radix as u8 {
112 return Err(Error::InvalidDigit);
113 }
114 }
115
116 if is_power_of_two(radix) {
117 let bpd = bits_per_digit(radix);
118 let mut value: u128 = 0;
119
120 for (i, &digit) in digits.iter().enumerate() {
121 let shift = (i as u32) * bpd;
122 if shift < 128 {
123 value |= (digit as u128) << shift;
124 }
125 }
126 return Ok(value);
127 }
128
129 let mut value: u128 = 0;
130 for &digit in digits.iter().rev() {
131 value = value
132 .wrapping_mul(radix as u128)
133 .wrapping_add(digit as u128);
134 }
135
136 Ok(value)
137}
138
139pub struct Hctr2Fp<Aes: AesCipher, const RADIX: u16> {
141 ks_enc: Aes,
142 ks_dec: Aes::Dec,
143 h: [u8; BLOCK_LENGTH],
144 l: [u8; BLOCK_LENGTH],
145}
146
147#[allow(non_camel_case_types)]
148pub type Hctr2Fp_128_Decimal = Hctr2Fp<Aes128, 10>;
150
151#[allow(non_camel_case_types)]
152pub type Hctr2Fp_256_Decimal = Hctr2Fp<Aes256, 10>;
154
155#[allow(non_camel_case_types)]
156pub type Hctr2Fp_128_Hex = Hctr2Fp<Aes128, 16>;
158
159#[allow(non_camel_case_types)]
160pub type Hctr2Fp_256_Hex = Hctr2Fp<Aes256, 16>;
162
163#[allow(non_camel_case_types)]
164pub type Hctr2Fp_128_Base64 = Hctr2Fp<Aes128, 64>;
166
167#[allow(non_camel_case_types)]
168pub type Hctr2Fp_256_Base64 = Hctr2Fp<Aes256, 64>;
170
171impl<Aes: AesCipher, const RADIX: u16> Hctr2Fp<Aes, RADIX> {
172 pub const FIRST_BLOCK_LENGTH: usize = first_block_length(RADIX);
174
175 pub const MIN_MESSAGE_LENGTH: usize = Self::FIRST_BLOCK_LENGTH;
177
178 pub const BLOCK_LENGTH: usize = BLOCK_LENGTH;
180
181 pub fn new(key: &[u8]) -> Self {
183 debug_assert_eq!(key.len(), Aes::KEY_LEN);
184
185 let ks_enc = Aes::new(Array::from_slice(key));
186 let ks_dec = Aes::new_dec(key);
187
188 let mut h_block = Array::clone_from_slice(&[0u8; 16]);
189 let mut l_block = Array::clone_from_slice(&{
190 let mut b = [0u8; 16];
191 b[0] = 1;
192 b
193 });
194 ks_enc.encrypt_block(&mut h_block);
195 ks_enc.encrypt_block(&mut l_block);
196
197 let h: [u8; 16] = h_block.as_slice().try_into().unwrap();
198 let l: [u8; 16] = l_block.as_slice().try_into().unwrap();
199 Self {
200 ks_enc,
201 ks_dec,
202 h,
203 l,
204 }
205 }
206
207 pub fn encrypt(
211 &self,
212 plaintext: &[u8],
213 tweak: &[u8],
214 ciphertext: &mut [u8],
215 ) -> Result<(), Error> {
216 self.hctr2fp(plaintext, tweak, ciphertext, Direction::Encrypt)
217 }
218
219 pub fn decrypt(
221 &self,
222 ciphertext: &[u8],
223 tweak: &[u8],
224 plaintext: &mut [u8],
225 ) -> Result<(), Error> {
226 self.hctr2fp(ciphertext, tweak, plaintext, Direction::Decrypt)
227 }
228
229 fn hctr2fp(
230 &self,
231 src: &[u8],
232 tweak: &[u8],
233 dst: &mut [u8],
234 direction: Direction,
235 ) -> Result<(), Error> {
236 debug_assert_eq!(dst.len(), src.len());
237
238 let first_block_len = Self::FIRST_BLOCK_LENGTH;
239 if src.len() < first_block_len {
240 return Err(Error::InputTooShort);
241 }
242
243 for &digit in src {
244 if digit >= RADIX as u8 {
245 return Err(Error::InvalidDigit);
246 }
247 }
248
249 let first_part = &src[..first_block_len];
250 let tail = &src[first_block_len..];
251
252 let mut block_bytes = [0u8; BLOCK_LENGTH];
253 let tweak_len_bits = tweak.len() * 8;
254 let tweak_len_bytes: u128 = if tail.len() % BLOCK_LENGTH == 0 {
255 (2 * tweak_len_bits + 2) as u128
256 } else {
257 (2 * tweak_len_bits + 3) as u128
258 };
259 block_bytes.copy_from_slice(&tweak_len_bytes.to_le_bytes());
260
261 let mut poly = Polyval::new(Array::from_slice(&self.h));
262 poly.update(&[Array::clone_from_slice(&block_bytes)]);
263
264 let full_tweak_blocks = tweak.len() / BLOCK_LENGTH;
265 for i in 0..full_tweak_blocks {
266 let block = Array::clone_from_slice(&tweak[i * BLOCK_LENGTH..(i + 1) * BLOCK_LENGTH]);
267 poly.update(&[block]);
268 }
269 let tweak_remainder = tweak.len() % BLOCK_LENGTH;
270 if tweak_remainder > 0 {
271 let mut padded_tweak = [0u8; BLOCK_LENGTH];
272 padded_tweak[..tweak_remainder]
273 .copy_from_slice(&tweak[full_tweak_blocks * BLOCK_LENGTH..]);
274 poly.update(&[Array::clone_from_slice(&padded_tweak)]);
275 }
276
277 let poly_after_tweak = poly.clone();
278
279 match direction {
280 Direction::Encrypt => {
281 let hh = absorb(&mut poly, tail);
282 let m_bits = decode_base_radix(first_part, RADIX)?;
283 let mut mm: [u8; BLOCK_LENGTH] = m_bits.to_le_bytes();
284 xor_block(&mut mm, &hh);
285
286 let mut uu_block = Array::clone_from_slice(&mm);
287 self.ks_enc.encrypt_block(&mut uu_block);
288 let uu: [u8; BLOCK_LENGTH] = uu_block.as_slice().try_into().unwrap();
289
290 let s = xor_blocks_3(&mm, &uu, &self.l);
291 fp_xctr::<Aes, RADIX>(
292 &self.ks_enc,
293 &mut dst[first_block_len..],
294 tail,
295 &s,
296 Direction::Encrypt,
297 );
298
299 let mut poly = poly_after_tweak;
300 let hh2 = absorb(&mut poly, &dst[first_block_len..]);
301 let mut u_bytes = uu;
302 xor_block(&mut u_bytes, &hh2);
303 encode_base_radix(
304 u128::from_le_bytes(u_bytes),
305 RADIX,
306 &mut dst[..first_block_len],
307 );
308 }
309 Direction::Decrypt => {
310 let hh2 = absorb(&mut poly, tail);
311 let u_bits = decode_base_radix(first_part, RADIX)?;
312 let mut uu: [u8; BLOCK_LENGTH] = u_bits.to_le_bytes();
313 xor_block(&mut uu, &hh2);
314
315 let mut mm_block = Array::clone_from_slice(&uu);
316 self.ks_dec.decrypt_block(&mut mm_block);
317 let mm: [u8; BLOCK_LENGTH] = mm_block.as_slice().try_into().unwrap();
318
319 let s = xor_blocks_3(&mm, &uu, &self.l);
320 fp_xctr::<Aes, RADIX>(
321 &self.ks_enc,
322 &mut dst[first_block_len..],
323 tail,
324 &s,
325 Direction::Decrypt,
326 );
327
328 let mut poly = poly_after_tweak;
329 let hh = absorb(&mut poly, &dst[first_block_len..]);
330 let mut m_bytes = mm;
331 xor_block(&mut m_bytes, &hh);
332 encode_base_radix(
333 u128::from_le_bytes(m_bytes),
334 RADIX,
335 &mut dst[..first_block_len],
336 );
337 }
338 }
339
340 Ok(())
341 }
342}
343
344fn fp_xctr<Aes: BlockCipherEncrypt, const RADIX: u16>(
345 ks_enc: &Aes,
346 dst: &mut [u8],
347 src: &[u8],
348 seed: &[u8; BLOCK_LENGTH],
349 dir: Direction,
350) {
351 debug_assert_eq!(dst.len(), src.len());
352
353 let mut counter: u64 = 1;
354 let mut i = 0;
355
356 if is_power_of_two(RADIX) {
357 let bpd = bits_per_digit(RADIX);
358 let digits_per_block = 128 / bpd as usize;
359 let mask: u128 = (RADIX as u128) - 1;
360
361 let mut block = [0u8; BLOCK_LENGTH];
362
363 while i + digits_per_block <= src.len() {
364 block[..8].copy_from_slice(&counter.to_le_bytes());
365 block[8..].fill(0);
366 for j in 0..BLOCK_LENGTH {
367 block[j] ^= seed[j];
368 }
369 let mut ga_block = Array::clone_from_slice(&block);
370 ks_enc.encrypt_block(&mut ga_block);
371 let mut ks_bytes = [0u8; 16];
372 ks_bytes.copy_from_slice(ga_block.as_slice());
373 let keystream = u128::from_le_bytes(ks_bytes);
374
375 let mut ks = keystream;
376 for j in 0..digits_per_block {
377 let ks_digit = (ks & mask) as u8;
378 let adjustment = match dir {
379 Direction::Encrypt => ks_digit,
380 Direction::Decrypt => {
381 (RADIX as u8).wrapping_sub(ks_digit) & ((RADIX as u8) - 1)
382 }
383 };
384 dst[i + j] = ((src[i + j] as u16 + adjustment as u16) & (RADIX - 1)) as u8;
385 ks >>= bpd;
386 }
387
388 counter += 1;
389 i += digits_per_block;
390 }
391
392 if i < src.len() {
393 block[..8].copy_from_slice(&counter.to_le_bytes());
394 block[8..].fill(0);
395 for j in 0..BLOCK_LENGTH {
396 block[j] ^= seed[j];
397 }
398 let mut ga_block = Array::clone_from_slice(&block);
399 ks_enc.encrypt_block(&mut ga_block);
400 let mut ks_bytes = [0u8; 16];
401 ks_bytes.copy_from_slice(ga_block.as_slice());
402 let keystream = u128::from_le_bytes(ks_bytes);
403
404 let mut ks = keystream;
405 while i < src.len() {
406 let ks_digit = (ks & mask) as u8;
407 let adjustment = match dir {
408 Direction::Encrypt => ks_digit,
409 Direction::Decrypt => {
410 (RADIX as u8).wrapping_sub(ks_digit) & ((RADIX as u8) - 1)
411 }
412 };
413 dst[i] = ((src[i] as u16 + adjustment as u16) & (RADIX - 1)) as u8;
414 ks >>= bpd;
415 i += 1;
416 }
417 }
418
419 return;
420 }
421
422 let mut block = [0u8; BLOCK_LENGTH];
423
424 while i < src.len() {
425 block[..8].copy_from_slice(&counter.to_le_bytes());
426 block[8..].fill(0);
427 for j in 0..BLOCK_LENGTH {
428 block[j] ^= seed[j];
429 }
430
431 let mut ga_block = Array::clone_from_slice(&block);
432 ks_enc.encrypt_block(&mut ga_block);
433 let mut ks_bytes = [0u8; 16];
434 ks_bytes.copy_from_slice(ga_block.as_slice());
435 let keystream = u128::from_le_bytes(ks_bytes);
436
437 let ks_digit = (keystream % (RADIX as u128)) as u8;
438 match dir {
439 Direction::Encrypt => {
440 dst[i] = ((src[i] as u16 + ks_digit as u16) % RADIX) as u8;
441 }
442 Direction::Decrypt => {
443 dst[i] = ((src[i] as u16 + RADIX - ks_digit as u16) % RADIX) as u8;
444 }
445 }
446
447 counter += 1;
448 i += 1;
449 }
450}
451
452#[cfg(test)]
453mod tests {
454 use super::*;
455
456 #[test]
457 fn test_first_block_length() {
458 assert_eq!(first_block_length(2), 128);
459 assert_eq!(first_block_length(10), 39);
460 assert_eq!(first_block_length(16), 32);
461 assert_eq!(first_block_length(64), 22);
462 assert_eq!(first_block_length(256), 16);
463 }
464
465 #[test]
466 fn test_encode_decode_decimal() {
467 let value: u128 = 12345678901234567890;
468 let mut digits = [0u8; 39];
469 encode_base_radix(value, 10, &mut digits);
470
471 let decoded = decode_base_radix(&digits, 10).unwrap();
472 assert_eq!(value, decoded);
473 }
474
475 #[test]
476 fn test_encode_decode_hex() {
477 let value: u128 = 0xDEADBEEFCAFEBABE_u128 << 64 | 0x123456789ABCDEF0_u128;
478 let mut digits = [0u8; 32];
479 encode_base_radix(value, 16, &mut digits);
480
481 let decoded = decode_base_radix(&digits, 16).unwrap();
482 assert_eq!(value, decoded);
483 }
484
485 #[test]
486 fn test_encode_decode_base64() {
487 let value: u128 = u128::MAX / 2;
488 let mut digits = [0u8; 22];
489 encode_base_radix(value, 64, &mut digits);
490
491 let decoded = decode_base_radix(&digits, 64).unwrap();
492 assert_eq!(value, decoded);
493 }
494
495 #[test]
496 fn test_hctr2fp_decimal_roundtrip() {
497 let key = [0u8; 16];
498 let cipher = Hctr2Fp_128_Decimal::new(&key);
499
500 let mut plaintext = vec![0u8; 40];
501 for i in 0..38 {
502 plaintext[i] = (i % 10) as u8;
503 }
504 plaintext[38] = 2;
505 plaintext[39] = 5;
506
507 let mut ciphertext = vec![0u8; plaintext.len()];
508 let mut decrypted = vec![0u8; plaintext.len()];
509
510 cipher
511 .encrypt(&plaintext, b"tweak", &mut ciphertext)
512 .unwrap();
513
514 for &d in &ciphertext {
515 assert!(d < 10);
516 }
517
518 cipher
519 .decrypt(&ciphertext, b"tweak", &mut decrypted)
520 .unwrap();
521 assert_eq!(plaintext, decrypted);
522 }
523
524 #[test]
525 fn test_hctr2fp_hex_roundtrip() {
526 let key = [0u8; 16];
527 let cipher = Hctr2Fp_128_Hex::new(&key);
528
529 let plaintext: Vec<u8> = (0..33).map(|i| (i % 16) as u8).collect();
530 let mut ciphertext = vec![0u8; plaintext.len()];
531 let mut decrypted = vec![0u8; plaintext.len()];
532
533 cipher
534 .encrypt(&plaintext, b"tweak", &mut ciphertext)
535 .unwrap();
536
537 for &d in &ciphertext {
538 assert!(d < 16);
539 }
540
541 cipher
542 .decrypt(&ciphertext, b"tweak", &mut decrypted)
543 .unwrap();
544 assert_eq!(plaintext, decrypted);
545 }
546
547 #[test]
548 fn test_hctr2fp_decimal_nonzero_key() {
549 let key: [u8; 16] = core::array::from_fn(|i| (i + 1) as u8);
550 let cipher = Hctr2Fp_128_Decimal::new(&key);
551
552 let mut plaintext = vec![0u8; 40];
553 for i in 0..38 {
554 plaintext[i] = (i % 10) as u8;
555 }
556 plaintext[38] = 1;
557 plaintext[39] = 7;
558
559 let mut ciphertext = vec![0u8; plaintext.len()];
560 let mut decrypted = vec![0u8; plaintext.len()];
561
562 cipher
563 .encrypt(&plaintext, b"tweak", &mut ciphertext)
564 .unwrap();
565 assert_ne!(plaintext, ciphertext);
566
567 cipher
568 .decrypt(&ciphertext, b"tweak", &mut decrypted)
569 .unwrap();
570 assert_eq!(plaintext, decrypted);
571 }
572
573 #[test]
574 fn test_hctr2fp_decimal_minimum_length() {
575 let key = [0u8; 16];
576 let cipher = Hctr2Fp_128_Decimal::new(&key);
577
578 let mut plaintext = [5u8; 39];
579 plaintext[38] = 2;
580
581 let mut ciphertext = [0u8; 39];
582 let mut decrypted = [0u8; 39];
583
584 cipher.encrypt(&plaintext, b"", &mut ciphertext).unwrap();
585 cipher.decrypt(&ciphertext, b"", &mut decrypted).unwrap();
586
587 assert_eq!(plaintext.as_slice(), decrypted.as_slice());
588 }
589
590 #[test]
591 fn test_hctr2fp_decimal_too_short() {
592 let key = [0u8; 16];
593 let cipher = Hctr2Fp_128_Decimal::new(&key);
594
595 let plaintext = [5u8; 38]; let mut ciphertext = [0u8; 38];
597
598 assert_eq!(
599 cipher.encrypt(&plaintext, b"", &mut ciphertext),
600 Err(Error::InputTooShort)
601 );
602 }
603
604 #[test]
605 fn test_hctr2fp_decimal_invalid_digit() {
606 let key = [0u8; 16];
607 let cipher = Hctr2Fp_128_Decimal::new(&key);
608
609 let mut plaintext = [5u8; 40];
610 plaintext[0] = 10; let mut ciphertext = [0u8; 40];
612
613 assert_eq!(
614 cipher.encrypt(&plaintext, b"", &mut ciphertext),
615 Err(Error::InvalidDigit)
616 );
617 }
618
619 #[test]
620 fn test_hctr2fp_different_tweaks() {
621 let key = [0u8; 16];
622 let cipher = Hctr2Fp_128_Decimal::new(&key);
623
624 let plaintext = [5u8; 40];
625 let mut ciphertext1 = [0u8; 40];
626 let mut ciphertext2 = [0u8; 40];
627
628 cipher
629 .encrypt(&plaintext, b"tweak1", &mut ciphertext1)
630 .unwrap();
631 cipher
632 .encrypt(&plaintext, b"tweak2", &mut ciphertext2)
633 .unwrap();
634
635 assert_ne!(ciphertext1, ciphertext2);
636 }
637
638 #[test]
639 fn test_hctr2fp_256_decimal_roundtrip() {
640 let key = [0u8; 32];
641 let cipher = Hctr2Fp_256_Decimal::new(&key);
642
643 let mut plaintext = vec![0u8; 50];
644 plaintext[0] = 5;
645 plaintext[1] = 7;
646 plaintext[2] = 9;
647 plaintext[38] = 3;
648 for i in 39..50 {
649 plaintext[i] = ((i - 39) % 10) as u8;
650 }
651
652 let mut ciphertext = vec![0u8; plaintext.len()];
653 let mut decrypted = vec![0u8; plaintext.len()];
654
655 cipher
656 .encrypt(&plaintext, b"tweak", &mut ciphertext)
657 .unwrap();
658 cipher
659 .decrypt(&ciphertext, b"tweak", &mut decrypted)
660 .unwrap();
661
662 assert_eq!(plaintext, decrypted);
663 }
664
665 #[test]
666 fn test_first_block_encode_decode_consistency() {
667 let value: u128 = 0x123456789ABCDEF0_u128 << 64 | 0xFEDCBA9876543210_u128;
668
669 let mut digits = [0u8; 39];
670 encode_base_radix(value, 10, &mut digits);
671
672 for &d in &digits {
673 assert!(d < 10, "digit {} out of range", d);
674 }
675
676 let decoded = decode_base_radix(&digits, 10).unwrap();
677 assert_eq!(value, decoded, "encode/decode roundtrip failed");
678 }
679
680 #[test]
681 fn test_xor_and_encode_decode() {
682 let a: u128 = 0x123456789ABCDEF0_u128 << 64 | 0xFEDCBA9876543210_u128;
683 let b: u128 = 0xFFFFFFFFFFFFFFFF_u128 << 64 | 0xFFFFFFFFFFFFFFFF_u128;
684
685 let c = a ^ b;
686
687 let mut digits = [0u8; 39];
688 encode_base_radix(c, 10, &mut digits);
689
690 let decoded = decode_base_radix(&digits, 10).unwrap();
691 assert_eq!(c, decoded);
692 }
693
694 #[test]
695 fn test_max_u128_encode_decode() {
696 let value = u128::MAX;
697
698 let mut digits = [0u8; 39];
699 encode_base_radix(value, 10, &mut digits);
700
701 assert!(digits[38] <= 3, "39th digit {} is too large", digits[38]);
702
703 let decoded = decode_base_radix(&digits, 10).unwrap();
704 assert_eq!(value, decoded);
705 }
706
707 #[test]
708 fn test_aes_encrypt_decrypt_roundtrip() {
709 #[allow(deprecated)]
710 use aes::cipher::{Array, BlockCipherDecrypt, BlockCipherEncrypt, KeyInit};
711 use aes::{Aes128, Aes128Dec};
712
713 let key = [0u8; 16];
714 let ks_enc = Aes128::new(Array::from_slice(&key));
715 let ks_dec = Aes128Dec::new(Array::from_slice(&key));
716
717 let plaintext = [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
718
719 let mut block = Array::clone_from_slice(&plaintext);
720 ks_enc.encrypt_block(&mut block);
721 let ciphertext: [u8; 16] = block.as_slice().try_into().unwrap();
722
723 let mut block2 = Array::clone_from_slice(&ciphertext);
724 ks_dec.decrypt_block(&mut block2);
725 let decrypted: [u8; 16] = block2.as_slice().try_into().unwrap();
726
727 assert_eq!(plaintext, decrypted);
728 }
729
730 #[test]
731 fn test_hctr2fp_decimal_debug() {
732 let key = [0u8; 16];
733 let cipher = Hctr2Fp_128_Decimal::new(&key);
734
735 let plaintext = [0u8; 39];
736 let mut ciphertext = [0u8; 39];
737 let mut decrypted = [0u8; 39];
738
739 cipher.encrypt(&plaintext, b"", &mut ciphertext).unwrap();
740
741 for &d in &ciphertext {
742 assert!(d < 10, "ciphertext digit {} >= 10", d);
743 }
744
745 cipher.decrypt(&ciphertext, b"", &mut decrypted).unwrap();
746
747 assert_eq!(plaintext.as_slice(), decrypted.as_slice());
748 }
749
750 #[test]
751 fn test_hctr2fp_decimal_nonzero_plain_empty_tweak() {
752 let key = [0u8; 16];
753 let cipher = Hctr2Fp_128_Decimal::new(&key);
754
755 let mut plaintext = vec![0u8; 40];
756 for i in 0..38 {
757 plaintext[i] = ((i + 1) % 10) as u8;
758 }
759 plaintext[38] = 2;
760 plaintext[39] = 8;
761
762 let mut ciphertext = vec![0u8; 40];
763 let mut decrypted = vec![0u8; 40];
764
765 cipher.encrypt(&plaintext, b"", &mut ciphertext).unwrap();
766 cipher.decrypt(&ciphertext, b"", &mut decrypted).unwrap();
767
768 assert_eq!(plaintext, decrypted);
769 }
770
771 #[test]
772 fn test_hctr2fp_decimal_zeros_plain_with_tweak() {
773 let key = [0u8; 16];
774 let cipher = Hctr2Fp_128_Decimal::new(&key);
775
776 let plaintext = [0u8; 40];
777 let mut ciphertext = [0u8; 40];
778 let mut decrypted = [0u8; 40];
779
780 cipher
781 .encrypt(&plaintext, b"tweak", &mut ciphertext)
782 .unwrap();
783 cipher
784 .decrypt(&ciphertext, b"tweak", &mut decrypted)
785 .unwrap();
786
787 assert_eq!(plaintext.as_slice(), decrypted.as_slice());
788 }
789
790 #[test]
791 fn test_decode_specific_pattern() {
792 let mut digits = [0u8; 39];
793 digits[0] = 1;
794 digits[1] = 2;
795 digits[2] = 3;
796 digits[38] = 3;
797
798 let value = decode_base_radix(&digits, 10).unwrap();
799
800 let mut reencoded = [0u8; 39];
801 encode_base_radix(value, 10, &mut reencoded);
802
803 assert_eq!(digits.as_slice(), reencoded.as_slice());
804 }
805
806 #[test]
807 fn test_hctr2fp_decimal_single_digit_1() {
808 let key = [0u8; 16];
809 let cipher = Hctr2Fp_128_Decimal::new(&key);
810
811 let plaintext = [1u8; 40];
812 let mut ciphertext = [0u8; 40];
813 let mut decrypted = [0u8; 40];
814
815 cipher.encrypt(&plaintext, b"", &mut ciphertext).unwrap();
816 cipher.decrypt(&ciphertext, b"", &mut decrypted).unwrap();
817
818 assert_eq!(plaintext.as_slice(), decrypted.as_slice());
819 }
820}