1extern crate alloc;
2use crate::{
3 constants::{PlonkSpongeConstantsKimchi, SpongeConstants},
4 poseidon::{ArithmeticSponge, ArithmeticSpongeParams, Sponge},
5};
6use alloc::{vec, vec::Vec};
7use ark_ec::models::short_weierstrass::{Affine, SWCurveConfig};
8use ark_ff::{BigInteger, Field, One, PrimeField, Zero};
9
10pub trait FqSponge<Fq: Field, G, Fr, const FULL_ROUNDS: usize> {
14 fn new(p: &'static ArithmeticSpongeParams<Fq, FULL_ROUNDS>) -> Self;
16
17 fn absorb_fq(&mut self, x: &[Fq]);
20
21 fn absorb_g(&mut self, g: &[G]);
24
25 fn absorb_fr(&mut self, x: &[Fr]);
28
29 fn challenge_fq(&mut self) -> Fq;
32
33 fn challenge(&mut self) -> Fr;
37
38 fn digest_fq(self) -> Fq;
40
41 fn digest(self) -> Fr;
43}
44
45pub const CHALLENGE_LENGTH_IN_LIMBS: usize = 2;
46
47const HIGH_ENTROPY_LIMBS: usize = 2;
48
49#[derive(Clone, Debug)]
52pub struct ScalarChallenge<F>(pub F);
53
54pub fn endo_coefficient<F: PrimeField>() -> F {
55 let p_minus_1_over_3 = (F::zero() - F::one()) / F::from(3u64);
56
57 F::GENERATOR.pow(p_minus_1_over_3.into_bigint().as_ref())
58}
59
60fn get_bit(limbs_lsb: &[u64], i: u64) -> u64 {
61 let limb = i / 64;
62 let j = i % 64;
63 (limbs_lsb[limb as usize] >> j) & 1
64}
65
66impl<F: PrimeField> ScalarChallenge<F> {
67 pub fn to_field_with_length(&self, length_in_bits: usize, endo_coeff: &F) -> F {
68 let rep = self.0.into_bigint();
69 let r = rep.as_ref();
70
71 let mut a: F = 2_u64.into();
72 let mut b: F = 2_u64.into();
73
74 let one = F::one();
75 let neg_one = -one;
76
77 for i in (0..(length_in_bits as u64 / 2)).rev() {
78 a.double_in_place();
79 b.double_in_place();
80
81 let r_2i = get_bit(r, 2 * i);
82 let s = if r_2i == 0 { &neg_one } else { &one };
83
84 if get_bit(r, 2 * i + 1) == 0 {
85 b += s;
86 } else {
87 a += s;
88 }
89 }
90
91 a * endo_coeff + b
92 }
93
94 pub fn to_field(&self, endo_coeff: &F) -> F {
95 let length_in_bits = 64 * CHALLENGE_LENGTH_IN_LIMBS;
96 self.to_field_with_length(length_in_bits, endo_coeff)
97 }
98}
99
100#[derive(Clone)]
101pub struct DefaultFqSponge<P: SWCurveConfig, SC: SpongeConstants, const FULL_ROUNDS: usize> {
102 pub sponge: ArithmeticSponge<P::BaseField, SC, FULL_ROUNDS>,
103 pub last_squeezed: Vec<u64>,
104}
105
106pub struct DefaultFrSponge<Fr: Field, SC: SpongeConstants, const FULL_ROUNDS: usize> {
107 pub sponge: ArithmeticSponge<Fr, SC, FULL_ROUNDS>,
108 pub last_squeezed: Vec<u64>,
109}
110
111impl<const FULL_ROUNDS: usize, Fr> From<&'static ArithmeticSpongeParams<Fr, FULL_ROUNDS>>
112 for DefaultFrSponge<Fr, PlonkSpongeConstantsKimchi, FULL_ROUNDS>
113where
114 Fr: PrimeField,
115{
116 fn from(p: &'static ArithmeticSpongeParams<Fr, FULL_ROUNDS>) -> Self {
117 DefaultFrSponge {
118 sponge: ArithmeticSponge::new(p),
119 last_squeezed: vec![],
120 }
121 }
122}
123
124fn pack<B: BigInteger>(limbs_lsb: &[u64]) -> B {
125 let mut res: B = 0u64.into();
126 for &x in limbs_lsb.iter().rev() {
127 res <<= 64;
128 res.add_with_carry(&x.into());
129 }
130 res
131}
132
133impl<Fr: PrimeField, SC: SpongeConstants, const FULL_ROUNDS: usize>
134 DefaultFrSponge<Fr, SC, FULL_ROUNDS>
135{
136 pub fn squeeze(&mut self, num_limbs: usize) -> Fr {
137 if self.last_squeezed.len() >= num_limbs {
138 let last_squeezed = self.last_squeezed.clone();
139 let (limbs, remaining) = last_squeezed.split_at(num_limbs);
140 self.last_squeezed = remaining.to_vec();
141 Fr::from(pack::<Fr::BigInt>(limbs))
142 } else {
143 let x = self.sponge.squeeze().into_bigint();
144 self.last_squeezed
145 .extend(&x.as_ref()[0..HIGH_ENTROPY_LIMBS]);
146 self.squeeze(num_limbs)
147 }
148 }
149}
150
151impl<P: SWCurveConfig, SC: SpongeConstants, const FULL_ROUNDS: usize>
152 DefaultFqSponge<P, SC, FULL_ROUNDS>
153where
154 P::BaseField: PrimeField,
155 <P::BaseField as PrimeField>::BigInt: Into<<P::ScalarField as PrimeField>::BigInt>,
156{
157 pub fn squeeze_limbs(&mut self, num_limbs: usize) -> Vec<u64> {
158 if self.last_squeezed.len() >= num_limbs {
159 let last_squeezed = self.last_squeezed.clone();
160 let (limbs, remaining) = last_squeezed.split_at(num_limbs);
161 self.last_squeezed = remaining.to_vec();
162 limbs.to_vec()
163 } else {
164 let x = self.sponge.squeeze().into_bigint();
165 self.last_squeezed
166 .extend(&x.as_ref()[0..HIGH_ENTROPY_LIMBS]);
167 self.squeeze_limbs(num_limbs)
168 }
169 }
170
171 pub fn squeeze_field(&mut self) -> P::BaseField {
172 self.last_squeezed = vec![];
173 self.sponge.squeeze()
174 }
175
176 pub fn squeeze(&mut self, num_limbs: usize) -> P::ScalarField {
177 P::ScalarField::from_bigint(pack(&self.squeeze_limbs(num_limbs)))
178 .expect("internal representation was not a valid field element")
179 }
180}
181
182impl<P: SWCurveConfig, SC: SpongeConstants, const FULL_ROUNDS: usize>
183 FqSponge<P::BaseField, Affine<P>, P::ScalarField, FULL_ROUNDS>
184 for DefaultFqSponge<P, SC, FULL_ROUNDS>
185where
186 P::BaseField: PrimeField,
187 <P::BaseField as PrimeField>::BigInt: Into<<P::ScalarField as PrimeField>::BigInt>,
188{
189 fn new(params: &'static ArithmeticSpongeParams<P::BaseField, FULL_ROUNDS>) -> Self {
190 let sponge = ArithmeticSponge::new(params);
191 DefaultFqSponge {
192 sponge,
193 last_squeezed: vec![],
194 }
195 }
196
197 fn absorb_g(&mut self, g: &[Affine<P>]) {
198 self.last_squeezed = vec![];
199 for g in g.iter() {
200 if g.infinity {
201 let zero = P::BaseField::zero();
203 self.sponge.absorb(&[zero]);
204 self.sponge.absorb(&[zero]);
205 } else {
206 self.sponge.absorb(&[g.x]);
207 self.sponge.absorb(&[g.y]);
208 }
209 }
210 }
211
212 fn absorb_fq(&mut self, x: &[P::BaseField]) {
213 self.last_squeezed = vec![];
214
215 for fe in x {
216 self.sponge.absorb(&[*fe])
217 }
218 }
219
220 fn absorb_fr(&mut self, x: &[P::ScalarField]) {
221 self.last_squeezed = vec![];
222
223 x.iter().for_each(|x| {
224 let bits = x.into_bigint().to_bits_le();
225
226 if <P::ScalarField as PrimeField>::MODULUS
228 < <P::BaseField as PrimeField>::MODULUS.into()
229 {
230 let fe = P::BaseField::from_bigint(
231 <P::BaseField as PrimeField>::BigInt::from_bits_le(&bits),
232 )
233 .expect("padding code has a bug");
234 self.sponge.absorb(&[fe]);
235 } else {
236 let low_bit = if bits[0] {
237 P::BaseField::one()
238 } else {
239 P::BaseField::zero()
240 };
241
242 let high_bits = P::BaseField::from_bigint(
243 <P::BaseField as PrimeField>::BigInt::from_bits_le(&bits[1..bits.len()]),
244 )
245 .expect("padding code has a bug");
246
247 self.sponge.absorb(&[high_bits]);
248 self.sponge.absorb(&[low_bit]);
249 }
250 });
251 }
252
253 fn digest(mut self) -> P::ScalarField {
254 let x: <P::BaseField as PrimeField>::BigInt = self.squeeze_field().into_bigint();
255 P::ScalarField::from_bigint(x.into()).unwrap_or_else(P::ScalarField::zero)
262 }
263
264 fn digest_fq(mut self) -> P::BaseField {
265 self.squeeze_field()
266 }
267
268 fn challenge(&mut self) -> P::ScalarField {
269 self.squeeze(CHALLENGE_LENGTH_IN_LIMBS)
270 }
271
272 fn challenge_fq(&mut self) -> P::BaseField {
273 self.squeeze_field()
274 }
275}
276
277#[cfg(feature = "ocaml_types")]
282#[allow(non_local_definitions)]
283pub mod caml {
284 use super::*;
285
286 extern crate alloc;
287 use alloc::{
288 format,
289 string::{String, ToString},
290 };
291
292 #[derive(Debug, Clone, ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)]
297 pub struct CamlScalarChallenge<CamlF>(pub CamlF);
298
299 impl<F, CamlF> From<ScalarChallenge<F>> for CamlScalarChallenge<CamlF>
300 where
301 CamlF: From<F>,
302 {
303 fn from(sc: ScalarChallenge<F>) -> Self {
304 Self(sc.0.into())
305 }
306 }
307
308 impl<F, CamlF> From<CamlScalarChallenge<CamlF>> for ScalarChallenge<F>
309 where
310 CamlF: Into<F>,
311 {
312 fn from(caml_sc: CamlScalarChallenge<CamlF>) -> Self {
313 Self(caml_sc.0.into())
314 }
315 }
316}