use crate::algebra::field::MontFelt;
use crate::hash::poseidon::permutation::*;
pub fn poseidon_hash(x: MontFelt, y: MontFelt) -> MontFelt {
let mut state = [x, y, MontFelt::TWO];
permute(&mut state);
state[0]
}
pub fn poseidon_hash_many(msgs: &[MontFelt]) -> MontFelt {
let mut state = [MontFelt::ZERO, MontFelt::ZERO, MontFelt::ZERO];
let mut iter = msgs.chunks_exact(2);
for msg in iter.by_ref() {
state[0] += msg[0];
state[1] += msg[1];
permute(&mut state);
}
let r = iter.remainder();
if r.len() == 1 {
state[0] += r[0];
}
state[r.len()] += MontFelt::ONE;
permute(&mut state);
state[0]
}
pub struct PoseidonHasher {
state: PoseidonState,
buffer: Option<MontFelt>,
}
impl PoseidonHasher {
pub fn new() -> PoseidonHasher {
PoseidonHasher {
state: [MontFelt::ZERO, MontFelt::ZERO, MontFelt::ZERO],
buffer: None,
}
}
pub fn write(&mut self, msg: MontFelt) {
match self.buffer.take() {
Some(previous_message) => {
self.state[0] += previous_message;
self.state[1] += msg;
permute(&mut self.state);
}
None => {
self.buffer = Some(msg);
}
}
}
pub fn chain(mut self, msg: MontFelt) -> Self {
self.write(msg);
self
}
pub fn finish(mut self) -> MontFelt {
match self.buffer.take() {
Some(last_message) => {
self.state[0] += last_message;
self.state[1] += MontFelt::ONE;
}
None => {
self.state[0] += MontFelt::ONE;
}
}
permute(&mut self.state);
self.state[0]
}
}
impl Default for PoseidonHasher {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::{poseidon_hash, poseidon_hash_many, PoseidonHasher};
use crate::algebra::field::{Felt, MontFelt};
#[test]
fn test_poseidon_hash() {
let x =
Felt::from_hex_str("0x23a77118133287637ebdcd9e87a1613e443df789558867f5ba91faf7a024204")
.unwrap();
let y =
Felt::from_hex_str("0x259f432e6f4590b9a164106cf6a659eb4862b21fb97d43588561712e8e5216a")
.unwrap();
let expected_hash =
Felt::from_hex_str("0x4be9af45b942b4b0c9f04a15e37b7f34f8109873ef7ef20e9eef8a38a3011e1")
.unwrap();
assert_eq!(poseidon_hash(x.into(), y.into()), expected_hash.into());
}
#[test]
fn test_poseidon_hash_many_empty_input() {
assert_eq!(
poseidon_hash_many(&[]),
Felt::from_hex_str("0x2272be0f580fd156823304800919530eaa97430e972d7213ee13f4fbf7a5dbc")
.unwrap()
.into()
);
}
#[test]
fn test_poseidon_hash_many_single_input() {
assert_eq!(
poseidon_hash_many(&[Felt::from_hex_str(
"0x23a77118133287637ebdcd9e87a1613e443df789558867f5ba91faf7a024204"
)
.unwrap()
.into()]),
Felt::from_hex_str("0x7d1f569e0e898982de6515c20132703410abca88ee56100e02df737fc4bf10e")
.unwrap()
.into()
);
}
#[test]
fn test_poseidon_hash_many_two_inputs() {
assert_eq!(
poseidon_hash_many(&[
Felt::from_hex_str(
"0x259f432e6f4590b9a164106cf6a659eb4862b21fb97d43588561712e8e5216a"
)
.unwrap()
.into(),
Felt::from_hex_str(
"0x5487ce1af19922ad9b8a714e61a441c12e0c8b2bad640fb19488dec4f65d4d9"
)
.unwrap()
.into(),
]),
Felt::from_hex_str("0x70869d36570fc0b364777c9322373fb7e15452d2282ebdb5b4f3212669f2e7")
.unwrap()
.into()
);
}
#[test]
fn test_sponge() {
let expected_result = MontFelt::from(
Felt::from_hex_str(
"0x07b8f30ac298ea12d170c0873f1fa631a18c00756c6e7d1fd273b9a239d0d413",
)
.unwrap(),
);
let msgs = [
MontFelt::ZERO,
MontFelt::ONE,
MontFelt::TWO,
MontFelt::THREE,
];
let mut hasher = PoseidonHasher::new();
for msg in msgs {
hasher.write(msg);
}
let hasher_result = hasher.finish();
let hash_result = poseidon_hash_many(&msgs);
assert_eq!(hasher_result, hash_result);
assert_eq!(expected_result, hash_result);
}
}