mul::process_lsb(): Clean up assignments and boolean-constrain LSB.

Co-authored-by: Jack Grigg <jack@electriccoin.co>
This commit is contained in:
therealyingtong 2021-07-03 00:29:50 +08:00
parent 6ffd867e23
commit 3f961ab29a
1 changed files with 43 additions and 42 deletions

View File

@ -99,26 +99,24 @@ impl Config {
let z_1 = meta.query_advice(self.complete_config.z_complete, Rotation::prev()); let z_1 = meta.query_advice(self.complete_config.z_complete, Rotation::prev());
let z_0 = meta.query_advice(self.complete_config.z_complete, Rotation::cur()); let z_0 = meta.query_advice(self.complete_config.z_complete, Rotation::cur());
let x_p = meta.query_advice(self.add_config.x_p, Rotation::next()); let x_p = meta.query_advice(self.add_config.x_p, Rotation::prev());
let y_p = meta.query_advice(self.add_config.y_p, Rotation::next()); let y_p = meta.query_advice(self.add_config.y_p, Rotation::prev());
let x = meta.query_advice(self.add_config.x_qr, Rotation::next()); let base_x = meta.query_advice(self.add_config.x_p, Rotation::cur());
let y = meta.query_advice(self.add_config.y_qr, Rotation::next()); let base_y = meta.query_advice(self.add_config.y_p, Rotation::cur());
// z_0 = 2 * z_1 + k_0 // z_0 = 2 * z_1 + k_0
// => k_0 = z_0 - 2 * z_1 // => k_0 = z_0 - 2 * z_1
let lsb = z_0 - z_1 * pallas::Base::from_u64(2); let lsb = z_0 - z_1 * pallas::Base::from_u64(2);
let one_minus_lsb = Expression::Constant(pallas::Base::one()) - lsb.clone();
let one = Expression::Constant(pallas::Base::one()); let bool_check = lsb.clone() * one_minus_lsb.clone();
// `lsb` = 0 => (x, y) = (x_p, -y_p) // `lsb` = 0 => (x_p, y_p) = (x, -y)
let lsb0_x = (one.clone() - lsb.clone()) * (x.clone() - x_p); // `lsb` = 1 => (x_p, y_p) = (0,0)
let lsb0_y = (one - lsb.clone()) * (y.clone() + y_p); let lsb_x = (lsb.clone() * x_p.clone()) + one_minus_lsb.clone() * (x_p - base_x);
let lsb_y = (lsb * y_p.clone()) + one_minus_lsb * (y_p + base_y);
// `lsb` = 1 => (x, y) = (0,0) std::array::IntoIter::new([bool_check, lsb_x, lsb_y])
let lsb1_x = lsb.clone() * x;
let lsb1_y = lsb * y;
std::array::IntoIter::new([lsb0_x, lsb0_y, lsb1_x, lsb1_y])
.map(move |poly| q_mul_lsb.clone() * poly) .map(move |poly| q_mul_lsb.clone() * poly)
}); });
@ -157,24 +155,15 @@ impl Config {
// Initialize the running sum for scalar decomposition to zero // Initialize the running sum for scalar decomposition to zero
let z_init = { let z_init = {
// Constrain the initialization of `z` to equal zero. // Constrain the initialization of `z` to equal zero.
let fixed_zero_cell = region.assign_fixed( let z_init_val = pallas::Base::zero();
let z_init_cell = region.assign_fixed(
|| "fixed z_init = 0", || "fixed z_init = 0",
self.constants, self.constants,
offset, offset,
|| Ok(pallas::Base::zero()), || Ok(z_init_val),
)?; )?;
let z_val = pallas::Base::zero(); Z(CellValue::new(z_init_cell, Some(z_init_val)))
let z_cell = region.assign_advice(
|| "initial z",
self.hi_config.z,
offset,
|| Ok(z_val),
)?;
region.constrain_equal(&self.perm, fixed_zero_cell, z_cell)?;
Z(CellValue::new(z_cell, Some(z_val)))
}; };
// Double-and-add (incomplete addition) for the `hi` half of the scalar decomposition // Double-and-add (incomplete addition) for the `hi` half of the scalar decomposition
@ -187,13 +176,13 @@ impl Config {
)?; )?;
// Double-and-add (incomplete addition) for the `lo` half of the scalar decomposition // Double-and-add (incomplete addition) for the `lo` half of the scalar decomposition
let z = &zs_incomplete_hi.last().expect("should not be empty"); let z = zs_incomplete_hi.last().expect("should not be empty");
let (x_a, y_a, zs_incomplete_lo) = self.lo_config.double_and_add( let (x_a, y_a, zs_incomplete_lo) = self.lo_config.double_and_add(
&mut region, &mut region,
offset, offset,
&base, &base,
bits_incomplete_lo, bits_incomplete_lo,
(x_a, y_a, **z), (x_a, y_a, *z),
)?; )?;
// Move from incomplete addition to complete addition. // Move from incomplete addition to complete addition.
@ -206,7 +195,7 @@ impl Config {
// Complete addition // Complete addition
let (acc, zs_complete) = { let (acc, zs_complete) = {
let z = &zs_incomplete_lo[zs_incomplete_lo.len() - 1]; let z = zs_incomplete_lo.last().expect("should not be empty");
// Bits used in complete addition. k_{3} to k_{1} inclusive // Bits used in complete addition. k_{3} to k_{1} inclusive
// The LSB k_{0} is handled separately. // The LSB k_{0} is handled separately.
let bits_complete = &bits[COMPLETE_RANGE]; let bits_complete = &bits[COMPLETE_RANGE];
@ -268,6 +257,21 @@ impl Config {
Ok(result) Ok(result)
} }
/// Processes the final scalar bit `k_0`.
///
/// Assumptions for this sub-region:
/// - `acc_x` and `acc_y` are assigned in row `offset` by the previous complete
/// addition. They will be copied into themselves.
/// - `z_1 is assigned in row `offset` by the mul::complete region assignment. We only
/// use its value here.
///
/// `x_p` and `y_p` are assigned here, and then copied into themselves by the complete
/// addition subregion.
///
/// ```text
/// | x_p | y_p | acc_x | acc_y | complete addition | z_1 |
/// |base_x|base_y| res_x | res_y | | | | | | z_0 | q_mul_lsb = 1
/// ```
fn process_lsb( fn process_lsb(
&self, &self,
region: &mut Region<'_, pallas::Base>, region: &mut Region<'_, pallas::Base>,
@ -278,8 +282,9 @@ impl Config {
lsb: Option<bool>, lsb: Option<bool>,
) -> Result<(EccPoint, Z<pallas::Base>), Error> { ) -> Result<(EccPoint, Z<pallas::Base>), Error> {
// Enforce switching logic on LSB using a custom gate // Enforce switching logic on LSB using a custom gate
self.q_mul_lsb.enable(region, offset)?; self.q_mul_lsb.enable(region, offset + 1)?;
// z_1 has been assigned at (z_complete, offset).
// Assign z_0 = 2⋅z_1 + k_0 // Assign z_0 = 2⋅z_1 + k_0
let z_0 = { let z_0 = {
let z_0_val = z_1.value().zip(lsb).map(|(z_1, lsb)| { let z_0_val = z_1.value().zip(lsb).map(|(z_1, lsb)| {
@ -289,29 +294,27 @@ impl Config {
let z_0_cell = region.assign_advice( let z_0_cell = region.assign_advice(
|| "z_0", || "z_0",
self.complete_config.z_complete, self.complete_config.z_complete,
offset, offset + 1,
|| z_0_val.ok_or(Error::SynthesisError), || z_0_val.ok_or(Error::SynthesisError),
)?; )?;
Z(CellValue::new(z_0_cell, z_0_val)) Z(CellValue::new(z_0_cell, z_0_val))
}; };
let offset = offset + 1; // Copy in `base_x`, `base_y` to use in the LSB gate
// Copy in `x_p`, `y_p` to use in the LSB gate
copy( copy(
region, region,
|| "copy x_p", || "copy base_x",
self.add_config.x_p, self.add_config.x_p,
offset, offset + 1,
&base.x(), &base.x(),
&self.perm, &self.perm,
)?; )?;
copy( copy(
region, region,
|| "copy y_p", || "copy base_y",
self.add_config.y_p, self.add_config.y_p,
offset, offset + 1,
&base.y(), &base.y(),
&self.perm, &self.perm,
)?; )?;
@ -339,14 +342,14 @@ impl Config {
let x_cell = region.assign_advice( let x_cell = region.assign_advice(
|| "x", || "x",
self.add_config.x_qr, self.add_config.x_p,
offset, offset,
|| x.ok_or(Error::SynthesisError), || x.ok_or(Error::SynthesisError),
)?; )?;
let y_cell = region.assign_advice( let y_cell = region.assign_advice(
|| "y", || "y",
self.add_config.y_qr, self.add_config.y_p,
offset, offset,
|| y.ok_or(Error::SynthesisError), || y.ok_or(Error::SynthesisError),
)?; )?;
@ -356,8 +359,6 @@ impl Config {
y: CellValue::<pallas::Base>::new(y_cell, y), y: CellValue::<pallas::Base>::new(y_cell, y),
}; };
let offset = offset + 1;
// Return the result of the final complete addition as `[scalar]B` // Return the result of the final complete addition as `[scalar]B`
let result = self.add_config.assign_region(&p, &acc, offset, region)?; let result = self.add_config.assign_region(&p, &acc, offset, region)?;