2022-10-12 02:39:13 +11:00
|
|
|
use std::ops::{Add, AddAssign, Mul, Neg, Range, Shr, Sub, SubAssign};
|
2022-10-07 17:15:50 +11:00
|
|
|
|
|
|
|
|
use plonky2::field::extension::Extendable;
|
|
|
|
|
use plonky2::hash::hash_types::RichField;
|
|
|
|
|
use plonky2::iop::ext_target::ExtensionTarget;
|
|
|
|
|
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
|
|
|
|
|
2022-10-12 02:39:13 +11:00
|
|
|
use crate::arithmetic::columns::{NUM_ARITH_COLUMNS, N_LIMBS};
|
2022-06-29 11:56:48 +10:00
|
|
|
|
|
|
|
|
/// Emit an error message regarding unchecked range assumptions.
|
|
|
|
|
/// Assumes the values in `cols` are `[cols[0], cols[0] + 1, ...,
|
|
|
|
|
/// cols[0] + cols.len() - 1]`.
|
2022-11-09 10:47:15 +11:00
|
|
|
///
|
|
|
|
|
/// TODO: Hamish to delete this when he has implemented and integrated
|
|
|
|
|
/// range checks.
|
2022-10-07 17:15:50 +11:00
|
|
|
pub(crate) fn _range_check_error<const RC_BITS: u32>(
|
2022-11-09 10:47:15 +11:00
|
|
|
_file: &str,
|
|
|
|
|
_line: u32,
|
|
|
|
|
_cols: Range<usize>,
|
|
|
|
|
_signedness: &str,
|
2022-10-07 17:15:50 +11:00
|
|
|
) {
|
2022-11-09 10:47:15 +11:00
|
|
|
// error!(
|
|
|
|
|
// "{}:{}: arithmetic unit skipped {}-bit {} range-checks on columns {}--{}: not yet implemented",
|
|
|
|
|
// line,
|
|
|
|
|
// file,
|
|
|
|
|
// RC_BITS,
|
|
|
|
|
// signedness,
|
|
|
|
|
// cols.start,
|
|
|
|
|
// cols.end - 1,
|
|
|
|
|
// );
|
2022-06-29 11:56:48 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[macro_export]
|
|
|
|
|
macro_rules! range_check_error {
|
|
|
|
|
($cols:ident, $rc_bits:expr) => {
|
2022-10-07 17:15:50 +11:00
|
|
|
$crate::arithmetic::utils::_range_check_error::<$rc_bits>(
|
|
|
|
|
file!(),
|
|
|
|
|
line!(),
|
2022-10-12 02:39:13 +11:00
|
|
|
$cols,
|
2022-10-07 17:15:50 +11:00
|
|
|
"unsigned",
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
($cols:ident, $rc_bits:expr, signed) => {
|
|
|
|
|
$crate::arithmetic::utils::_range_check_error::<$rc_bits>(
|
|
|
|
|
file!(),
|
|
|
|
|
line!(),
|
2022-10-12 02:39:13 +11:00
|
|
|
$cols,
|
2022-10-07 17:15:50 +11:00
|
|
|
"signed",
|
|
|
|
|
);
|
2022-06-29 11:56:48 +10:00
|
|
|
};
|
2022-08-26 09:13:47 +10:00
|
|
|
([$cols:ident], $rc_bits:expr) => {
|
2022-10-07 17:15:50 +11:00
|
|
|
$crate::arithmetic::utils::_range_check_error::<$rc_bits>(
|
|
|
|
|
file!(),
|
|
|
|
|
line!(),
|
|
|
|
|
&[$cols],
|
|
|
|
|
"unsigned",
|
|
|
|
|
);
|
2022-08-26 09:13:47 +10:00
|
|
|
};
|
2022-06-29 11:56:48 +10:00
|
|
|
}
|
2022-10-07 17:15:50 +11:00
|
|
|
|
|
|
|
|
/// Return an array of `N` zeros of type T.
|
|
|
|
|
pub(crate) fn pol_zero<T, const N: usize>() -> [T; N]
|
|
|
|
|
where
|
|
|
|
|
T: Copy + Default,
|
|
|
|
|
{
|
|
|
|
|
// TODO: This should really be T::zero() from num::Zero, because
|
|
|
|
|
// default() doesn't guarantee to initialise to zero (though in
|
|
|
|
|
// our case it always does). However I couldn't work out how to do
|
|
|
|
|
// that without touching half of the entire crate because it
|
|
|
|
|
// involves replacing Field::is_zero() with num::Zero::is_zero()
|
|
|
|
|
// which is used everywhere. Hence Default::default() it is.
|
|
|
|
|
[T::default(); N]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// a(x) += b(x), but must have deg(a) >= deg(b).
|
|
|
|
|
pub(crate) fn pol_add_assign<T>(a: &mut [T], b: &[T])
|
|
|
|
|
where
|
|
|
|
|
T: AddAssign + Copy + Default,
|
|
|
|
|
{
|
|
|
|
|
debug_assert!(a.len() >= b.len(), "expected {} >= {}", a.len(), b.len());
|
|
|
|
|
for (a_item, b_item) in a.iter_mut().zip(b) {
|
|
|
|
|
*a_item += *b_item;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn pol_add_assign_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
|
|
|
|
builder: &mut CircuitBuilder<F, D>,
|
|
|
|
|
a: &mut [ExtensionTarget<D>],
|
|
|
|
|
b: &[ExtensionTarget<D>],
|
|
|
|
|
) {
|
|
|
|
|
debug_assert!(a.len() >= b.len(), "expected {} >= {}", a.len(), b.len());
|
|
|
|
|
for (a_item, b_item) in a.iter_mut().zip(b) {
|
|
|
|
|
*a_item = builder.add_extension(*a_item, *b_item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Return a(x) + b(x); returned array is bigger than necessary to
|
|
|
|
|
/// make the interface consistent with `pol_mul_wide`.
|
|
|
|
|
pub(crate) fn pol_add<T>(a: [T; N_LIMBS], b: [T; N_LIMBS]) -> [T; 2 * N_LIMBS - 1]
|
|
|
|
|
where
|
|
|
|
|
T: Add<Output = T> + Copy + Default,
|
|
|
|
|
{
|
|
|
|
|
let mut sum = pol_zero();
|
|
|
|
|
for i in 0..N_LIMBS {
|
|
|
|
|
sum[i] = a[i] + b[i];
|
|
|
|
|
}
|
|
|
|
|
sum
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn pol_add_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
|
|
|
|
builder: &mut CircuitBuilder<F, D>,
|
|
|
|
|
a: [ExtensionTarget<D>; N_LIMBS],
|
|
|
|
|
b: [ExtensionTarget<D>; N_LIMBS],
|
|
|
|
|
) -> [ExtensionTarget<D>; 2 * N_LIMBS - 1] {
|
|
|
|
|
let zero = builder.zero_extension();
|
|
|
|
|
let mut sum = [zero; 2 * N_LIMBS - 1];
|
|
|
|
|
for i in 0..N_LIMBS {
|
|
|
|
|
sum[i] = builder.add_extension(a[i], b[i]);
|
|
|
|
|
}
|
|
|
|
|
sum
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-20 04:46:01 +11:00
|
|
|
/// Return a(x) - b(x); returned array is bigger than necessary to
|
|
|
|
|
/// make the interface consistent with `pol_mul_wide`.
|
|
|
|
|
pub(crate) fn pol_sub<T>(a: [T; N_LIMBS], b: [T; N_LIMBS]) -> [T; 2 * N_LIMBS - 1]
|
|
|
|
|
where
|
|
|
|
|
T: Sub<Output = T> + Copy + Default,
|
|
|
|
|
{
|
|
|
|
|
let mut diff = pol_zero();
|
|
|
|
|
for i in 0..N_LIMBS {
|
|
|
|
|
diff[i] = a[i] - b[i];
|
|
|
|
|
}
|
|
|
|
|
diff
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn pol_sub_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
|
|
|
|
builder: &mut CircuitBuilder<F, D>,
|
|
|
|
|
a: [ExtensionTarget<D>; N_LIMBS],
|
|
|
|
|
b: [ExtensionTarget<D>; N_LIMBS],
|
|
|
|
|
) -> [ExtensionTarget<D>; 2 * N_LIMBS - 1] {
|
|
|
|
|
let zero = builder.zero_extension();
|
|
|
|
|
let mut sum = [zero; 2 * N_LIMBS - 1];
|
|
|
|
|
for i in 0..N_LIMBS {
|
|
|
|
|
sum[i] = builder.sub_extension(a[i], b[i]);
|
|
|
|
|
}
|
|
|
|
|
sum
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-07 17:15:50 +11:00
|
|
|
/// a(x) -= b(x), but must have deg(a) >= deg(b).
|
|
|
|
|
pub(crate) fn pol_sub_assign<T>(a: &mut [T], b: &[T])
|
|
|
|
|
where
|
|
|
|
|
T: SubAssign + Copy,
|
|
|
|
|
{
|
|
|
|
|
debug_assert!(a.len() >= b.len(), "expected {} >= {}", a.len(), b.len());
|
|
|
|
|
for (a_item, b_item) in a.iter_mut().zip(b) {
|
|
|
|
|
*a_item -= *b_item;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn pol_sub_assign_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
|
|
|
|
builder: &mut CircuitBuilder<F, D>,
|
|
|
|
|
a: &mut [ExtensionTarget<D>],
|
|
|
|
|
b: &[ExtensionTarget<D>],
|
|
|
|
|
) {
|
|
|
|
|
debug_assert!(a.len() >= b.len(), "expected {} >= {}", a.len(), b.len());
|
|
|
|
|
for (a_item, b_item) in a.iter_mut().zip(b) {
|
|
|
|
|
*a_item = builder.sub_extension(*a_item, *b_item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Given polynomials a(x) and b(x), return a(x)*b(x).
|
|
|
|
|
///
|
|
|
|
|
/// NB: The caller is responsible for ensuring that no undesired
|
|
|
|
|
/// overflow occurs during the calculation of the coefficients of the
|
|
|
|
|
/// product.
|
|
|
|
|
pub(crate) fn pol_mul_wide<T>(a: [T; N_LIMBS], b: [T; N_LIMBS]) -> [T; 2 * N_LIMBS - 1]
|
|
|
|
|
where
|
|
|
|
|
T: AddAssign + Copy + Mul<Output = T> + Default,
|
|
|
|
|
{
|
|
|
|
|
let mut res = [T::default(); 2 * N_LIMBS - 1];
|
|
|
|
|
for (i, &ai) in a.iter().enumerate() {
|
|
|
|
|
for (j, &bj) in b.iter().enumerate() {
|
|
|
|
|
res[i + j] += ai * bj;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn pol_mul_wide_ext_circuit<
|
|
|
|
|
F: RichField + Extendable<D>,
|
|
|
|
|
const D: usize,
|
|
|
|
|
const M: usize,
|
|
|
|
|
const N: usize,
|
|
|
|
|
const P: usize,
|
|
|
|
|
>(
|
|
|
|
|
builder: &mut CircuitBuilder<F, D>,
|
|
|
|
|
a: [ExtensionTarget<D>; M],
|
|
|
|
|
b: [ExtensionTarget<D>; N],
|
|
|
|
|
) -> [ExtensionTarget<D>; P] {
|
|
|
|
|
let zero = builder.zero_extension();
|
|
|
|
|
let mut res = [zero; P];
|
|
|
|
|
for (i, &ai) in a.iter().enumerate() {
|
|
|
|
|
for (j, &bj) in b.iter().enumerate() {
|
|
|
|
|
res[i + j] = builder.mul_add_extension(ai, bj, res[i + j]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// As for `pol_mul_wide` but the first argument has 2N elements and
|
|
|
|
|
/// hence the result has 3N-1.
|
|
|
|
|
pub(crate) fn pol_mul_wide2<T>(a: [T; 2 * N_LIMBS], b: [T; N_LIMBS]) -> [T; 3 * N_LIMBS - 1]
|
|
|
|
|
where
|
|
|
|
|
T: AddAssign + Copy + Mul<Output = T> + Default,
|
|
|
|
|
{
|
|
|
|
|
let mut res = [T::default(); 3 * N_LIMBS - 1];
|
|
|
|
|
for (i, &ai) in a.iter().enumerate() {
|
|
|
|
|
for (j, &bj) in b.iter().enumerate() {
|
|
|
|
|
res[i + j] += ai * bj;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn pol_mul_wide2_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
|
|
|
|
builder: &mut CircuitBuilder<F, D>,
|
|
|
|
|
a: [ExtensionTarget<D>; 2 * N_LIMBS],
|
|
|
|
|
b: [ExtensionTarget<D>; N_LIMBS],
|
|
|
|
|
) -> [ExtensionTarget<D>; 3 * N_LIMBS - 1] {
|
|
|
|
|
let zero = builder.zero_extension();
|
|
|
|
|
let mut res = [zero; 3 * N_LIMBS - 1];
|
|
|
|
|
for (i, &ai) in a.iter().enumerate() {
|
|
|
|
|
for (j, &bj) in b.iter().enumerate() {
|
|
|
|
|
res[i + j] = builder.mul_add_extension(ai, bj, res[i + j]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Given a(x) and b(x), return a(x)*b(x) mod 2^256.
|
|
|
|
|
pub(crate) fn pol_mul_lo<T, const N: usize>(a: [T; N], b: [T; N]) -> [T; N]
|
|
|
|
|
where
|
|
|
|
|
T: AddAssign + Copy + Default + Mul<Output = T>,
|
|
|
|
|
{
|
|
|
|
|
let mut res = pol_zero();
|
|
|
|
|
for deg in 0..N {
|
|
|
|
|
// Invariant: i + j = deg
|
|
|
|
|
for i in 0..=deg {
|
|
|
|
|
let j = deg - i;
|
|
|
|
|
res[deg] += a[i] * b[j];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-11 18:59:02 +11:00
|
|
|
pub(crate) fn pol_mul_lo_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
|
|
|
|
builder: &mut CircuitBuilder<F, D>,
|
|
|
|
|
a: [ExtensionTarget<D>; N_LIMBS],
|
|
|
|
|
b: [ExtensionTarget<D>; N_LIMBS],
|
|
|
|
|
) -> [ExtensionTarget<D>; N_LIMBS] {
|
|
|
|
|
let zero = builder.zero_extension();
|
|
|
|
|
let mut res = [zero; N_LIMBS];
|
|
|
|
|
for deg in 0..N_LIMBS {
|
|
|
|
|
for i in 0..=deg {
|
|
|
|
|
let j = deg - i;
|
|
|
|
|
res[deg] = builder.mul_add_extension(a[i], b[j], res[deg]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-07 17:15:50 +11:00
|
|
|
/// Adjoin M - N zeros to a, returning [a[0], a[1], ..., a[N-1], 0, 0, ..., 0].
|
|
|
|
|
pub(crate) fn pol_extend<T, const N: usize, const M: usize>(a: [T; N]) -> [T; M]
|
|
|
|
|
where
|
|
|
|
|
T: Copy + Default,
|
|
|
|
|
{
|
|
|
|
|
assert_eq!(M, 2 * N - 1);
|
|
|
|
|
|
|
|
|
|
let mut zero_extend = pol_zero();
|
|
|
|
|
zero_extend[..N].copy_from_slice(&a);
|
|
|
|
|
zero_extend
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn pol_extend_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
|
|
|
|
builder: &mut CircuitBuilder<F, D>,
|
|
|
|
|
a: [ExtensionTarget<D>; N_LIMBS],
|
|
|
|
|
) -> [ExtensionTarget<D>; 2 * N_LIMBS - 1] {
|
|
|
|
|
let zero = builder.zero_extension();
|
|
|
|
|
let mut zero_extend = [zero; 2 * N_LIMBS - 1];
|
|
|
|
|
|
|
|
|
|
zero_extend[..N_LIMBS].copy_from_slice(&a);
|
|
|
|
|
zero_extend
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-11 18:59:02 +11:00
|
|
|
/// Given polynomial a(x) = \sum_{i=0}^{N-2} a[i] x^i and an element
|
2022-10-07 17:15:50 +11:00
|
|
|
/// `root`, return b = (x - root) * a(x).
|
2022-10-11 18:59:02 +11:00
|
|
|
pub(crate) fn pol_adjoin_root<T, U, const N: usize>(a: [T; N], root: U) -> [T; N]
|
2022-10-07 17:15:50 +11:00
|
|
|
where
|
|
|
|
|
T: Add<Output = T> + Copy + Default + Mul<Output = T> + Sub<Output = T>,
|
|
|
|
|
U: Copy + Mul<T, Output = T> + Neg<Output = U>,
|
|
|
|
|
{
|
|
|
|
|
// \sum_i res[i] x^i = (x - root) \sum_i a[i] x^i. Comparing
|
|
|
|
|
// coefficients, res[0] = -root*a[0] and
|
|
|
|
|
// res[i] = a[i-1] - root * a[i]
|
|
|
|
|
|
2022-10-11 18:59:02 +11:00
|
|
|
let mut res = [T::default(); N];
|
2022-10-07 17:15:50 +11:00
|
|
|
res[0] = -root * a[0];
|
2022-10-11 18:59:02 +11:00
|
|
|
for deg in 1..N {
|
2022-10-07 17:15:50 +11:00
|
|
|
res[deg] = a[deg - 1] - (root * a[deg]);
|
|
|
|
|
}
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-11 18:59:02 +11:00
|
|
|
pub(crate) fn pol_adjoin_root_ext_circuit<
|
|
|
|
|
F: RichField + Extendable<D>,
|
|
|
|
|
const D: usize,
|
|
|
|
|
const N: usize,
|
|
|
|
|
>(
|
2022-10-07 17:15:50 +11:00
|
|
|
builder: &mut CircuitBuilder<F, D>,
|
2022-10-11 18:59:02 +11:00
|
|
|
a: [ExtensionTarget<D>; N],
|
2022-10-07 17:15:50 +11:00
|
|
|
root: ExtensionTarget<D>,
|
2022-10-11 18:59:02 +11:00
|
|
|
) -> [ExtensionTarget<D>; N] {
|
2022-10-07 17:15:50 +11:00
|
|
|
let zero = builder.zero_extension();
|
2022-10-11 18:59:02 +11:00
|
|
|
let mut res = [zero; N];
|
2022-10-07 17:15:50 +11:00
|
|
|
// res[deg] = NEG_ONE * root * a[0] + ZERO * zero
|
|
|
|
|
res[0] = builder.arithmetic_extension(F::NEG_ONE, F::ZERO, root, a[0], zero);
|
2022-10-11 18:59:02 +11:00
|
|
|
for deg in 1..N {
|
2022-10-07 17:15:50 +11:00
|
|
|
// res[deg] = NEG_ONE * root * a[deg] + ONE * a[deg - 1]
|
|
|
|
|
res[deg] = builder.arithmetic_extension(F::NEG_ONE, F::ONE, root, a[deg], a[deg - 1]);
|
|
|
|
|
}
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-11 18:59:02 +11:00
|
|
|
/// Given polynomial a(x) = \sum_{i=0}^{N-1} a[i] x^i and a root of `a`
|
2022-10-07 17:15:50 +11:00
|
|
|
/// of the form 2^EXP, return q(x) satisfying a(x) = (x - root) * q(x).
|
|
|
|
|
///
|
|
|
|
|
/// NB: We do not verify that a(2^EXP) = 0; if this doesn't hold the
|
|
|
|
|
/// result is basically junk.
|
|
|
|
|
///
|
2022-10-11 18:59:02 +11:00
|
|
|
/// NB: The result could be returned in N-1 elements, but we return
|
|
|
|
|
/// N and set the last element to zero since the calling code
|
|
|
|
|
/// happens to require a result zero-extended to N elements.
|
|
|
|
|
pub(crate) fn pol_remove_root_2exp<const EXP: usize, T, const N: usize>(a: [T; N]) -> [T; N]
|
2022-10-07 17:15:50 +11:00
|
|
|
where
|
|
|
|
|
T: Copy + Default + Neg<Output = T> + Shr<usize, Output = T> + Sub<Output = T>,
|
|
|
|
|
{
|
|
|
|
|
// By assumption β := 2^EXP is a root of `a`, i.e. (x - β) divides
|
|
|
|
|
// `a`; if we write
|
|
|
|
|
//
|
2022-10-11 18:59:02 +11:00
|
|
|
// a(x) = \sum_{i=0}^{N-1} a[i] x^i
|
|
|
|
|
// = (x - β) \sum_{i=0}^{N-2} q[i] x^i
|
2022-10-07 17:15:50 +11:00
|
|
|
//
|
|
|
|
|
// then by comparing coefficients it is easy to see that
|
|
|
|
|
//
|
|
|
|
|
// q[0] = -a[0] / β and q[i] = (q[i-1] - a[i]) / β
|
|
|
|
|
//
|
2022-10-11 18:59:02 +11:00
|
|
|
// for 0 < i <= N-1 (and the divisions are exact).
|
2022-10-07 17:15:50 +11:00
|
|
|
|
2022-10-11 18:59:02 +11:00
|
|
|
let mut q = [T::default(); N];
|
2022-10-07 17:15:50 +11:00
|
|
|
q[0] = -(a[0] >> EXP);
|
|
|
|
|
|
|
|
|
|
// NB: Last element of q is deliberately left equal to zero.
|
2022-10-11 18:59:02 +11:00
|
|
|
for deg in 1..N - 1 {
|
2022-10-07 17:15:50 +11:00
|
|
|
q[deg] = (q[deg - 1] - a[deg]) >> EXP;
|
|
|
|
|
}
|
|
|
|
|
q
|
|
|
|
|
}
|
2022-10-12 02:39:13 +11:00
|
|
|
|
|
|
|
|
/// 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)
|
|
|
|
|
}
|