mirror of https://github.com/zcash/orchard.git
Return full running sum [z_0, ..., z_W] from lookup_range_check and decompose_running_sum.
Previously, these two helpers were returning different outputs. They have now been standardised to return only the full running sum. Note the z_0 is the original element being decomposed by the helper.
This commit is contained in:
parent
092cc389bb
commit
4d1cd2651a
|
@ -291,7 +291,7 @@ pub struct EccScalarFixed {
|
||||||
pub struct EccScalarFixedShort {
|
pub struct EccScalarFixedShort {
|
||||||
magnitude: CellValue<pallas::Base>,
|
magnitude: CellValue<pallas::Base>,
|
||||||
sign: CellValue<pallas::Base>,
|
sign: CellValue<pallas::Base>,
|
||||||
running_sum: ArrayVec<CellValue<pallas::Base>, { constants::NUM_WINDOWS_SHORT }>,
|
running_sum: ArrayVec<CellValue<pallas::Base>, { constants::NUM_WINDOWS_SHORT + 1 }>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A base field element used for fixed-base scalar multiplication.
|
/// A base field element used for fixed-base scalar multiplication.
|
||||||
|
@ -300,13 +300,13 @@ pub struct EccScalarFixedShort {
|
||||||
/// for element α = a_0 + (2^3) a_1 + ... + (2^{3(n-1)}) a_{n-1}.
|
/// for element α = a_0 + (2^3) a_1 + ... + (2^{3(n-1)}) a_{n-1}.
|
||||||
/// Each `a_i` is in the range [0..2^3).
|
/// Each `a_i` is in the range [0..2^3).
|
||||||
///
|
///
|
||||||
/// `windows` = [z_1, ..., z_85], where we expect z_85 = 0.
|
/// `running_sum` = [z_0, ..., z_85], where we expect z_85 = 0.
|
||||||
/// Since z_0 is initialized as the scalar α, we store it as
|
/// Since z_0 is initialized as the scalar α, we store it as
|
||||||
/// `base_field_elem`.
|
/// `base_field_elem`.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct EccBaseFieldElemFixed {
|
struct EccBaseFieldElemFixed {
|
||||||
base_field_elem: CellValue<pallas::Base>,
|
base_field_elem: CellValue<pallas::Base>,
|
||||||
running_sum: ArrayVec<CellValue<pallas::Base>, { constants::NUM_WINDOWS }>,
|
running_sum: ArrayVec<CellValue<pallas::Base>, { constants::NUM_WINDOWS + 1 }>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EccBaseFieldElemFixed {
|
impl EccBaseFieldElemFixed {
|
||||||
|
|
|
@ -511,16 +511,8 @@ impl ScalarFixed {
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
};
|
};
|
||||||
match self {
|
match self {
|
||||||
Self::BaseFieldElem(scalar) => {
|
Self::BaseFieldElem(scalar) => running_sum_to_windows(scalar.running_sum.to_vec()),
|
||||||
let mut zs = vec![scalar.base_field_elem];
|
Self::Short(scalar) => running_sum_to_windows(scalar.running_sum.to_vec()),
|
||||||
zs.extend_from_slice(&scalar.running_sum);
|
|
||||||
running_sum_to_windows(zs)
|
|
||||||
}
|
|
||||||
Self::Short(scalar) => {
|
|
||||||
let mut zs = vec![scalar.magnitude];
|
|
||||||
zs.extend_from_slice(&scalar.running_sum);
|
|
||||||
running_sum_to_windows(zs)
|
|
||||||
}
|
|
||||||
Self::FullWidth(scalar) => scalar
|
Self::FullWidth(scalar) => scalar
|
||||||
.windows
|
.windows
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -166,7 +166,7 @@ impl Config {
|
||||||
|
|
||||||
// Decompose scalar
|
// Decompose scalar
|
||||||
let scalar = {
|
let scalar = {
|
||||||
let (base_field_elem, running_sum) = self.running_sum_config.copy_decompose(
|
let running_sum = self.running_sum_config.copy_decompose(
|
||||||
&mut region,
|
&mut region,
|
||||||
offset,
|
offset,
|
||||||
scalar,
|
scalar,
|
||||||
|
@ -175,7 +175,7 @@ impl Config {
|
||||||
constants::NUM_WINDOWS,
|
constants::NUM_WINDOWS,
|
||||||
)?;
|
)?;
|
||||||
EccBaseFieldElemFixed {
|
EccBaseFieldElemFixed {
|
||||||
base_field_elem,
|
base_field_elem: running_sum[0],
|
||||||
running_sum: (*running_sum).as_slice().try_into().unwrap(),
|
running_sum: (*running_sum).as_slice().try_into().unwrap(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -240,9 +240,9 @@ impl Config {
|
||||||
// => z_13_alpha_0_prime = 0
|
// => z_13_alpha_0_prime = 0
|
||||||
//
|
//
|
||||||
let (alpha, running_sum) = (scalar.base_field_elem, &scalar.running_sum);
|
let (alpha, running_sum) = (scalar.base_field_elem, &scalar.running_sum);
|
||||||
let z_43_alpha = running_sum[42];
|
let z_43_alpha = running_sum[43];
|
||||||
let z_44_alpha = running_sum[43];
|
let z_44_alpha = running_sum[44];
|
||||||
let z_84_alpha = running_sum[83];
|
let z_84_alpha = running_sum[84];
|
||||||
|
|
||||||
// α_0 = α - z_84_alpha * 2^252
|
// α_0 = α - z_84_alpha * 2^252
|
||||||
let alpha_0 = alpha
|
let alpha_0 = alpha
|
||||||
|
@ -260,12 +260,13 @@ impl Config {
|
||||||
let t_p = pallas::Base::from_u128(T_P);
|
let t_p = pallas::Base::from_u128(T_P);
|
||||||
alpha_0 + two_pow_130 - t_p
|
alpha_0 + two_pow_130 - t_p
|
||||||
});
|
});
|
||||||
let (alpha_0_prime, zs) = self.lookup_config.witness_check(
|
let zs = self.lookup_config.witness_check(
|
||||||
layouter.namespace(|| "Lookup range check alpha_0 + 2^130 - t_p"),
|
layouter.namespace(|| "Lookup range check alpha_0 + 2^130 - t_p"),
|
||||||
alpha_0_prime,
|
alpha_0_prime,
|
||||||
13,
|
13,
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
let alpha_0_prime = zs[0];
|
||||||
|
|
||||||
(alpha_0_prime, zs[13])
|
(alpha_0_prime, zs[13])
|
||||||
};
|
};
|
||||||
|
|
|
@ -80,7 +80,7 @@ impl Config {
|
||||||
let (magnitude, sign) = magnitude_sign;
|
let (magnitude, sign) = magnitude_sign;
|
||||||
|
|
||||||
// Decompose magnitude
|
// Decompose magnitude
|
||||||
let (magnitude, running_sum) = self.running_sum_config.copy_decompose(
|
let running_sum = self.running_sum_config.copy_decompose(
|
||||||
region,
|
region,
|
||||||
offset,
|
offset,
|
||||||
magnitude,
|
magnitude,
|
||||||
|
@ -150,7 +150,7 @@ impl Config {
|
||||||
// Copy last window to `u` column.
|
// Copy last window to `u` column.
|
||||||
// (Although the last window is not a `u` value; we are copying it into the `u`
|
// (Although the last window is not a `u` value; we are copying it into the `u`
|
||||||
// column because there is an available cell there.)
|
// column because there is an available cell there.)
|
||||||
let z_21 = scalar.running_sum[20];
|
let z_21 = scalar.running_sum[21];
|
||||||
copy(
|
copy(
|
||||||
&mut region,
|
&mut region,
|
||||||
|| "last_window",
|
|| "last_window",
|
||||||
|
|
|
@ -392,12 +392,13 @@ impl CommitIvkConfig {
|
||||||
let t_p = pallas::Base::from_u128(T_P);
|
let t_p = pallas::Base::from_u128(T_P);
|
||||||
a + two_pow_130 - t_p
|
a + two_pow_130 - t_p
|
||||||
});
|
});
|
||||||
let (a_prime, zs) = self.sinsemilla_config.lookup_config.witness_check(
|
let zs = self.sinsemilla_config.lookup_config.witness_check(
|
||||||
layouter.namespace(|| "Decompose low 130 bits of (a + 2^130 - t_P)"),
|
layouter.namespace(|| "Decompose low 130 bits of (a + 2^130 - t_P)"),
|
||||||
a_prime,
|
a_prime,
|
||||||
13,
|
13,
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
let a_prime = zs[0];
|
||||||
assert_eq!(zs.len(), 14); // [z_0, z_1, ..., z13_a]
|
assert_eq!(zs.len(), 14); // [z_0, z_1, ..., z13_a]
|
||||||
|
|
||||||
Ok((a_prime, zs[13]))
|
Ok((a_prime, zs[13]))
|
||||||
|
@ -428,12 +429,13 @@ impl CommitIvkConfig {
|
||||||
let t_p = pallas::Base::from_u128(T_P);
|
let t_p = pallas::Base::from_u128(T_P);
|
||||||
b_2 + c * two_pow_5 + two_pow_140 - t_p
|
b_2 + c * two_pow_5 + two_pow_140 - t_p
|
||||||
});
|
});
|
||||||
let (b2_c_prime, zs) = self.sinsemilla_config.lookup_config.witness_check(
|
let zs = self.sinsemilla_config.lookup_config.witness_check(
|
||||||
layouter.namespace(|| "Decompose low 140 bits of (b_2 + c * 2^5 + 2^140 - t_P)"),
|
layouter.namespace(|| "Decompose low 140 bits of (b_2 + c * 2^5 + 2^140 - t_P)"),
|
||||||
b2_c_prime,
|
b2_c_prime,
|
||||||
14,
|
14,
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
let b2_c_prime = zs[0];
|
||||||
assert_eq!(zs.len(), 15); // [z_0, z_1, ..., z14]
|
assert_eq!(zs.len(), 15); // [z_0, z_1, ..., z14]
|
||||||
|
|
||||||
Ok((b2_c_prime, zs[14]))
|
Ok((b2_c_prime, zs[14]))
|
||||||
|
|
|
@ -710,12 +710,13 @@ impl NoteCommitConfig {
|
||||||
let t_p = pallas::Base::from_u128(T_P);
|
let t_p = pallas::Base::from_u128(T_P);
|
||||||
a + two_pow_130 - t_p
|
a + two_pow_130 - t_p
|
||||||
});
|
});
|
||||||
let (a_prime, zs) = self.sinsemilla_config.lookup_config.witness_check(
|
let zs = self.sinsemilla_config.lookup_config.witness_check(
|
||||||
layouter.namespace(|| "Decompose low 130 bits of (a + 2^130 - t_P)"),
|
layouter.namespace(|| "Decompose low 130 bits of (a + 2^130 - t_P)"),
|
||||||
a_prime,
|
a_prime,
|
||||||
13,
|
13,
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
let a_prime = zs[0];
|
||||||
assert_eq!(zs.len(), 14); // [z_0, z_1, ..., z_13]
|
assert_eq!(zs.len(), 14); // [z_0, z_1, ..., z_13]
|
||||||
|
|
||||||
Ok((a_prime, zs[13]))
|
Ok((a_prime, zs[13]))
|
||||||
|
@ -748,12 +749,13 @@ impl NoteCommitConfig {
|
||||||
b_3 + (two_pow_4 * c) + two_pow_140 - t_p
|
b_3 + (two_pow_4 * c) + two_pow_140 - t_p
|
||||||
});
|
});
|
||||||
|
|
||||||
let (b3_c_prime, zs) = self.sinsemilla_config.lookup_config.witness_check(
|
let zs = self.sinsemilla_config.lookup_config.witness_check(
|
||||||
layouter.namespace(|| "Decompose low 140 bits of (b_3 + 2^4 c + 2^140 - t_P)"),
|
layouter.namespace(|| "Decompose low 140 bits of (b_3 + 2^4 c + 2^140 - t_P)"),
|
||||||
b3_c_prime,
|
b3_c_prime,
|
||||||
14,
|
14,
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
let b3_c_prime = zs[0];
|
||||||
assert_eq!(zs.len(), 15); // [z_0, z_1, ..., z_13, z_14]
|
assert_eq!(zs.len(), 15); // [z_0, z_1, ..., z_13, z_14]
|
||||||
|
|
||||||
Ok((b3_c_prime, zs[14]))
|
Ok((b3_c_prime, zs[14]))
|
||||||
|
@ -787,12 +789,13 @@ impl NoteCommitConfig {
|
||||||
// Decompose the low 140 bits of e1_f_prime = e_1 + 2^4 f + 2^140 - t_P,
|
// Decompose the low 140 bits of e1_f_prime = e_1 + 2^4 f + 2^140 - t_P,
|
||||||
// and output the running sum at the end of it.
|
// and output the running sum at the end of it.
|
||||||
// If e1_f_prime < 2^140, the running sum will be 0.
|
// If e1_f_prime < 2^140, the running sum will be 0.
|
||||||
let (e1_f_prime, zs) = self.sinsemilla_config.lookup_config.witness_check(
|
let zs = self.sinsemilla_config.lookup_config.witness_check(
|
||||||
layouter.namespace(|| "Decompose low 140 bits of (e_1 + 2^4 f + 2^140 - t_P)"),
|
layouter.namespace(|| "Decompose low 140 bits of (e_1 + 2^4 f + 2^140 - t_P)"),
|
||||||
e1_f_prime,
|
e1_f_prime,
|
||||||
14,
|
14,
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
let e1_f_prime = zs[0];
|
||||||
assert_eq!(zs.len(), 15); // [z_0, z_1, ..., z_13, z_14]
|
assert_eq!(zs.len(), 15); // [z_0, z_1, ..., z_13, z_14]
|
||||||
|
|
||||||
Ok((e1_f_prime, zs[14]))
|
Ok((e1_f_prime, zs[14]))
|
||||||
|
@ -823,12 +826,13 @@ impl NoteCommitConfig {
|
||||||
g_1 + (two_pow_9 * g_2) + two_pow_140 - t_p
|
g_1 + (two_pow_9 * g_2) + two_pow_140 - t_p
|
||||||
});
|
});
|
||||||
|
|
||||||
let (g1_g2_prime, zs) = self.sinsemilla_config.lookup_config.witness_check(
|
let zs = self.sinsemilla_config.lookup_config.witness_check(
|
||||||
layouter.namespace(|| "Decompose low 140 bits of (g_1 + (2^9)g_2 + 2^140 - t_P)"),
|
layouter.namespace(|| "Decompose low 140 bits of (g_1 + (2^9)g_2 + 2^140 - t_P)"),
|
||||||
g1_g2_prime,
|
g1_g2_prime,
|
||||||
14,
|
14,
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
let g1_g2_prime = zs[0];
|
||||||
assert_eq!(zs.len(), 15); // [z_0, z_1, ..., z_13, z_14]
|
assert_eq!(zs.len(), 15); // [z_0, z_1, ..., z_13, z_14]
|
||||||
|
|
||||||
Ok((g1_g2_prime, zs[14]))
|
Ok((g1_g2_prime, zs[14]))
|
||||||
|
|
|
@ -34,7 +34,7 @@ use crate::constants::util::decompose_word;
|
||||||
use pasta_curves::arithmetic::FieldExt;
|
use pasta_curves::arithmetic::FieldExt;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
/// The running sum $[z_1, ..., z_W]$. If created in strict mode, $z_W = 0$.
|
/// The running sum $[z_0, ..., z_W]$. If created in strict mode, $z_W = 0$.
|
||||||
pub struct RunningSum<F: FieldExt + PrimeFieldBits>(Vec<CellValue<F>>);
|
pub struct RunningSum<F: FieldExt + PrimeFieldBits>(Vec<CellValue<F>>);
|
||||||
impl<F: FieldExt + PrimeFieldBits> std::ops::Deref for RunningSum<F> {
|
impl<F: FieldExt + PrimeFieldBits> std::ops::Deref for RunningSum<F> {
|
||||||
type Target = Vec<CellValue<F>>;
|
type Target = Vec<CellValue<F>>;
|
||||||
|
@ -43,6 +43,7 @@ impl<F: FieldExt + PrimeFieldBits> std::ops::Deref for RunningSum<F> {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct RunningSumConfig<F: FieldExt + PrimeFieldBits, const WINDOW_NUM_BITS: usize> {
|
pub struct RunningSumConfig<F: FieldExt + PrimeFieldBits, const WINDOW_NUM_BITS: usize> {
|
||||||
q_range_check: Selector,
|
q_range_check: Selector,
|
||||||
|
@ -103,7 +104,7 @@ impl<F: FieldExt + PrimeFieldBits, const WINDOW_NUM_BITS: usize>
|
||||||
strict: bool,
|
strict: bool,
|
||||||
word_num_bits: usize,
|
word_num_bits: usize,
|
||||||
num_windows: usize,
|
num_windows: usize,
|
||||||
) -> Result<(CellValue<F>, RunningSum<F>), Error> {
|
) -> Result<RunningSum<F>, Error> {
|
||||||
let z_0 = {
|
let z_0 = {
|
||||||
let cell = region.assign_advice(
|
let cell = region.assign_advice(
|
||||||
|| "z_0 = alpha",
|
|| "z_0 = alpha",
|
||||||
|
@ -128,7 +129,7 @@ impl<F: FieldExt + PrimeFieldBits, const WINDOW_NUM_BITS: usize>
|
||||||
strict: bool,
|
strict: bool,
|
||||||
word_num_bits: usize,
|
word_num_bits: usize,
|
||||||
num_windows: usize,
|
num_windows: usize,
|
||||||
) -> Result<(CellValue<F>, RunningSum<F>), Error> {
|
) -> Result<RunningSum<F>, Error> {
|
||||||
let z_0 = copy(region, || "copy z_0 = alpha", self.z, offset, &alpha)?;
|
let z_0 = copy(region, || "copy z_0 = alpha", self.z, offset, &alpha)?;
|
||||||
self.decompose(region, offset, z_0, strict, word_num_bits, num_windows)
|
self.decompose(region, offset, z_0, strict, word_num_bits, num_windows)
|
||||||
}
|
}
|
||||||
|
@ -146,7 +147,7 @@ impl<F: FieldExt + PrimeFieldBits, const WINDOW_NUM_BITS: usize>
|
||||||
strict: bool,
|
strict: bool,
|
||||||
word_num_bits: usize,
|
word_num_bits: usize,
|
||||||
num_windows: usize,
|
num_windows: usize,
|
||||||
) -> Result<(CellValue<F>, RunningSum<F>), Error> {
|
) -> Result<RunningSum<F>, Error> {
|
||||||
// Make sure that we do not have more windows than required for the number
|
// Make sure that we do not have more windows than required for the number
|
||||||
// of bits in the word. In other words, every window must contain at least
|
// of bits in the word. In other words, every window must contain at least
|
||||||
// one bit of the word (no empty windows).
|
// one bit of the word (no empty windows).
|
||||||
|
@ -177,8 +178,8 @@ impl<F: FieldExt + PrimeFieldBits, const WINDOW_NUM_BITS: usize>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialize empty vector to store running sum values [z_1, ..., z_W].
|
// Initialize empty vector to store running sum values [z_0, ..., z_W].
|
||||||
let mut zs: Vec<CellValue<F>> = Vec::with_capacity(num_windows);
|
let mut zs: Vec<CellValue<F>> = vec![z_0];
|
||||||
let mut z = z_0;
|
let mut z = z_0;
|
||||||
|
|
||||||
// Assign running sum `z_{i+1}` = (z_i - k_i) / (2^K) for i = 0..=n-1.
|
// Assign running sum `z_{i+1}` = (z_i - k_i) / (2^K) for i = 0..=n-1.
|
||||||
|
@ -206,13 +207,14 @@ impl<F: FieldExt + PrimeFieldBits, const WINDOW_NUM_BITS: usize>
|
||||||
z = z_next;
|
z = z_next;
|
||||||
zs.push(z);
|
zs.push(z);
|
||||||
}
|
}
|
||||||
|
assert_eq!(zs.len(), num_windows + 1);
|
||||||
|
|
||||||
if strict {
|
if strict {
|
||||||
// Constrain the final running sum output to be zero.
|
// Constrain the final running sum output to be zero.
|
||||||
region.constrain_constant(zs.last().unwrap().cell(), F::zero())?;
|
region.constrain_constant(zs.last().unwrap().cell(), F::zero())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((z_0, RunningSum(zs)))
|
Ok(RunningSum(zs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,7 +276,7 @@ mod tests {
|
||||||
|| "decompose",
|
|| "decompose",
|
||||||
|mut region| {
|
|mut region| {
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
let (alpha, _zs) = config.witness_decompose(
|
let zs = config.witness_decompose(
|
||||||
&mut region,
|
&mut region,
|
||||||
offset,
|
offset,
|
||||||
self.alpha,
|
self.alpha,
|
||||||
|
@ -282,6 +284,7 @@ mod tests {
|
||||||
WORD_NUM_BITS,
|
WORD_NUM_BITS,
|
||||||
NUM_WINDOWS,
|
NUM_WINDOWS,
|
||||||
)?;
|
)?;
|
||||||
|
let alpha = zs[0];
|
||||||
|
|
||||||
let offset = offset + NUM_WINDOWS + 1;
|
let offset = offset + NUM_WINDOWS + 1;
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,16 @@ use ff::PrimeFieldBits;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
/// The running sum $[z_0, ..., z_W]$. If created in strict mode, $z_W = 0$.
|
||||||
|
pub struct RunningSum<F: FieldExt + PrimeFieldBits>(Vec<CellValue<F>>);
|
||||||
|
impl<F: FieldExt + PrimeFieldBits> std::ops::Deref for RunningSum<F> {
|
||||||
|
type Target = Vec<CellValue<F>>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Vec<CellValue<F>> {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
#[derive(Eq, PartialEq, Debug, Clone)]
|
||||||
pub struct LookupRangeCheckConfig<F: FieldExt + PrimeFieldBits, const K: usize> {
|
pub struct LookupRangeCheckConfig<F: FieldExt + PrimeFieldBits, const K: usize> {
|
||||||
pub q_lookup: Selector,
|
pub q_lookup: Selector,
|
||||||
|
@ -125,16 +135,13 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
||||||
element: CellValue<F>,
|
element: CellValue<F>,
|
||||||
num_words: usize,
|
num_words: usize,
|
||||||
strict: bool,
|
strict: bool,
|
||||||
) -> Result<Vec<CellValue<F>>, Error> {
|
) -> Result<RunningSum<F>, Error> {
|
||||||
layouter.assign_region(
|
layouter.assign_region(
|
||||||
|| format!("{:?} words range check", num_words),
|
|| format!("{:?} words range check", num_words),
|
||||||
|mut region| {
|
|mut region| {
|
||||||
// Copy `element` and initialize running sum `z_0 = element` to decompose it.
|
// Copy `element` and initialize running sum `z_0 = element` to decompose it.
|
||||||
let z_0 = copy(&mut region, || "z_0", self.running_sum, 0, &element)?;
|
let z_0 = copy(&mut region, || "z_0", self.running_sum, 0, &element)?;
|
||||||
|
self.range_check(&mut region, z_0, num_words, strict)
|
||||||
let zs = self.range_check(&mut region, z_0, num_words, strict)?;
|
|
||||||
|
|
||||||
Ok(zs)
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -146,7 +153,7 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
||||||
value: Option<F>,
|
value: Option<F>,
|
||||||
num_words: usize,
|
num_words: usize,
|
||||||
strict: bool,
|
strict: bool,
|
||||||
) -> Result<(CellValue<F>, Vec<CellValue<F>>), Error> {
|
) -> Result<RunningSum<F>, Error> {
|
||||||
layouter.assign_region(
|
layouter.assign_region(
|
||||||
|| "Witness element",
|
|| "Witness element",
|
||||||
|mut region| {
|
|mut region| {
|
||||||
|
@ -159,10 +166,7 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
||||||
)?;
|
)?;
|
||||||
CellValue::new(cell, value)
|
CellValue::new(cell, value)
|
||||||
};
|
};
|
||||||
|
self.range_check(&mut region, z_0, num_words, strict)
|
||||||
let zs = self.range_check(&mut region, z_0, num_words, strict)?;
|
|
||||||
|
|
||||||
Ok((z_0, zs))
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -180,7 +184,7 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
||||||
element: CellValue<F>,
|
element: CellValue<F>,
|
||||||
num_words: usize,
|
num_words: usize,
|
||||||
strict: bool,
|
strict: bool,
|
||||||
) -> Result<Vec<CellValue<F>>, Error> {
|
) -> Result<RunningSum<F>, Error> {
|
||||||
// `num_words` must fit into a single field element.
|
// `num_words` must fit into a single field element.
|
||||||
assert!(num_words * K <= F::CAPACITY as usize);
|
assert!(num_words * K <= F::CAPACITY as usize);
|
||||||
let num_bits = num_words * K;
|
let num_bits = num_words * K;
|
||||||
|
@ -247,7 +251,7 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
||||||
region.constrain_constant(zs.last().unwrap().cell(), F::zero())?;
|
region.constrain_constant(zs.last().unwrap().cell(), F::zero())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(zs)
|
Ok(RunningSum(zs))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Short range check on an existing cell that is copied into this helper.
|
/// Short range check on an existing cell that is copied into this helper.
|
||||||
|
@ -440,7 +444,7 @@ mod tests {
|
||||||
for (element, expected_final_z, strict) in elements_and_expected_final_zs.iter() {
|
for (element, expected_final_z, strict) in elements_and_expected_final_zs.iter() {
|
||||||
let expected_zs = expected_zs::<F, K>(*element, self.num_words);
|
let expected_zs = expected_zs::<F, K>(*element, self.num_words);
|
||||||
|
|
||||||
let (_, zs) = config.witness_check(
|
let zs = config.witness_check(
|
||||||
layouter.namespace(|| format!("Lookup {:?}", self.num_words)),
|
layouter.namespace(|| format!("Lookup {:?}", self.num_words)),
|
||||||
Some(*element),
|
Some(*element),
|
||||||
self.num_words,
|
self.num_words,
|
||||||
|
|
Loading…
Reference in New Issue