mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-03 22:33:06 +00:00
Represent input columns as ranges rather than arrays (#776)
* Use std::ops::Range of columns rather than arrays of column indices. * Refactor reading from the local values table. * The inevitable post-push fmt/clippy commit.
This commit is contained in:
parent
0d0067554e
commit
68a5428500
@ -6,6 +6,7 @@ use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::ext_target::ExtensionTarget;
|
||||
|
||||
use crate::arithmetic::columns::*;
|
||||
use crate::arithmetic::utils::read_value_u64_limbs;
|
||||
use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer};
|
||||
use crate::range_check_error;
|
||||
|
||||
@ -94,15 +95,12 @@ where
|
||||
}
|
||||
|
||||
pub fn generate<F: RichField>(lv: &mut [F; NUM_ARITH_COLUMNS]) {
|
||||
let input0_limbs = ADD_INPUT_0.map(|c| lv[c].to_canonical_u64());
|
||||
let input1_limbs = ADD_INPUT_1.map(|c| lv[c].to_canonical_u64());
|
||||
let input0 = read_value_u64_limbs(lv, ADD_INPUT_0);
|
||||
let input1 = read_value_u64_limbs(lv, ADD_INPUT_1);
|
||||
|
||||
// Input and output have 16-bit limbs
|
||||
let (output_limbs, _) = u256_add_cc(input0_limbs, input1_limbs);
|
||||
|
||||
for (&c, output_limb) in ADD_OUTPUT.iter().zip(output_limbs) {
|
||||
lv[c] = F::from_canonical_u64(output_limb);
|
||||
}
|
||||
let (output_limbs, _) = u256_add_cc(input0, input1);
|
||||
lv[ADD_OUTPUT].copy_from_slice(&output_limbs.map(|c| F::from_canonical_u64(c)));
|
||||
}
|
||||
|
||||
pub fn eval_packed_generic<P: PackedField>(
|
||||
@ -114,15 +112,20 @@ pub fn eval_packed_generic<P: PackedField>(
|
||||
range_check_error!(ADD_OUTPUT, 16);
|
||||
|
||||
let is_add = lv[IS_ADD];
|
||||
let input0_limbs = ADD_INPUT_0.iter().map(|&c| lv[c]);
|
||||
let input1_limbs = ADD_INPUT_1.iter().map(|&c| lv[c]);
|
||||
let output_limbs = ADD_OUTPUT.iter().map(|&c| lv[c]);
|
||||
let input0_limbs = &lv[ADD_INPUT_0];
|
||||
let input1_limbs = &lv[ADD_INPUT_1];
|
||||
let output_limbs = &lv[ADD_OUTPUT];
|
||||
|
||||
// This computed output is not yet reduced; i.e. some limbs may be
|
||||
// more than 16 bits.
|
||||
let output_computed = input0_limbs.zip(input1_limbs).map(|(a, b)| a + b);
|
||||
let output_computed = input0_limbs.iter().zip(input1_limbs).map(|(&a, &b)| a + b);
|
||||
|
||||
eval_packed_generic_are_equal(yield_constr, is_add, output_computed, output_limbs);
|
||||
eval_packed_generic_are_equal(
|
||||
yield_constr,
|
||||
is_add,
|
||||
output_computed,
|
||||
output_limbs.iter().copied(),
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_collect)]
|
||||
@ -132,17 +135,18 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
yield_constr: &mut RecursiveConstraintConsumer<F, D>,
|
||||
) {
|
||||
let is_add = lv[IS_ADD];
|
||||
let input0_limbs = ADD_INPUT_0.iter().map(|&c| lv[c]);
|
||||
let input1_limbs = ADD_INPUT_1.iter().map(|&c| lv[c]);
|
||||
let output_limbs = ADD_OUTPUT.iter().map(|&c| lv[c]);
|
||||
let input0_limbs = &lv[ADD_INPUT_0];
|
||||
let input1_limbs = &lv[ADD_INPUT_1];
|
||||
let output_limbs = &lv[ADD_OUTPUT];
|
||||
|
||||
// Since `map` is lazy and the closure passed to it borrows
|
||||
// `builder`, we can't then borrow builder again below in the call
|
||||
// to `eval_ext_circuit_are_equal`. The solution is to force
|
||||
// evaluation with `collect`.
|
||||
let output_computed = input0_limbs
|
||||
.iter()
|
||||
.zip(input1_limbs)
|
||||
.map(|(a, b)| builder.add_extension(a, b))
|
||||
.map(|(&a, &b)| builder.add_extension(a, b))
|
||||
.collect::<Vec<ExtensionTarget<D>>>();
|
||||
|
||||
eval_ext_circuit_are_equal(
|
||||
@ -150,7 +154,7 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
yield_constr,
|
||||
is_add,
|
||||
output_computed.into_iter(),
|
||||
output_limbs,
|
||||
output_limbs.iter().copied(),
|
||||
);
|
||||
}
|
||||
|
||||
@ -203,7 +207,7 @@ mod tests {
|
||||
|
||||
for _ in 0..N_RND_TESTS {
|
||||
// set inputs to random values
|
||||
for (&ai, bi) in ADD_INPUT_0.iter().zip(ADD_INPUT_1) {
|
||||
for (ai, bi) in ADD_INPUT_0.zip(ADD_INPUT_1) {
|
||||
lv[ai] = F::from_canonical_u16(rng.gen());
|
||||
lv[bi] = F::from_canonical_u16(rng.gen());
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
//! Arithmetic unit
|
||||
|
||||
use std::ops::Range;
|
||||
|
||||
pub const LIMB_BITS: usize = 16;
|
||||
const EVM_REGISTER_BITS: usize = 256;
|
||||
|
||||
@ -44,57 +46,42 @@ pub(crate) const ALL_OPERATIONS: [usize; 16] = [
|
||||
/// used by any arithmetic circuit, depending on which one is active
|
||||
/// this cycle. Can be increased as needed as other operations are
|
||||
/// implemented.
|
||||
const NUM_SHARED_COLS: usize = 144; // only need 64 for add, sub, and mul
|
||||
const NUM_SHARED_COLS: usize = 9 * N_LIMBS; // only need 64 for add, sub, and mul
|
||||
|
||||
const fn shared_col(i: usize) -> usize {
|
||||
assert!(i < NUM_SHARED_COLS);
|
||||
START_SHARED_COLS + i
|
||||
}
|
||||
const GENERAL_INPUT_0: Range<usize> = START_SHARED_COLS..START_SHARED_COLS + N_LIMBS;
|
||||
const GENERAL_INPUT_1: Range<usize> = GENERAL_INPUT_0.end..GENERAL_INPUT_0.end + N_LIMBS;
|
||||
const GENERAL_INPUT_2: Range<usize> = GENERAL_INPUT_1.end..GENERAL_INPUT_1.end + N_LIMBS;
|
||||
const GENERAL_INPUT_3: Range<usize> = GENERAL_INPUT_2.end..GENERAL_INPUT_2.end + N_LIMBS;
|
||||
const AUX_INPUT_0: Range<usize> = GENERAL_INPUT_3.end..GENERAL_INPUT_3.end + 2 * N_LIMBS;
|
||||
const AUX_INPUT_1: Range<usize> = AUX_INPUT_0.end..AUX_INPUT_0.end + 2 * N_LIMBS;
|
||||
const AUX_INPUT_2: Range<usize> = AUX_INPUT_1.end..AUX_INPUT_1.end + N_LIMBS;
|
||||
|
||||
const fn gen_input_cols<const N: usize>(start: usize) -> [usize; N] {
|
||||
let mut cols = [0usize; N];
|
||||
let mut i = 0;
|
||||
while i < N {
|
||||
cols[i] = shared_col(start + i);
|
||||
i += 1;
|
||||
}
|
||||
cols
|
||||
}
|
||||
pub(crate) const ADD_INPUT_0: Range<usize> = GENERAL_INPUT_0;
|
||||
pub(crate) const ADD_INPUT_1: Range<usize> = GENERAL_INPUT_1;
|
||||
pub(crate) const ADD_OUTPUT: Range<usize> = GENERAL_INPUT_2;
|
||||
|
||||
const GENERAL_INPUT_0: [usize; N_LIMBS] = gen_input_cols::<N_LIMBS>(0);
|
||||
const GENERAL_INPUT_1: [usize; N_LIMBS] = gen_input_cols::<N_LIMBS>(N_LIMBS);
|
||||
const GENERAL_INPUT_2: [usize; N_LIMBS] = gen_input_cols::<N_LIMBS>(2 * N_LIMBS);
|
||||
const GENERAL_INPUT_3: [usize; N_LIMBS] = gen_input_cols::<N_LIMBS>(3 * N_LIMBS);
|
||||
const AUX_INPUT_0: [usize; 2 * N_LIMBS] = gen_input_cols::<{ 2 * N_LIMBS }>(4 * N_LIMBS);
|
||||
const AUX_INPUT_1: [usize; 2 * N_LIMBS] = gen_input_cols::<{ 2 * N_LIMBS }>(6 * N_LIMBS);
|
||||
const AUX_INPUT_2: [usize; N_LIMBS] = gen_input_cols::<N_LIMBS>(8 * N_LIMBS);
|
||||
pub(crate) const SUB_INPUT_0: Range<usize> = GENERAL_INPUT_0;
|
||||
pub(crate) const SUB_INPUT_1: Range<usize> = GENERAL_INPUT_1;
|
||||
pub(crate) const SUB_OUTPUT: Range<usize> = GENERAL_INPUT_2;
|
||||
|
||||
pub(crate) const ADD_INPUT_0: [usize; N_LIMBS] = GENERAL_INPUT_0;
|
||||
pub(crate) const ADD_INPUT_1: [usize; N_LIMBS] = GENERAL_INPUT_1;
|
||||
pub(crate) const ADD_OUTPUT: [usize; N_LIMBS] = GENERAL_INPUT_2;
|
||||
pub(crate) const MUL_INPUT_0: Range<usize> = GENERAL_INPUT_0;
|
||||
pub(crate) const MUL_INPUT_1: Range<usize> = GENERAL_INPUT_1;
|
||||
pub(crate) const MUL_OUTPUT: Range<usize> = GENERAL_INPUT_2;
|
||||
pub(crate) const MUL_AUX_INPUT: Range<usize> = GENERAL_INPUT_3;
|
||||
|
||||
pub(crate) const SUB_INPUT_0: [usize; N_LIMBS] = GENERAL_INPUT_0;
|
||||
pub(crate) const SUB_INPUT_1: [usize; N_LIMBS] = GENERAL_INPUT_1;
|
||||
pub(crate) const SUB_OUTPUT: [usize; N_LIMBS] = GENERAL_INPUT_2;
|
||||
pub(crate) const CMP_INPUT_0: Range<usize> = GENERAL_INPUT_0;
|
||||
pub(crate) const CMP_INPUT_1: Range<usize> = GENERAL_INPUT_1;
|
||||
pub(crate) const CMP_OUTPUT: usize = GENERAL_INPUT_2.start;
|
||||
pub(crate) const CMP_AUX_INPUT: Range<usize> = GENERAL_INPUT_3;
|
||||
|
||||
pub(crate) const MUL_INPUT_0: [usize; N_LIMBS] = GENERAL_INPUT_0;
|
||||
pub(crate) const MUL_INPUT_1: [usize; N_LIMBS] = GENERAL_INPUT_1;
|
||||
pub(crate) const MUL_OUTPUT: [usize; N_LIMBS] = GENERAL_INPUT_2;
|
||||
pub(crate) const MUL_AUX_INPUT: [usize; N_LIMBS] = GENERAL_INPUT_3;
|
||||
|
||||
pub(crate) const CMP_INPUT_0: [usize; N_LIMBS] = GENERAL_INPUT_0;
|
||||
pub(crate) const CMP_INPUT_1: [usize; N_LIMBS] = GENERAL_INPUT_1;
|
||||
pub(crate) const CMP_OUTPUT: usize = GENERAL_INPUT_2[0];
|
||||
pub(crate) const CMP_AUX_INPUT: [usize; N_LIMBS] = GENERAL_INPUT_3;
|
||||
|
||||
pub(crate) const MODULAR_INPUT_0: [usize; N_LIMBS] = GENERAL_INPUT_0;
|
||||
pub(crate) const MODULAR_INPUT_1: [usize; N_LIMBS] = GENERAL_INPUT_1;
|
||||
pub(crate) const MODULAR_MODULUS: [usize; N_LIMBS] = GENERAL_INPUT_2;
|
||||
pub(crate) const MODULAR_OUTPUT: [usize; N_LIMBS] = GENERAL_INPUT_3;
|
||||
pub(crate) const MODULAR_QUO_INPUT: [usize; 2 * N_LIMBS] = AUX_INPUT_0;
|
||||
// NB: Last value is not used in AUX, it is used in IS_ZERO
|
||||
pub(crate) const MODULAR_AUX_INPUT: [usize; 2 * N_LIMBS] = AUX_INPUT_1;
|
||||
pub(crate) const MODULAR_MOD_IS_ZERO: usize = AUX_INPUT_1[2 * N_LIMBS - 1];
|
||||
pub(crate) const MODULAR_OUT_AUX_RED: [usize; N_LIMBS] = AUX_INPUT_2;
|
||||
pub(crate) const MODULAR_INPUT_0: Range<usize> = GENERAL_INPUT_0;
|
||||
pub(crate) const MODULAR_INPUT_1: Range<usize> = GENERAL_INPUT_1;
|
||||
pub(crate) const MODULAR_MODULUS: Range<usize> = GENERAL_INPUT_2;
|
||||
pub(crate) const MODULAR_OUTPUT: Range<usize> = GENERAL_INPUT_3;
|
||||
pub(crate) const MODULAR_QUO_INPUT: Range<usize> = AUX_INPUT_0;
|
||||
// NB: Last value is not used in AUX, it is used in MOD_IS_ZERO
|
||||
pub(crate) const MODULAR_AUX_INPUT: Range<usize> = AUX_INPUT_1;
|
||||
pub(crate) const MODULAR_MOD_IS_ZERO: usize = AUX_INPUT_1.end - 1;
|
||||
pub(crate) const MODULAR_OUT_AUX_RED: Range<usize> = AUX_INPUT_2;
|
||||
|
||||
pub const NUM_ARITH_COLUMNS: usize = START_SHARED_COLS + NUM_SHARED_COLS;
|
||||
|
||||
@ -22,12 +22,13 @@ use plonky2::iop::ext_target::ExtensionTarget;
|
||||
use crate::arithmetic::add::{eval_ext_circuit_are_equal, eval_packed_generic_are_equal};
|
||||
use crate::arithmetic::columns::*;
|
||||
use crate::arithmetic::sub::u256_sub_br;
|
||||
use crate::arithmetic::utils::read_value_u64_limbs;
|
||||
use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer};
|
||||
use crate::range_check_error;
|
||||
|
||||
pub(crate) fn generate<F: RichField>(lv: &mut [F; NUM_ARITH_COLUMNS], op: usize) {
|
||||
let input0 = CMP_INPUT_0.map(|c| lv[c].to_canonical_u64());
|
||||
let input1 = CMP_INPUT_1.map(|c| lv[c].to_canonical_u64());
|
||||
let input0 = read_value_u64_limbs(lv, CMP_INPUT_0);
|
||||
let input1 = read_value_u64_limbs(lv, CMP_INPUT_1);
|
||||
|
||||
let (diff, br) = match op {
|
||||
// input0 - input1 == diff + br*2^256
|
||||
@ -39,9 +40,7 @@ pub(crate) fn generate<F: RichField>(lv: &mut [F; NUM_ARITH_COLUMNS], op: usize)
|
||||
_ => panic!("op code not a comparison"),
|
||||
};
|
||||
|
||||
for (&c, diff_limb) in CMP_AUX_INPUT.iter().zip(diff) {
|
||||
lv[c] = F::from_canonical_u64(diff_limb);
|
||||
}
|
||||
lv[CMP_AUX_INPUT].copy_from_slice(&diff.map(|c| F::from_canonical_u64(c)));
|
||||
lv[CMP_OUTPUT] = F::from_canonical_u64(br);
|
||||
}
|
||||
|
||||
@ -56,15 +55,17 @@ fn eval_packed_generic_check_is_one_bit<P: PackedField>(
|
||||
pub(crate) fn eval_packed_generic_lt<P: PackedField>(
|
||||
yield_constr: &mut ConstraintConsumer<P>,
|
||||
is_op: P,
|
||||
input0: [P; N_LIMBS],
|
||||
input1: [P; N_LIMBS],
|
||||
aux: [P; N_LIMBS],
|
||||
input0: &[P],
|
||||
input1: &[P],
|
||||
aux: &[P],
|
||||
output: P,
|
||||
) {
|
||||
debug_assert!(input0.len() == N_LIMBS && input1.len() == N_LIMBS && aux.len() == N_LIMBS);
|
||||
|
||||
// Verify (input0 < input1) == output by providing aux such that
|
||||
// input0 - input1 == aux + output*2^256.
|
||||
let lhs_limbs = input0.iter().zip(input1).map(|(&a, b)| a - b);
|
||||
let cy = eval_packed_generic_are_equal(yield_constr, is_op, aux.into_iter(), lhs_limbs);
|
||||
let lhs_limbs = input0.iter().zip(input1).map(|(&a, &b)| a - b);
|
||||
let cy = eval_packed_generic_are_equal(yield_constr, is_op, aux.iter().copied(), lhs_limbs);
|
||||
// We don't need to check that cy is 0 or 1, since output has
|
||||
// already been checked to be 0 or 1.
|
||||
yield_constr.constraint(is_op * (cy - output));
|
||||
@ -81,9 +82,9 @@ pub fn eval_packed_generic<P: PackedField>(
|
||||
let is_lt = lv[IS_LT];
|
||||
let is_gt = lv[IS_GT];
|
||||
|
||||
let input0 = CMP_INPUT_0.map(|c| lv[c]);
|
||||
let input1 = CMP_INPUT_1.map(|c| lv[c]);
|
||||
let aux = CMP_AUX_INPUT.map(|c| lv[c]);
|
||||
let input0 = &lv[CMP_INPUT_0];
|
||||
let input1 = &lv[CMP_INPUT_1];
|
||||
let aux = &lv[CMP_AUX_INPUT];
|
||||
let output = lv[CMP_OUTPUT];
|
||||
|
||||
let is_cmp = is_lt + is_gt;
|
||||
@ -109,11 +110,13 @@ pub(crate) fn eval_ext_circuit_lt<F: RichField + Extendable<D>, const D: usize>(
|
||||
builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder<F, D>,
|
||||
yield_constr: &mut RecursiveConstraintConsumer<F, D>,
|
||||
is_op: ExtensionTarget<D>,
|
||||
input0: [ExtensionTarget<D>; N_LIMBS],
|
||||
input1: [ExtensionTarget<D>; N_LIMBS],
|
||||
aux: [ExtensionTarget<D>; N_LIMBS],
|
||||
input0: &[ExtensionTarget<D>],
|
||||
input1: &[ExtensionTarget<D>],
|
||||
aux: &[ExtensionTarget<D>],
|
||||
output: ExtensionTarget<D>,
|
||||
) {
|
||||
debug_assert!(input0.len() == N_LIMBS && input1.len() == N_LIMBS && aux.len() == N_LIMBS);
|
||||
|
||||
// Since `map` is lazy and the closure passed to it borrows
|
||||
// `builder`, we can't then borrow builder again below in the call
|
||||
// to `eval_ext_circuit_are_equal`. The solution is to force
|
||||
@ -121,14 +124,14 @@ pub(crate) fn eval_ext_circuit_lt<F: RichField + Extendable<D>, const D: usize>(
|
||||
let lhs_limbs = input0
|
||||
.iter()
|
||||
.zip(input1)
|
||||
.map(|(&a, b)| builder.sub_extension(a, b))
|
||||
.map(|(&a, &b)| builder.sub_extension(a, b))
|
||||
.collect::<Vec<ExtensionTarget<D>>>();
|
||||
|
||||
let cy = eval_ext_circuit_are_equal(
|
||||
builder,
|
||||
yield_constr,
|
||||
is_op,
|
||||
aux.into_iter(),
|
||||
aux.iter().copied(),
|
||||
lhs_limbs.into_iter(),
|
||||
);
|
||||
let good_output = builder.sub_extension(cy, output);
|
||||
@ -144,9 +147,9 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
let is_lt = lv[IS_LT];
|
||||
let is_gt = lv[IS_GT];
|
||||
|
||||
let input0 = CMP_INPUT_0.map(|c| lv[c]);
|
||||
let input1 = CMP_INPUT_1.map(|c| lv[c]);
|
||||
let aux = CMP_AUX_INPUT.map(|c| lv[c]);
|
||||
let input0 = &lv[CMP_INPUT_0];
|
||||
let input1 = &lv[CMP_INPUT_1];
|
||||
let aux = &lv[CMP_AUX_INPUT];
|
||||
let output = lv[CMP_OUTPUT];
|
||||
|
||||
let is_cmp = builder.add_extension(is_lt, is_gt);
|
||||
@ -210,7 +213,7 @@ mod tests {
|
||||
lv[other_op] = F::ZERO;
|
||||
|
||||
// set inputs to random values
|
||||
for (&ai, bi) in CMP_INPUT_0.iter().zip(CMP_INPUT_1) {
|
||||
for (ai, bi) in CMP_INPUT_0.zip(CMP_INPUT_1) {
|
||||
lv[ai] = F::from_canonical_u16(rng.gen());
|
||||
lv[bi] = F::from_canonical_u16(rng.gen());
|
||||
}
|
||||
|
||||
@ -160,9 +160,9 @@ fn generate_modular_op<F: RichField>(
|
||||
) {
|
||||
// Inputs are all range-checked in [0, 2^16), so the "as i64"
|
||||
// conversion is safe.
|
||||
let input0_limbs = MODULAR_INPUT_0.map(|c| F::to_canonical_u64(&lv[c]) as i64);
|
||||
let input1_limbs = MODULAR_INPUT_1.map(|c| F::to_canonical_u64(&lv[c]) as i64);
|
||||
let mut modulus_limbs = MODULAR_MODULUS.map(|c| F::to_canonical_u64(&lv[c]) as i64);
|
||||
let input0_limbs = read_value_i64_limbs(lv, MODULAR_INPUT_0);
|
||||
let input1_limbs = read_value_i64_limbs(lv, MODULAR_INPUT_1);
|
||||
let mut modulus_limbs = read_value_i64_limbs(lv, MODULAR_MODULUS);
|
||||
|
||||
// The use of BigUints is just to avoid having to implement
|
||||
// modular reduction.
|
||||
@ -175,12 +175,11 @@ fn generate_modular_op<F: RichField>(
|
||||
let mut constr_poly = [0i64; 2 * N_LIMBS];
|
||||
constr_poly[..2 * N_LIMBS - 1].copy_from_slice(&operation(input0_limbs, input1_limbs));
|
||||
|
||||
let mut mod_is_zero = F::ZERO;
|
||||
if modulus.is_zero() {
|
||||
modulus += 1u32;
|
||||
modulus_limbs[0] += 1i64;
|
||||
lv[MODULAR_MOD_IS_ZERO] = F::ONE;
|
||||
} else {
|
||||
lv[MODULAR_MOD_IS_ZERO] = F::ZERO;
|
||||
mod_is_zero = F::ONE;
|
||||
}
|
||||
|
||||
let input = columns_to_biguint(&constr_poly);
|
||||
@ -214,19 +213,11 @@ fn generate_modular_op<F: RichField>(
|
||||
// the result of removing that root.
|
||||
let aux_limbs = pol_remove_root_2exp::<LIMB_BITS, _, { 2 * N_LIMBS }>(constr_poly);
|
||||
|
||||
for deg in 0..N_LIMBS {
|
||||
lv[MODULAR_OUTPUT[deg]] = F::from_canonical_i64(output_limbs[deg]);
|
||||
lv[MODULAR_OUT_AUX_RED[deg]] = F::from_canonical_i64(out_aux_red[deg]);
|
||||
lv[MODULAR_QUO_INPUT[deg]] = F::from_canonical_i64(quot_limbs[deg]);
|
||||
lv[MODULAR_QUO_INPUT[deg + N_LIMBS]] = F::from_canonical_i64(quot_limbs[deg + N_LIMBS]);
|
||||
lv[MODULAR_AUX_INPUT[deg]] = F::from_noncanonical_i64(aux_limbs[deg]);
|
||||
// Don't overwrite MODULAR_MOD_IS_ZERO, which is at the last
|
||||
// index of MODULAR_AUX_INPUT
|
||||
if deg < N_LIMBS - 1 {
|
||||
lv[MODULAR_AUX_INPUT[deg + N_LIMBS]] =
|
||||
F::from_noncanonical_i64(aux_limbs[deg + N_LIMBS]);
|
||||
}
|
||||
}
|
||||
lv[MODULAR_OUTPUT].copy_from_slice(&output_limbs.map(|c| F::from_canonical_i64(c)));
|
||||
lv[MODULAR_OUT_AUX_RED].copy_from_slice(&out_aux_red.map(|c| F::from_canonical_i64(c)));
|
||||
lv[MODULAR_QUO_INPUT].copy_from_slice("_limbs.map(|c| F::from_canonical_i64(c)));
|
||||
lv[MODULAR_AUX_INPUT].copy_from_slice(&aux_limbs.map(|c| F::from_noncanonical_i64(c)));
|
||||
lv[MODULAR_MOD_IS_ZERO] = mod_is_zero;
|
||||
}
|
||||
|
||||
/// Generate the output and auxiliary values for modular operations.
|
||||
@ -262,7 +253,7 @@ fn modular_constr_poly<P: PackedField>(
|
||||
range_check_error!(MODULAR_AUX_INPUT, 20, signed);
|
||||
range_check_error!(MODULAR_OUTPUT, 16);
|
||||
|
||||
let mut modulus = MODULAR_MODULUS.map(|c| lv[c]);
|
||||
let mut modulus = read_value::<N_LIMBS, _>(lv, MODULAR_MODULUS);
|
||||
let mod_is_zero = lv[MODULAR_MOD_IS_ZERO];
|
||||
|
||||
// Check that mod_is_zero is zero or one
|
||||
@ -277,22 +268,22 @@ fn modular_constr_poly<P: PackedField>(
|
||||
// modulus = 0.
|
||||
modulus[0] += mod_is_zero;
|
||||
|
||||
let output = MODULAR_OUTPUT.map(|c| lv[c]);
|
||||
let output = &lv[MODULAR_OUTPUT];
|
||||
|
||||
// Verify that the output is reduced, i.e. output < modulus.
|
||||
let out_aux_red = MODULAR_OUT_AUX_RED.map(|c| lv[c]);
|
||||
let out_aux_red = &lv[MODULAR_OUT_AUX_RED];
|
||||
let is_less_than = P::ONES;
|
||||
eval_packed_generic_lt(
|
||||
yield_constr,
|
||||
filter,
|
||||
output,
|
||||
modulus,
|
||||
&modulus,
|
||||
out_aux_red,
|
||||
is_less_than,
|
||||
);
|
||||
|
||||
// prod = q(x) * m(x)
|
||||
let quot = MODULAR_QUO_INPUT.map(|c| lv[c]);
|
||||
let quot = read_value::<{ 2 * N_LIMBS }, _>(lv, MODULAR_QUO_INPUT);
|
||||
let prod = pol_mul_wide2(quot, modulus);
|
||||
// higher order terms must be zero
|
||||
for &x in prod[2 * N_LIMBS..].iter() {
|
||||
@ -301,10 +292,10 @@ fn modular_constr_poly<P: PackedField>(
|
||||
|
||||
// constr_poly = c(x) + q(x) * m(x)
|
||||
let mut constr_poly: [_; 2 * N_LIMBS] = prod[0..2 * N_LIMBS].try_into().unwrap();
|
||||
pol_add_assign(&mut constr_poly, &output);
|
||||
pol_add_assign(&mut constr_poly, output);
|
||||
|
||||
// constr_poly = c(x) + q(x) * m(x) + (x - β) * s(x)
|
||||
let mut aux = MODULAR_AUX_INPUT.map(|c| lv[c]);
|
||||
let mut aux = read_value::<{ 2 * N_LIMBS }, _>(lv, MODULAR_AUX_INPUT);
|
||||
aux[2 * N_LIMBS - 1] = P::ZEROS; // zero out the MOD_IS_ZERO flag
|
||||
let base = P::Scalar::from_canonical_u64(1 << LIMB_BITS);
|
||||
pol_add_assign(&mut constr_poly, &pol_adjoin_root(aux, base));
|
||||
@ -324,8 +315,8 @@ pub(crate) fn eval_packed_generic<P: PackedField>(
|
||||
// constr_poly has 2*N_LIMBS limbs
|
||||
let constr_poly = modular_constr_poly(lv, yield_constr, filter);
|
||||
|
||||
let input0 = MODULAR_INPUT_0.map(|c| lv[c]);
|
||||
let input1 = MODULAR_INPUT_1.map(|c| lv[c]);
|
||||
let input0 = read_value(lv, MODULAR_INPUT_0);
|
||||
let input1 = read_value(lv, MODULAR_INPUT_1);
|
||||
|
||||
let add_input = pol_add(input0, input1);
|
||||
let mul_input = pol_mul_wide(input0, input1);
|
||||
@ -362,7 +353,7 @@ fn modular_constr_poly_ext_circuit<F: RichField + Extendable<D>, const D: usize>
|
||||
yield_constr: &mut RecursiveConstraintConsumer<F, D>,
|
||||
filter: ExtensionTarget<D>,
|
||||
) -> [ExtensionTarget<D>; 2 * N_LIMBS] {
|
||||
let mut modulus = MODULAR_MODULUS.map(|c| lv[c]);
|
||||
let mut modulus = read_value::<N_LIMBS, _>(lv, MODULAR_MODULUS);
|
||||
let mod_is_zero = lv[MODULAR_MOD_IS_ZERO];
|
||||
|
||||
let t = builder.mul_sub_extension(mod_is_zero, mod_is_zero, mod_is_zero);
|
||||
@ -376,20 +367,20 @@ fn modular_constr_poly_ext_circuit<F: RichField + Extendable<D>, const D: usize>
|
||||
|
||||
modulus[0] = builder.add_extension(modulus[0], mod_is_zero);
|
||||
|
||||
let output = MODULAR_OUTPUT.map(|c| lv[c]);
|
||||
let out_aux_red = MODULAR_OUT_AUX_RED.map(|c| lv[c]);
|
||||
let output = &lv[MODULAR_OUTPUT];
|
||||
let out_aux_red = &lv[MODULAR_OUT_AUX_RED];
|
||||
let is_less_than = builder.one_extension();
|
||||
eval_ext_circuit_lt(
|
||||
builder,
|
||||
yield_constr,
|
||||
filter,
|
||||
output,
|
||||
modulus,
|
||||
&modulus,
|
||||
out_aux_red,
|
||||
is_less_than,
|
||||
);
|
||||
|
||||
let quot = MODULAR_QUO_INPUT.map(|c| lv[c]);
|
||||
let quot = read_value::<{ 2 * N_LIMBS }, _>(lv, MODULAR_QUO_INPUT);
|
||||
let prod = pol_mul_wide2_ext_circuit(builder, quot, modulus);
|
||||
for &x in prod[2 * N_LIMBS..].iter() {
|
||||
let t = builder.mul_extension(filter, x);
|
||||
@ -397,9 +388,9 @@ fn modular_constr_poly_ext_circuit<F: RichField + Extendable<D>, const D: usize>
|
||||
}
|
||||
|
||||
let mut constr_poly: [_; 2 * N_LIMBS] = prod[0..2 * N_LIMBS].try_into().unwrap();
|
||||
pol_add_assign_ext_circuit(builder, &mut constr_poly, &output);
|
||||
pol_add_assign_ext_circuit(builder, &mut constr_poly, output);
|
||||
|
||||
let mut aux = MODULAR_AUX_INPUT.map(|c| lv[c]);
|
||||
let mut aux = read_value::<{ 2 * N_LIMBS }, _>(lv, MODULAR_AUX_INPUT);
|
||||
aux[2 * N_LIMBS - 1] = builder.zero_extension();
|
||||
let base = builder.constant_extension(F::Extension::from_canonical_u64(1u64 << LIMB_BITS));
|
||||
let t = pol_adjoin_root_ext_circuit(builder, aux, base);
|
||||
@ -421,8 +412,8 @@ pub(crate) fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
|
||||
let constr_poly = modular_constr_poly_ext_circuit(lv, builder, yield_constr, filter);
|
||||
|
||||
let input0 = MODULAR_INPUT_0.map(|c| lv[c]);
|
||||
let input1 = MODULAR_INPUT_1.map(|c| lv[c]);
|
||||
let input0 = read_value(lv, MODULAR_INPUT_0);
|
||||
let input1 = read_value(lv, MODULAR_INPUT_1);
|
||||
|
||||
let add_input = pol_add_ext_circuit(builder, input0, input1);
|
||||
let mul_input = pol_mul_wide_ext_circuit(builder, input0, input1);
|
||||
@ -498,11 +489,7 @@ mod tests {
|
||||
|
||||
for i in 0..N_RND_TESTS {
|
||||
// set inputs to random values
|
||||
for (&ai, &bi, &mi) in izip!(
|
||||
MODULAR_INPUT_0.iter(),
|
||||
MODULAR_INPUT_1.iter(),
|
||||
MODULAR_MODULUS.iter()
|
||||
) {
|
||||
for (ai, bi, mi) in izip!(MODULAR_INPUT_0, MODULAR_INPUT_1, MODULAR_MODULUS) {
|
||||
lv[ai] = F::from_canonical_u16(rng.gen());
|
||||
lv[bi] = F::from_canonical_u16(rng.gen());
|
||||
lv[mi] = F::from_canonical_u16(rng.gen());
|
||||
@ -514,7 +501,7 @@ mod tests {
|
||||
if i > N_RND_TESTS / 2 {
|
||||
// 1 <= start < N_LIMBS
|
||||
let start = (rng.gen::<usize>() % (N_LIMBS - 1)) + 1;
|
||||
for &mi in &MODULAR_MODULUS[start..N_LIMBS] {
|
||||
for mi in MODULAR_MODULUS.skip(start) {
|
||||
lv[mi] = F::ZERO;
|
||||
}
|
||||
}
|
||||
@ -552,11 +539,7 @@ mod tests {
|
||||
for _i in 0..N_RND_TESTS {
|
||||
// set inputs to random values and the modulus to zero;
|
||||
// the output is defined to be zero when modulus is zero.
|
||||
for (&ai, &bi, &mi) in izip!(
|
||||
MODULAR_INPUT_0.iter(),
|
||||
MODULAR_INPUT_1.iter(),
|
||||
MODULAR_MODULUS.iter()
|
||||
) {
|
||||
for (ai, bi, mi) in izip!(MODULAR_INPUT_0, MODULAR_INPUT_1, MODULAR_MODULUS) {
|
||||
lv[ai] = F::from_canonical_u16(rng.gen());
|
||||
lv[bi] = F::from_canonical_u16(rng.gen());
|
||||
lv[mi] = F::ZERO;
|
||||
@ -565,7 +548,7 @@ mod tests {
|
||||
generate(&mut lv, op_filter);
|
||||
|
||||
// check that the correct output was generated
|
||||
assert!(MODULAR_OUTPUT.iter().all(|&oi| lv[oi] == F::ZERO));
|
||||
assert!(lv[MODULAR_OUTPUT].iter().all(|&c| c == F::ZERO));
|
||||
|
||||
let mut constraint_consumer = ConstraintConsumer::new(
|
||||
vec![GoldilocksField(2), GoldilocksField(3), GoldilocksField(5)],
|
||||
@ -580,7 +563,7 @@ mod tests {
|
||||
.all(|&acc| acc == F::ZERO));
|
||||
|
||||
// Corrupt one output limb by setting it to a non-zero value
|
||||
let random_oi = MODULAR_OUTPUT[rng.gen::<usize>() % N_LIMBS];
|
||||
let random_oi = MODULAR_OUTPUT.start + rng.gen::<usize>() % N_LIMBS;
|
||||
lv[random_oi] = F::from_canonical_u16(rng.gen_range(1..u16::MAX));
|
||||
|
||||
eval_packed_generic(&lv, &mut constraint_consumer);
|
||||
|
||||
@ -67,8 +67,8 @@ use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer
|
||||
use crate::range_check_error;
|
||||
|
||||
pub fn generate<F: RichField>(lv: &mut [F; NUM_ARITH_COLUMNS]) {
|
||||
let input0_limbs = MUL_INPUT_0.map(|c| lv[c].to_canonical_u64() as i64);
|
||||
let input1_limbs = MUL_INPUT_1.map(|c| lv[c].to_canonical_u64() as i64);
|
||||
let input0 = read_value_i64_limbs(lv, MUL_INPUT_0);
|
||||
let input1 = read_value_i64_limbs(lv, MUL_INPUT_1);
|
||||
|
||||
const MASK: i64 = (1i64 << LIMB_BITS) - 1i64;
|
||||
|
||||
@ -79,7 +79,7 @@ pub fn generate<F: RichField>(lv: &mut [F; NUM_ARITH_COLUMNS]) {
|
||||
// First calculate the coefficients of a(x)*b(x) (in unreduced_prod),
|
||||
// then do carry propagation to obtain C = c(β) = a(β)*b(β).
|
||||
let mut cy = 0i64;
|
||||
let mut unreduced_prod = pol_mul_lo(input0_limbs, input1_limbs);
|
||||
let mut unreduced_prod = pol_mul_lo(input0, input1);
|
||||
for col in 0..N_LIMBS {
|
||||
let t = unreduced_prod[col] + cy;
|
||||
cy = t >> LIMB_BITS;
|
||||
@ -90,15 +90,13 @@ pub fn generate<F: RichField>(lv: &mut [F; NUM_ARITH_COLUMNS]) {
|
||||
// aux_limbs to handle the fact that unreduced_prod will
|
||||
// inevitably contain one digit's worth that is > 2^256.
|
||||
|
||||
lv[MUL_OUTPUT].copy_from_slice(&output_limbs.map(|c| F::from_canonical_i64(c)));
|
||||
pol_sub_assign(&mut unreduced_prod, &output_limbs);
|
||||
|
||||
let mut aux_limbs = pol_remove_root_2exp::<LIMB_BITS, _, N_LIMBS>(unreduced_prod);
|
||||
aux_limbs[N_LIMBS - 1] = -cy;
|
||||
|
||||
for deg in 0..N_LIMBS {
|
||||
lv[MUL_OUTPUT[deg]] = F::from_canonical_i64(output_limbs[deg]);
|
||||
lv[MUL_AUX_INPUT[deg]] = F::from_noncanonical_i64(aux_limbs[deg]);
|
||||
}
|
||||
lv[MUL_AUX_INPUT].copy_from_slice(&aux_limbs.map(|c| F::from_noncanonical_i64(c)));
|
||||
}
|
||||
|
||||
pub fn eval_packed_generic<P: PackedField>(
|
||||
@ -111,10 +109,10 @@ pub fn eval_packed_generic<P: PackedField>(
|
||||
range_check_error!(MUL_AUX_INPUT, 20);
|
||||
|
||||
let is_mul = lv[IS_MUL];
|
||||
let input0_limbs = MUL_INPUT_0.map(|c| lv[c]);
|
||||
let input1_limbs = MUL_INPUT_1.map(|c| lv[c]);
|
||||
let output_limbs = MUL_OUTPUT.map(|c| lv[c]);
|
||||
let aux_limbs = MUL_AUX_INPUT.map(|c| lv[c]);
|
||||
let input0_limbs = read_value::<N_LIMBS, _>(lv, MUL_INPUT_0);
|
||||
let input1_limbs = read_value::<N_LIMBS, _>(lv, MUL_INPUT_1);
|
||||
let output_limbs = read_value::<N_LIMBS, _>(lv, MUL_OUTPUT);
|
||||
let aux_limbs = read_value::<N_LIMBS, _>(lv, MUL_AUX_INPUT);
|
||||
|
||||
// Constraint poly holds the coefficients of the polynomial that
|
||||
// must be identically zero for this multiplication to be
|
||||
@ -123,13 +121,13 @@ pub fn eval_packed_generic<P: PackedField>(
|
||||
// These two lines set constr_poly to the polynomial a(x)b(x) - c(x),
|
||||
// where a, b and c are the polynomials
|
||||
//
|
||||
// a(x) = \sum_i input0_limbs[i] * β^i
|
||||
// b(x) = \sum_i input1_limbs[i] * β^i
|
||||
// c(x) = \sum_i output_limbs[i] * β^i
|
||||
// a(x) = \sum_i input0_limbs[i] * x^i
|
||||
// b(x) = \sum_i input1_limbs[i] * x^i
|
||||
// c(x) = \sum_i output_limbs[i] * x^i
|
||||
//
|
||||
// This polynomial should equal where s is
|
||||
// This polynomial should equal (x - β)*s(x) where s is
|
||||
//
|
||||
// s(x) = \sum_i aux_limbs[i] * β^i
|
||||
// s(x) = \sum_i aux_limbs[i] * x^i
|
||||
//
|
||||
let mut constr_poly = pol_mul_lo(input0_limbs, input1_limbs);
|
||||
pol_sub_assign(&mut constr_poly, &output_limbs);
|
||||
@ -153,10 +151,10 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
yield_constr: &mut RecursiveConstraintConsumer<F, D>,
|
||||
) {
|
||||
let is_mul = lv[IS_MUL];
|
||||
let input0_limbs = MUL_INPUT_0.map(|c| lv[c]);
|
||||
let input1_limbs = MUL_INPUT_1.map(|c| lv[c]);
|
||||
let output_limbs = MUL_OUTPUT.map(|c| lv[c]);
|
||||
let aux_limbs = MUL_AUX_INPUT.map(|c| lv[c]);
|
||||
let input0_limbs = read_value::<N_LIMBS, _>(lv, MUL_INPUT_0);
|
||||
let input1_limbs = read_value::<N_LIMBS, _>(lv, MUL_INPUT_1);
|
||||
let output_limbs = read_value::<N_LIMBS, _>(lv, MUL_OUTPUT);
|
||||
let aux_limbs = read_value::<N_LIMBS, _>(lv, MUL_AUX_INPUT);
|
||||
|
||||
let mut constr_poly = pol_mul_lo_ext_circuit(builder, input0_limbs, input1_limbs);
|
||||
pol_sub_assign_ext_circuit(builder, &mut constr_poly, &output_limbs);
|
||||
@ -220,7 +218,7 @@ mod tests {
|
||||
|
||||
for _i in 0..N_RND_TESTS {
|
||||
// set inputs to random values
|
||||
for (&ai, bi) in MUL_INPUT_0.iter().zip(MUL_INPUT_1) {
|
||||
for (ai, bi) in MUL_INPUT_0.zip(MUL_INPUT_1) {
|
||||
lv[ai] = F::from_canonical_u16(rng.gen());
|
||||
lv[bi] = F::from_canonical_u16(rng.gen());
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ use plonky2::iop::ext_target::ExtensionTarget;
|
||||
|
||||
use crate::arithmetic::add::{eval_ext_circuit_are_equal, eval_packed_generic_are_equal};
|
||||
use crate::arithmetic::columns::*;
|
||||
use crate::arithmetic::utils::read_value_u64_limbs;
|
||||
use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer};
|
||||
use crate::range_check_error;
|
||||
|
||||
@ -28,14 +29,12 @@ pub(crate) fn u256_sub_br(input0: [u64; N_LIMBS], input1: [u64; N_LIMBS]) -> ([u
|
||||
}
|
||||
|
||||
pub fn generate<F: RichField>(lv: &mut [F; NUM_ARITH_COLUMNS]) {
|
||||
let input0_limbs = SUB_INPUT_0.map(|c| lv[c].to_canonical_u64());
|
||||
let input1_limbs = SUB_INPUT_1.map(|c| lv[c].to_canonical_u64());
|
||||
let input0 = read_value_u64_limbs(lv, SUB_INPUT_0);
|
||||
let input1 = read_value_u64_limbs(lv, SUB_INPUT_1);
|
||||
|
||||
let (output_limbs, _) = u256_sub_br(input0_limbs, input1_limbs);
|
||||
let (output_limbs, _) = u256_sub_br(input0, input1);
|
||||
|
||||
for (&c, output_limb) in SUB_OUTPUT.iter().zip(output_limbs) {
|
||||
lv[c] = F::from_canonical_u64(output_limb);
|
||||
}
|
||||
lv[SUB_OUTPUT].copy_from_slice(&output_limbs.map(|c| F::from_canonical_u64(c)));
|
||||
}
|
||||
|
||||
pub fn eval_packed_generic<P: PackedField>(
|
||||
@ -47,13 +46,18 @@ pub fn eval_packed_generic<P: PackedField>(
|
||||
range_check_error!(SUB_OUTPUT, 16);
|
||||
|
||||
let is_sub = lv[IS_SUB];
|
||||
let input0_limbs = SUB_INPUT_0.iter().map(|&c| lv[c]);
|
||||
let input1_limbs = SUB_INPUT_1.iter().map(|&c| lv[c]);
|
||||
let output_limbs = SUB_OUTPUT.iter().map(|&c| lv[c]);
|
||||
let input0_limbs = &lv[SUB_INPUT_0];
|
||||
let input1_limbs = &lv[SUB_INPUT_1];
|
||||
let output_limbs = &lv[SUB_OUTPUT];
|
||||
|
||||
let output_computed = input0_limbs.zip(input1_limbs).map(|(a, b)| a - b);
|
||||
let output_computed = input0_limbs.iter().zip(input1_limbs).map(|(&a, &b)| a - b);
|
||||
|
||||
eval_packed_generic_are_equal(yield_constr, is_sub, output_limbs, output_computed);
|
||||
eval_packed_generic_are_equal(
|
||||
yield_constr,
|
||||
is_sub,
|
||||
output_limbs.iter().copied(),
|
||||
output_computed,
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_collect)]
|
||||
@ -63,24 +67,25 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
yield_constr: &mut RecursiveConstraintConsumer<F, D>,
|
||||
) {
|
||||
let is_sub = lv[IS_SUB];
|
||||
let input0_limbs = SUB_INPUT_0.iter().map(|&c| lv[c]);
|
||||
let input1_limbs = SUB_INPUT_1.iter().map(|&c| lv[c]);
|
||||
let output_limbs = SUB_OUTPUT.iter().map(|&c| lv[c]);
|
||||
let input0_limbs = &lv[SUB_INPUT_0];
|
||||
let input1_limbs = &lv[SUB_INPUT_1];
|
||||
let output_limbs = &lv[SUB_OUTPUT];
|
||||
|
||||
// Since `map` is lazy and the closure passed to it borrows
|
||||
// `builder`, we can't then borrow builder again below in the call
|
||||
// to `eval_ext_circuit_are_equal`. The solution is to force
|
||||
// evaluation with `collect`.
|
||||
let output_computed = input0_limbs
|
||||
.iter()
|
||||
.zip(input1_limbs)
|
||||
.map(|(a, b)| builder.sub_extension(a, b))
|
||||
.map(|(&a, &b)| builder.sub_extension(a, b))
|
||||
.collect::<Vec<ExtensionTarget<D>>>();
|
||||
|
||||
eval_ext_circuit_are_equal(
|
||||
builder,
|
||||
yield_constr,
|
||||
is_sub,
|
||||
output_limbs,
|
||||
output_limbs.iter().copied(),
|
||||
output_computed.into_iter(),
|
||||
);
|
||||
}
|
||||
@ -134,7 +139,7 @@ mod tests {
|
||||
|
||||
for _ in 0..N_RND_TESTS {
|
||||
// set inputs to random values
|
||||
for (&ai, bi) in SUB_INPUT_0.iter().zip(SUB_INPUT_1) {
|
||||
for (ai, bi) in SUB_INPUT_0.zip(SUB_INPUT_1) {
|
||||
lv[ai] = F::from_canonical_u16(rng.gen());
|
||||
lv[bi] = F::from_canonical_u16(rng.gen());
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use std::ops::{Add, AddAssign, Mul, Neg, Shr, Sub, SubAssign};
|
||||
use std::ops::{Add, AddAssign, Mul, Neg, Range, Shr, Sub, SubAssign};
|
||||
|
||||
use log::error;
|
||||
use plonky2::field::extension::Extendable;
|
||||
@ -6,7 +6,7 @@ use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::ext_target::ExtensionTarget;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
|
||||
use crate::arithmetic::columns::N_LIMBS;
|
||||
use crate::arithmetic::columns::{NUM_ARITH_COLUMNS, N_LIMBS};
|
||||
|
||||
/// Emit an error message regarding unchecked range assumptions.
|
||||
/// Assumes the values in `cols` are `[cols[0], cols[0] + 1, ...,
|
||||
@ -14,7 +14,7 @@ use crate::arithmetic::columns::N_LIMBS;
|
||||
pub(crate) fn _range_check_error<const RC_BITS: u32>(
|
||||
file: &str,
|
||||
line: u32,
|
||||
cols: &[usize],
|
||||
cols: Range<usize>,
|
||||
signedness: &str,
|
||||
) {
|
||||
error!(
|
||||
@ -23,8 +23,8 @@ pub(crate) fn _range_check_error<const RC_BITS: u32>(
|
||||
file,
|
||||
RC_BITS,
|
||||
signedness,
|
||||
cols[0],
|
||||
cols[0] + cols.len() - 1
|
||||
cols.start,
|
||||
cols.end - 1,
|
||||
);
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ macro_rules! range_check_error {
|
||||
$crate::arithmetic::utils::_range_check_error::<$rc_bits>(
|
||||
file!(),
|
||||
line!(),
|
||||
&$cols,
|
||||
$cols,
|
||||
"unsigned",
|
||||
);
|
||||
};
|
||||
@ -42,7 +42,7 @@ macro_rules! range_check_error {
|
||||
$crate::arithmetic::utils::_range_check_error::<$rc_bits>(
|
||||
file!(),
|
||||
line!(),
|
||||
&$cols,
|
||||
$cols,
|
||||
"signed",
|
||||
);
|
||||
};
|
||||
@ -337,3 +337,34 @@ where
|
||||
}
|
||||
q
|
||||
}
|
||||
|
||||
/// Read the range `value_idxs` of values from `lv` into an array of
|
||||
/// length `N`. Panics if the length of the range is not `N`.
|
||||
pub(crate) fn read_value<const N: usize, T: Copy>(
|
||||
lv: &[T; NUM_ARITH_COLUMNS],
|
||||
value_idxs: Range<usize>,
|
||||
) -> [T; N] {
|
||||
lv[value_idxs].try_into().unwrap()
|
||||
}
|
||||
|
||||
/// Read the range `value_idxs` of values from `lv` into an array of
|
||||
/// length `N`, interpreting the values as `u64`s. Panics if the
|
||||
/// length of the range is not `N`.
|
||||
pub(crate) fn read_value_u64_limbs<const N: usize, F: RichField>(
|
||||
lv: &[F; NUM_ARITH_COLUMNS],
|
||||
value_idxs: Range<usize>,
|
||||
) -> [u64; N] {
|
||||
let limbs: [_; N] = lv[value_idxs].try_into().unwrap();
|
||||
limbs.map(|c| F::to_canonical_u64(&c))
|
||||
}
|
||||
|
||||
/// Read the range `value_idxs` of values from `lv` into an array of
|
||||
/// length `N`, interpreting the values as `i64`s. Panics if the
|
||||
/// length of the range is not `N`.
|
||||
pub(crate) fn read_value_i64_limbs<const N: usize, F: RichField>(
|
||||
lv: &[F; NUM_ARITH_COLUMNS],
|
||||
value_idxs: Range<usize>,
|
||||
) -> [i64; N] {
|
||||
let limbs: [_; N] = lv[value_idxs].try_into().unwrap();
|
||||
limbs.map(|c| F::to_canonical_u64(&c) as i64)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user