snarkvm_circuit_algorithms/poseidon/mod.rs
1// Copyright 2024 Aleo Network Foundation
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(all(test, feature = "console"))]
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
71#[cfg(feature = "console")]
72impl<E: Environment, const RATE: usize> Inject for Poseidon<E, RATE> {
73 type Primitive = console::Poseidon<E::Network, RATE>;
74
75 fn new(_mode: Mode, poseidon: Self::Primitive) -> Self {
76 // Initialize the domain separator.
77 let domain = Field::constant(poseidon.domain());
78
79 // Initialize the Poseidon parameters.
80 let parameters = poseidon.parameters();
81 let full_rounds = parameters.full_rounds;
82 let partial_rounds = parameters.partial_rounds;
83 let alpha = Field::constant(console::Field::from_u128(parameters.alpha as u128));
84 // Cache the bits for the field element.
85 alpha.to_bits_le();
86 let ark = parameters
87 .ark
88 .iter()
89 .take(full_rounds + partial_rounds)
90 .map(|round| {
91 round.iter().take(RATE + 1).copied().map(|field| Field::constant(console::Field::new(field))).collect()
92 })
93 .collect();
94 let mds = parameters
95 .mds
96 .iter()
97 .take(RATE + 1)
98 .map(|round| {
99 round.iter().take(RATE + 1).copied().map(|field| Field::constant(console::Field::new(field))).collect()
100 })
101 .collect();
102
103 Self { domain, full_rounds, partial_rounds, alpha, ark, mds }
104 }
105}