1use crate::{
3 frontend::{
4 gadgets::poseidon::{
5 Elt, IOPattern, PoseidonConstants, Simplex, Sponge, SpongeAPI, SpongeCircuit, SpongeOp,
6 SpongeTrait, Strength,
7 },
8 num::AllocatedNum,
9 AllocatedBit, Boolean, ConstraintSystem, SynthesisError,
10 },
11 traits::{ROCircuitTrait, ROTrait},
12};
13use ff::{PrimeField, PrimeFieldBits};
14use generic_array::typenum::U24;
15use serde::{Deserialize, Serialize};
16
17#[derive(Clone, PartialEq, Serialize, Deserialize)]
19pub struct PoseidonConstantsCircuit<Scalar: PrimeField>(PoseidonConstants<Scalar, U24>);
20
21impl<Scalar: PrimeField> Default for PoseidonConstantsCircuit<Scalar> {
22 fn default() -> Self {
24 Self(Sponge::<Scalar, U24>::api_constants(Strength::Standard))
25 }
26}
27
28#[derive(Serialize, Deserialize)]
30pub struct PoseidonRO<Base: PrimeField> {
31 state: Vec<Base>,
33 constants: PoseidonConstantsCircuit<Base>,
34}
35
36impl<Base> ROTrait<Base> for PoseidonRO<Base>
37where
38 Base: PrimeField + PrimeFieldBits + Serialize + for<'de> Deserialize<'de>,
39{
40 type CircuitRO = PoseidonROCircuit<Base>;
41 type Constants = PoseidonConstantsCircuit<Base>;
42
43 fn new(constants: PoseidonConstantsCircuit<Base>) -> Self {
44 Self {
45 state: Vec::new(),
46 constants,
47 }
48 }
49
50 fn absorb(&mut self, e: Base) {
52 self.state.push(e);
53 }
54
55 fn squeeze(&mut self, num_bits: usize, start_with_one: bool) -> Base {
57 let mut sponge = Sponge::new_with_constants(&self.constants.0, Simplex);
58 let acc = &mut ();
59 let parameter = IOPattern(vec![
60 SpongeOp::Absorb(self.state.len() as u32),
61 SpongeOp::Squeeze(1u32),
62 ]);
63
64 sponge.start(parameter, None, acc);
65 SpongeAPI::absorb(&mut sponge, self.state.len() as u32, &self.state, acc);
66 let hash = SpongeAPI::squeeze(&mut sponge, 1, acc);
67 sponge.finish(acc).unwrap();
68
69 self.state = vec![hash[0]];
71
72 let bits = hash[0].to_le_bits();
74 let mut res = Base::ZERO;
75 let mut coeff = Base::ONE;
76 for bit in bits[..num_bits].into_iter() {
77 if *bit {
78 res += coeff;
79 }
80 coeff += coeff;
81 }
82 if start_with_one {
84 let msb_coeff = coeff * Base::from(2u64).invert().unwrap();
86 if !bits[num_bits - 1] {
88 res += msb_coeff;
89 }
90 }
91 res
92 }
93}
94
95#[derive(Serialize, Deserialize)]
97pub struct PoseidonROCircuit<Scalar: PrimeField> {
98 state: Vec<AllocatedNum<Scalar>>,
100 constants: PoseidonConstantsCircuit<Scalar>,
101}
102
103impl<Scalar> ROCircuitTrait<Scalar> for PoseidonROCircuit<Scalar>
104where
105 Scalar: PrimeField + PrimeFieldBits + Serialize + for<'de> Deserialize<'de>,
106{
107 type NativeRO = PoseidonRO<Scalar>;
108 type Constants = PoseidonConstantsCircuit<Scalar>;
109
110 fn new(constants: PoseidonConstantsCircuit<Scalar>) -> Self {
112 Self {
113 state: Vec::new(),
114 constants,
115 }
116 }
117
118 fn absorb(&mut self, e: &AllocatedNum<Scalar>) {
120 self.state.push(e.clone());
121 }
122
123 fn squeeze<CS: ConstraintSystem<Scalar>>(
125 &mut self,
126 mut cs: CS,
127 num_bits: usize,
128 start_with_one: bool,
129 ) -> Result<Vec<AllocatedBit>, SynthesisError> {
130 let parameter = IOPattern(vec![
131 SpongeOp::Absorb(self.state.len() as u32),
132 SpongeOp::Squeeze(1u32),
133 ]);
134 let mut ns = cs.namespace(|| "ns");
135
136 let hash = {
137 let mut sponge = SpongeCircuit::new_with_constants(&self.constants.0, Simplex);
138 let acc = &mut ns;
139
140 sponge.start(parameter, None, acc);
141 SpongeAPI::absorb(
142 &mut sponge,
143 self.state.len() as u32,
144 &(0..self.state.len())
145 .map(|i| Elt::Allocated(self.state[i].clone()))
146 .collect::<Vec<Elt<Scalar>>>(),
147 acc,
148 );
149
150 let output = SpongeAPI::squeeze(&mut sponge, 1, acc);
151 sponge.finish(acc).unwrap();
152 output
153 };
154
155 let hash = Elt::ensure_allocated(&hash[0], &mut ns.namespace(|| "ensure allocated"))?;
156
157 self.state = vec![hash.clone()];
159
160 let mut bits: Vec<AllocatedBit> = hash
162 .to_bits_le_strict(ns.namespace(|| "poseidon hash to boolean"))?
163 .iter()
164 .map(|boolean| match boolean {
165 Boolean::Is(ref x) => x.clone(),
166 _ => panic!("Wrong type of input. We should have never reached there"),
167 })
168 .collect::<Vec<AllocatedBit>>()[..num_bits]
169 .to_vec();
170
171 if start_with_one {
172 let msb_idx = num_bits - 1;
173 bits[msb_idx] = AllocatedBit::alloc(ns.namespace(|| "set msb to 1"), Some(true))?;
174 ns.enforce(
175 || "check bits[msb] = 1",
176 |lc| lc + bits[msb_idx].get_variable(),
177 |lc| lc + CS::one(),
178 |lc| lc + CS::one(),
179 );
180 }
181
182 Ok(bits)
183 }
184
185 fn squeeze_scalar<CS: ConstraintSystem<Scalar>>(
186 &mut self,
187 mut cs: CS,
188 ) -> Result<AllocatedNum<Scalar>, SynthesisError> {
189 let parameter = IOPattern(vec![
190 SpongeOp::Absorb(self.state.len() as u32),
191 SpongeOp::Squeeze(1u32),
192 ]);
193 let mut ns = cs.namespace(|| "ns");
194
195 let hash = {
196 let mut sponge = SpongeCircuit::new_with_constants(&self.constants.0, Simplex);
197 let acc = &mut ns;
198
199 sponge.start(parameter, None, acc);
200 SpongeAPI::absorb(
201 &mut sponge,
202 self.state.len() as u32,
203 &(0..self.state.len())
204 .map(|i| Elt::Allocated(self.state[i].clone()))
205 .collect::<Vec<Elt<Scalar>>>(),
206 acc,
207 );
208
209 let output = SpongeAPI::squeeze(&mut sponge, 1, acc);
210 sponge.finish(acc).unwrap();
211 output
212 };
213
214 let hash = Elt::ensure_allocated(&hash[0], &mut ns.namespace(|| "ensure allocated"))?;
215
216 self.state = vec![hash.clone()];
218
219 Ok(hash)
220 }
221}
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226 use crate::{
227 constants::NUM_CHALLENGE_BITS,
228 frontend::solver::SatisfyingAssignment,
229 gadgets::utils::le_bits_to_num,
230 provider::{
231 Bn256EngineKZG, GrumpkinEngine, PallasEngine, Secp256k1Engine, Secq256k1Engine, VestaEngine,
232 },
233 traits::Engine,
234 };
235 use ff::Field;
236 use rand::rngs::OsRng;
237
238 fn test_poseidon_ro_with<E: Engine>() {
239 let mut csprng: OsRng = OsRng;
241 let constants = PoseidonConstantsCircuit::<E::Scalar>::default();
242 let num_absorbs = 32;
243 let mut ro: PoseidonRO<E::Scalar> = PoseidonRO::new(constants.clone());
244 let mut ro_gadget: PoseidonROCircuit<E::Scalar> = PoseidonROCircuit::new(constants);
245 let mut cs = SatisfyingAssignment::<E>::new();
246 for i in 0..num_absorbs {
247 let num = E::Scalar::random(&mut csprng);
248 ro.absorb(num);
249 let num_gadget = AllocatedNum::alloc_infallible(cs.namespace(|| format!("data {i}")), || num);
250 num_gadget
251 .inputize(&mut cs.namespace(|| format!("input {i}")))
252 .unwrap();
253 ro_gadget.absorb(&num_gadget);
254 }
255 let num = ro.squeeze(NUM_CHALLENGE_BITS, false);
256 let num2_bits = ro_gadget
257 .squeeze(&mut cs, NUM_CHALLENGE_BITS, false)
258 .unwrap();
259 let num2 = le_bits_to_num(&mut cs, &num2_bits).unwrap();
260 assert_eq!(num, num2.get_value().unwrap());
261 }
262
263 #[test]
264 fn test_poseidon_ro() {
265 test_poseidon_ro_with::<PallasEngine>();
266 test_poseidon_ro_with::<VestaEngine>();
267 test_poseidon_ro_with::<Bn256EngineKZG>();
268 test_poseidon_ro_with::<GrumpkinEngine>();
269 test_poseidon_ro_with::<Secp256k1Engine>();
270 test_poseidon_ro_with::<Secq256k1Engine>();
271 }
272}