Skip to main content

belt_block/
cipher_impl.rs

1use crate::{belt_block_raw, from_u32, g5, g13, g21, key_idx, to_u32};
2use cipher::{
3    AlgorithmName, Block, BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt,
4    BlockCipherEncBackend, BlockCipherEncClosure, BlockCipherEncrypt, BlockSizeUser, InOut, Key,
5    KeyInit, KeySizeUser, ParBlocksSizeUser,
6    consts::{U1, U16, U32},
7};
8use core::{fmt, mem::swap, num::Wrapping};
9
10#[cfg(feature = "zeroize")]
11use cipher::zeroize::{Zeroize, ZeroizeOnDrop};
12
13/// BelT block cipher.
14#[derive(Clone)]
15pub struct BeltBlock {
16    key: [u32; 8],
17}
18
19impl KeySizeUser for BeltBlock {
20    type KeySize = U32;
21}
22
23impl KeyInit for BeltBlock {
24    fn new(key: &Key<Self>) -> Self {
25        Self { key: to_u32(key) }
26    }
27}
28
29impl BlockSizeUser for BeltBlock {
30    type BlockSize = U16;
31}
32
33impl ParBlocksSizeUser for BeltBlock {
34    type ParBlocksSize = U1;
35}
36
37impl BlockCipherEncrypt for BeltBlock {
38    #[inline]
39    fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure<BlockSize = Self::BlockSize>) {
40        f.call(self)
41    }
42}
43
44impl BlockCipherEncBackend for BeltBlock {
45    #[inline]
46    fn encrypt_block(&self, mut block: InOut<'_, '_, Block<Self>>) {
47        // Encryption as described in section 6.1.3
48        // Steps 1 and 4
49        let x = to_u32(block.get_in());
50        let y = belt_block_raw(x, &self.key);
51
52        let block_out = block.get_out();
53        // 6) Y ← b ‖ d ‖ a ‖ c
54        *block_out = from_u32(&y).into();
55    }
56}
57
58impl BlockCipherDecrypt for BeltBlock {
59    #[inline]
60    fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure<BlockSize = Self::BlockSize>) {
61        f.call(self)
62    }
63}
64
65impl BlockCipherDecBackend for BeltBlock {
66    #[inline]
67    fn decrypt_block(&self, mut block: InOut<'_, '_, Block<Self>>) {
68        let key = &self.key;
69        let block_in: [u32; 4] = to_u32(block.get_in());
70        // Steps 1 and 4
71        let mut a = Wrapping(block_in[0]);
72        let mut b = Wrapping(block_in[1]);
73        let mut c = Wrapping(block_in[2]);
74        let mut d = Wrapping(block_in[3]);
75
76        // Step 5
77        for i in (1..9).rev() {
78            // 5.1) b ← b ⊕ G₅(a ⊞ 𝑘[7i])
79            b ^= g5(a + key_idx(key, i, 0));
80            // 5.2) c ← c ⊕ G₂₁(d ⊞ 𝑘[7i-1])
81            c ^= g21(d + key_idx(key, i, 1));
82            // 5.3) a ← a ⊟ G₁₃(b ⊞ 𝑘[7i-2])
83            a -= g13(b + key_idx(key, i, 2));
84            // 5.4) e ← G₂₁(b ⊞ c ⊞ 𝑘[7i-3]) ⊕ ⟨i⟩₃₂
85            let e = g21(b + c + key_idx(key, i, 3)) ^ Wrapping(i as u32);
86            // 5.5) b ← b ⊞ e
87            b += e;
88            // 5.6) c ← c ⊟ e
89            c -= e;
90            // 5.7) d ← d ⊞ G₁₃(c ⊞ 𝑘[7i-4])
91            d += g13(c + key_idx(key, i, 4));
92            // 5.8) b ← b ⊕ G₂₁(a ⊞ 𝑘[7i-5])
93            b ^= g21(a + key_idx(key, i, 5));
94            // 5.9) c ← c ⊕ G₅(d ⊞ 𝑘[7i-6])
95            c ^= g5(d + key_idx(key, i, 6));
96            // 5.10) a ↔ b
97            swap(&mut a, &mut b);
98            // 5.11) c ↔ d
99            swap(&mut c, &mut d);
100            // 5.12) a ↔ d
101            swap(&mut a, &mut d);
102        }
103
104        let block_out = block.get_out();
105        // 6) 𝑋 ← c ‖ a ‖ d ‖ b
106        let x = [c.0, a.0, d.0, b.0];
107        *block_out = from_u32(&x).into();
108    }
109}
110
111impl AlgorithmName for BeltBlock {
112    fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        f.write_str("BeltBlock")
114    }
115}
116
117impl Drop for BeltBlock {
118    fn drop(&mut self) {
119        #[cfg(feature = "zeroize")]
120        self.key.zeroize();
121    }
122}
123
124#[cfg(feature = "zeroize")]
125impl ZeroizeOnDrop for BeltBlock {}