ecc::chip.rs: Introduce circuit-wide "constants" fixed column

At certain points in the circuit, we need to constrain cells in
advice columns to equal a fixed constant. Instead of defining a
new fixed column for each constant, we pass around a single
shared by all chips, that is included in the permutation over all
advice columns.

This lets us load all needed constants into a single column and
directly constrain advice cells with an equality constraint.
This commit is contained in:
therealyingtong 2021-06-19 19:08:46 +08:00
parent 69d6629ac6
commit b363492a35
6 changed files with 43 additions and 31 deletions

View File

@ -454,15 +454,17 @@ mod tests {
meta.advice_column(),
];
let lookup_table = meta.fixed_column();
let constants = [meta.fixed_column(), meta.fixed_column()];
let perm = meta.permutation(
&advices
.iter()
.map(|advice| (*advice).into())
.chain(constants.iter().map(|fixed| (*fixed).into()))
.collect::<Vec<_>>(),
);
EccChip::configure(meta, advices, lookup_table, perm)
let lookup_table = meta.fixed_column();
EccChip::configure(meta, advices, lookup_table, constants, perm)
}
fn synthesize(

View File

@ -91,8 +91,6 @@ pub struct EccConfig {
pub q_mul_hi: Selector,
/// Variable-base scalar multiplication (lo half)
pub q_mul_lo: Selector,
/// Selector used to initialize running sum to zero in variable-base scalar mul
pub q_init_z: Selector,
/// Selector used to enforce boolean decomposition in variable-base scalar mul
pub q_mul_decompose_var: Selector,
/// Selector used to enforce switching logic on LSB in variable-base scalar mul
@ -109,14 +107,19 @@ pub struct EccConfig {
/// Witness point
pub q_point: Selector,
/// Witness full-width scalar for fixed-base scalar mul
pub q_scalar_fixed: Selector,
/// Witness signed short scalar for full-width fixed-base scalar mul
pub q_scalar_fixed_short: Selector,
/// Permutation
/// Shared fixed column used for loading constants. This is included in
/// the permutation so that cells in advice columns can be constrained to
/// equal cells in this fixed column.
pub constants: Column<Fixed>,
/// Permutation over all advice columns and the `constants` fixed column.
pub perm: Permutation,
/// 10-bit lookup
/// 10-bit lookup table
pub lookup_config: LookupRangeCheckConfig<pallas::Base, { sinsemilla::K }>,
}
@ -149,10 +152,17 @@ impl EccChip {
meta: &mut ConstraintSystem<pallas::Base>,
advices: [Column<Advice>; 10],
lookup_table: Column<Fixed>,
// TODO: Replace with public inputs API
constants: [Column<Fixed>; 2],
perm: Permutation,
) -> <Self as Chip<pallas::Base>>::Config {
let lookup_config =
LookupRangeCheckConfig::configure(meta, advices[9], lookup_table, perm.clone());
let lookup_config = LookupRangeCheckConfig::configure(
meta,
advices[9],
constants[0],
lookup_table,
perm.clone(),
);
let config = EccConfig {
advices,
@ -171,7 +181,6 @@ impl EccChip {
q_add: meta.selector(),
q_mul_hi: meta.selector(),
q_mul_lo: meta.selector(),
q_init_z: meta.selector(),
q_mul_decompose_var: meta.selector(),
q_mul_overflow: meta.selector(),
q_mul_lsb: meta.selector(),
@ -181,6 +190,7 @@ impl EccChip {
q_point: meta.selector(),
q_scalar_fixed: meta.selector(),
q_scalar_fixed_short: meta.selector(),
constants: constants[1],
perm,
lookup_config,
};

View File

@ -10,7 +10,7 @@ use ff::PrimeField;
use halo2::{
arithmetic::FieldExt,
circuit::{Layouter, Region},
plonk::{ConstraintSystem, Error, Expression, Permutation, Selector},
plonk::{Column, ConstraintSystem, Error, Expression, Fixed, Permutation, Selector},
poly::Rotation,
};
@ -37,8 +37,8 @@ const INCOMPLETE_LO_RANGE: Range<usize> = (INCOMPLETE_LEN / 2)..INCOMPLETE_LEN;
const COMPLETE_RANGE: Range<usize> = INCOMPLETE_LEN..(INCOMPLETE_LEN + NUM_COMPLETE_BITS);
pub struct Config {
// Selector used to constrain the initialization of the running sum to be zero.
q_init_z: Selector,
// Fixed column used to constrain the initialization of the running sum to be zero.
constants: Column<Fixed>,
// Selector used to check z_i = 2*z_{i+1} + k_i
q_mul_decompose_var: Selector,
// Selector used to check switching logic on LSB
@ -60,7 +60,7 @@ pub struct Config {
impl From<&EccConfig> for Config {
fn from(ecc_config: &EccConfig) -> Self {
let config = Self {
q_init_z: ecc_config.q_init_z,
constants: ecc_config.constants,
q_mul_decompose_var: ecc_config.q_mul_decompose_var,
q_mul_lsb: ecc_config.q_mul_lsb,
perm: ecc_config.perm.clone(),
@ -96,14 +96,6 @@ impl From<&EccConfig> for Config {
impl Config {
pub(super) fn create_gate(&self, meta: &mut ConstraintSystem<pallas::Base>) {
// Gate used to check that the running sum for scalar decomposition is initialized to zero.
meta.create_gate("Initialize running sum for variable-base mul", |meta| {
let q_init_z = meta.query_selector(self.q_init_z);
let z = meta.query_advice(self.hi_config.z, Rotation::cur());
vec![q_init_z * z]
});
// If `lsb` is 0, (x, y) = (x_p, -y_p). If `lsb` is 1, (x, y) = (0,0).
meta.create_gate("LSB check", |meta| {
let q_mul_lsb = meta.query_selector(self.q_mul_lsb);
@ -168,7 +160,12 @@ impl Config {
// Initialize the running sum for scalar decomposition to zero
let z_init = {
// Constrain the initialization of `z` to equal zero.
self.q_init_z.enable(&mut region, offset)?;
let fixed_zero_cell = region.assign_fixed(
|| "fixed z_init = 0",
self.constants,
offset,
|| Ok(pallas::Base::zero()),
)?;
let z_val = pallas::Base::zero();
let z_cell = region.assign_advice(
@ -178,6 +175,8 @@ impl Config {
|| Ok(z_val),
)?;
region.constrain_equal(&self.perm, fixed_zero_cell, z_cell)?;
Z(CellValue::new(z_cell, Some(z_val)))
};

View File

@ -238,6 +238,7 @@ impl Config {
layouter.namespace(|| "Decompose low 130 bits of s"),
s,
num_words,
false,
)?;
Ok(zs[zs.len() - 1])
}

View File

@ -270,7 +270,7 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
|| {
let z = &constants.as_ref().unwrap().1;
Ok(z[window])
}
},
)?;
}

View File

@ -355,6 +355,11 @@ mod tests {
meta.fixed_column(),
meta.fixed_column(),
];
let ecc_constants = [meta.fixed_column(), meta.fixed_column()];
let table_idx = meta.fixed_column();
// Fixed columns for the Sinsemilla generator lookup table
let lookup = (table_idx, meta.fixed_column(), meta.fixed_column());
let perm = meta.permutation(
&advices
@ -362,17 +367,12 @@ mod tests {
.map(|advice| (*advice).into())
.chain(constants_1.iter().map(|fixed| (*fixed).into()))
.chain(constants_2.iter().map(|fixed| (*fixed).into()))
.chain(ecc_constants.iter().map(|fixed| (*fixed).into()))
.collect::<Vec<_>>(),
);
let ecc_config = EccChip::configure(meta, advices, perm.clone());
// Fixed columns for the Sinsemilla generator lookup table
let lookup = (
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
);
let ecc_config =
EccChip::configure(meta, advices, table_idx, ecc_constants, perm.clone());
let config1 = SinsemillaChip::configure(
meta,