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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#[cfg(feature = "curl-p")]
#[cfg_attr(docsrs, doc(cfg(feature = "curl-p")))]
pub mod curl_p;
#[cfg(feature = "kerl_deprecated_do_not_use")]
#[cfg_attr(docsrs, doc(cfg(feature = "kerl_deprecated_do_not_use")))]
#[cfg_attr(not(test), deprecated)]
pub mod kerl;
pub const HASH_LENGTH: usize = 243;
pub const HASH_LENGTH_TRYTES: usize = 243 / 3;
use bee_ternary::{raw::RawEncoding, Btrit, TritBuf, Trits, T1B1};
use core::ops::DerefMut;
pub trait Sponge {
type Error;
fn reset(&mut self);
fn absorb(&mut self, input: &Trits) -> Result<(), Self::Error>;
fn squeeze_into(&mut self, buf: &mut Trits) -> Result<(), Self::Error>;
fn squeeze(&mut self) -> Result<TritBuf, Self::Error> {
let mut output = TritBuf::zeros(HASH_LENGTH);
self.squeeze_into(&mut output)?;
Ok(output)
}
fn digest_into(&mut self, input: &Trits, buf: &mut Trits) -> Result<(), Self::Error> {
self.absorb(input)?;
self.squeeze_into(buf)?;
self.reset();
Ok(())
}
fn digest(&mut self, input: &Trits) -> Result<TritBuf, Self::Error> {
self.absorb(input)?;
let output = self.squeeze()?;
self.reset();
Ok(output)
}
}
impl<T: Sponge, U: DerefMut<Target = T>> Sponge for U {
type Error = T::Error;
fn reset(&mut self) {
T::reset(self)
}
fn absorb(&mut self, input: &Trits) -> Result<(), Self::Error> {
T::absorb(self, input)
}
fn squeeze_into(&mut self, buf: &mut Trits) -> Result<(), Self::Error> {
T::squeeze_into(self, buf)
}
}
#[derive(Debug)]
pub enum HashError {
WrongLength,
}
#[derive(Copy, Clone)]
pub struct Hash([Btrit; HASH_LENGTH]);
impl Hash {
pub fn zeros() -> Self {
Self([Btrit::Zero; HASH_LENGTH])
}
pub fn as_trits(&self) -> &Trits<T1B1> {
&*self
}
pub fn as_trits_mut(&mut self) -> &mut Trits<T1B1> {
&mut *self
}
#[allow(clippy::cast_possible_truncation)]
pub fn weight(&self) -> u8 {
self.iter().rev().take_while(|t| *t == Btrit::Zero).count() as u8
}
}
impl<'a, T: RawEncoding<Trit = Btrit>> core::convert::TryFrom<&'a Trits<T>> for Hash {
type Error = HashError;
fn try_from(trits: &'a Trits<T>) -> Result<Self, Self::Error> {
if trits.len() == HASH_LENGTH {
let mut hash = Self([Btrit::Zero; HASH_LENGTH]);
hash.copy_from(trits);
Ok(hash)
} else {
Err(HashError::WrongLength)
}
}
}
impl core::ops::Deref for Hash {
type Target = Trits<T1B1>;
fn deref(&self) -> &Trits<T1B1> {
<&Trits>::from(&self.0 as &[_])
}
}
impl DerefMut for Hash {
fn deref_mut(&mut self) -> &mut Trits<T1B1> {
<&mut Trits>::from(&mut self.0 as &mut [_])
}
}
impl PartialEq for Hash {
fn eq(&self, other: &Self) -> bool {
self.as_trits() == other.as_trits()
}
}
impl Eq for Hash {}
impl core::fmt::Display for Hash {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(self, f)
}
}
impl core::fmt::Debug for Hash {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{:?}", self.as_trits())
}
}
impl core::hash::Hash for Hash {
fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) {
self.0.hash(hasher)
}
}