mod.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  mod hash;
 17  mod hash_many;
 18  mod hash_to_group;
 19  mod hash_to_scalar;
 20  mod prf;
 21  
 22  #[cfg(test)]
 23  use alphavm_circuit_types::environment::assert_scope;
 24  #[cfg(test)]
 25  use alphavm_utilities::{TestRng, Uniform};
 26  
 27  use crate::{Elligator2, Hash, HashMany, HashToGroup, HashToScalar, PRF};
 28  use alphavm_circuit_types::{Field, Group, Scalar, environment::prelude::*};
 29  
 30  /// Poseidon2 is a cryptographic hash function of input rate 2.
 31  pub type Poseidon2<E> = Poseidon<E, 2>;
 32  /// Poseidon4 is a cryptographic hash function of input rate 4.
 33  pub type Poseidon4<E> = Poseidon<E, 4>;
 34  /// Poseidon8 is a cryptographic hash function of input rate 8.
 35  pub type Poseidon8<E> = Poseidon<E, 8>;
 36  
 37  const CAPACITY: usize = 1;
 38  
 39  /// The mode structure for duplex sponges.
 40  #[derive(PartialEq, Eq, Clone, Debug)]
 41  pub enum DuplexSpongeMode {
 42      /// The sponge is currently absorbing data.
 43      Absorbing {
 44          /// The next position of the state to be XOR-ed when absorbing.
 45          next_absorb_index: usize,
 46      },
 47      /// The sponge is currently squeezing data out.
 48      Squeezing {
 49          /// The next position of the state to be outputted when squeezing.
 50          next_squeeze_index: usize,
 51      },
 52  }
 53  
 54  #[derive(Clone)]
 55  pub struct Poseidon<E: Environment, const RATE: usize> {
 56      /// The domain separator for the Poseidon hash function.
 57      domain: Field<E>,
 58      /// The number of rounds in a full-round operation.
 59      full_rounds: usize,
 60      /// The number of rounds in a partial-round operation.
 61      partial_rounds: usize,
 62      /// The exponent used in S-boxes.
 63      alpha: Field<E>,
 64      /// The additive round keys. These are added before each MDS matrix application to make it an affine shift.
 65      /// They are indexed by `ark[round_number][state_element_index]`
 66      ark: Vec<Vec<Field<E>>>,
 67      /// The Maximally Distance Separating (MDS) matrix.
 68      mds: Vec<Vec<Field<E>>>,
 69  }
 70  
 71  impl<E: Environment, const RATE: usize> Inject for Poseidon<E, RATE> {
 72      type Primitive = console::Poseidon<E::Network, RATE>;
 73  
 74      fn new(_mode: Mode, poseidon: Self::Primitive) -> Self {
 75          // Initialize the domain separator.
 76          let domain = Field::constant(poseidon.domain());
 77  
 78          // Initialize the Poseidon parameters.
 79          let parameters = poseidon.parameters();
 80          let full_rounds = parameters.full_rounds;
 81          let partial_rounds = parameters.partial_rounds;
 82          let alpha = Field::constant(console::Field::from_u128(parameters.alpha as u128));
 83          // Cache the bits for the field element.
 84          alpha.to_bits_le();
 85          let ark = parameters
 86              .ark
 87              .iter()
 88              .take(full_rounds + partial_rounds)
 89              .map(|round| {
 90                  round.iter().take(RATE + 1).copied().map(|field| Field::constant(console::Field::new(field))).collect()
 91              })
 92              .collect();
 93          let mds = parameters
 94              .mds
 95              .iter()
 96              .take(RATE + 1)
 97              .map(|round| {
 98                  round.iter().take(RATE + 1).copied().map(|field| Field::constant(console::Field::new(field))).collect()
 99              })
100              .collect();
101  
102          Self { domain, full_rounds, partial_rounds, alpha, ark, mds }
103      }
104  }