1use ark_ec::{short_weierstrass::Projective, AffineRepr, CurveGroup};
2use ark_ff::{BigInteger256, FftField, Field, PrimeField};
3use kimchi::curve::KimchiCurve;
4use mina_curves::pasta::{
5 fields::fft::FpParameters as _, Fp, Fq, PallasParameters, ProjectivePallas, ProjectiveVesta,
6 VestaParameters,
7};
8use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge};
9
10use poseidon::SpongeParamsForField;
11
12use crate::proofs;
13
14use super::{
15 public_input::plonk_checks::{self, ShiftedValue},
16 to_field_elements::ToFieldElements,
17 transaction::Check,
18 witness::Witness,
19 BACKEND_TICK_ROUNDS_N, BACKEND_TOCK_ROUNDS_N,
20};
21
22pub type GroupAffine<F> = ark_ec::short_weierstrass::Affine<<F as FieldWitness>::Parameters>;
23
24pub trait FieldWitness
26where
27 Self: Field
28 + Send
29 + Sync
30 + Into<BigInteger256>
31 + From<BigInteger256>
32 + Into<mina_p2p_messages::bigint::BigInt>
33 + From<i64>
34 + From<i32>
35 + ToFieldElements<Self>
36 + Check<Self>
37 + FromFpFq
38 + PrimeField
39 + FftField
40 + SpongeParamsForField<Self>
41 + std::fmt::Debug
42 + 'static,
43{
44 type Scalar: FieldWitness<Scalar = Self>;
45 type Affine: AffineRepr<
46 Group = Self::Projective,
47 BaseField = Self,
48 ScalarField = <Self as proofs::field::FieldWitness>::Scalar,
49 > + Into<GroupAffine<Self>>
50 + KimchiCurve
51 + std::fmt::Debug;
52 type Projective: CurveGroup<
53 Affine = Self::Affine,
54 BaseField = Self,
55 ScalarField = <Self as proofs::field::FieldWitness>::Scalar,
56 > + From<Projective<Self::Parameters>>
57 + std::fmt::Debug;
58 type Parameters: ark_ec::short_weierstrass::SWCurveConfig<
59 BaseField = Self,
60 ScalarField = <Self as proofs::field::FieldWitness>::Scalar,
61 > + Clone
62 + std::fmt::Debug;
63 type Shifting: plonk_checks::ShiftingValue<Self> + Clone + std::fmt::Debug;
64 type OtherCurve: KimchiCurve<
65 ScalarField = Self,
66 BaseField = <Self as proofs::field::FieldWitness>::Scalar,
67 >;
68 type FqSponge: Clone
69 + mina_poseidon::FqSponge<
70 <Self as proofs::field::FieldWitness>::Scalar,
71 Self::OtherCurve,
72 Self,
73 >;
74
75 const PARAMS: Params<Self>;
76 const SIZE: BigInteger256;
77 const NROUNDS: usize;
78 const SRS_DEPTH: usize;
79}
80
81pub struct Params<F> {
82 pub a: F,
83 pub b: F,
84}
85
86impl FieldWitness for Fp {
87 type Scalar = Fq;
88 type Parameters = PallasParameters;
89 type Affine = GroupAffine<Self>;
90 type Projective = ProjectivePallas;
91 type Shifting = ShiftedValue<Fp>;
92 type OtherCurve = GroupAffine<Fq>;
93 type FqSponge = DefaultFqSponge<VestaParameters, PlonkSpongeConstantsKimchi>;
94
95 const PARAMS: Params<Self> = Params::<Self> {
97 a: ark_ff::MontFp!("0"),
98 b: ark_ff::MontFp!("5"),
99 };
100 const SIZE: BigInteger256 = mina_curves::pasta::fields::FpParameters::MODULUS;
101 const NROUNDS: usize = BACKEND_TICK_ROUNDS_N;
102 const SRS_DEPTH: usize = 32768;
103}
104
105impl FieldWitness for Fq {
106 type Scalar = Fp;
107 type Parameters = VestaParameters;
108 type Affine = GroupAffine<Self>;
109 type Projective = ProjectiveVesta;
110 type Shifting = ShiftedValue<Fq>;
111 type OtherCurve = GroupAffine<Fp>;
112 type FqSponge = DefaultFqSponge<PallasParameters, PlonkSpongeConstantsKimchi>;
113
114 const PARAMS: Params<Self> = Params::<Self> {
116 a: ark_ff::MontFp!("0"),
117 b: ark_ff::MontFp!("5"),
118 };
119 const SIZE: BigInteger256 = mina_curves::pasta::fields::FqParameters::MODULUS;
120 const NROUNDS: usize = BACKEND_TOCK_ROUNDS_N;
121 const SRS_DEPTH: usize = 65536;
122}
123
124pub trait FromFpFq {
126 fn from_fp(fp: Fp) -> Self;
127 fn from_fq(fp: Fq) -> Self;
128}
129
130impl FromFpFq for Fp {
131 fn from_fp(fp: Fp) -> Self {
132 fp
133 }
134 fn from_fq(_fq: Fq) -> Self {
135 panic!("Attempt to convert a `Fq` into `Fp`")
139 }
140}
141
142impl FromFpFq for Fq {
143 fn from_fp(fp: Fp) -> Self {
144 let bigint: BigInteger256 = fp.into();
146 Self::from(bigint)
147 }
148 fn from_fq(fq: Fq) -> Self {
149 fq
150 }
151}
152
153pub trait IntoGeneric<F: FieldWitness> {
155 fn into_gen(self) -> F;
156}
157
158impl<F: FieldWitness> IntoGeneric<F> for Fp {
159 fn into_gen(self) -> F {
160 F::from_fp(self)
161 }
162}
163
164impl<F: FieldWitness> IntoGeneric<F> for Fq {
165 fn into_gen(self) -> F {
166 F::from_fq(self)
167 }
168}
169
170#[allow(clippy::module_inception)]
171pub mod field {
172 use crate::proofs::transaction::field_to_bits2;
173
174 use super::*;
175
176 pub fn square<F>(field: F, w: &mut Witness<F>) -> F
178 where
179 F: FieldWitness,
180 {
181 w.exists(field.square())
182 }
184
185 pub fn mul<F>(x: F, y: F, w: &mut Witness<F>) -> F
186 where
187 F: FieldWitness,
188 {
189 w.exists(x * y)
190 }
191
192 pub fn const_mul<F>(x: F, y: F) -> F
193 where
194 F: FieldWitness,
195 {
196 x * y
197 }
198
199 pub fn muls<F>(xs: &[F], w: &mut Witness<F>) -> F
200 where
201 F: FieldWitness,
202 {
203 xs.iter()
204 .copied()
205 .reduce(|acc, v| w.exists(acc * v))
206 .expect("invalid param")
207 }
208
209 pub fn div<F>(x: F, y: F, w: &mut Witness<F>) -> F
210 where
211 F: FieldWitness,
212 {
213 w.exists(x / y)
214 }
215
216 pub fn div_by_inv<F>(x: F, y: F, w: &mut Witness<F>) -> F
218 where
219 F: FieldWitness,
220 {
221 let y_inv = w.exists(y.inverse().unwrap_or_else(F::zero));
222 mul(x, y_inv, w)
223 }
224
225 pub fn sub<F>(x: F, y: F, w: &mut Witness<F>) -> F
226 where
227 F: FieldWitness,
228 {
229 w.exists(x - y)
230 }
231
232 pub fn add<F>(x: F, y: F, w: &mut Witness<F>) -> F
233 where
234 F: FieldWitness,
235 {
236 w.exists(x + y)
237 }
238
239 pub fn const_add<F>(x: F, y: F) -> F
240 where
241 F: FieldWitness,
242 {
243 x + y
244 }
245
246 pub fn equal<F: FieldWitness>(x: F, y: F, w: &mut Witness<F>) -> Boolean {
247 let z = x - y;
248
249 let (boolean, r, inv) = if x == y {
250 (Boolean::True, F::one(), F::zero())
251 } else {
252 (Boolean::False, F::zero(), z.inverse().unwrap())
253 };
254 w.exists([r, inv]);
255
256 boolean
257 }
258
259 pub fn compare<F: FieldWitness>(
260 bit_length: u64,
261 a: F,
262 b: F,
263 w: &mut Witness<F>,
264 ) -> (Boolean, Boolean) {
265 let two_to_the = |n: usize| (0..n).fold(F::one(), |acc, _| acc.double());
266
267 let bit_length = bit_length as usize;
268 let alpha_packed = { two_to_the(bit_length) + b - a };
269 let alpha = w.exists(field_to_bits2(alpha_packed, bit_length + 1));
270 let (less_or_equal, prefix) = alpha.split_last().unwrap();
271
272 let less_or_equal = less_or_equal.to_boolean();
273 let prefix = prefix.iter().map(|b| b.to_boolean()).collect::<Vec<_>>();
274
275 let not_all_zeros = Boolean::any(&prefix, w);
276 let less = less_or_equal.and(¬_all_zeros, w);
277
278 (less, less_or_equal)
279 }
280
281 pub fn assert_lt<F: FieldWitness>(bit_length: u64, x: F, y: F, w: &mut Witness<F>) {
282 compare(bit_length, x, y, w);
283 }
284}
285
286pub trait ToBoolean {
287 fn to_boolean(&self) -> Boolean;
288}
289
290impl ToBoolean for bool {
291 fn to_boolean(&self) -> Boolean {
292 if *self {
293 Boolean::True
294 } else {
295 Boolean::False
296 }
297 }
298}
299
300#[derive(Clone, Copy, Debug, PartialEq, Eq)]
301pub enum Boolean {
302 True = 1,
303 False = 0,
304}
305
306impl Boolean {
307 pub fn of_field<F: FieldWitness>(field: F) -> Self {
308 if field.is_zero() {
309 Self::False
310 } else {
311 Self::True
312 }
313 }
314
315 pub fn as_bool(&self) -> bool {
316 match self {
317 Boolean::True => true,
318 Boolean::False => false,
319 }
320 }
321
322 pub fn neg(&self) -> Self {
323 match self {
324 Boolean::False => Boolean::True,
325 Boolean::True => Boolean::False,
326 }
327 }
328
329 pub fn to_field<F: FieldWitness>(self) -> F {
330 F::from(self.as_bool())
331 }
332
333 fn mul<F: FieldWitness>(&self, other: &Self, w: &mut Witness<F>) -> Self {
334 let result: F = self.to_field::<F>() * other.to_field::<F>();
335 w.exists(result);
336 if result.is_zero() {
337 Self::False
338 } else {
339 assert_eq!(result, F::one());
340 Self::True
341 }
342 }
343
344 pub fn and<F: FieldWitness>(&self, other: &Self, w: &mut Witness<F>) -> Self {
345 self.mul(other, w)
346 }
347
348 pub fn const_and(&self, other: &Self) -> Self {
350 (self.as_bool() && other.as_bool()).to_boolean()
351 }
352
353 pub fn or<F: FieldWitness>(&self, other: &Self, w: &mut Witness<F>) -> Self {
354 let both_false = self.neg().and(&other.neg(), w);
355 both_false.neg()
356 }
357
358 pub fn const_or(&self, other: &Self) -> Self {
360 (self.as_bool() || other.as_bool()).to_boolean()
361 }
362
363 pub fn all<F: FieldWitness>(x: &[Self], w: &mut Witness<F>) -> Self {
364 match x {
365 [] => Self::True,
366 [b1] => *b1,
367 [b1, b2] => b1.and(b2, w),
368 bs => {
369 let len = F::from(bs.len() as u64);
370 let sum = bs.iter().fold(0u64, |acc, b| {
371 acc + match b {
372 Boolean::True => 1,
373 Boolean::False => 0,
374 }
375 });
376 field::equal(len, F::from(sum), w)
377 }
378 }
379 }
380
381 pub fn const_all<F: FieldWitness>(x: &[Self]) -> Self {
382 match x {
383 [] => Self::True,
384 [b1] => *b1,
385 [b1, b2] => b1.const_and(b2),
386 bs => {
387 let len = F::from(bs.len() as u64);
388 let sum = bs.iter().fold(0u64, |acc, b| {
389 acc + match b {
390 Boolean::True => 1,
391 Boolean::False => 0,
392 }
393 });
394 (len == F::from(sum)).to_boolean()
395 }
396 }
397 }
398
399 pub fn lxor<F: FieldWitness>(&self, other: &Self, w: &mut Witness<F>) -> Self {
401 let result = (self.as_bool() ^ other.as_bool()).to_boolean();
402 w.exists(result.to_field::<F>());
403 result
404 }
405
406 pub fn const_lxor(&self, other: &Self) -> Self {
407 (self.as_bool() ^ other.as_bool()).to_boolean()
408 }
409
410 pub fn equal<F: FieldWitness>(&self, other: &Self, w: &mut Witness<F>) -> Self {
411 self.lxor(other, w).neg()
412 }
413
414 pub fn const_equal(&self, other: &Self) -> Self {
415 (self.as_bool() == other.as_bool()).to_boolean()
416 }
417
418 pub fn const_any<F: FieldWitness>(x: &[Self]) -> Self {
419 match x {
420 [] => Self::False,
421 [b1] => *b1,
422 [b1, b2] => b1.const_or(b2),
423 bs => {
424 let sum = bs.iter().fold(0u64, |acc, b| {
425 acc + match b {
426 Boolean::True => 1,
427 Boolean::False => 0,
428 }
429 });
430 (F::from(sum) == F::zero()).to_boolean().neg()
431 }
432 }
433 }
434
435 pub fn any<F: FieldWitness>(x: &[Self], w: &mut Witness<F>) -> Self {
436 match x {
437 [] => Self::False,
438 [b1] => *b1,
439 [b1, b2] => b1.or(b2, w),
440 bs => {
441 let sum = bs.iter().fold(0u64, |acc, b| {
442 acc + match b {
443 Boolean::True => 1,
444 Boolean::False => 0,
445 }
446 });
447 field::equal(F::from(sum), F::zero(), w).neg()
448 }
449 }
450 }
451
452 pub fn assert_non_zero<F: FieldWitness>(v: F, w: &mut Witness<F>) {
454 if v.is_zero() {
455 w.exists(v);
456 } else {
457 w.exists(v.inverse().unwrap());
458 }
459 }
460
461 pub fn assert_any<F: FieldWitness>(bs: &[Self], w: &mut Witness<F>) {
462 let num_true = bs.iter().fold(0u64, |acc, b| {
463 acc + match b {
464 Boolean::True => 1,
465 Boolean::False => 0,
466 }
467 });
468 Self::assert_non_zero::<F>(F::from(num_true), w)
469 }
470
471 pub fn var(&self) -> CircuitVar<Boolean> {
472 CircuitVar::Var(*self)
473 }
474
475 pub fn constant(&self) -> CircuitVar<Boolean> {
476 CircuitVar::Constant(*self)
477 }
478}
479
480impl<F: FieldWitness> Check<F> for Boolean {
481 fn check(&self, _w: &mut Witness<F>) {
482 }
484}
485
486impl<F: FieldWitness> Check<F> for CircuitVar<Boolean> {
487 fn check(&self, _w: &mut Witness<F>) {
488 }
490}
491
492#[derive(Clone, Copy, Debug)]
499pub enum CircuitVar<F> {
500 Var(F),
501 Constant(F),
502}
503
504impl<F: FieldWitness> CircuitVar<F> {
505 pub fn as_field(&self) -> F {
506 match self {
507 CircuitVar::Var(f) => *f,
508 CircuitVar::Constant(f) => *f,
509 }
510 }
511
512 fn scale(x: CircuitVar<F>, s: F) -> CircuitVar<F> {
513 use CircuitVar::*;
514
515 if s.is_zero() {
516 Constant(F::zero())
517 } else if s.is_one() {
518 x
519 } else {
520 match x {
521 Constant(x) => Constant(x * s),
522 Var(x) => Var(x * s),
523 }
524 }
525 }
526
527 fn mul(&self, other: &Self, w: &mut Witness<F>) -> CircuitVar<F> {
528 use CircuitVar::*;
529
530 let (x, y) = (*self, *other);
531 match (x, y) {
532 (Constant(x), Constant(y)) => Constant(x * y),
533 (Constant(x), _) => Self::scale(y, x),
534 (_, Constant(y)) => Self::scale(x, y),
535 (Var(x), Var(y)) => Var(w.exists(x * y)),
536 }
537 }
538
539 fn equal(x: &Self, y: &Self, w: &mut Witness<F>) -> CircuitVar<Boolean> {
540 match (x, y) {
541 (CircuitVar::Constant(x), CircuitVar::Constant(y)) => {
542 let eq = if x == y {
543 Boolean::True
544 } else {
545 Boolean::False
546 };
547 CircuitVar::Constant(eq)
548 }
549 _ => {
550 let x = x.as_field();
551 let y = y.as_field();
552 CircuitVar::Var(field::equal(x, y, w))
553 }
554 }
555 }
556}
557
558impl<T> CircuitVar<T> {
559 pub fn is_const(&self) -> bool {
560 match self {
561 CircuitVar::Var(_) => false,
562 CircuitVar::Constant(_) => true,
563 }
564 }
565
566 pub fn value(&self) -> &T {
567 match self {
568 CircuitVar::Var(v) => v,
569 CircuitVar::Constant(v) => v,
570 }
571 }
572
573 pub fn map<Fun, V>(&self, fun: Fun) -> CircuitVar<V>
574 where
575 Fun: Fn(&T) -> V,
576 {
577 match self {
578 CircuitVar::Var(v) => CircuitVar::Var(fun(v)),
579 CircuitVar::Constant(v) => CircuitVar::Constant(fun(v)),
580 }
581 }
582}
583
584impl CircuitVar<Boolean> {
585 pub fn as_boolean(&self) -> Boolean {
586 match self {
587 CircuitVar::Var(b) => *b,
588 CircuitVar::Constant(b) => *b,
589 }
590 }
591
592 fn as_cvar<F: FieldWitness>(&self) -> CircuitVar<F> {
593 self.map(|b| b.to_field::<F>())
594 }
595
596 pub fn of_cvar<F: FieldWitness>(cvar: CircuitVar<F>) -> Self {
597 cvar.map(|b| {
598 if b.is_one() {
600 Boolean::True
601 } else {
602 Boolean::False
603 }
604 })
605 }
606
607 pub fn and<F: FieldWitness>(&self, other: &Self, w: &mut Witness<F>) -> Self {
608 self.as_cvar().mul(&other.as_cvar(), w).map(|v| {
609 if v.is_one() {
611 Boolean::True
612 } else {
613 Boolean::False
614 }
615 })
616 }
617
618 fn boolean_sum<F: FieldWitness>(x: &[Self]) -> CircuitVar<F> {
619 let sum = x.iter().fold(0u64, |acc, b| {
620 acc + match b.as_boolean() {
621 Boolean::True => 1,
622 Boolean::False => 0,
623 }
624 });
625 if x.iter().all(|x| matches!(x, CircuitVar::Constant(_))) {
626 CircuitVar::Constant(F::from(sum))
627 } else {
628 CircuitVar::Var(F::from(sum))
629 }
630 }
631
632 pub fn any<F: FieldWitness>(x: &[Self], w: &mut Witness<F>) -> CircuitVar<Boolean> {
633 match x {
634 [] => CircuitVar::Constant(Boolean::False),
635 [b1] => *b1,
636 [b1, b2] => b1.or(b2, w),
637 bs => {
638 let sum = Self::boolean_sum(bs);
639 CircuitVar::equal(&sum, &CircuitVar::Constant(F::zero()), w).map(Boolean::neg)
640 }
641 }
642 }
643
644 pub fn all<F: FieldWitness>(x: &[Self], w: &mut Witness<F>) -> CircuitVar<Boolean> {
645 match x {
646 [] => CircuitVar::Constant(Boolean::True),
647 [b1] => *b1,
648 [b1, b2] => b1.and(b2, w),
649 bs => {
650 let sum = Self::boolean_sum(bs);
651 let len = F::from(bs.len() as u64);
652 CircuitVar::equal(&CircuitVar::Constant(len), &sum, w)
653 }
654 }
655 }
656
657 pub fn neg(&self) -> Self {
658 self.map(Boolean::neg)
659 }
660
661 pub fn or<F: FieldWitness>(&self, other: &Self, w: &mut Witness<F>) -> Self {
662 let both_false = self.neg().and(&other.neg(), w);
663 both_false.neg()
664 }
665
666 pub fn lxor<F: FieldWitness>(&self, other: &Self, w: &mut Witness<F>) -> Self {
667 match (self, other) {
668 (CircuitVar::Var(a), CircuitVar::Var(b)) => CircuitVar::Var(a.lxor(b, w)),
669 (CircuitVar::Constant(a), CircuitVar::Constant(b)) => {
670 CircuitVar::Constant(a.const_lxor(b))
671 }
672 (a, b) => CircuitVar::Var(a.as_boolean().const_lxor(&b.as_boolean())),
673 }
674 }
675
676 pub fn equal_bool<F: FieldWitness>(&self, other: &Self, w: &mut Witness<F>) -> Self {
677 self.lxor(other, w).neg()
678 }
679
680 pub fn assert_any<F: FieldWitness>(bs: &[Self], w: &mut Witness<F>) {
681 let num_true = bs.iter().fold(0u64, |acc, b| {
682 acc + match b.as_boolean() {
683 Boolean::True => 1,
684 Boolean::False => 0,
685 }
686 });
687 Boolean::assert_non_zero::<F>(F::from(num_true), w)
688 }
689}