halo2_ecc/bigint/
scalar_mul_and_add_no_carry.rs
1use super::{CRTInteger, OverflowInteger};
2use halo2_base::{
3 gates::GateInstructions,
4 utils::{log2_ceil, ScalarField},
5 Context,
6 QuantumCell::Constant,
7};
8use itertools::Itertools;
9use std::cmp::max;
10
11pub fn assign<F: ScalarField>(
19 gate: &impl GateInstructions<F>,
20 ctx: &mut Context<F>,
21 a: OverflowInteger<F>,
22 b: OverflowInteger<F>,
23 c_f: F,
24 c_log2_ceil: usize,
25) -> OverflowInteger<F> {
26 let out_limbs = a
27 .limbs
28 .into_iter()
29 .zip_eq(b.limbs)
30 .map(|(a_limb, b_limb)| gate.mul_add(ctx, a_limb, Constant(c_f), b_limb))
31 .collect();
32
33 OverflowInteger::new(out_limbs, max(a.max_limb_bits + c_log2_ceil, b.max_limb_bits) + 1)
34}
35
36pub fn crt<F: ScalarField>(
38 gate: &impl GateInstructions<F>,
39 ctx: &mut Context<F>,
40 a: CRTInteger<F>,
41 b: CRTInteger<F>,
42 c: i64,
43) -> CRTInteger<F> {
44 debug_assert_eq!(a.truncation.limbs.len(), b.truncation.limbs.len());
45
46 let (c_f, c_abs) = if c >= 0 {
47 let c_abs = u64::try_from(c).unwrap();
48 (F::from(c_abs), c_abs)
49 } else {
50 let c_abs = u64::try_from(-c).unwrap();
51 (-F::from(c_abs), c_abs)
52 };
53
54 let out_trunc = assign(gate, ctx, a.truncation, b.truncation, c_f, log2_ceil(c_abs));
55 let out_native = gate.mul_add(ctx, a.native, Constant(c_f), b.native);
56 let out_val = a.value * c + b.value;
57 CRTInteger::new(out_trunc, out_native, out_val)
58}