mirror of https://github.com/zcash/orchard.git
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:
parent
69d6629ac6
commit
b363492a35
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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)))
|
||||
};
|
||||
|
||||
|
|
|
@ -238,6 +238,7 @@ impl Config {
|
|||
layouter.namespace(|| "Decompose low 130 bits of s"),
|
||||
s,
|
||||
num_words,
|
||||
false,
|
||||
)?;
|
||||
Ok(zs[zs.len() - 1])
|
||||
}
|
||||
|
|
|
@ -270,7 +270,7 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
|
|||
|| {
|
||||
let z = &constants.as_ref().unwrap().1;
|
||||
Ok(z[window])
|
||||
}
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue