use ark_bn254::Fr;
use ark_ff::{BigInteger, PrimeField};
use pso_poseidon::{Poseidon, PoseidonError, PoseidonHasher};
#[test]
fn test_poseidon_bn254_x5_fq_input_ones_twos() {
let input1 = Fr::from_le_bytes_mod_order(&[1u8; 32]);
let input2 = Fr::from_le_bytes_mod_order(&[2u8; 32]);
let mut hasher = Poseidon::<Fr>::new_circom(2).unwrap();
let hash = hasher.hash(&[input1, input2]).unwrap();
let expected_le = [
144, 25, 130, 41, 200, 53, 231, 38, 27, 206, 162, 156, 254, 132, 123, 32, 25, 99, 242, 85,
3, 94, 235, 125, 28, 140, 138, 143, 147, 225, 84, 13,
];
assert_eq!(hash.into_bigint().to_bytes_le(), expected_le);
}
#[test]
fn test_poseidon_bn254_x5_fq_with_domain_tag() {
let input1 = Fr::from_le_bytes_mod_order(&[1u8; 32]);
let input2 = Fr::from_le_bytes_mod_order(&[2u8; 32]);
let mut hasher = Poseidon::<Fr>::with_domain_tag_circom(2, Fr::from(0u64)).unwrap();
let hash = hasher.hash(&[input1, input2]).unwrap();
let expected_tag_zero_le = [
144, 25, 130, 41, 200, 53, 231, 38, 27, 206, 162, 156, 254, 132, 123, 32, 25, 99, 242, 85,
3, 94, 235, 125, 28, 140, 138, 143, 147, 225, 84, 13,
];
assert_eq!(hash.into_bigint().to_bytes_le(), expected_tag_zero_le);
let mut hasher = Poseidon::<Fr>::with_domain_tag_circom(2, Fr::from(1u64)).unwrap();
let hash = hasher.hash(&[input1, input2]).unwrap();
assert_ne!(hash.into_bigint().to_bytes_le(), expected_tag_zero_le);
}
#[test]
fn test_poseidon_bn254_x5_fq_too_many_inputs() {
let input1 = Fr::from_le_bytes_mod_order(&[1u8; 32]);
let input2 = Fr::from_le_bytes_mod_order(&[2u8; 32]);
for i in 1..13 {
let mut hasher = Poseidon::<Fr>::new_circom(i).unwrap();
for j in 1..13 {
if i != j {
let inputs: Vec<_> = (0..j)
.map(|k| if k % 2 == 0 { input1 } else { input2 })
.collect();
let res = hasher.hash(&inputs);
assert!(res.is_err());
}
}
}
}
#[test]
fn test_circom_solana_t_gt_12_fails() {
for i in 13..16 {
let hasher = Poseidon::<Fr>::new_circom(i);
assert!(hasher.is_err());
if let Err(PoseidonError::InvalidWidthCircom { width, max_limit }) = hasher {
assert_eq!(width, i + 1);
assert_eq!(max_limit, 13);
} else {
panic!("Expected InvalidWidthCircom error");
}
}
}
#[test]
fn test_circom_t_0_fails() {
let hasher = Poseidon::<Fr>::new_circom(0);
assert!(hasher.is_err());
if let Err(PoseidonError::InvalidWidthCircom { width, max_limit }) = hasher {
assert_eq!(width, 1);
assert_eq!(max_limit, 13);
} else {
panic!("Expected InvalidWidthCircom error");
}
}
#[test]
fn test_poseidon_bn254_x5_fq_same_input_same_results() {
let input = Fr::from_le_bytes_mod_order(&[1u8; 32]);
for nr_inputs in 1..12 {
let mut hasher = Poseidon::<Fr>::new_circom(nr_inputs).unwrap();
let mut inputs = Vec::with_capacity(nr_inputs);
for _ in 0..nr_inputs {
inputs.push(input);
}
let hash1 = hasher.hash(&inputs).unwrap();
let hash2 = hasher.hash(&inputs).unwrap();
assert_eq!(hash1, hash2);
}
}
#[test]
fn test_poseidon_bn254_x5_fq_different_inputs_different_results() {
let input1 = Fr::from_le_bytes_mod_order(&[1u8; 32]);
let input2 = Fr::from_le_bytes_mod_order(&[2u8; 32]);
for nr_inputs in 1..12 {
let mut hasher = Poseidon::<Fr>::new_circom(nr_inputs).unwrap();
let mut inputs1 = Vec::with_capacity(nr_inputs);
let mut inputs2 = Vec::with_capacity(nr_inputs);
for _ in 0..nr_inputs {
inputs1.push(input1);
inputs2.push(input2);
}
let hash1 = hasher.hash(&inputs1).unwrap();
let hash2 = hasher.hash(&inputs2).unwrap();
assert_ne!(hash1, hash2);
}
}
#[test]
fn test_poseidon_bn254_x5_fq_different_widths_different_results() {
let input = Fr::from_le_bytes_mod_order(&[1u8; 32]);
let mut hashes = Vec::new();
for nr_inputs in 1..12 {
let mut hasher = Poseidon::<Fr>::new_circom(nr_inputs).unwrap();
let mut inputs = Vec::with_capacity(nr_inputs);
for _ in 0..nr_inputs {
inputs.push(input);
}
let hash = hasher.hash(&inputs).unwrap();
hashes.push(hash);
}
for i in 0..hashes.len() {
for j in (i + 1)..hashes.len() {
assert_ne!(hashes[i], hashes[j]);
}
}
}
#[test]
fn test_poseidon_bn254_x5_fq_deterministic() {
let input1 = Fr::from_le_bytes_mod_order(&[1u8; 32]);
let input2 = Fr::from_le_bytes_mod_order(&[2u8; 32]);
for nr_inputs in 1..12 {
let inputs: Vec<_> = (0..nr_inputs)
.map(|k| if k % 2 == 0 { input1 } else { input2 })
.collect();
let mut hasher1 = Poseidon::<Fr>::new_circom(nr_inputs).unwrap();
let mut hasher2 = Poseidon::<Fr>::new_circom(nr_inputs).unwrap();
let hash1 = hasher1.hash(&inputs).unwrap();
let hash2 = hasher2.hash(&inputs).unwrap();
assert_eq!(hash1, hash2);
}
}
#[test]
fn test_poseidon_bn254_x5_fq_various_inputs() {
let mut inputs_list = Vec::new();
inputs_list.push(Fr::from(0u64));
for i in 1..10 {
let mut bytes = [0u8; 32];
bytes[31] = i;
inputs_list.push(Fr::from_le_bytes_mod_order(&bytes));
}
inputs_list.push(Fr::from_le_bytes_mod_order(&[1u8; 32]));
inputs_list.push(Fr::from_le_bytes_mod_order(&[2u8; 32]));
for nr_inputs in 1..12 {
let mut hasher = Poseidon::<Fr>::new_circom(nr_inputs).unwrap();
let inputs: Vec<_> = (0..nr_inputs)
.map(|i| inputs_list[i % inputs_list.len()])
.collect();
let result = hasher.hash(&inputs);
assert!(result.is_ok());
let hash = result.unwrap();
let _ = hash.into_bigint().to_bytes_le(); }
}