1use super::{column::Column, interpreter::InterpreterEnv};
2use crate::{
3 column::{Gadget, E},
4 curve::{ArrabbiataCurve, PlonkSpongeConstants},
5 interpreter::{self, Instruction, Side},
6 MAX_DEGREE, NUMBER_OF_COLUMNS,
7};
8
9use ark_ff::PrimeField;
10use kimchi::circuits::{
11 expr::{ConstantTerm::Literal, Expr, ExprInner, Operations, Variable},
12 gate::CurrOrNext,
13};
14use log::debug;
15use mina_poseidon::constants::SpongeConstants;
16use num_bigint::BigInt;
17use o1_utils::FieldHelpers;
18use std::collections::HashMap;
19
20#[derive(Clone, Debug)]
21pub struct Env<C: ArrabbiataCurve>
22where
23 C::BaseField: PrimeField,
24{
25 pub a: BigInt,
28 pub idx_var: usize,
29 pub idx_var_next_row: usize,
30 pub constraints: Vec<E<C::ScalarField>>,
31}
32
33impl<C: ArrabbiataCurve> Env<C>
34where
35 C::BaseField: PrimeField,
36{
37 pub fn new() -> Self {
38 let a: C::BaseField = C::get_curve_params().0;
40 let a: BigInt = a.to_biguint().into();
41 assert!(
42 a < C::ScalarField::modulus_biguint().into(),
43 "a is too large"
44 );
45 Self {
46 a,
47 idx_var: 0,
48 idx_var_next_row: 0,
49 constraints: Vec::new(),
50 }
51 }
52}
53
54impl<C: ArrabbiataCurve> InterpreterEnv for Env<C>
60where
61 C::BaseField: PrimeField,
62{
63 type Position = (Column, CurrOrNext);
64
65 type Variable = E<C::ScalarField>;
66
67 fn allocate(&mut self) -> Self::Position {
68 assert!(self.idx_var < NUMBER_OF_COLUMNS, "Maximum number of columns reached ({NUMBER_OF_COLUMNS}), increase the number of columns");
69 let pos = Column::X(self.idx_var);
70 self.idx_var += 1;
71 (pos, CurrOrNext::Curr)
72 }
73
74 fn allocate_next_row(&mut self) -> Self::Position {
75 assert!(self.idx_var_next_row < NUMBER_OF_COLUMNS, "Maximum number of columns reached ({NUMBER_OF_COLUMNS}), increase the number of columns");
76 let pos = Column::X(self.idx_var_next_row);
77 self.idx_var_next_row += 1;
78 (pos, CurrOrNext::Next)
79 }
80
81 fn read_position(&self, pos: Self::Position) -> Self::Variable {
82 let (col, row) = pos;
83 Expr::Atom(ExprInner::Cell(Variable { col, row }))
84 }
85
86 fn constant(&self, value: BigInt) -> Self::Variable {
87 let v = value.to_biguint().unwrap();
88 let v = C::ScalarField::from_biguint(&v).unwrap();
89 let v_inner = Operations::from(Literal(v));
90 Self::Variable::constant(v_inner)
91 }
92
93 fn write_column(&mut self, pos: Self::Position, v: Self::Variable) -> Self::Variable {
95 let (col, row) = pos;
96 let res = Expr::Atom(ExprInner::Cell(Variable { col, row }));
97 self.assert_equal(res.clone(), v);
98 res
99 }
100
101 fn add_constraint(&mut self, constraint: Self::Variable) {
102 let degree = constraint.degree(1, 0);
103 debug!("Adding constraint of degree {degree}: {:}", constraint);
104 assert!(degree <= MAX_DEGREE.try_into().unwrap(), "degree is too high: {}. The folding scheme used currently allows constraint up to degree {}", degree, MAX_DEGREE);
105 self.constraints.push(constraint);
106 }
107
108 fn constrain_boolean(&mut self, x: Self::Variable) {
109 let one = self.one();
110 let c = x.clone() * (x.clone() - one);
111 self.constraints.push(c)
112 }
113 fn assert_zero(&mut self, x: Self::Variable) {
114 self.add_constraint(x);
115 }
116
117 fn assert_equal(&mut self, x: Self::Variable, y: Self::Variable) {
118 self.add_constraint(x - y);
119 }
120
121 unsafe fn bitmask_be(
122 &mut self,
123 _x: &Self::Variable,
124 _highest_bit: u32,
125 _lowest_bit: u32,
126 pos: Self::Position,
127 ) -> Self::Variable {
128 self.read_position(pos)
129 }
130
131 fn square(&mut self, pos: Self::Position, x: Self::Variable) -> Self::Variable {
132 let v = self.read_position(pos);
133 let x = x.square();
134 self.add_constraint(x - v.clone());
135 v
136 }
137
138 fn fetch_input(&mut self, pos: Self::Position) -> Self::Variable {
141 self.read_position(pos)
142 }
143
144 fn reset(&mut self) {
145 self.idx_var = 0;
146 self.idx_var_next_row = 0;
147 self.constraints.clear();
148 }
149
150 fn coin_folding_combiner(&mut self, pos: Self::Position) -> Self::Variable {
151 self.read_position(pos)
152 }
153
154 fn load_poseidon_state(&mut self, pos: Self::Position, _i: usize) -> Self::Variable {
155 self.read_position(pos)
156 }
157
158 unsafe fn save_poseidon_state(&mut self, _x: Self::Variable, _i: usize) {}
160
161 fn get_poseidon_round_constant(&self, round: usize, i: usize) -> Self::Variable {
162 let cst = C::sponge_params().round_constants[round][i];
163 let cst_inner = Operations::from(Literal(cst));
164 Self::Variable::constant(cst_inner)
165 }
166
167 fn get_poseidon_mds_matrix(&mut self, i: usize, j: usize) -> Self::Variable {
168 let v = C::sponge_params().mds[i][j];
169 let v_inner = Operations::from(Literal(v));
170 Self::Variable::constant(v_inner)
171 }
172
173 unsafe fn fetch_value_to_absorb(&mut self, pos: Self::Position) -> Self::Variable {
174 self.read_position(pos)
175 }
176
177 unsafe fn load_temporary_accumulators(
178 &mut self,
179 pos_x: Self::Position,
180 pos_y: Self::Position,
181 _side: Side,
182 ) -> (Self::Variable, Self::Variable) {
183 let x = self.read_position(pos_x);
184 let y = self.read_position(pos_y);
185 (x, y)
186 }
187
188 unsafe fn save_temporary_accumulators(
190 &mut self,
191 _x: Self::Variable,
192 _y: Self::Variable,
193 _side: Side,
194 ) {
195 }
196
197 unsafe fn inverse(&mut self, pos: Self::Position, x: Self::Variable) -> Self::Variable {
203 let v = self.read_position(pos);
204 let res = v.clone() * x.clone();
205 self.assert_equal(res.clone(), self.one());
206 v
207 }
208
209 unsafe fn is_same_ec_point(
210 &mut self,
211 pos: Self::Position,
212 _x1: Self::Variable,
213 _y1: Self::Variable,
214 _x2: Self::Variable,
215 _y2: Self::Variable,
216 ) -> Self::Variable {
217 self.read_position(pos)
218 }
219
220 fn zero(&self) -> Self::Variable {
221 self.constant(BigInt::from(0_usize))
222 }
223
224 fn one(&self) -> Self::Variable {
225 self.constant(BigInt::from(1_usize))
226 }
227
228 fn double_ec_point(
231 &mut self,
232 pos_x: Self::Position,
233 pos_y: Self::Position,
234 x1: Self::Variable,
235 y1: Self::Variable,
236 ) -> (Self::Variable, Self::Variable) {
237 let lambda = {
238 let pos = self.allocate();
239 self.read_position(pos)
240 };
241 let x3 = self.read_position(pos_x);
242 let y3 = self.read_position(pos_y);
243
244 let x1_square = x1.clone() * x1.clone();
246 let two_x1_square = x1_square.clone() + x1_square.clone();
247 let three_x1_square = two_x1_square.clone() + x1_square.clone();
248 let two_y1 = y1.clone() + y1.clone();
249 let res = lambda.clone() * two_y1 - (three_x1_square + self.constant(self.a.clone()));
250 self.assert_zero(res);
251 self.assert_equal(
253 x3.clone(),
254 lambda.clone() * lambda.clone() - x1.clone() - x1.clone(),
255 );
256 self.assert_equal(
258 y3.clone(),
259 lambda.clone() * (x1.clone() - x3.clone()) - y1.clone(),
260 );
261 (x3, y3.clone())
262 }
263
264 fn compute_lambda(
265 &mut self,
266 pos: Self::Position,
267 is_same_point: Self::Variable,
268 x1: Self::Variable,
269 y1: Self::Variable,
270 x2: Self::Variable,
271 y2: Self::Variable,
272 ) -> Self::Variable {
273 let lambda = self.read_position(pos);
274 let lhs = lambda.clone() * (x1.clone() - x2.clone()) - (y1.clone() - y2.clone());
275 let rhs = {
276 let x1_square = x1.clone() * x1.clone();
277 let two_x1_square = x1_square.clone() + x1_square.clone();
278 let three_x1_square = two_x1_square.clone() + x1_square.clone();
279 let two_y1 = y1.clone() + y1.clone();
280 lambda.clone() * two_y1 - (three_x1_square + self.constant(self.a.clone()))
281 };
282 let res = is_same_point.clone() * lhs + (self.one() - is_same_point.clone()) * rhs;
283 self.assert_zero(res);
284 lambda
285 }
286}
287
288impl<C: ArrabbiataCurve> Env<C>
289where
290 C::BaseField: PrimeField,
291{
292 pub fn get_all_constraints_for_verifier(&self) -> Vec<E<C::ScalarField>> {
306 let mut env = self.clone();
309 env.reset();
311
312 let mut constraints = vec![];
313
314 (0..PlonkSpongeConstants::PERM_ROUNDS_FULL / 12).for_each(|i| {
316 interpreter::run_ivc(&mut env, Instruction::PoseidonFullRound(5 * i));
317 constraints.extend(env.constraints.clone());
318 env.reset();
319 });
320
321 interpreter::run_ivc(&mut env, Instruction::PoseidonSpongeAbsorb);
322 constraints.extend(env.constraints.clone());
323 env.reset();
324
325 interpreter::run_ivc(&mut env, Instruction::EllipticCurveScaling(0, 0));
329 constraints.extend(env.constraints.clone());
330 env.reset();
331
332 interpreter::run_ivc(&mut env, Instruction::EllipticCurveAddition(0));
336 constraints.extend(env.constraints.clone());
337 env.reset();
338
339 constraints
340 }
341
342 pub fn get_all_constraints(&self) -> Vec<E<C::ScalarField>> {
347 let mut constraints = self.get_all_constraints_for_verifier();
348
349 let mut env = self.clone();
352 env.reset();
354
355 interpreter::run_app(&mut env);
357 constraints.extend(env.constraints.clone());
358
359 constraints
360 }
361
362 pub fn get_all_constraints_indexed_by_gadget(&self) -> HashMap<Gadget, Vec<E<C::ScalarField>>> {
363 let mut hashmap = HashMap::new();
364 let mut env = self.clone();
365
366 (0..PlonkSpongeConstants::PERM_ROUNDS_FULL / 12).for_each(|i| {
368 interpreter::run_ivc(&mut env, Instruction::PoseidonFullRound(5 * i));
369 hashmap.insert(Gadget::PoseidonFullRound(5 * i), env.constraints.clone());
370 env.reset();
371 });
372
373 interpreter::run_ivc(&mut env, Instruction::PoseidonSpongeAbsorb);
374 hashmap.insert(Gadget::PoseidonSpongeAbsorb, env.constraints.clone());
375 env.reset();
376
377 interpreter::run_ivc(&mut env, Instruction::EllipticCurveScaling(0, 0));
381 hashmap.insert(Gadget::EllipticCurveScaling, env.constraints.clone());
382 env.reset();
383
384 interpreter::run_ivc(&mut env, Instruction::EllipticCurveAddition(0));
388 hashmap.insert(Gadget::EllipticCurveAddition, env.constraints.clone());
389 env.reset();
390
391 interpreter::run_app(&mut env);
392 hashmap.insert(Gadget::App, env.constraints.clone());
393 env.reset();
394
395 hashmap
396 }
397}
398
399impl<C: ArrabbiataCurve> Default for Env<C>
400where
401 C::BaseField: PrimeField,
402{
403 fn default() -> Self {
404 Self::new()
405 }
406}