snarkvm_circuit_algorithms/poseidon/
mod.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkVM 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
16mod hash;
17mod hash_many;
18mod hash_to_group;
19mod hash_to_scalar;
20mod prf;
21
22#[cfg(test)]
23use snarkvm_circuit_types::environment::assert_scope;
24#[cfg(test)]
25use snarkvm_utilities::{TestRng, Uniform};
26
27use crate::{Elligator2, Hash, HashMany, HashToGroup, HashToScalar, PRF};
28use snarkvm_circuit_types::{Field, Group, Scalar, environment::prelude::*};
29
30/// Poseidon2 is a cryptographic hash function of input rate 2.
31pub type Poseidon2<E> = Poseidon<E, 2>;
32/// Poseidon4 is a cryptographic hash function of input rate 4.
33pub type Poseidon4<E> = Poseidon<E, 4>;
34/// Poseidon8 is a cryptographic hash function of input rate 8.
35pub type Poseidon8<E> = Poseidon<E, 8>;
36
37const CAPACITY: usize = 1;
38
39/// The mode structure for duplex sponges.
40#[derive(PartialEq, Eq, Clone, Debug)]
41pub 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)]
55pub 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
71impl<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}