secured_cipher/algorithm/chacha20/
core.rs1pub const CONSTANTS: [u32; 4] = [0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574];
20
21pub const STATE_WORDS: usize = 16;
24
25pub const ROUNDS: usize = 10;
29
30pub const CHACHA20_NONCE_SIZE: usize = 12;
33
34pub type Block = [u32; STATE_WORDS];
36
37pub fn quarter_round(a: usize, b: usize, c: usize, d: usize, state: &mut Block) {
46 state[a] = state[a].wrapping_add(state[b]);
47 state[d] ^= state[a];
48 state[d] = state[d].rotate_left(16);
49
50 state[c] = state[c].wrapping_add(state[d]);
51 state[b] ^= state[c];
52 state[b] = state[b].rotate_left(12);
53
54 state[a] = state[a].wrapping_add(state[b]);
55 state[d] ^= state[a];
56 state[d] = state[d].rotate_left(8);
57
58 state[c] = state[c].wrapping_add(state[d]);
59 state[b] ^= state[c];
60 state[b] = state[b].rotate_left(7);
61}
62
63pub fn permute(state: &Block) -> Block {
65 let mut block = *state;
66
67 run_rounds(&mut block);
69
70 for (s1, s0) in block.iter_mut().zip(state.iter()) {
72 *s1 = s1.wrapping_add(*s0);
73 }
74
75 block
76}
77
78pub fn run_rounds(state: &mut Block) {
81 for _ in 0..ROUNDS {
82 quarter_round(0, 4, 8, 12, state);
84 quarter_round(1, 5, 9, 13, state);
85 quarter_round(2, 6, 10, 14, state);
86 quarter_round(3, 7, 11, 15, state);
87 quarter_round(0, 5, 10, 15, state);
89 quarter_round(1, 6, 11, 12, state);
90 quarter_round(2, 7, 8, 13, state);
91 quarter_round(3, 4, 9, 14, state);
92 }
93}
94
95pub fn xor_bytes(left: &mut [u8], right: &[u8]) {
105 assert!(
106 right.len() >= left.len(),
107 "The left array can't be XORed completely with the right array"
108 );
109 left
110 .iter_mut()
111 .zip(right.iter())
112 .for_each(|(left, right)| *left ^= *right);
113}
114
115#[cfg(test)]
116mod test {
117 use super::*;
118
119 #[test]
120 fn it_should_do_the_quarter_round() {
121 let mut state: Block = [
122 0x879531e0, 0xc5ecf37d, 0x516461b1, 0xc9a62f8a, 0x44c20ef3, 0x3390af7f, 0xd9fc690b,
123 0x2a5f714c, 0x53372767, 0xb00a5631, 0x974c541a, 0x359e9963, 0x5c971061, 0x3d631689,
124 0x2098d9d6, 0x91dbd320,
125 ];
126
127 quarter_round(2, 7, 8, 13, &mut state);
128
129 assert_eq!(
130 state,
131 [
132 0x879531e0, 0xc5ecf37d, 0xbdb886dc, 0xc9a62f8a, 0x44c20ef3, 0x3390af7f, 0xd9fc690b,
133 0xcfacafd2, 0xe46bea80, 0xb00a5631, 0x974c541a, 0x359e9963, 0x5c971061, 0xccc07c79,
134 0x2098d9d6, 0x91dbd320,
135 ]
136 );
137 }
138
139 #[test]
140 fn it_runs_all_the_quarter_rounds() {
141 let mut state: Block = [
142 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574, 0x03020100, 0x07060504, 0x0b0a0908,
143 0x0f0e0d0c, 0x13121110, 0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x00000001, 0x09000000,
144 0x4a000000, 0x00000000,
145 ];
146
147 run_rounds(&mut state);
148
149 assert_eq!(
150 state,
151 [
152 0x837778ab, 0xe238d763, 0xa67ae21e, 0x5950bb2f, 0xc4f2d0c7, 0xfc62bb2f, 0x8fa018fc,
153 0x3f5ec7b7, 0x335271c2, 0xf29489f3, 0xeabda8fc, 0x82e46ebd, 0xd19c12b4, 0xb04e16de,
154 0x9e83d0cb, 0x4e3c50a2,
155 ]
156 );
157 }
158
159 #[test]
160 fn it_executes_the_chacha20_permutation() {
161 let state: Block = [
162 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574, 0x03020100, 0x07060504, 0x0b0a0908,
163 0x0f0e0d0c, 0x13121110, 0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x00000001, 0x09000000,
164 0x4a000000, 0x00000000,
165 ];
166
167 let result = permute(&state);
168
169 assert_eq!(
170 result,
171 [
172 0xe4e7f110, 0x15593bd1, 0x1fdd0f50, 0xc47120a3, 0xc7f4d1c7, 0x0368c033, 0x9aaa2204,
173 0x4e6cd4c3, 0x466482d2, 0x09aa9f07, 0x05d7c214, 0xa2028bd9, 0xd19c12b5, 0xb94e16de,
174 0xe883d0cb, 0x4e3c50a2,
175 ]
176 );
177 }
178}