1use crate::util::arithmetic::{CurveAffine, PrimeField};
2use std::{fmt::Debug, ops::Deref};
3
4pub trait IntegerInstructions<F: PrimeField>: Clone + Debug {
6 type Context: Debug;
8 type AssignedCell: Clone + Debug;
10 type AssignedInteger: Clone + Debug;
12
13 fn assign_integer(
15 &self,
16 ctx: &mut Self::Context,
17 integer: F, ) -> Self::AssignedInteger;
19
20 fn assign_constant(&self, ctx: &mut Self::Context, integer: F) -> Self::AssignedInteger;
22
23 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 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 fn sub(
45 &self,
46 ctx: &mut Self::Context,
47 lhs: &Self::AssignedInteger,
48 rhs: &Self::AssignedInteger,
49 ) -> Self::AssignedInteger;
50
51 fn neg(&self, ctx: &mut Self::Context, value: &Self::AssignedInteger) -> Self::AssignedInteger;
53
54 fn invert(
56 &self,
57 ctx: &mut Self::Context,
58 value: &Self::AssignedInteger,
59 ) -> Self::AssignedInteger;
60
61 fn assert_equal(
63 &self,
64 ctx: &mut Self::Context,
65 lhs: &Self::AssignedInteger,
66 rhs: &Self::AssignedInteger,
67 );
68
69 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
79pub trait EccInstructions<C: CurveAffine>: Clone + Debug {
81 type Context: Debug + Default;
83 type ScalarChip: IntegerInstructions<
85 C::Scalar,
86 Context = Self::Context,
87 AssignedCell = Self::AssignedCell,
88 AssignedInteger = Self::AssignedScalar,
89 >;
90 type AssignedCell: Clone + Debug;
92 type AssignedScalar: Clone + Debug;
94 type AssignedEcPoint: Clone + Debug;
96
97 fn scalar_chip(&self) -> &Self::ScalarChip;
99
100 fn assign_constant(&self, ctx: &mut Self::Context, ec_point: C) -> Self::AssignedEcPoint;
102
103 fn assign_point(&self, ctx: &mut Self::Context, ec_point: C) -> Self::AssignedEcPoint;
105
106 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 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 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 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 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}