mul_fixed::*: Use a separate region for complete addition assignment.

The mul_fixed regions use complete addition on the last window,
and incomplete addition on all other windows. However, the complete
addition does not depend on any offsets in the incomplete addition
region, and can be separated into a disjoint region. Since incomplete
addition uses only four advice columns, while complete addition uses
nine, separating the regions would allow the layouter to optimise
their placement.

Co-authored-by: Jack Grigg <jack@electriccoin.co>
This commit is contained in:
therealyingtong 2021-07-08 12:00:52 +08:00
parent d0e34cd204
commit 96863c9f73
3 changed files with 111 additions and 107 deletions

View File

@ -4,7 +4,7 @@ use crate::{
circuit::gadget::utilities::{
bitrange_subset, copy, lookup_range_check::LookupRangeCheckConfig, CellValue, Var,
},
constants::{self, util::decompose_scalar_fixed, NUM_WINDOWS, T_P},
constants::{self, util::decompose_scalar_fixed, T_P},
primitives::sinsemilla,
};
use halo2::{
@ -29,7 +29,7 @@ impl From<&EccConfig> for Config {
let config = Self {
base_field_fixed_mul: config.base_field_fixed_mul,
base_field_fixed_canon: config.base_field_fixed_canon,
canon_advices: [config.advices[7], config.advices[8], config.advices[9]],
canon_advices: [config.advices[6], config.advices[7], config.advices[8]],
lookup_config: config.lookup_config.clone(),
super_config: config.into(),
};
@ -205,8 +205,8 @@ impl Config {
scalar: CellValue<pallas::Base>,
base: OrchardFixedBasesFull,
) -> Result<EccPoint, Error> {
let (result, scalar) = layouter.assign_region(
|| "Base-field elem fixed-base mul",
let (scalar, acc, mul_b) = layouter.assign_region(
|| "Base-field elem fixed-base mul (incomplete addition)",
|mut region| {
let offset = 0;
@ -221,40 +221,38 @@ impl Config {
self.base_field_fixed_mul,
)?;
// Increase offset by 1 because the running sum decomposition takes
// up 86 rows (1 more than the number of windows.)
let offset = offset + 1;
// Add to the accumulator and return the final result as `[scalar]B`.
let result = self.super_config.add_config.assign_region(
&mul_b,
&acc,
offset + NUM_WINDOWS,
&mut region,
)?;
#[cfg(test)]
// Check that the correct multiple is obtained.
{
use group::Curve;
let base: super::OrchardFixedBases = base.into();
let scalar = &scalar
.base_field_elem()
.value()
.map(|scalar| pallas::Scalar::from_bytes(&scalar.to_bytes()).unwrap());
let real_mul = scalar.map(|scalar| base.generator() * scalar);
let result = result.point();
if let (Some(real_mul), Some(result)) = (real_mul, result) {
assert_eq!(real_mul.to_affine(), result);
}
}
Ok((result, scalar))
Ok((scalar, acc, mul_b))
},
)?;
// Add to the accumulator and return the final result as `[scalar]B`.
let result = layouter.assign_region(
|| "Base-field elem fixed-base mul (complete addition)",
|mut region| {
self.super_config
.add_config
.assign_region(&mul_b, &acc, 0, &mut region)
},
)?;
#[cfg(test)]
// Check that the correct multiple is obtained.
{
use group::Curve;
let base: super::OrchardFixedBases = base.into();
let scalar = &scalar
.base_field_elem()
.value()
.map(|scalar| pallas::Scalar::from_bytes(&scalar.to_bytes()).unwrap());
let real_mul = scalar.map(|scalar| base.generator() * scalar);
let result = result.point();
if let (Some(real_mul), Some(result)) = (real_mul, result) {
assert_eq!(real_mul.to_affine(), result);
}
}
// We want to enforce canonicity of a 255-bit base field element, α.
// That is, we want to check that 0 ≤ α < p, where p is Pallas base
// field modulus p = 2^254 + t_p

View File

@ -18,47 +18,49 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
scalar: &EccScalarFixed,
base: OrchardFixedBasesFull,
) -> Result<EccPoint, Error> {
layouter.assign_region(
|| "Full-width fixed-base mul",
let (acc, mul_b) = layouter.assign_region(
|| "Full-width fixed-base mul (incomplete addition)",
|mut region| {
let offset = 0;
// Copy the scalar decomposition
self.0.copy_scalar(&mut region, offset, &scalar.into())?;
let (acc, mul_b) = self.0.assign_region_inner(
self.0.assign_region_inner(
&mut region,
offset,
&scalar.into(),
base.into(),
self.0.q_mul_fixed,
)?;
// Add to the accumulator and return the final result as `[scalar]B`.
let result = self.0.add_config.assign_region(
&mul_b,
&acc,
offset + NUM_WINDOWS,
&mut region,
)?;
#[cfg(test)]
// Check that the correct multiple is obtained.
{
use group::Curve;
let base: super::OrchardFixedBases = base.into();
let real_mul = scalar.value.map(|scalar| base.generator() * scalar);
let result = result.point();
if let (Some(real_mul), Some(result)) = (real_mul, result) {
assert_eq!(real_mul.to_affine(), result);
}
}
Ok(result)
)
},
)
)?;
// Add to the accumulator and return the final result as `[scalar]B`.
let result = layouter.assign_region(
|| "Full-width fixed-base mul (last window, complete addition)",
|mut region| {
self.0
.add_config
.assign_region(&mul_b, &acc, 0, &mut region)
},
)?;
#[cfg(test)]
// Check that the correct multiple is obtained.
{
use group::Curve;
let base: super::OrchardFixedBases = base.into();
let real_mul = scalar.value.map(|scalar| base.generator() * scalar);
let result = result.point();
if let (Some(real_mul), Some(result)) = (real_mul, result) {
assert_eq!(real_mul.to_affine(), result);
}
}
Ok(result)
}
}

View File

@ -57,8 +57,8 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
scalar: &EccScalarFixedShort,
base: &ValueCommitV,
) -> Result<EccPoint, Error> {
layouter.assign_region(
|| "Short fixed-base mul",
let (acc, mul_b) = layouter.assign_region(
|| "Short fixed-base mul (incomplete addition)",
|mut region| {
let offset = 0;
@ -66,19 +66,25 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
self.super_config
.copy_scalar(&mut region, offset, &scalar.into())?;
let (acc, mul_b) = self.super_config.assign_region_inner(
self.super_config.assign_region_inner(
&mut region,
offset,
&scalar.into(),
base.clone().into(),
self.super_config.q_mul_fixed,
)?;
)
},
)?;
let result = layouter.assign_region(
|| "Short fixed-base mul (most significant word)",
|mut region| {
let offset = 0;
// Add to the cumulative sum to get `[magnitude]B`.
let magnitude_mul = self.super_config.add_config.assign_region(
&mul_b,
&acc,
offset + NUM_WINDOWS,
offset,
&mut region,
)?;
@ -90,7 +96,7 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
&mut region,
|| "sign",
self.super_config.window,
offset + NUM_WINDOWS,
offset,
&scalar.sign,
&self.super_config.perm,
)?;
@ -107,54 +113,52 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
};
// Enable mul_fixed_short selector on final row
self.q_mul_fixed_short
.enable(&mut region, offset + NUM_WINDOWS)?;
self.q_mul_fixed_short.enable(&mut region, offset)?;
// Assign final `y` to `y_p` column and return final point
let y_var = region.assign_advice(
|| "y_var",
self.super_config.y_p,
offset + NUM_WINDOWS,
offset,
|| y_val.ok_or(Error::SynthesisError),
)?;
let result = EccPoint {
Ok(EccPoint {
x: magnitude_mul.x,
y: CellValue::new(y_var, y_val),
};
#[cfg(test)]
// Check that the correct multiple is obtained.
{
use group::Curve;
let base: super::OrchardFixedBases = base.clone().into();
let scalar =
scalar
.magnitude
.zip(scalar.sign.value())
.map(|(magnitude, sign)| {
let sign = if sign == pallas::Base::one() {
pallas::Scalar::one()
} else if sign == -pallas::Base::one() {
-pallas::Scalar::one()
} else {
panic!("Sign should be 1 or -1.")
};
magnitude * sign
});
let real_mul = scalar.map(|scalar| base.generator() * scalar);
let result = result.point();
if let (Some(real_mul), Some(result)) = (real_mul, result) {
assert_eq!(real_mul.to_affine(), result);
}
}
Ok(result)
})
},
)
)?;
#[cfg(test)]
// Check that the correct multiple is obtained.
{
use group::Curve;
let base: super::OrchardFixedBases = base.clone().into();
let scalar = scalar
.magnitude
.zip(scalar.sign.value())
.map(|(magnitude, sign)| {
let sign = if sign == pallas::Base::one() {
pallas::Scalar::one()
} else if sign == -pallas::Base::one() {
-pallas::Scalar::one()
} else {
panic!("Sign should be 1 or -1.")
};
magnitude * sign
});
let real_mul = scalar.map(|scalar| base.generator() * scalar);
let result = result.point();
if let (Some(real_mul), Some(result)) = (real_mul, result) {
assert_eq!(real_mul.to_affine(), result);
}
}
Ok(result)
}
}