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 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 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}