bee_crypto/ternary/sponge/curlp/
mod.rs1mod batched;
5mod unrolled;
6
7pub use batched::{BatchHasher, BATCH_SIZE};
8pub use unrolled::UnrolledCurlP81;
9
10use crate::ternary::{sponge::Sponge, HASH_LENGTH};
11
12use bee_ternary::{Btrit, TritBuf, Trits};
13
14use std::{
15 convert::Infallible,
16 ops::{Deref, DerefMut},
17};
18
19const STATE_LENGTH: usize = HASH_LENGTH * 3;
20const HALF_STATE_LENGTH: usize = STATE_LENGTH / 2;
21
22const TRUTH_TABLE: [Btrit; 9] = [
23 Btrit::PlusOne,
24 Btrit::Zero,
25 Btrit::NegOne,
26 Btrit::PlusOne,
27 Btrit::NegOne,
28 Btrit::Zero,
29 Btrit::NegOne,
30 Btrit::PlusOne,
31 Btrit::Zero,
32];
33
34#[derive(Copy, Clone)]
36pub enum CurlPRounds {
37 Rounds27 = 27,
39 Rounds81 = 81,
41}
42
43pub struct CurlP {
45 rounds: CurlPRounds,
47 state: TritBuf,
49 work_state: TritBuf,
51}
52
53impl CurlP {
54 pub fn new(rounds: CurlPRounds) -> Self {
56 Self {
57 rounds,
58 state: TritBuf::zeros(STATE_LENGTH),
59 work_state: TritBuf::zeros(STATE_LENGTH),
60 }
61 }
62
63 fn transform(&mut self) {
68 #[inline]
76 unsafe fn truth_table_get(state: &Trits, p: usize, q: usize) -> Btrit {
77 #[allow(clippy::cast_sign_loss)] *TRUTH_TABLE
79 .get_unchecked((3 * (state.get_unchecked(q) as i8 + 1) + (state.get_unchecked(p) as i8 + 1)) as usize)
80 }
81
82 #[inline]
89 unsafe fn substitution_box(input: &Trits, output: &mut Trits) {
90 output.set_unchecked(0, truth_table_get(input, 0, HALF_STATE_LENGTH));
91
92 for state_index in 0..HALF_STATE_LENGTH {
93 let left_idx = HALF_STATE_LENGTH - state_index;
94 let right_idx = STATE_LENGTH - state_index - 1;
95 let state_index_2 = 2 * state_index;
96
97 output.set_unchecked(state_index_2 + 1, truth_table_get(input, left_idx, right_idx));
98 output.set_unchecked(state_index_2 + 2, truth_table_get(input, right_idx, left_idx - 1));
99 }
100 }
101
102 let (lhs, rhs) = (&mut self.state, &mut self.work_state);
103
104 for _ in 0..self.rounds as usize {
105 unsafe {
106 substitution_box(lhs, rhs);
107 }
108 std::mem::swap(lhs, rhs);
109 }
110 }
111}
112
113impl Sponge for CurlP {
114 type Error = Infallible;
115
116 fn reset(&mut self) {
118 self.state.fill(Btrit::Zero);
119 }
120
121 fn absorb(&mut self, input: &Trits) -> Result<(), Self::Error> {
129 for chunk in input.chunks(HASH_LENGTH) {
130 self.state[0..chunk.len()].copy_from(chunk);
131 self.transform();
132 }
133 Ok(())
134 }
135
136 fn squeeze_into(&mut self, buf: &mut Trits) -> Result<(), Self::Error> {
141 for chunk in buf.chunks_mut(HASH_LENGTH) {
142 chunk.copy_from(&self.state[0..chunk.len()]);
143 self.transform()
144 }
145 Ok(())
146 }
147}
148
149pub struct CurlP27(CurlP);
151
152impl CurlP27 {
153 pub fn new() -> Self {
155 Self(CurlP::new(CurlPRounds::Rounds27))
156 }
157}
158
159impl Default for CurlP27 {
160 fn default() -> Self {
161 CurlP27::new()
162 }
163}
164
165impl Deref for CurlP27 {
166 type Target = CurlP;
167
168 fn deref(&self) -> &Self::Target {
169 &self.0
170 }
171}
172
173impl DerefMut for CurlP27 {
174 fn deref_mut(&mut self) -> &mut Self::Target {
175 &mut self.0
176 }
177}
178
179pub struct CurlP81(CurlP);
181
182impl CurlP81 {
183 pub fn new() -> Self {
185 Self(CurlP::new(CurlPRounds::Rounds81))
186 }
187}
188
189impl Default for CurlP81 {
190 fn default() -> Self {
191 CurlP81::new()
192 }
193}
194
195impl Deref for CurlP81 {
196 type Target = CurlP;
197
198 fn deref(&self) -> &Self::Target {
199 &self.0
200 }
201}
202
203impl DerefMut for CurlP81 {
204 fn deref_mut(&mut self) -> &mut Self::Target {
205 &mut self.0
206 }
207}