From b363492a35a837c697db15228e38eced01d0c6ce Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Sat, 19 Jun 2021 19:08:46 +0800 Subject: [PATCH] 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. --- src/circuit/gadget/ecc.rs | 6 +++-- src/circuit/gadget/ecc/chip.rs | 24 ++++++++++++++------ src/circuit/gadget/ecc/chip/mul.rs | 25 ++++++++++----------- src/circuit/gadget/ecc/chip/mul/overflow.rs | 1 + src/circuit/gadget/ecc/chip/mul_fixed.rs | 2 +- src/circuit/gadget/sinsemilla.rs | 16 ++++++------- 6 files changed, 43 insertions(+), 31 deletions(-) diff --git a/src/circuit/gadget/ecc.rs b/src/circuit/gadget/ecc.rs index 3ae1798a..2fe3f56b 100644 --- a/src/circuit/gadget/ecc.rs +++ b/src/circuit/gadget/ecc.rs @@ -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::>(), ); - EccChip::configure(meta, advices, lookup_table, perm) + let lookup_table = meta.fixed_column(); + EccChip::configure(meta, advices, lookup_table, constants, perm) } fn synthesize( diff --git a/src/circuit/gadget/ecc/chip.rs b/src/circuit/gadget/ecc/chip.rs index aa5aa073..fa1db983 100644 --- a/src/circuit/gadget/ecc/chip.rs +++ b/src/circuit/gadget/ecc/chip.rs @@ -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, + /// Permutation over all advice columns and the `constants` fixed column. pub perm: Permutation, - /// 10-bit lookup + /// 10-bit lookup table pub lookup_config: LookupRangeCheckConfig, } @@ -149,10 +152,17 @@ impl EccChip { meta: &mut ConstraintSystem, advices: [Column; 10], lookup_table: Column, + // TODO: Replace with public inputs API + constants: [Column; 2], perm: Permutation, ) -> >::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, }; diff --git a/src/circuit/gadget/ecc/chip/mul.rs b/src/circuit/gadget/ecc/chip/mul.rs index fda5cb89..09768c06 100644 --- a/src/circuit/gadget/ecc/chip/mul.rs +++ b/src/circuit/gadget/ecc/chip/mul.rs @@ -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 = (INCOMPLETE_LEN / 2)..INCOMPLETE_LEN; const COMPLETE_RANGE: Range = 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, // 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) { - // 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))) }; diff --git a/src/circuit/gadget/ecc/chip/mul/overflow.rs b/src/circuit/gadget/ecc/chip/mul/overflow.rs index 2a741179..794d9f39 100644 --- a/src/circuit/gadget/ecc/chip/mul/overflow.rs +++ b/src/circuit/gadget/ecc/chip/mul/overflow.rs @@ -238,6 +238,7 @@ impl Config { layouter.namespace(|| "Decompose low 130 bits of s"), s, num_words, + false, )?; Ok(zs[zs.len() - 1]) } diff --git a/src/circuit/gadget/ecc/chip/mul_fixed.rs b/src/circuit/gadget/ecc/chip/mul_fixed.rs index 3c2e96e8..6cc94add 100644 --- a/src/circuit/gadget/ecc/chip/mul_fixed.rs +++ b/src/circuit/gadget/ecc/chip/mul_fixed.rs @@ -270,7 +270,7 @@ impl Config { || { let z = &constants.as_ref().unwrap().1; Ok(z[window]) - } + }, )?; } diff --git a/src/circuit/gadget/sinsemilla.rs b/src/circuit/gadget/sinsemilla.rs index 511f1b7a..11d8be46 100644 --- a/src/circuit/gadget/sinsemilla.rs +++ b/src/circuit/gadget/sinsemilla.rs @@ -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::>(), ); - 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,