mirror of https://github.com/zcash/halo2.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 {
|
||||
magnitude: 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.
|
||||
|
@ -300,13 +300,13 @@ pub struct EccScalarFixedShort {
|
|||
/// 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).
|
||||
///
|
||||
/// `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
|
||||
/// `base_field_elem`.
|
||||
#[derive(Clone, Debug)]
|
||||
struct EccBaseFieldElemFixed {
|
||||
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 {
|
||||
|
|
|
@ -511,16 +511,8 @@ impl ScalarFixed {
|
|||
.collect::<Vec<_>>()
|
||||
};
|
||||
match self {
|
||||
Self::BaseFieldElem(scalar) => {
|
||||
let mut zs = vec![scalar.base_field_elem];
|
||||
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::BaseFieldElem(scalar) => running_sum_to_windows(scalar.running_sum.to_vec()),
|
||||
Self::Short(scalar) => running_sum_to_windows(scalar.running_sum.to_vec()),
|
||||
Self::FullWidth(scalar) => scalar
|
||||
.windows
|
||||
.iter()
|
||||
|
|
|
@ -166,7 +166,7 @@ impl Config {
|
|||
|
||||
// Decompose 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,
|
||||
offset,
|
||||
scalar,
|
||||
|
@ -175,7 +175,7 @@ impl Config {
|
|||
constants::NUM_WINDOWS,
|
||||
)?;
|
||||
EccBaseFieldElemFixed {
|
||||
base_field_elem,
|
||||
base_field_elem: running_sum[0],
|
||||
running_sum: (*running_sum).as_slice().try_into().unwrap(),
|
||||
}
|
||||
};
|
||||
|
@ -240,9 +240,9 @@ impl Config {
|
|||
// => z_13_alpha_0_prime = 0
|
||||
//
|
||||
let (alpha, running_sum) = (scalar.base_field_elem, &scalar.running_sum);
|
||||
let z_43_alpha = running_sum[42];
|
||||
let z_44_alpha = running_sum[43];
|
||||
let z_84_alpha = running_sum[83];
|
||||
let z_43_alpha = running_sum[43];
|
||||
let z_44_alpha = running_sum[44];
|
||||
let z_84_alpha = running_sum[84];
|
||||
|
||||
// α_0 = α - z_84_alpha * 2^252
|
||||
let alpha_0 = alpha
|
||||
|
@ -260,12 +260,13 @@ impl Config {
|
|||
let t_p = pallas::Base::from_u128(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"),
|
||||
alpha_0_prime,
|
||||
13,
|
||||
false,
|
||||
)?;
|
||||
let alpha_0_prime = zs[0];
|
||||
|
||||
(alpha_0_prime, zs[13])
|
||||
};
|
||||
|
|
|
@ -80,7 +80,7 @@ impl Config {
|
|||
let (magnitude, sign) = magnitude_sign;
|
||||
|
||||
// Decompose magnitude
|
||||
let (magnitude, running_sum) = self.running_sum_config.copy_decompose(
|
||||
let running_sum = self.running_sum_config.copy_decompose(
|
||||
region,
|
||||
offset,
|
||||
magnitude,
|
||||
|
@ -150,7 +150,7 @@ impl Config {
|
|||
// Copy last window to `u` column.
|
||||
// (Although the last window is not a `u` value; we are copying it into the `u`
|
||||
// column because there is an available cell there.)
|
||||
let z_21 = scalar.running_sum[20];
|
||||
let z_21 = scalar.running_sum[21];
|
||||
copy(
|
||||
&mut region,
|
||||
|| "last_window",
|
||||
|
|
|
@ -392,12 +392,13 @@ impl CommitIvkConfig {
|
|||
let t_p = pallas::Base::from_u128(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)"),
|
||||
a_prime,
|
||||
13,
|
||||
false,
|
||||
)?;
|
||||
let a_prime = zs[0];
|
||||
assert_eq!(zs.len(), 14); // [z_0, z_1, ..., z13_a]
|
||||
|
||||
Ok((a_prime, zs[13]))
|
||||
|
@ -428,12 +429,13 @@ impl CommitIvkConfig {
|
|||
let t_p = pallas::Base::from_u128(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)"),
|
||||
b2_c_prime,
|
||||
14,
|
||||
false,
|
||||
)?;
|
||||
let b2_c_prime = zs[0];
|
||||
assert_eq!(zs.len(), 15); // [z_0, z_1, ..., z14]
|
||||
|
||||
Ok((b2_c_prime, zs[14]))
|
||||
|
|
|
@ -710,12 +710,13 @@ impl NoteCommitConfig {
|
|||
let t_p = pallas::Base::from_u128(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)"),
|
||||
a_prime,
|
||||
13,
|
||||
false,
|
||||
)?;
|
||||
let a_prime = zs[0];
|
||||
assert_eq!(zs.len(), 14); // [z_0, z_1, ..., z_13]
|
||||
|
||||
Ok((a_prime, zs[13]))
|
||||
|
@ -748,12 +749,13 @@ impl NoteCommitConfig {
|
|||
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)"),
|
||||
b3_c_prime,
|
||||
14,
|
||||
false,
|
||||
)?;
|
||||
let b3_c_prime = zs[0];
|
||||
assert_eq!(zs.len(), 15); // [z_0, z_1, ..., z_13, z_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,
|
||||
// and output the running sum at the end of it.
|
||||
// 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)"),
|
||||
e1_f_prime,
|
||||
14,
|
||||
false,
|
||||
)?;
|
||||
let e1_f_prime = zs[0];
|
||||
assert_eq!(zs.len(), 15); // [z_0, z_1, ..., z_13, z_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
|
||||
});
|
||||
|
||||
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)"),
|
||||
g1_g2_prime,
|
||||
14,
|
||||
false,
|
||||
)?;
|
||||
let g1_g2_prime = zs[0];
|
||||
assert_eq!(zs.len(), 15); // [z_0, z_1, ..., z_13, z_14]
|
||||
|
||||
Ok((g1_g2_prime, zs[14]))
|
||||
|
|
|
@ -34,7 +34,7 @@ use crate::constants::util::decompose_word;
|
|||
use pasta_curves::arithmetic::FieldExt;
|
||||
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>>);
|
||||
impl<F: FieldExt + PrimeFieldBits> std::ops::Deref for RunningSum<F> {
|
||||
type Target = Vec<CellValue<F>>;
|
||||
|
@ -43,6 +43,7 @@ impl<F: FieldExt + PrimeFieldBits> std::ops::Deref for RunningSum<F> {
|
|||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct RunningSumConfig<F: FieldExt + PrimeFieldBits, const WINDOW_NUM_BITS: usize> {
|
||||
q_range_check: Selector,
|
||||
|
@ -103,7 +104,7 @@ impl<F: FieldExt + PrimeFieldBits, const WINDOW_NUM_BITS: usize>
|
|||
strict: bool,
|
||||
word_num_bits: usize,
|
||||
num_windows: usize,
|
||||
) -> Result<(CellValue<F>, RunningSum<F>), Error> {
|
||||
) -> Result<RunningSum<F>, Error> {
|
||||
let z_0 = {
|
||||
let cell = region.assign_advice(
|
||||
|| "z_0 = alpha",
|
||||
|
@ -128,7 +129,7 @@ impl<F: FieldExt + PrimeFieldBits, const WINDOW_NUM_BITS: usize>
|
|||
strict: bool,
|
||||
word_num_bits: 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)?;
|
||||
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,
|
||||
word_num_bits: 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
|
||||
// of bits in the word. In other words, every window must contain at least
|
||||
// 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].
|
||||
let mut zs: Vec<CellValue<F>> = Vec::with_capacity(num_windows);
|
||||
// Initialize empty vector to store running sum values [z_0, ..., z_W].
|
||||
let mut zs: Vec<CellValue<F>> = vec![z_0];
|
||||
let mut z = z_0;
|
||||
|
||||
// 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;
|
||||
zs.push(z);
|
||||
}
|
||||
assert_eq!(zs.len(), num_windows + 1);
|
||||
|
||||
if strict {
|
||||
// Constrain the final running sum output to be 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",
|
||||
|mut region| {
|
||||
let offset = 0;
|
||||
let (alpha, _zs) = config.witness_decompose(
|
||||
let zs = config.witness_decompose(
|
||||
&mut region,
|
||||
offset,
|
||||
self.alpha,
|
||||
|
@ -282,6 +284,7 @@ mod tests {
|
|||
WORD_NUM_BITS,
|
||||
NUM_WINDOWS,
|
||||
)?;
|
||||
let alpha = zs[0];
|
||||
|
||||
let offset = offset + NUM_WINDOWS + 1;
|
||||
|
||||
|
|
|
@ -13,6 +13,16 @@ use ff::PrimeFieldBits;
|
|||
|
||||
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)]
|
||||
pub struct LookupRangeCheckConfig<F: FieldExt + PrimeFieldBits, const K: usize> {
|
||||
pub q_lookup: Selector,
|
||||
|
@ -125,16 +135,13 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
|||
element: CellValue<F>,
|
||||
num_words: usize,
|
||||
strict: bool,
|
||||
) -> Result<Vec<CellValue<F>>, Error> {
|
||||
) -> Result<RunningSum<F>, Error> {
|
||||
layouter.assign_region(
|
||||
|| format!("{:?} words range check", num_words),
|
||||
|mut region| {
|
||||
// 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 zs = self.range_check(&mut region, z_0, num_words, strict)?;
|
||||
|
||||
Ok(zs)
|
||||
self.range_check(&mut region, z_0, num_words, strict)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -146,7 +153,7 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
|||
value: Option<F>,
|
||||
num_words: usize,
|
||||
strict: bool,
|
||||
) -> Result<(CellValue<F>, Vec<CellValue<F>>), Error> {
|
||||
) -> Result<RunningSum<F>, Error> {
|
||||
layouter.assign_region(
|
||||
|| "Witness element",
|
||||
|mut region| {
|
||||
|
@ -159,10 +166,7 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
|||
)?;
|
||||
CellValue::new(cell, value)
|
||||
};
|
||||
|
||||
let zs = self.range_check(&mut region, z_0, num_words, strict)?;
|
||||
|
||||
Ok((z_0, zs))
|
||||
self.range_check(&mut region, z_0, num_words, strict)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -180,7 +184,7 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
|||
element: CellValue<F>,
|
||||
num_words: usize,
|
||||
strict: bool,
|
||||
) -> Result<Vec<CellValue<F>>, Error> {
|
||||
) -> Result<RunningSum<F>, Error> {
|
||||
// `num_words` must fit into a single field element.
|
||||
assert!(num_words * K <= F::CAPACITY as usize);
|
||||
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())?;
|
||||
}
|
||||
|
||||
Ok(zs)
|
||||
Ok(RunningSum(zs))
|
||||
}
|
||||
|
||||
/// 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() {
|
||||
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)),
|
||||
Some(*element),
|
||||
self.num_words,
|
||||
|
|
Loading…
Reference in New Issue