chacha20/backends/
soft.rs1#![allow(clippy::cast_possible_truncation)]
4
5use crate::{ChaChaCore, Rounds, STATE_WORDS, Variant, quarter_round};
6
7#[cfg(feature = "cipher")]
8use crate::chacha::Block;
9#[cfg(feature = "cipher")]
10use cipher::{
11 BlockSizeUser, ParBlocksSizeUser, StreamCipherBackend,
12 consts::{U1, U64},
13};
14
15#[cfg(feature = "rng")]
16use crate::rng::BLOCK_WORDS;
17
18pub(crate) struct Backend<'a, R: Rounds, V: Variant>(pub(crate) &'a mut ChaChaCore<R, V>);
19
20#[cfg(feature = "cipher")]
21impl<R: Rounds, V: Variant> BlockSizeUser for Backend<'_, R, V> {
22 type BlockSize = U64;
23}
24
25#[cfg(feature = "cipher")]
26impl<R: Rounds, V: Variant> ParBlocksSizeUser for Backend<'_, R, V> {
27 type ParBlocksSize = U1;
28}
29
30#[cfg(feature = "cipher")]
31impl<R: Rounds, V: Variant> StreamCipherBackend for Backend<'_, R, V> {
32 #[inline(always)]
33 fn gen_ks_block(&mut self, block: &mut Block) {
34 let res = run_rounds::<R>(&self.0.state);
35 let mut ctr = (u64::from(self.0.state[13]) << 32) | u64::from(self.0.state[12]);
36 ctr = ctr.wrapping_add(1);
37 self.0.state[12] = ctr as u32;
38 if size_of::<V::Counter>() == 8 {
39 self.0.state[13] = (ctr >> 32) as u32;
40 }
41
42 for (chunk, val) in block.chunks_exact_mut(4).zip(res.iter()) {
43 chunk.copy_from_slice(&val.to_le_bytes());
44 }
45 }
46}
47
48#[cfg(feature = "rng")]
49impl<R: Rounds, V: Variant> Backend<'_, R, V> {
50 #[inline(always)]
51 pub(crate) fn gen_ks_blocks(&mut self, buffer: &mut [u32; 64]) {
52 for block in 0..4 {
53 let res = run_rounds::<R>(&self.0.state);
54 let mut ctr = (u64::from(self.0.state[13]) << 32) | u64::from(self.0.state[12]);
55 ctr = ctr.wrapping_add(1);
56 self.0.state[12] = ctr as u32;
57 self.0.state[13] = (ctr >> 32) as u32;
58
59 buffer[block * BLOCK_WORDS as usize..(block + 1) * BLOCK_WORDS as usize]
60 .copy_from_slice(&res);
61 }
62 }
63}
64
65#[inline(always)]
66fn run_rounds<R: Rounds>(state: &[u32; STATE_WORDS]) -> [u32; STATE_WORDS] {
67 let mut res = *state;
68
69 for _ in 0..R::COUNT {
70 quarter_round(0, 4, 8, 12, &mut res);
72 quarter_round(1, 5, 9, 13, &mut res);
73 quarter_round(2, 6, 10, 14, &mut res);
74 quarter_round(3, 7, 11, 15, &mut res);
75
76 quarter_round(0, 5, 10, 15, &mut res);
78 quarter_round(1, 6, 11, 12, &mut res);
79 quarter_round(2, 7, 8, 13, &mut res);
80 quarter_round(3, 4, 9, 14, &mut res);
81 }
82
83 for (s1, s0) in res.iter_mut().zip(state.iter()) {
84 *s1 = s1.wrapping_add(*s0);
85 }
86 res
87}