deck_farfalle/
output.rs

1//! Expansion layer of the Farfalle construction.
2
3use crate::RollFunction;
4
5use super::FarfalleConfig;
6use crypto_permutation::io::{check_write_size, CryptoReader, Reader, WriteTooLargeError, Writer};
7use crypto_permutation::{Permutation, PermutationState};
8
9/// Expansion part in the Farfalle construction.
10pub struct FarfalleOutputGenerator<C: FarfalleConfig> {
11    /// Farfalle parameters.
12    config: C,
13    /// Immutable expansion key k' from the Farfalle construction.
14    key: C::State,
15    /// The accumulated state, to which permutation D and a number of roll E
16    /// operations have already been applied.
17    state: C::State,
18    /// Buffer to store output bytes that haven't been output yet.
19    output_buffer: C::State,
20    /// Number of output bytes still available in `output_buffer`.
21    buffered: usize,
22}
23
24impl<C: FarfalleConfig> FarfalleOutputGenerator<C> {
25    /// Create a new [`FarfalleOutputGenerator`] from an expansion key `key`,
26    /// state `state` (to which permutation D has already been applied) and
27    /// Farfalle parameters `config`.
28    pub(super) fn new(key: C::State, state: C::State, config: C) -> Self {
29        Self {
30            config,
31            key,
32            state,
33            output_buffer: Default::default(),
34            buffered: 0,
35        }
36    }
37
38    /// Apply rolling function E to the state `self.state`.
39    fn roll_e_state(&mut self) {
40        self.config.roll_e().apply(&mut self.state);
41    }
42
43    /// Write the next output block to `self.output_buffer` and updates
44    /// `self.state`. Does not modify `self.buffered`.
45    fn next_out_block(&mut self) {
46        self.output_buffer = self.state.clone();
47        self.roll_e_state();
48        self.config.perm_e().apply(&mut self.output_buffer);
49        self.output_buffer ^= &self.key;
50    }
51}
52
53impl<C: FarfalleConfig> Reader for FarfalleOutputGenerator<C> {
54    fn capacity(&self) -> usize {
55        usize::MAX
56    }
57
58    fn skip(&mut self, mut n: usize) -> Result<(), WriteTooLargeError> {
59        if self.buffered != 0 {
60            let out_size = core::cmp::min(self.buffered, n);
61            n -= out_size;
62            self.buffered -= out_size;
63        }
64        let remainder = n % C::State::SIZE;
65        let n_blocks = (n - remainder) / C::State::SIZE;
66        for _ in 0..n_blocks {
67            self.next_out_block();
68        }
69        if remainder != 0 {
70            self.next_out_block();
71            self.buffered = C::State::SIZE - remainder;
72        }
73        Ok(())
74    }
75
76    fn write_to<W: Writer>(
77        &mut self,
78        writer: &mut W,
79        mut n: usize,
80    ) -> Result<(), WriteTooLargeError> {
81        check_write_size(n, writer.capacity())?;
82        if self.buffered != 0 {
83            let out_size = core::cmp::min(self.buffered, n);
84            let mut reader = self.output_buffer.reader();
85            reader.skip(C::State::SIZE - self.buffered)?;
86            reader.write_to(writer, out_size)?;
87            n -= out_size;
88            self.buffered -= out_size;
89        }
90        let remainder = n % C::State::SIZE;
91        let n_blocks = (n - remainder) / C::State::SIZE;
92        for _ in 0..n_blocks {
93            self.next_out_block();
94            let mut reader = self.output_buffer.reader();
95            reader.write_to(writer, C::State::SIZE)?;
96        }
97        if remainder != 0 {
98            self.next_out_block();
99            let mut reader = self.output_buffer.reader();
100            reader.write_to(writer, remainder)?;
101            self.buffered = C::State::SIZE - remainder;
102        }
103        Ok(())
104    }
105}
106
107impl<C: FarfalleConfig> CryptoReader for FarfalleOutputGenerator<C> {}