deck_farfalle/
input.rs

1//! Compression layer of the Farfalle construction.
2
3use super::{FarfalleConfig, RollFunction};
4use crypto_permutation::{Permutation, PermutationState, WriteTooLargeError, Writer};
5
6/// Generic Farfalle construction.
7///
8/// The intended way to interact with it is through the
9/// [`crypto_permutation::DeckFunction`] trait. The [`Self::init_default`]
10/// method provides a way to create an instance using a custom length key (but
11/// it has to fit in a permutation block minus one byte).
12#[derive(Clone)]
13#[cfg_attr(feature = "debug", derive(Debug, PartialEq))]
14pub struct Farfalle<C: FarfalleConfig> {
15    pub(super) key: C::State,
16    pub(super) state: C::State,
17    pub(super) config: C,
18}
19
20const PAD_BYTE: u8 = 1;
21
22impl<C: FarfalleConfig> Farfalle<C> {
23    fn key_expand(key: &[u8], p_b: C::PermutationB) -> C::State {
24        assert!(key.len() < C::State::SIZE);
25        let mut key_state = C::State::default();
26        let mut state_writer = key_state.copy_writer();
27        state_writer.write_bytes(key).unwrap();
28        state_writer.write_bytes(&[PAD_BYTE]).unwrap();
29        state_writer.finish();
30        p_b.apply(&mut key_state);
31        key_state
32    }
33
34    /// Create an instance using a key of custom length and non-default
35    /// [`FarfalleConfig`] `config`. The key plus padding (1 byte) must fit in a
36    /// single permutation block.
37    ///
38    /// # Panics
39    /// Panics when the key plus padding (1 byte) don't fit a single permutation
40    /// block.
41    pub fn init_custom(key: &[u8], config: C) -> Self {
42        Self {
43            key: Self::key_expand(key, config.perm_b()),
44            state: Default::default(),
45            config,
46        }
47    }
48
49    /// Create an instance using a key of custom length. The key plus padding (1
50    /// byte) must fit in a single permutation block.
51    ///
52    /// # Panics
53    /// Panics when the key plus padding (1 byte) don't fit a single permutation
54    /// block.
55    pub fn init_default(key: &[u8]) -> Self
56    where
57        C: Default,
58    {
59        Self::init_custom(key, C::default())
60    }
61
62    /// Apply rolling function C to the key.
63    fn roll_c_key(&mut self) {
64        self.config.roll_c().apply(&mut self.key);
65    }
66
67    /// Process one block of data, given as a permutation state.
68    ///
69    /// Note: this modifies `block`. The user should wipe or reuse it.
70    fn process_block(&mut self, block: &mut C::State) {
71        *block ^= &self.key;
72        self.roll_c_key();
73        self.config.perm_c().apply(block);
74        self.state ^= block;
75    }
76}
77
78/// A [`Writer`] structure that inputs all data that is written to it into the
79/// Farfalle construction.
80pub struct InputWriter<'a, C: FarfalleConfig> {
81    /// A permutation state to accumulate data into before processing.
82    block: C::State,
83    /// Number of bytes of `block` that are initialised.
84    filled: usize,
85    /// The Farfalle construction to write data to.
86    farfalle: &'a mut Farfalle<C>,
87}
88
89impl<'a, C: FarfalleConfig> InputWriter<'a, C> {
90    /// Create a new writer inputting data into `farfalle`.
91    pub(super) fn new(farfalle: &'a mut Farfalle<C>) -> Self {
92        Self {
93            block: Default::default(),
94            filled: 0,
95            farfalle,
96        }
97    }
98
99    fn process_block(&mut self) {
100        self.farfalle.process_block(&mut self.block);
101        self.filled = 0;
102    }
103}
104
105impl<'a, C: FarfalleConfig> Writer for InputWriter<'a, C> {
106    type Return = ();
107
108    fn capacity(&self) -> usize {
109        usize::MAX
110    }
111
112    /// No-op.
113    fn skip(&mut self, _n: usize) -> Result<(), WriteTooLargeError> {
114        Ok(())
115    }
116
117    fn write_bytes(&mut self, mut data: &[u8]) -> Result<(), WriteTooLargeError> {
118        if self.filled != 0 {
119            let add_partial = core::cmp::min(data.len(), C::State::SIZE - self.filled);
120            let old_filled = self.filled;
121            self.filled += add_partial;
122            let mut block_writer = self.block.copy_writer();
123            block_writer.skip(old_filled).unwrap();
124            block_writer.write_bytes(&data[..add_partial]).unwrap();
125            block_writer.finish();
126            data = &data[add_partial..];
127            if self.filled == C::State::SIZE {
128                self.process_block();
129            }
130        }
131
132        let mut chunks = data.chunks_exact(C::State::SIZE);
133        for chunk in &mut chunks {
134            let mut block_writer = self.block.copy_writer();
135            block_writer.write_bytes(chunk).unwrap();
136            block_writer.finish();
137            self.process_block();
138        }
139
140        let remainder = chunks.remainder();
141        if !remainder.is_empty() {
142            self.filled = remainder.len();
143            let mut block_writer = self.block.copy_writer();
144            block_writer.write_bytes(remainder).unwrap();
145            block_writer.finish();
146        }
147
148        Ok(())
149    }
150
151    /// Applies padding to the final block and processes it.
152    fn finish(mut self) {
153        self.write_bytes(&[PAD_BYTE]).unwrap();
154        self.process_block();
155        self.farfalle.roll_c_key();
156    }
157}