-
Notifications
You must be signed in to change notification settings - Fork 250
/
Copy pathposeidon2.nr
108 lines (94 loc) · 3.34 KB
/
poseidon2.nr
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
use crate::hash::Hasher;
use crate::default::Default;
comptime global RATE: u32 = 3;
pub struct Poseidon2 {
cache: [Field;3],
state: [Field;4],
cache_size: u32,
squeeze_mode: bool, // 0 => absorb, 1 => squeeze
}
impl Poseidon2 {
#[no_predicates]
pub fn hash<let N: u32>(input: [Field; N], message_size: u32) -> Field {
if message_size == N {
Poseidon2::hash_internal(input, N, false)
} else {
Poseidon2::hash_internal(input, message_size, true)
}
}
pub(crate) fn new(iv: Field) -> Poseidon2 {
let mut result = Poseidon2 { cache: [0; 3], state: [0; 4], cache_size: 0, squeeze_mode: false };
result.state[RATE] = iv;
result
}
fn perform_duplex(&mut self) {
// add the cache into sponge state
for i in 0..RATE {
// We effectively zero-pad the cache by only adding to the state
// cache that is less than the specified `cache_size`
if i < self.cache_size {
self.state[i] += self.cache[i];
}
}
self.state = crate::hash::poseidon2_permutation(self.state, 4);
}
fn absorb(&mut self, input: Field) {
assert(!self.squeeze_mode);
if self.cache_size == RATE {
// If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache
self.perform_duplex();
self.cache[0] = input;
self.cache_size = 1;
} else {
// If we're absorbing, and the cache is not full, add the input into the cache
self.cache[self.cache_size] = input;
self.cache_size += 1;
}
}
fn squeeze(&mut self) -> Field {
assert(!self.squeeze_mode);
// If we're in absorb mode, apply sponge permutation to compress the cache.
self.perform_duplex();
self.squeeze_mode = true;
// Pop one item off the top of the permutation and return it.
self.state[0]
}
fn hash_internal<let N: u32>(input: [Field; N], in_len: u32, is_variable_length: bool) -> Field {
let two_pow_64 = 18446744073709551616;
let iv : Field = (in_len as Field) * two_pow_64;
let mut sponge = Poseidon2::new(iv);
for i in 0..input.len() {
if i < in_len {
sponge.absorb(input[i]);
}
}
// In the case where the hash preimage is variable-length, we append `1` to the end of the input, to distinguish
// from fixed-length hashes. (the combination of this additional field element + the hash IV ensures
// fixed-length and variable-length hashes do not collide)
if is_variable_length {
sponge.absorb(1);
}
sponge.squeeze()
}
}
pub struct Poseidon2Hasher{
_state: [Field],
}
impl Hasher for Poseidon2Hasher {
fn finish(self) -> Field {
let iv : Field = (self._state.len() as Field) * 18446744073709551616; // iv = (self._state.len() << 64)
let mut sponge = Poseidon2::new(iv);
for i in 0..self._state.len() {
sponge.absorb(self._state[i]);
}
sponge.squeeze()
}
fn write(&mut self, input: Field) {
self._state = self._state.push_back(input);
}
}
impl Default for Poseidon2Hasher {
fn default() -> Self {
Poseidon2Hasher { _state: &[] }
}
}