De-duplicate LookupRangeCheckConfig

We were configuring multiple instances of this across all of the advice
columns, in order to spread their assignments. However, we are actually
more constrained by columns than rows, and we have comparatively few
rows of range check logic required for the Action circuit.

We now use a single LookupRangeCheckConfig for the entire circuit. The
reduction in lookup arguments and fixed columns cuts the proof size in
half (now at 6048 bytes when using `floor_planner::V1`).

Co-authored-by: therealyingtong <yingtong@z.cash>
This commit is contained in:
Jack Grigg 2021-07-21 15:59:08 +01:00
parent 5e6c8ae380
commit bf72e308bd
10 changed files with 117 additions and 75 deletions

View File

@ -62,6 +62,8 @@ use gadget::{
use std::convert::TryInto;
use self::gadget::utilities::lookup_range_check::LookupRangeCheckConfig;
pub(crate) mod gadget;
/// Size of the Orchard circuit.
@ -221,9 +223,13 @@ impl plonk::Circuit<pallas::Base> for Circuit {
let rc_a = lagrange_coeffs[2..5].try_into().unwrap();
let rc_b = lagrange_coeffs[5..8].try_into().unwrap();
// We have a lot of free space in the right-most advice columns; use one of them
// for all of our range checks.
let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx);
// Configuration for curve point operations.
// This uses 10 advice columns and spans the whole circuit.
let ecc_config = EccChip::configure(meta, advices, table_idx, lagrange_coeffs);
let ecc_config = EccChip::configure(meta, advices, lagrange_coeffs, range_check.clone());
// Configuration for the Poseidon hash.
let poseidon_config = PoseidonChip::configure(
@ -243,8 +249,12 @@ impl plonk::Circuit<pallas::Base> for Circuit {
// Since the Sinsemilla config uses only 5 advice columns,
// we can fit two instances side-by-side.
let (sinsemilla_config_1, merkle_config_1) = {
let sinsemilla_config_1 =
SinsemillaChip::configure(meta, advices[..5].try_into().unwrap(), lookup);
let sinsemilla_config_1 = SinsemillaChip::configure(
meta,
advices[..5].try_into().unwrap(),
lookup,
range_check.clone(),
);
let merkle_config_1 = MerkleChip::configure(meta, sinsemilla_config_1.clone());
(sinsemilla_config_1, merkle_config_1)
@ -255,8 +265,12 @@ impl plonk::Circuit<pallas::Base> for Circuit {
// Since the Sinsemilla config uses only 5 advice columns,
// we can fit two instances side-by-side.
let (sinsemilla_config_2, merkle_config_2) = {
let sinsemilla_config_2 =
SinsemillaChip::configure(meta, advices[5..].try_into().unwrap(), lookup);
let sinsemilla_config_2 = SinsemillaChip::configure(
meta,
advices[5..].try_into().unwrap(),
lookup,
range_check,
);
let merkle_config_2 = MerkleChip::configure(meta, sinsemilla_config_2.clone());
(sinsemilla_config_2, merkle_config_2)

View File

@ -407,6 +407,7 @@ mod tests {
use pasta_curves::pallas;
use super::chip::{EccChip, EccConfig};
use crate::circuit::gadget::utilities::lookup_range_check::LookupRangeCheckConfig;
struct MyCircuit {}
@ -447,7 +448,8 @@ mod tests {
let constants = meta.fixed_column();
meta.enable_constant(constants);
EccChip::configure(meta, advices, lookup_table, lagrange_coeffs)
let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table);
EccChip::configure(meta, advices, lagrange_coeffs, range_check)
}
fn synthesize(

View File

@ -152,8 +152,8 @@ impl EccChip {
pub fn configure(
meta: &mut ConstraintSystem<pallas::Base>,
advices: [Column<Advice>; 10],
lookup_table: Column<Fixed>,
lagrange_coeffs: [Column<Fixed>; 8],
range_check: LookupRangeCheckConfig<pallas::Base, { sinsemilla::K }>,
) -> <Self as Chip<pallas::Base>>::Config {
// The following columns need to be equality-enabled for their use in sub-configs:
//
@ -186,8 +186,6 @@ impl EccChip {
meta.enable_equality((*column).into());
}
let lookup_config = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table);
let q_mul_fixed_running_sum = meta.selector();
let running_sum_config =
RunningSumConfig::configure(meta, q_mul_fixed_running_sum, advices[4]);
@ -208,7 +206,7 @@ impl EccChip {
q_mul_fixed_base_field: meta.selector(),
q_mul_fixed_running_sum,
q_point: meta.selector(),
lookup_config,
lookup_config: range_check,
running_sum_config,
};

View File

@ -247,7 +247,7 @@ pub mod tests {
use crate::circuit::gadget::{
ecc::{chip::EccChip, FixedPointShort, Point},
utilities::{CellValue, UtilitiesInstructions},
utilities::{lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions},
};
use crate::constants::load::ValueCommitV;
@ -420,7 +420,8 @@ pub mod tests {
let constants = meta.fixed_column();
meta.enable_constant(constants);
EccChip::configure(meta, advices, lookup_table, lagrange_coeffs)
let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table);
EccChip::configure(meta, advices, lagrange_coeffs, range_check)
}
fn synthesize(

View File

@ -416,9 +416,12 @@ mod tests {
};
use crate::{
circuit::gadget::ecc::{
chip::{EccChip, EccConfig},
Point,
circuit::gadget::{
ecc::{
chip::{EccChip, EccConfig},
Point,
},
utilities::lookup_range_check::LookupRangeCheckConfig,
},
constants::{COMMIT_IVK_PERSONALIZATION, MERKLE_CRH_PERSONALIZATION},
primitives::sinsemilla::{self, K},
@ -473,10 +476,23 @@ mod tests {
// Fixed columns for the Sinsemilla generator lookup table
let lookup = (table_idx, meta.fixed_column(), meta.fixed_column());
let ecc_config = EccChip::configure(meta, advices, table_idx, lagrange_coeffs);
let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx);
let config1 = SinsemillaChip::configure(meta, advices[..5].try_into().unwrap(), lookup);
let config2 = SinsemillaChip::configure(meta, advices[5..].try_into().unwrap(), lookup);
let ecc_config =
EccChip::configure(meta, advices, lagrange_coeffs, range_check.clone());
let config1 = SinsemillaChip::configure(
meta,
advices[..5].try_into().unwrap(),
lookup,
range_check.clone(),
);
let config2 = SinsemillaChip::configure(
meta,
advices[5..].try_into().unwrap(),
lookup,
range_check,
);
(ecc_config, config1, config2)
}

View File

@ -56,12 +56,8 @@ pub struct SinsemillaConfig {
/// The lookup table where $(\mathsf{idx}, x_p, y_p)$ are loaded for the $2^K$
/// generators of the Sinsemilla hash.
pub(super) generator_table: GeneratorTableConfig,
/// Configure each advice column to be able to perform lookup range checks.
pub(super) lookup_config_0: LookupRangeCheckConfig<pallas::Base, { sinsemilla::K }>,
pub(super) lookup_config_1: LookupRangeCheckConfig<pallas::Base, { sinsemilla::K }>,
pub(super) lookup_config_2: LookupRangeCheckConfig<pallas::Base, { sinsemilla::K }>,
pub(super) lookup_config_3: LookupRangeCheckConfig<pallas::Base, { sinsemilla::K }>,
pub(super) lookup_config_4: LookupRangeCheckConfig<pallas::Base, { sinsemilla::K }>,
/// An advice column configured to perform lookup range checks.
pub(super) lookup_config: LookupRangeCheckConfig<pallas::Base, { sinsemilla::K }>,
}
impl SinsemillaConfig {
@ -111,16 +107,8 @@ impl SinsemillaChip {
meta: &mut ConstraintSystem<pallas::Base>,
advices: [Column<Advice>; 5],
lookup: (Column<Fixed>, Column<Fixed>, Column<Fixed>),
range_check: LookupRangeCheckConfig<pallas::Base, { sinsemilla::K }>,
) -> <Self as Chip<pallas::Base>>::Config {
// This chip requires all advice columns and the `constants` fixed columns to be
// equality-enabled. The advice columns and the first five `constants` columns
// are equality-enabled by the calls to LookupRangeCheckConfig::configure.
let lookup_config_0 = LookupRangeCheckConfig::configure(meta, advices[0], lookup.0);
let lookup_config_1 = LookupRangeCheckConfig::configure(meta, advices[1], lookup.0);
let lookup_config_2 = LookupRangeCheckConfig::configure(meta, advices[2], lookup.0);
let lookup_config_3 = LookupRangeCheckConfig::configure(meta, advices[3], lookup.0);
let lookup_config_4 = LookupRangeCheckConfig::configure(meta, advices[4], lookup.0);
let config = SinsemillaConfig {
q_sinsemilla1: meta.selector(),
q_sinsemilla2: meta.fixed_column(),
@ -135,11 +123,7 @@ impl SinsemillaChip {
table_x: lookup.1,
table_y: lookup.2,
},
lookup_config_0,
lookup_config_1,
lookup_config_2,
lookup_config_3,
lookup_config_4,
lookup_config: range_check,
};
// Set up lookup argument

View File

@ -263,13 +263,13 @@ impl CommitIvkConfig {
});
// Constrain b_0 to be 4 bits.
let b_0 = self.sinsemilla_config.lookup_config_0.witness_short_check(
let b_0 = self.sinsemilla_config.lookup_config.witness_short_check(
layouter.namespace(|| "b_0 is 4 bits"),
b_0,
4,
)?;
// Constrain b_2 to be 5 bits.
let b_2 = self.sinsemilla_config.lookup_config_1.witness_short_check(
let b_2 = self.sinsemilla_config.lookup_config.witness_short_check(
layouter.namespace(|| "b_2 is 5 bits"),
b_2,
5,
@ -307,7 +307,7 @@ impl CommitIvkConfig {
.map(|(d_0, d_1)| d_0 + d_1 * pallas::Base::from_u64(1 << 9));
// Constrain d_0 to be 9 bits.
let d_0 = self.sinsemilla_config.lookup_config_2.witness_short_check(
let d_0 = self.sinsemilla_config.lookup_config.witness_short_check(
layouter.namespace(|| "d_0 is 9 bits"),
d_0,
9,
@ -400,7 +400,7 @@ impl CommitIvkConfig {
let t_p = pallas::Base::from_u128(T_P);
a + two_pow_130 - t_p
});
let (a_prime, zs) = self.sinsemilla_config.lookup_config_3.witness_check(
let (a_prime, zs) = self.sinsemilla_config.lookup_config.witness_check(
layouter.namespace(|| "Decompose low 130 bits of (a + 2^130 - t_P)"),
a_prime,
13,
@ -436,7 +436,7 @@ impl CommitIvkConfig {
let t_p = pallas::Base::from_u128(T_P);
b_2 + c * two_pow_5 + two_pow_140 - t_p
});
let (b2_c_prime, zs) = self.sinsemilla_config.lookup_config_4.witness_check(
let (b2_c_prime, zs) = self.sinsemilla_config.lookup_config.witness_check(
layouter.namespace(|| "Decompose low 140 bits of (b_2 + c * 2^5 + 2^140 - t_P)"),
b2_c_prime,
14,
@ -629,7 +629,9 @@ mod tests {
circuit::gadget::{
ecc::chip::{EccChip, EccConfig},
sinsemilla::chip::SinsemillaChip,
utilities::{CellValue, UtilitiesInstructions},
utilities::{
lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions,
},
},
constants::T_Q,
};
@ -696,12 +698,18 @@ mod tests {
meta.fixed_column(),
];
let sinsemilla_config =
SinsemillaChip::configure(meta, advices[..5].try_into().unwrap(), lookup);
let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx);
let sinsemilla_config = SinsemillaChip::configure(
meta,
advices[..5].try_into().unwrap(),
lookup,
range_check.clone(),
);
let commit_ivk_config =
CommitIvkConfig::configure(meta, advices, sinsemilla_config);
let ecc_config = EccChip::configure(meta, advices, table_idx, lagrange_coeffs);
let ecc_config = EccChip::configure(meta, advices, lagrange_coeffs, range_check);
(commit_ivk_config, ecc_config)
}

View File

@ -139,7 +139,7 @@ pub mod tests {
use crate::{
circuit::gadget::{
sinsemilla::chip::{SinsemillaChip, SinsemillaHashDomains},
utilities::{UtilitiesInstructions, Var},
utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions, Var},
},
constants::{L_ORCHARD_BASE, MERKLE_CRH_PERSONALIZATION, MERKLE_DEPTH_ORCHARD},
primitives::sinsemilla::HashDomain,
@ -198,12 +198,22 @@ pub mod tests {
meta.fixed_column(),
);
let sinsemilla_config_1 =
SinsemillaChip::configure(meta, advices[5..].try_into().unwrap(), lookup);
let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup.0);
let sinsemilla_config_1 = SinsemillaChip::configure(
meta,
advices[5..].try_into().unwrap(),
lookup,
range_check.clone(),
);
let config1 = MerkleChip::configure(meta, sinsemilla_config_1);
let sinsemilla_config_2 =
SinsemillaChip::configure(meta, advices[..5].try_into().unwrap(), lookup);
let sinsemilla_config_2 = SinsemillaChip::configure(
meta,
advices[..5].try_into().unwrap(),
lookup,
range_check,
);
let config2 = MerkleChip::configure(meta, sinsemilla_config_2);
(config1, config2)

View File

@ -214,10 +214,11 @@ impl MerkleInstructions<pallas::Affine, MERKLE_DEPTH_ORCHARD, { sinsemilla::K },
.value()
.map(|value| bitrange_subset(value, 250..L_ORCHARD_BASE));
config
.sinsemilla_config
.lookup_config_0
.witness_short_check(layouter.namespace(|| "Constrain b_1 to 5 bits"), b_1, 5)?
config.sinsemilla_config.lookup_config.witness_short_check(
layouter.namespace(|| "Constrain b_1 to 5 bits"),
b_1,
5,
)?
};
// b_2 = (bits 0..=4 of `right`)
@ -225,10 +226,11 @@ impl MerkleInstructions<pallas::Affine, MERKLE_DEPTH_ORCHARD, { sinsemilla::K },
let b_2 = {
let b_2 = right.value().map(|value| bitrange_subset(value, 0..5));
config
.sinsemilla_config
.lookup_config_1
.witness_short_check(layouter.namespace(|| "Constrain b_2 to 5 bits"), b_2, 5)?
config.sinsemilla_config.lookup_config.witness_short_check(
layouter.namespace(|| "Constrain b_2 to 5 bits"),
b_2,
5,
)?
};
let b = {

View File

@ -454,14 +454,14 @@ impl NoteCommitConfig {
let b_3 = pkd_x.map(|pkd_x| bitrange_subset(pkd_x, 0..4));
// Constrain b_0 to be 4 bits
let b_0 = self.sinsemilla_config.lookup_config_0.witness_short_check(
let b_0 = self.sinsemilla_config.lookup_config.witness_short_check(
layouter.namespace(|| "b_0 is 4 bits"),
b_0,
4,
)?;
// Constrain b_3 to be 4 bits
let b_3 = self.sinsemilla_config.lookup_config_1.witness_short_check(
let b_3 = self.sinsemilla_config.lookup_config.witness_short_check(
layouter.namespace(|| "b_3 is 4 bits"),
b_3,
4,
@ -499,7 +499,7 @@ impl NoteCommitConfig {
let d_3 = value_val.map(|value| bitrange_subset(value, 8..58));
// Constrain d_2 to be 8 bits
let d_2 = self.sinsemilla_config.lookup_config_2.witness_short_check(
let d_2 = self.sinsemilla_config.lookup_config.witness_short_check(
layouter.namespace(|| "d_2 is 8 bits"),
d_2,
8,
@ -530,14 +530,14 @@ impl NoteCommitConfig {
let e_1 = rho_val.map(|rho| bitrange_subset(rho, 0..4));
// Constrain e_0 to be 6 bits.
let e_0 = self.sinsemilla_config.lookup_config_3.witness_short_check(
let e_0 = self.sinsemilla_config.lookup_config.witness_short_check(
layouter.namespace(|| "e_0 is 6 bits"),
e_0,
6,
)?;
// Constrain e_1 to be 4 bits.
let e_1 = self.sinsemilla_config.lookup_config_4.witness_short_check(
let e_1 = self.sinsemilla_config.lookup_config.witness_short_check(
layouter.namespace(|| "e_1 is 4 bits"),
e_1,
4,
@ -566,7 +566,7 @@ impl NoteCommitConfig {
let g_2 = psi_val.map(|psi| bitrange_subset(psi, 9..249));
// Constrain g_1 to be 9 bits.
let g_1 = self.sinsemilla_config.lookup_config_0.witness_short_check(
let g_1 = self.sinsemilla_config.lookup_config.witness_short_check(
layouter.namespace(|| "g_1 is 9 bits"),
g_1,
9,
@ -592,7 +592,7 @@ impl NoteCommitConfig {
let h_1 = psi_val.map(|psi| bitrange_subset(psi, 254..255));
// Constrain h_0 to be 5 bits.
let h_0 = self.sinsemilla_config.lookup_config_1.witness_short_check(
let h_0 = self.sinsemilla_config.lookup_config.witness_short_check(
layouter.namespace(|| "h_0 is 5 bits"),
h_0,
5,
@ -728,7 +728,7 @@ impl NoteCommitConfig {
let t_p = pallas::Base::from_u128(T_P);
a + two_pow_130 - t_p
});
let (a_prime, zs) = self.sinsemilla_config.lookup_config_0.witness_check(
let (a_prime, zs) = self.sinsemilla_config.lookup_config.witness_check(
layouter.namespace(|| "Decompose low 130 bits of (a + 2^130 - t_P)"),
a_prime,
13,
@ -766,7 +766,7 @@ impl NoteCommitConfig {
b_3 + (two_pow_4 * c) + two_pow_140 - t_p
});
let (b3_c_prime, zs) = self.sinsemilla_config.lookup_config_1.witness_check(
let (b3_c_prime, zs) = self.sinsemilla_config.lookup_config.witness_check(
layouter.namespace(|| "Decompose low 140 bits of (b_3 + 2^4 c + 2^140 - t_P)"),
b3_c_prime,
14,
@ -805,7 +805,7 @@ impl NoteCommitConfig {
// Decompose the low 140 bits of e1_f_prime = e_1 + 2^4 f + 2^140 - t_P,
// and output the running sum at the end of it.
// If e1_f_prime < 2^140, the running sum will be 0.
let (e1_f_prime, zs) = self.sinsemilla_config.lookup_config_1.witness_check(
let (e1_f_prime, zs) = self.sinsemilla_config.lookup_config.witness_check(
layouter.namespace(|| "Decompose low 140 bits of (e_1 + 2^4 f + 2^140 - t_P)"),
e1_f_prime,
14,
@ -841,7 +841,7 @@ impl NoteCommitConfig {
g_1 + (two_pow_9 * g_2) + two_pow_140 - t_p
});
let (g1_g2_prime, zs) = self.sinsemilla_config.lookup_config_2.witness_check(
let (g1_g2_prime, zs) = self.sinsemilla_config.lookup_config.witness_check(
layouter.namespace(|| "Decompose low 140 bits of (g_1 + (2^9)g_2 + 2^140 - t_P)"),
g1_g2_prime,
14,
@ -1282,7 +1282,9 @@ mod tests {
Point,
},
sinsemilla::chip::SinsemillaChip,
utilities::{CellValue, UtilitiesInstructions},
utilities::{
lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions,
},
},
constants::T_Q,
};
@ -1358,12 +1360,17 @@ mod tests {
meta.fixed_column(),
];
let sinsemilla_config =
SinsemillaChip::configure(meta, advices[..5].try_into().unwrap(), lookup);
let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx);
let sinsemilla_config = SinsemillaChip::configure(
meta,
advices[..5].try_into().unwrap(),
lookup,
range_check.clone(),
);
let note_commit_config =
NoteCommitConfig::configure(meta, advices, sinsemilla_config);
let ecc_config = EccChip::configure(meta, advices, table_idx, lagrange_coeffs);
let ecc_config = EccChip::configure(meta, advices, lagrange_coeffs, range_check);
(note_commit_config, ecc_config)
}