1#[allow(clippy::unit_arg)]
2mod any;
3mod hash;
4mod keyed;
5mod tag;
6
7pub use any::*;
8pub use hash::*;
9pub use keyed::*;
10pub use tag::*;
11
12use crate::error::*;
13use crate::xoodoo::*;
14
15pub(crate) const HASH_ABSORB_RATE: usize = 16;
16pub(crate) const HASH_SQUEEZE_RATE: usize = 16;
17pub(crate) const KEYED_ABSORB_RATE: usize = 44;
18pub(crate) const KEYED_SQUEEZE_RATE: usize = 24;
19pub(crate) const RATCHET_RATE: usize = 16;
20
21mod internal {
22 use super::*;
23
24 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
25 pub enum Mode {
26 Hash,
27 Keyed,
28 }
29
30 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
31 pub enum Phase {
32 Up,
33 Down,
34 }
35
36 pub trait XoodyakCommon {
37 fn state(&mut self) -> &mut Xoodoo;
38 fn mode(&self) -> Mode;
39 fn phase(&self) -> Phase;
40 fn set_phase(&mut self, phase: Phase);
41 fn absorb_rate(&self) -> usize;
42 fn squeeze_rate(&self) -> usize;
43
44 #[inline(always)]
45 fn permute(&mut self) {
46 self.state().permute()
47 }
48
49 #[inline(always)]
50 fn add_byte(&mut self, byte: u8, offset: usize) {
51 self.state().add_byte(byte, offset);
52 }
53
54 #[inline(always)]
55 fn add_bytes(&mut self, bytes: &[u8]) {
56 self.state().add_bytes(bytes);
57 }
58
59 #[inline(always)]
60 fn extract_bytes(&mut self, out: &mut [u8]) {
61 self.state().extract_bytes(out);
62 }
63
64 #[inline(always)]
65 fn up(&mut self, out: Option<&mut [u8]>, cu: u8) {
66 debug_assert!(out.as_ref().map(|x| x.len()).unwrap_or(0) <= self.squeeze_rate());
67 self.set_phase(Phase::Up);
68 if self.mode() != Mode::Hash {
69 self.add_byte(cu, 47);
70 }
71 self.permute();
72 if let Some(out) = out {
73 self.extract_bytes(out);
74 }
75 }
76
77 #[inline(always)]
78 fn down(&mut self, bin: Option<&[u8]>, cd: u8) {
79 debug_assert!(bin.as_ref().map(|x| x.len()).unwrap_or(0) <= self.absorb_rate());
80 self.set_phase(Phase::Down);
81 if let Some(bin) = bin {
82 self.add_bytes(bin);
83 self.add_byte(0x01, bin.len());
84 } else {
85 self.add_byte(0x01, 0);
86 }
87 if self.mode() == Mode::Hash {
88 self.add_byte(cd & 0x01, 47);
89 } else {
90 self.add_byte(cd, 47);
91 }
92 }
93
94 #[inline]
95 fn absorb_any(&mut self, bin: &[u8], rate: usize, cd: u8) {
96 let mut chunks_it = bin.chunks(rate);
97 if self.phase() != Phase::Up {
98 self.up(None, 0x00)
99 }
100 self.down(chunks_it.next(), cd);
101 for chunk in chunks_it {
102 self.up(None, 0x00);
103 self.down(Some(chunk), 0x00);
104 }
105 }
106
107 #[inline]
108 fn squeeze_any(&mut self, out: &mut [u8], cu: u8) {
109 let mut chunks_it = out.chunks_mut(self.squeeze_rate());
110 self.up(chunks_it.next(), cu);
111 for chunk in chunks_it {
112 self.down(None, 0x00);
113 self.up(Some(chunk), 0x00);
114 }
115 }
116 }
117}
118
119pub trait XoodyakCommon: internal::XoodyakCommon {
120 #[inline(always)]
121 fn absorb(&mut self, bin: &[u8]) {
122 self.absorb_any(bin, self.absorb_rate(), 0x03);
123 }
124
125 #[inline]
126 fn absorb_more(&mut self, bin: &[u8], rate: usize) {
127 for chunk in bin.chunks(rate) {
128 self.up(None, 0x00);
129 self.down(Some(chunk), 0x00);
130 }
131 }
132
133 #[inline(always)]
134 fn squeeze(&mut self, out: &mut [u8]) {
135 self.squeeze_any(out, 0x40);
136 }
137
138 #[inline(always)]
139 fn squeeze_key(&mut self, out: &mut [u8]) {
140 self.squeeze_any(out, 0x20);
141 }
142
143 #[inline]
144 fn squeeze_more(&mut self, out: &mut [u8]) {
145 for chunk in out.chunks_mut(self.squeeze_rate()) {
146 self.down(None, 0x00);
147 self.up(Some(chunk), 0x00);
148 }
149 }
150
151 #[cfg(feature = "std")]
152 fn squeeze_to_vec(&mut self, len: usize) -> Vec<u8> {
153 let mut out = vec![0u8; len];
154 self.squeeze(&mut out);
155 out
156 }
157}