snarkvm_console_algorithms/poseidon/
hash_to_group.rs1use super::*;
17
18impl<E: Environment, const RATE: usize> HashToGroup for Poseidon<E, RATE> {
19 type Input = Field<E>;
20 type Output = Group<E>;
21
22 #[inline]
24 fn hash_to_group(&self, input: &[Self::Input]) -> Result<Self::Output> {
25 ensure!(!input.is_empty(), "Input to hash to group cannot be empty");
27 match self.hash_many(input, 2).iter().map(Elligator2::<E>::encode).collect_tuple() {
29 Some((Ok((h0, _)), Ok((h1, _)))) => Ok(h0 + h1),
30 _ => bail!("Poseidon failed to compute hash to group on the given input"),
31 }
32 }
33}
34
35#[cfg(test)]
36mod tests {
37 use super::*;
38 use snarkvm_console_types::environment::Console;
39
40 type CurrentEnvironment = Console;
41
42 const ITERATIONS: u64 = 1000;
43
44 macro_rules! check_hash_to_group {
45 ($poseidon:ident) => {{
46 let poseidon = $poseidon::<CurrentEnvironment>::setup("HashToGroupTest")?;
48
49 assert!(poseidon.hash_to_group(&[]).is_err());
51
52 let mut rng = TestRng::default();
53
54 for _ in 0..ITERATIONS {
55 for num_inputs in 1..8 {
56 let inputs = (0..num_inputs).map(|_| Uniform::rand(&mut rng)).collect::<Vec<_>>();
58
59 let candidate = poseidon.hash_to_group(&inputs)?;
61 assert!((*candidate).to_affine().is_on_curve());
62 assert!((*candidate).to_affine().is_in_correct_subgroup_assuming_on_curve());
63 assert_ne!(Group::<CurrentEnvironment>::zero(), candidate);
64 assert_ne!(Group::<CurrentEnvironment>::generator(), candidate);
65
66 let candidate_cofactor_inv = candidate.div_by_cofactor();
67 assert_eq!(candidate, candidate_cofactor_inv.mul_by_cofactor());
68 }
69 }
70 Ok(())
71 }};
72 }
73
74 #[test]
75 fn test_poseidon2_hash_to_group() -> Result<()> {
76 check_hash_to_group!(Poseidon2)
77 }
78
79 #[test]
80 fn test_poseidon4_hash_to_group() -> Result<()> {
81 check_hash_to_group!(Poseidon4)
82 }
83
84 #[test]
85 fn test_poseidon8_hash_to_group() -> Result<()> {
86 check_hash_to_group!(Poseidon8)
87 }
88}