const_ciphers/
rc4.rs

1use const_for::const_for;
2
3pub struct Rc4Const {}
4
5impl Rc4Const {
6    pub const fn encrypt<const N: usize, const K: usize>(
7        plaintext: &[u8; N],
8        key: &[u8; K],
9    ) -> [u8; N] {
10        if K == 0 {
11            panic!("Key cannot be empty");
12        }
13
14        let mut s = [0u8; 256];
15        const_for!(i in 0..256 => {
16            s[i] = i as u8;
17        });
18
19        let mut j = 0usize;
20        const_for!(i in 0..256 => {
21            j = (j + s[i] as usize + key[i % K] as usize) % 256;
22
23            // Manual swap
24            let tmp = s[i];
25            s[i] = s[j];
26            s[j] = tmp;
27        });
28
29        let mut i = 0usize;
30        j = 0usize;
31        let mut ciphertext = [0u8; N];
32
33        const_for!(n in 0..N => {
34            i = (i + 1) % 256;
35            j = (j + s[i] as usize) % 256;
36
37            // Manual swap
38            let tmp = s[i];
39            s[i] = s[j];
40            s[j] = tmp;
41
42            let k = s[(s[i] as usize + s[j] as usize) % 256];
43            ciphertext[n] = plaintext[n] ^ k;
44        });
45
46        ciphertext
47    }
48
49    pub const fn decrypt<const N: usize, const K: usize>(
50        ciphertext: &[u8; N],
51        key: &[u8; K],
52    ) -> [u8; N] {
53        Self::encrypt(ciphertext, key)
54    }
55}
56
57pub struct Rc4 {}
58
59impl Rc4 {
60    pub fn encrypt<const N: usize, const K: usize>(plaintext: &[u8; N], key: &[u8; K]) -> [u8; N] {
61        if K == 0 {
62            panic!("Key cannot be empty");
63        }
64
65        let mut s = [0u8; 256];
66        const_for!(i in 0..256 => {
67            s[i] = i as u8;
68        });
69
70        let mut j = 0usize;
71        const_for!(i in 0..256 => {
72            j = (j + s[i] as usize + key[i % K] as usize) % 256;
73
74            s.swap(i, j);
75        });
76
77        let mut i = 0usize;
78        j = 0usize;
79        let mut ciphertext = [0u8; N];
80
81        const_for!(n in 0..N => {
82            i = (i + 1) % 256;
83            j = (j + s[i] as usize) % 256;
84
85            s.swap(i, j);
86
87            let k = s[(s[i] as usize + s[j] as usize) % 256];
88            ciphertext[n] = plaintext[n] ^ k;
89        });
90
91        ciphertext
92    }
93
94    pub fn decrypt<const N: usize, const K: usize>(ciphertext: &[u8; N], key: &[u8; K]) -> [u8; N] {
95        Self::encrypt(ciphertext, key)
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use crate::rc4::Rc4Const;
102
103    #[test]
104    fn test_const_mode() {
105        let plaintext = [0u8; 16];
106        let key = [0xFF; 16];
107
108        let ciphertext = Rc4Const::encrypt(&plaintext, &key);
109        let decrypted = Rc4Const::decrypt(&ciphertext, &key);
110
111        assert_eq!(
112            decrypted, plaintext,
113            "Decrypted text does not match original plaintext"
114        );
115    }
116
117    use crate::rc4::Rc4;
118
119    #[test]
120    fn test_nonconst_mode() {
121        let plaintext = [0u8; 16];
122        let key = [0xFF; 16];
123
124        let ciphertext = Rc4::encrypt(&plaintext, &key);
125        let decrypted = Rc4::decrypt(&ciphertext, &key);
126
127        assert_eq!(
128            decrypted, plaintext,
129            "Decrypted text does not match original plaintext"
130        );
131    }
132}