mina_tree/zkapps/
checks.rs

1use mina_curves::pasta::Fp;
2use mina_signer::CompressedPubKey;
3
4use crate::{
5    checked_equal_compressed_key,
6    proofs::{
7        field::{field, Boolean, ToBoolean},
8        numbers::common::ForZkappCheck,
9        witness::Witness,
10    },
11    scan_state::transaction_logic::zkapp_command::{ClosedInterval, OrIgnore},
12    MyCow,
13};
14
15/// Check zkapp preconditions
16pub trait ZkappCheck {
17    type T;
18
19    fn zcheck<Ops: ZkappCheckOps>(&self, x: &Self::T, w: &mut Witness<Fp>) -> Boolean;
20}
21
22impl<T> OrIgnore<T> {
23    fn make_zcheck<Ops, CompareFn, DefaultFn>(
24        &self,
25        default_fn: CompareFn,
26        compare_fun: DefaultFn,
27        w: &mut Witness<Fp>,
28    ) -> Boolean
29    where
30        Ops: ZkappCheckOps,
31        CompareFn: Fn() -> T,
32        DefaultFn: Fn(&T, &mut Witness<Fp>) -> Boolean,
33    {
34        let (is_some, value) = match self {
35            OrIgnore::Check(v) => (Boolean::True, MyCow::Borrow(v)),
36            OrIgnore::Ignore => (Boolean::False, MyCow::Own(default_fn())),
37        };
38        let is_good = compare_fun(value.as_ref(), w);
39        Ops::boolean_any([is_some.neg(), is_good], w)
40    }
41}
42
43impl<DefaultFn> ZkappCheck for (&OrIgnore<Boolean>, DefaultFn)
44where
45    DefaultFn: Fn() -> Boolean,
46{
47    type T = Boolean;
48
49    fn zcheck<Ops: ZkappCheckOps>(&self, x: &Self::T, w: &mut Witness<Fp>) -> Boolean {
50        let (this, default_fn) = self;
51        let compare = |value: &Self::T, w: &mut Witness<Fp>| Ops::is_boolean_equal(x, value, w);
52        this.make_zcheck::<Ops, _, _>(default_fn, compare, w)
53    }
54}
55
56impl<DefaultFn> ZkappCheck for (&OrIgnore<Fp>, DefaultFn)
57where
58    DefaultFn: Fn() -> Fp,
59{
60    type T = Fp;
61
62    fn zcheck<Ops: ZkappCheckOps>(&self, x: &Self::T, w: &mut Witness<Fp>) -> Boolean {
63        let (this, default_fn) = self;
64        let compare = |value: &Self::T, w: &mut Witness<Fp>| Ops::is_field_equal(x, value, w);
65        this.make_zcheck::<Ops, _, _>(default_fn, compare, w)
66    }
67}
68
69impl<DefaultFn> ZkappCheck for (&OrIgnore<CompressedPubKey>, DefaultFn)
70where
71    DefaultFn: Fn() -> CompressedPubKey,
72{
73    type T = CompressedPubKey;
74
75    fn zcheck<Ops: ZkappCheckOps>(&self, x: &Self::T, w: &mut Witness<Fp>) -> Boolean {
76        let (this, default_fn) = self;
77        let compare =
78            |value: &Self::T, w: &mut Witness<Fp>| Ops::is_compressed_key_equal(x, value, w);
79        this.make_zcheck::<Ops, _, _>(default_fn, compare, w)
80    }
81}
82
83impl<T, DefaultFn> ZkappCheck for (&OrIgnore<ClosedInterval<T>>, DefaultFn)
84where
85    DefaultFn: Fn() -> ClosedInterval<T>,
86    T: ForZkappCheck<Fp>,
87{
88    type T = T;
89
90    fn zcheck<Ops: ZkappCheckOps>(&self, x: &Self::T, w: &mut Witness<Fp>) -> Boolean {
91        let (this, default_fn) = self;
92        let compare = |value: &ClosedInterval<T>, w: &mut Witness<Fp>| {
93            Ops::compare_closed_interval(value, x, w)
94        };
95        this.make_zcheck::<Ops, _, _>(default_fn, compare, w)
96    }
97}
98
99pub trait ZkappCheckOps {
100    fn compare_closed_interval<T: ForZkappCheck<Fp>>(
101        interval: &ClosedInterval<T>,
102        value: &T,
103        w: &mut Witness<Fp>,
104    ) -> Boolean;
105    fn is_boolean_equal(a: &Boolean, b: &Boolean, w: &mut Witness<Fp>) -> Boolean;
106    fn is_field_equal(a: &Fp, b: &Fp, w: &mut Witness<Fp>) -> Boolean;
107    fn is_compressed_key_equal(
108        a: &CompressedPubKey,
109        b: &CompressedPubKey,
110        w: &mut Witness<Fp>,
111    ) -> Boolean;
112    fn boolean_all<I>(bools: I, w: &mut Witness<Fp>) -> Boolean
113    where
114        I: IntoIterator<Item = Boolean>;
115    fn boolean_any<I>(bools: I, w: &mut Witness<Fp>) -> Boolean
116    where
117        I: IntoIterator<Item = Boolean>;
118}
119
120pub struct InSnarkOps;
121pub struct NonSnarkOps;
122
123impl ZkappCheckOps for InSnarkOps {
124    fn compare_closed_interval<T: ForZkappCheck<Fp>>(
125        interval: &ClosedInterval<T>,
126        value: &T,
127        w: &mut Witness<Fp>,
128    ) -> Boolean {
129        let ClosedInterval { lower, upper } = interval;
130        let lower = lower.to_checked();
131        let upper = upper.to_checked();
132        let x = value.to_checked();
133        // We decompose this way because of OCaml evaluation order
134        let lower_than_upper = <T as ForZkappCheck<Fp>>::lte(&x, &upper, w);
135        let greater_than_lower = <T as ForZkappCheck<Fp>>::lte(&lower, &x, w);
136        Boolean::all(&[greater_than_lower, lower_than_upper], w)
137    }
138    fn is_boolean_equal(a: &Boolean, b: &Boolean, w: &mut Witness<Fp>) -> Boolean {
139        Boolean::equal(a, b, w)
140    }
141    fn is_field_equal(a: &Fp, b: &Fp, w: &mut Witness<Fp>) -> Boolean {
142        field::equal(*a, *b, w)
143    }
144    fn is_compressed_key_equal(
145        a: &CompressedPubKey,
146        b: &CompressedPubKey,
147        w: &mut Witness<Fp>,
148    ) -> Boolean {
149        checked_equal_compressed_key(a, b, w)
150    }
151    fn boolean_all<I>(bools: I, w: &mut Witness<Fp>) -> Boolean
152    where
153        I: IntoIterator<Item = Boolean>,
154    {
155        let bools = bools.into_iter().collect::<Vec<_>>();
156        Boolean::all(&bools, w)
157    }
158    fn boolean_any<I>(bools: I, w: &mut Witness<Fp>) -> Boolean
159    where
160        I: IntoIterator<Item = Boolean>,
161    {
162        let bools = bools.into_iter().collect::<Vec<_>>();
163        Boolean::any(&bools, w)
164    }
165}
166
167impl ZkappCheckOps for NonSnarkOps {
168    fn compare_closed_interval<T: ForZkappCheck<Fp>>(
169        interval: &ClosedInterval<T>,
170        value: &T,
171        _w: &mut Witness<Fp>,
172    ) -> Boolean {
173        let ClosedInterval { lower, upper } = interval;
174        (lower <= value && value <= upper).to_boolean()
175    }
176    fn is_boolean_equal(a: &Boolean, b: &Boolean, _w: &mut Witness<Fp>) -> Boolean {
177        (a == b).to_boolean()
178    }
179    fn is_field_equal(a: &Fp, b: &Fp, _w: &mut Witness<Fp>) -> Boolean {
180        (a == b).to_boolean()
181    }
182    fn is_compressed_key_equal(
183        a: &CompressedPubKey,
184        b: &CompressedPubKey,
185        _w: &mut Witness<Fp>,
186    ) -> Boolean {
187        (a == b).to_boolean()
188    }
189    fn boolean_all<I>(bools: I, _w: &mut Witness<Fp>) -> Boolean
190    where
191        I: IntoIterator<Item = Boolean>,
192    {
193        bools.into_iter().all(|b| b.as_bool()).to_boolean()
194    }
195    fn boolean_any<I>(bools: I, _w: &mut Witness<Fp>) -> Boolean
196    where
197        I: IntoIterator<Item = Boolean>,
198    {
199        bools.into_iter().any(|b| b.as_bool()).to_boolean()
200    }
201}