1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use crate::ternary::{
bigint::{binary_representation::U8Repr, endianness::BigEndian, error::Error as ConversionError, I384, T242, T243},
sponge::Sponge,
HASH_LENGTH,
};
use bee_ternary::{Btrit, Trits, T1B1};
use tiny_keccak::{Hasher, Keccak};
#[derive(Clone)]
pub struct Kerl {
keccak: Keccak,
binary_state: I384<BigEndian, U8Repr>,
ternary_state: T243<Btrit>,
}
impl Default for Kerl {
fn default() -> Self {
Self {
keccak: Keccak::v384(),
binary_state: Default::default(),
ternary_state: Default::default(),
}
}
}
impl Kerl {
pub fn new() -> Self {
Self::default()
}
}
#[derive(Debug)]
pub enum Error {
NotMultipleOfHashLength,
TernaryBinaryConversion(ConversionError),
}
impl From<ConversionError> for Error {
fn from(error: ConversionError) -> Self {
Error::TernaryBinaryConversion(error)
}
}
impl Sponge for Kerl {
type Error = Error;
fn reset(&mut self) {
self.keccak = Keccak::v384();
}
fn absorb(&mut self, input: &Trits) -> Result<(), Self::Error> {
if input.len() % HASH_LENGTH != 0 {
return Err(Error::NotMultipleOfHashLength);
}
for trits_chunk in input.chunks(HASH_LENGTH) {
self.ternary_state.copy_from(trits_chunk);
self.binary_state = self.ternary_state.clone().into_t242().into();
self.keccak.update(&self.binary_state[..]);
}
Ok(())
}
fn squeeze_into(&mut self, buf: &mut Trits<T1B1>) -> Result<(), Self::Error> {
if buf.len() % HASH_LENGTH != 0 {
return Err(Error::NotMultipleOfHashLength);
}
for trit_chunk in buf.chunks_mut(HASH_LENGTH) {
let mut keccak = Keccak::v384();
std::mem::swap(&mut self.keccak, &mut keccak);
keccak.finalize(&mut self.binary_state[..]);
let ternary_value = T242::from_i384_ignoring_mst(self.binary_state).into_t243();
trit_chunk.copy_from(&ternary_value);
self.binary_state.not_inplace();
self.keccak.update(&self.binary_state[..]);
}
Ok(())
}
}