/ circuit / algorithms / src / poseidon / hash.rs
hash.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  2  // This file is part of the alphavm library.
  3  
  4  // Licensed under the Apache License, Version 2.0 (the "License");
  5  // you may not use this file except in compliance with the License.
  6  // You may obtain a copy of the License at:
  7  
  8  // http://www.apache.org/licenses/LICENSE-2.0
  9  
 10  // Unless required by applicable law or agreed to in writing, software
 11  // distributed under the License is distributed on an "AS IS" BASIS,
 12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  // See the License for the specific language governing permissions and
 14  // limitations under the License.
 15  
 16  use super::*;
 17  
 18  impl<E: Environment, const RATE: usize> Hash for Poseidon<E, RATE> {
 19      type Input = Field<E>;
 20      type Output = Field<E>;
 21  
 22      #[inline]
 23      fn hash(&self, input: &[Self::Input]) -> Self::Output {
 24          self.hash_many(input, 1).swap_remove(0)
 25      }
 26  }
 27  
 28  #[cfg(test)]
 29  mod tests {
 30      use super::*;
 31      use alphavm_circuit_types::environment::Circuit;
 32  
 33      use anyhow::Result;
 34  
 35      const DOMAIN: &str = "PoseidonCircuit0";
 36      const ITERATIONS: usize = 10;
 37      const RATE: usize = 4;
 38  
 39      fn check_hash(
 40          mode: Mode,
 41          num_inputs: usize,
 42          num_constants: u64,
 43          num_public: u64,
 44          num_private: u64,
 45          num_constraints: u64,
 46          rng: &mut TestRng,
 47      ) -> Result<()> {
 48          use console::Hash as H;
 49  
 50          let native = console::Poseidon::<<Circuit as Environment>::Network, RATE>::setup(DOMAIN)?;
 51          let poseidon = Poseidon::<Circuit, RATE>::constant(native.clone());
 52  
 53          for i in 0..ITERATIONS {
 54              // Prepare the preimage.
 55              let native_input = (0..num_inputs)
 56                  .map(|_| console::Field::<<Circuit as Environment>::Network>::rand(rng))
 57                  .collect::<Vec<_>>();
 58              let input = native_input.iter().map(|v| Field::<Circuit>::new(mode, *v)).collect::<Vec<_>>();
 59  
 60              // Compute the native hash.
 61              let expected = native.hash(&native_input).expect("Failed to hash native input");
 62  
 63              // Compute the circuit hash.
 64              Circuit::scope(format!("Poseidon {mode} {i}"), || {
 65                  let candidate = poseidon.hash(&input);
 66                  assert_eq!(expected, candidate.eject_value());
 67                  let case = format!("(mode = {mode}, num_inputs = {num_inputs})");
 68                  assert_scope!(case, num_constants, num_public, num_private, num_constraints);
 69              });
 70              Circuit::reset();
 71          }
 72          Ok(())
 73      }
 74  
 75      #[test]
 76      fn test_hash_constant() -> Result<()> {
 77          let mut rng = TestRng::default();
 78  
 79          for num_inputs in 0..=RATE {
 80              check_hash(Mode::Constant, num_inputs, 1, 0, 0, 0, &mut rng)?;
 81          }
 82          Ok(())
 83      }
 84  
 85      #[test]
 86      fn test_hash_public() -> Result<()> {
 87          let mut rng = TestRng::default();
 88  
 89          check_hash(Mode::Public, 0, 1, 0, 0, 0, &mut rng)?;
 90          check_hash(Mode::Public, 1, 1, 0, 335, 335, &mut rng)?;
 91          check_hash(Mode::Public, 2, 1, 0, 340, 340, &mut rng)?;
 92          check_hash(Mode::Public, 3, 1, 0, 345, 345, &mut rng)?;
 93          check_hash(Mode::Public, 4, 1, 0, 350, 350, &mut rng)?;
 94          check_hash(Mode::Public, 5, 1, 0, 705, 705, &mut rng)?;
 95          check_hash(Mode::Public, 6, 1, 0, 705, 705, &mut rng)?;
 96          check_hash(Mode::Public, 7, 1, 0, 705, 705, &mut rng)?;
 97          check_hash(Mode::Public, 8, 1, 0, 705, 705, &mut rng)?;
 98          check_hash(Mode::Public, 9, 1, 0, 1060, 1060, &mut rng)?;
 99          check_hash(Mode::Public, 10, 1, 0, 1060, 1060, &mut rng)
100      }
101  
102      #[test]
103      fn test_hash_private() -> Result<()> {
104          let mut rng = TestRng::default();
105  
106          check_hash(Mode::Private, 0, 1, 0, 0, 0, &mut rng)?;
107          check_hash(Mode::Private, 1, 1, 0, 335, 335, &mut rng)?;
108          check_hash(Mode::Private, 2, 1, 0, 340, 340, &mut rng)?;
109          check_hash(Mode::Private, 3, 1, 0, 345, 345, &mut rng)?;
110          check_hash(Mode::Private, 4, 1, 0, 350, 350, &mut rng)?;
111          check_hash(Mode::Private, 5, 1, 0, 705, 705, &mut rng)?;
112          check_hash(Mode::Private, 6, 1, 0, 705, 705, &mut rng)?;
113          check_hash(Mode::Private, 7, 1, 0, 705, 705, &mut rng)?;
114          check_hash(Mode::Private, 8, 1, 0, 705, 705, &mut rng)?;
115          check_hash(Mode::Private, 9, 1, 0, 1060, 1060, &mut rng)?;
116          check_hash(Mode::Private, 10, 1, 0, 1060, 1060, &mut rng)
117      }
118  }