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