snark_verifier/loader/halo2/
shim.rs

1use crate::util::arithmetic::{CurveAffine, PrimeField};
2use std::{fmt::Debug, ops::Deref};
3
4/// Instructions to handle field element operations.
5pub trait IntegerInstructions<F: PrimeField>: Clone + Debug {
6    /// Context (either enhanced `region` or some kind of builder).
7    type Context: Debug;
8    /// Assigned cell.
9    type AssignedCell: Clone + Debug;
10    /// Assigned integer.
11    type AssignedInteger: Clone + Debug;
12
13    /// Assign an integer witness.
14    fn assign_integer(
15        &self,
16        ctx: &mut Self::Context,
17        integer: F, // witness
18    ) -> Self::AssignedInteger;
19
20    /// Assign an integer constant.
21    fn assign_constant(&self, ctx: &mut Self::Context, integer: F) -> Self::AssignedInteger;
22
23    /// Sum integers with coefficients and constant.
24    fn sum_with_coeff_and_const(
25        &self,
26        ctx: &mut Self::Context,
27        values: &[(F, impl Deref<Target = Self::AssignedInteger>)],
28        constant: F,
29    ) -> Self::AssignedInteger;
30
31    /// Sum product of integers with coefficients and constant.
32    fn sum_products_with_coeff_and_const(
33        &self,
34        ctx: &mut Self::Context,
35        values: &[(
36            F,
37            impl Deref<Target = Self::AssignedInteger>,
38            impl Deref<Target = Self::AssignedInteger>,
39        )],
40        constant: F,
41    ) -> Self::AssignedInteger;
42
43    /// Returns `lhs - rhs`.
44    fn sub(
45        &self,
46        ctx: &mut Self::Context,
47        lhs: &Self::AssignedInteger,
48        rhs: &Self::AssignedInteger,
49    ) -> Self::AssignedInteger;
50
51    /// Returns `-value`.
52    fn neg(&self, ctx: &mut Self::Context, value: &Self::AssignedInteger) -> Self::AssignedInteger;
53
54    /// Returns `1/value`.
55    fn invert(
56        &self,
57        ctx: &mut Self::Context,
58        value: &Self::AssignedInteger,
59    ) -> Self::AssignedInteger;
60
61    /// Enforce `lhs` and `rhs` are equal.
62    fn assert_equal(
63        &self,
64        ctx: &mut Self::Context,
65        lhs: &Self::AssignedInteger,
66        rhs: &Self::AssignedInteger,
67    );
68
69    /// Returns `base^exponent` and constrains that `exponent` has at most `max_bits` bits.
70    fn pow_var(
71        &self,
72        ctx: &mut Self::Context,
73        base: &Self::AssignedInteger,
74        exponent: &Self::AssignedInteger,
75        max_bits: usize,
76    ) -> Self::AssignedInteger;
77}
78
79/// Instructions to handle elliptic curve point operations.
80pub trait EccInstructions<C: CurveAffine>: Clone + Debug {
81    /// Context
82    type Context: Debug + Default;
83    /// [`IntegerInstructions`] to handle scalar field operation.
84    type ScalarChip: IntegerInstructions<
85        C::Scalar,
86        Context = Self::Context,
87        AssignedCell = Self::AssignedCell,
88        AssignedInteger = Self::AssignedScalar,
89    >;
90    /// Assigned cell.
91    type AssignedCell: Clone + Debug;
92    /// Assigned scalar field element.
93    type AssignedScalar: Clone + Debug;
94    /// Assigned elliptic curve point.
95    type AssignedEcPoint: Clone + Debug;
96
97    /// Returns reference of [`EccInstructions::ScalarChip`].
98    fn scalar_chip(&self) -> &Self::ScalarChip;
99
100    /// Assign a elliptic curve point constant.
101    fn assign_constant(&self, ctx: &mut Self::Context, ec_point: C) -> Self::AssignedEcPoint;
102
103    /// Assign a elliptic curve point witness.
104    fn assign_point(&self, ctx: &mut Self::Context, ec_point: C) -> Self::AssignedEcPoint;
105
106    /// Sum elliptic curve points and constant.
107    fn sum_with_const(
108        &self,
109        ctx: &mut Self::Context,
110        values: &[impl Deref<Target = Self::AssignedEcPoint>],
111        constant: C,
112    ) -> Self::AssignedEcPoint;
113
114    /// Perform fixed base multi-scalar multiplication.
115    fn fixed_base_msm(
116        &mut self,
117        ctx: &mut Self::Context,
118        pairs: &[(impl Deref<Target = Self::AssignedScalar>, C)],
119    ) -> Self::AssignedEcPoint;
120
121    /// Perform variable base multi-scalar multiplication.
122    fn variable_base_msm(
123        &mut self,
124        ctx: &mut Self::Context,
125        pairs: &[(
126            impl Deref<Target = Self::AssignedScalar>,
127            impl Deref<Target = Self::AssignedEcPoint>,
128        )],
129    ) -> Self::AssignedEcPoint;
130
131    /// Enforce `lhs` and `rhs` are equal.
132    fn assert_equal(
133        &self,
134        ctx: &mut Self::Context,
135        lhs: &Self::AssignedEcPoint,
136        rhs: &Self::AssignedEcPoint,
137    );
138}
139
140mod halo2_lib {
141    use crate::{
142        loader::halo2::{EccInstructions, IntegerInstructions},
143        util::arithmetic::{CurveAffine, PrimeField},
144    };
145    use halo2_base::{
146        self,
147        gates::{
148            flex_gate::threads::SinglePhaseCoreManager, GateChip, GateInstructions,
149            RangeInstructions,
150        },
151        utils::{BigPrimeField, CurveAffineExt},
152        AssignedValue,
153        QuantumCell::{Constant, Existing},
154    };
155    use halo2_ecc::{
156        bigint::ProperCrtUint,
157        ecc::{BaseFieldEccChip, EcPoint},
158        fields::FieldChip,
159    };
160    use std::ops::Deref;
161
162    type AssignedInteger<C> = ProperCrtUint<<C as CurveAffine>::ScalarExt>;
163    type AssignedEcPoint<C> = EcPoint<<C as CurveAffine>::ScalarExt, AssignedInteger<C>>;
164
165    impl<F: BigPrimeField> IntegerInstructions<F> for GateChip<F> {
166        type Context = SinglePhaseCoreManager<F>;
167        type AssignedCell = AssignedValue<F>;
168        type AssignedInteger = AssignedValue<F>;
169
170        fn assign_integer(&self, ctx: &mut Self::Context, integer: F) -> Self::AssignedInteger {
171            ctx.main().load_witness(integer)
172        }
173
174        fn assign_constant(&self, ctx: &mut Self::Context, integer: F) -> Self::AssignedInteger {
175            ctx.main().load_constant(integer)
176        }
177
178        fn sum_with_coeff_and_const(
179            &self,
180            ctx: &mut Self::Context,
181            values: &[(F, impl Deref<Target = Self::AssignedInteger>)],
182            constant: F,
183        ) -> Self::AssignedInteger {
184            let mut a = Vec::with_capacity(values.len() + 1);
185            let mut b = Vec::with_capacity(values.len() + 1);
186            if constant != F::ZERO {
187                a.push(Constant(constant));
188                b.push(Constant(F::ONE));
189            }
190            a.extend(values.iter().map(|(_, a)| Existing(*a.deref())));
191            b.extend(values.iter().map(|(c, _)| Constant(*c)));
192            self.inner_product(ctx.main(), a, b)
193        }
194
195        fn sum_products_with_coeff_and_const(
196            &self,
197            ctx: &mut Self::Context,
198            values: &[(
199                F,
200                impl Deref<Target = Self::AssignedInteger>,
201                impl Deref<Target = Self::AssignedInteger>,
202            )],
203            constant: F,
204        ) -> Self::AssignedInteger {
205            match values.len() {
206                0 => ctx.main().load_constant(constant),
207                _ => self.sum_products_with_coeff_and_var(
208                    ctx.main(),
209                    values.iter().map(|(c, a, b)| (*c, Existing(*a.deref()), Existing(*b.deref()))),
210                    Constant(constant),
211                ),
212            }
213        }
214
215        fn sub(
216            &self,
217            ctx: &mut Self::Context,
218            a: &Self::AssignedInteger,
219            b: &Self::AssignedInteger,
220        ) -> Self::AssignedInteger {
221            GateInstructions::sub(self, ctx.main(), Existing(*a), Existing(*b))
222        }
223
224        fn neg(&self, ctx: &mut Self::Context, a: &Self::AssignedInteger) -> Self::AssignedInteger {
225            GateInstructions::neg(self, ctx.main(), Existing(*a))
226        }
227
228        fn invert(
229            &self,
230            ctx: &mut Self::Context,
231            a: &Self::AssignedInteger,
232        ) -> Self::AssignedInteger {
233            // make sure scalar != 0
234            let is_zero = self.is_zero(ctx.main(), *a);
235            self.assert_is_const(ctx.main(), &is_zero, &F::ZERO);
236            GateInstructions::div_unsafe(self, ctx.main(), Constant(F::ONE), Existing(*a))
237        }
238
239        fn assert_equal(
240            &self,
241            ctx: &mut Self::Context,
242            a: &Self::AssignedInteger,
243            b: &Self::AssignedInteger,
244        ) {
245            ctx.main().constrain_equal(a, b);
246        }
247
248        fn pow_var(
249            &self,
250            ctx: &mut Self::Context,
251            base: &Self::AssignedInteger,
252            exponent: &Self::AssignedInteger,
253            max_bits: usize,
254        ) -> Self::AssignedInteger {
255            GateInstructions::pow_var(self, ctx.main(), *base, *exponent, max_bits)
256        }
257    }
258
259    impl<C: CurveAffineExt> EccInstructions<C> for BaseFieldEccChip<'_, C>
260    where
261        C::ScalarExt: BigPrimeField,
262        C::Base: BigPrimeField,
263    {
264        type Context = SinglePhaseCoreManager<C::Scalar>;
265        type ScalarChip = GateChip<C::Scalar>;
266        type AssignedCell = AssignedValue<C::Scalar>;
267        type AssignedScalar = AssignedValue<C::Scalar>;
268        type AssignedEcPoint = AssignedEcPoint<C>;
269
270        fn scalar_chip(&self) -> &Self::ScalarChip {
271            self.field_chip.range().gate()
272        }
273
274        fn assign_constant(&self, ctx: &mut Self::Context, point: C) -> Self::AssignedEcPoint {
275            self.assign_constant_point(ctx.main(), point)
276        }
277
278        fn assign_point(&self, ctx: &mut Self::Context, point: C) -> Self::AssignedEcPoint {
279            self.assign_point(ctx.main(), point)
280        }
281
282        fn sum_with_const(
283            &self,
284            ctx: &mut Self::Context,
285            values: &[impl Deref<Target = Self::AssignedEcPoint>],
286            constant: C,
287        ) -> Self::AssignedEcPoint {
288            let constant = if bool::from(constant.is_identity()) {
289                None
290            } else {
291                let constant = EccInstructions::assign_constant(self, ctx, constant);
292                Some(constant)
293            };
294            self.sum::<C>(
295                ctx.main(),
296                constant.into_iter().chain(values.iter().map(|v| v.deref().clone())),
297            )
298        }
299
300        fn variable_base_msm(
301            &mut self,
302            builder: &mut Self::Context,
303            pairs: &[(
304                impl Deref<Target = Self::AssignedScalar>,
305                impl Deref<Target = Self::AssignedEcPoint>,
306            )],
307        ) -> Self::AssignedEcPoint {
308            let (scalars, points): (Vec<_>, Vec<_>) = pairs
309                .iter()
310                .map(|(scalar, point)| (vec![*scalar.deref()], point.deref().clone()))
311                .unzip();
312            BaseFieldEccChip::<C>::variable_base_msm::<C>(
313                self,
314                builder,
315                &points,
316                scalars,
317                C::Scalar::NUM_BITS as usize,
318            )
319        }
320
321        fn fixed_base_msm(
322            &mut self,
323            builder: &mut Self::Context,
324            pairs: &[(impl Deref<Target = Self::AssignedScalar>, C)],
325        ) -> Self::AssignedEcPoint {
326            let (scalars, points): (Vec<_>, Vec<_>) = pairs
327                .iter()
328                .filter_map(|(scalar, point)| {
329                    if point.is_identity().into() {
330                        None
331                    } else {
332                        Some((vec![*scalar.deref()], *point))
333                    }
334                })
335                .unzip();
336            BaseFieldEccChip::<C>::fixed_base_msm::<C>(
337                self,
338                builder,
339                &points,
340                scalars,
341                C::Scalar::NUM_BITS as usize,
342            )
343        }
344
345        fn assert_equal(
346            &self,
347            ctx: &mut Self::Context,
348            a: &Self::AssignedEcPoint,
349            b: &Self::AssignedEcPoint,
350        ) {
351            self.assert_equal(ctx.main(), a.clone(), b.clone());
352        }
353    }
354}