chacha20/backends/
soft.rs
1use crate::{Block, ChaChaCore, Unsigned, STATE_WORDS};
5use cipher::{
6 consts::{U1, U64},
7 BlockSizeUser, ParBlocksSizeUser, StreamBackend,
8};
9
10pub(crate) struct Backend<'a, R: Unsigned>(pub(crate) &'a mut ChaChaCore<R>);
11
12impl<'a, R: Unsigned> BlockSizeUser for Backend<'a, R> {
13 type BlockSize = U64;
14}
15
16impl<'a, R: Unsigned> ParBlocksSizeUser for Backend<'a, R> {
17 type ParBlocksSize = U1;
18}
19
20impl<'a, R: Unsigned> StreamBackend for Backend<'a, R> {
21 #[inline(always)]
22 fn gen_ks_block(&mut self, block: &mut Block) {
23 let res = run_rounds::<R>(&self.0.state);
24 self.0.state[12] = self.0.state[12].wrapping_add(1);
25
26 for (chunk, val) in block.chunks_exact_mut(4).zip(res.iter()) {
27 chunk.copy_from_slice(&val.to_le_bytes());
28 }
29 }
30}
31
32#[inline(always)]
33fn run_rounds<R: Unsigned>(state: &[u32; STATE_WORDS]) -> [u32; STATE_WORDS] {
34 let mut res = *state;
35
36 for _ in 0..R::USIZE {
37 quarter_round(0, 4, 8, 12, &mut res);
39 quarter_round(1, 5, 9, 13, &mut res);
40 quarter_round(2, 6, 10, 14, &mut res);
41 quarter_round(3, 7, 11, 15, &mut res);
42
43 quarter_round(0, 5, 10, 15, &mut res);
45 quarter_round(1, 6, 11, 12, &mut res);
46 quarter_round(2, 7, 8, 13, &mut res);
47 quarter_round(3, 4, 9, 14, &mut res);
48 }
49
50 for (s1, s0) in res.iter_mut().zip(state.iter()) {
51 *s1 = s1.wrapping_add(*s0);
52 }
53 res
54}
55
56fn quarter_round(a: usize, b: usize, c: usize, d: usize, state: &mut [u32; STATE_WORDS]) {
58 state[a] = state[a].wrapping_add(state[b]);
59 state[d] ^= state[a];
60 state[d] = state[d].rotate_left(16);
61
62 state[c] = state[c].wrapping_add(state[d]);
63 state[b] ^= state[c];
64 state[b] = state[b].rotate_left(12);
65
66 state[a] = state[a].wrapping_add(state[b]);
67 state[d] ^= state[a];
68 state[d] = state[d].rotate_left(8);
69
70 state[c] = state[c].wrapping_add(state[d]);
71 state[b] ^= state[c];
72 state[b] = state[b].rotate_left(7);
73}