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}