mul::incomplete: Refactor incomplete::Config.

This is only used in chip::mul::Config. In a subsequent commit,
this will be configured from mul::Config instead of from
ecc::chip::Config.

This commit does not result in circuit changes.
This commit is contained in:
therealyingtong 2021-11-30 15:59:29 -05:00 committed by Jack Grigg
parent 0ede6b2301
commit 22f57005a9
3 changed files with 67 additions and 75 deletions

View File

@ -145,9 +145,9 @@ pub struct EccConfig {
add: add::Config,
/// Variable-base scalar multiplication (hi half)
pub q_mul_hi: (Selector, Selector, Selector),
mul_hi: mul::incomplete::Config<{ mul::INCOMPLETE_HI_LEN }>,
/// Variable-base scalar multiplication (lo half)
pub q_mul_lo: (Selector, Selector, Selector),
mul_lo: mul::incomplete::Config<{ mul::INCOMPLETE_LO_LEN }>,
/// 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
@ -253,14 +253,23 @@ impl EccChip {
advices[6], advices[7], advices[8],
);
// Components of mul::Config
// TODO: Move this into mul::Config.
let mul_hi = mul::incomplete::Config::configure(
meta, advices[9], advices[3], advices[0], advices[1], advices[4], advices[5],
);
let mul_lo = mul::incomplete::Config::configure(
meta, advices[6], advices[7], advices[0], advices[1], advices[8], advices[2],
);
let config = EccConfig {
advices,
lagrange_coeffs,
fixed_z: meta.fixed_column(),
add_incomplete,
add,
q_mul_hi: (meta.selector(), meta.selector(), meta.selector()),
q_mul_lo: (meta.selector(), meta.selector(), meta.selector()),
mul_hi,
mul_lo,
q_mul_decompose_var: meta.selector(),
q_mul_overflow: meta.selector(),
q_mul_lsb: meta.selector(),

View File

@ -17,7 +17,8 @@ use halo2::{
use pasta_curves::pallas;
mod complete;
mod incomplete;
// TODO: Undo this pub(crate).
pub(crate) mod incomplete;
mod overflow;
/// Number of bits for which complete addition needs to be used in variable-base
@ -33,10 +34,12 @@ const INCOMPLETE_RANGE: Range<usize> = 0..INCOMPLETE_LEN;
// (It is a coincidence that k_{130} matches the boundary of the
// overflow check described in [the book](https://zcash.github.io/halo2/design/gadgets/ecc/var-base-scalar-mul.html#overflow-check).)
const INCOMPLETE_HI_RANGE: Range<usize> = 0..(INCOMPLETE_LEN / 2);
pub const INCOMPLETE_HI_LEN: usize = INCOMPLETE_LEN / 2;
// Bits k_{254} to k_{4} inclusive are used in incomplete addition.
// The `lo` half is k_{129} to k_{4} inclusive (length 126 bits).
const INCOMPLETE_LO_RANGE: Range<usize> = (INCOMPLETE_LEN / 2)..INCOMPLETE_LEN;
pub const INCOMPLETE_LO_LEN: usize = (INCOMPLETE_LEN / 2) + 1;
// Bits k_{3} to k_{1} inclusive are used in complete addition.
// Bit k_{0} is handled separately.
@ -48,9 +51,9 @@ pub struct Config {
// Configuration used in complete addition
add_config: add::Config,
// Configuration used for `hi` bits of the scalar
hi_config: incomplete::HiConfig,
hi_config: incomplete::Config<INCOMPLETE_HI_LEN>,
// Configuration used for `lo` bits of the scalar
lo_config: incomplete::LoConfig,
lo_config: incomplete::Config<INCOMPLETE_LO_LEN>,
// Configuration used for complete addition part of double-and-add algorithm
complete_config: complete::Config,
// Configuration used to check for overflow
@ -62,8 +65,8 @@ impl From<&EccConfig> for Config {
let config = Self {
q_mul_lsb: ecc_config.q_mul_lsb,
add_config: ecc_config.add,
hi_config: ecc_config.into(),
lo_config: ecc_config.into(),
hi_config: ecc_config.mul_hi,
lo_config: ecc_config.mul_lo,
complete_config: ecc_config.into(),
overflow_config: ecc_config.into(),
};
@ -81,13 +84,23 @@ impl From<&EccConfig> for Config {
// z and lambda1 are assigned on the same row as the add_config output.
// Therefore, z and lambda1 must not overlap with add_config.x_qr, add_config.y_qr.
let add_config_outputs = config.add_config.output_columns();
for config in [&(*config.hi_config), &(*config.lo_config)].iter() {
{
assert!(
!add_config_outputs.contains(&config.z),
!add_config_outputs.contains(&config.hi_config.z),
"incomplete config z cannot overlap with complete addition columns."
);
assert!(
!add_config_outputs.contains(&config.lambda1),
!add_config_outputs.contains(&config.hi_config.lambda1),
"incomplete config lambda1 cannot overlap with complete addition columns."
);
}
{
assert!(
!add_config_outputs.contains(&config.lo_config.z),
"incomplete config z cannot overlap with complete addition columns."
);
assert!(
!add_config_outputs.contains(&config.lo_config.lambda1),
"incomplete config lambda1 cannot overlap with complete addition columns."
);
}
@ -98,8 +111,6 @@ impl From<&EccConfig> for Config {
impl Config {
pub(super) fn create_gate(&self, meta: &mut ConstraintSystem<pallas::Base>) {
self.hi_config.create_gate(meta);
self.lo_config.create_gate(meta);
self.complete_config.create_gate(meta);
self.overflow_config.create_gate(meta);

View File

@ -1,7 +1,5 @@
use std::ops::Deref;
use super::super::{copy, CellValue, EccConfig, NonIdentityEccPoint, Var};
use super::{INCOMPLETE_HI_RANGE, INCOMPLETE_LO_RANGE, X, Y, Z};
use super::super::{copy, CellValue, NonIdentityEccPoint, Var};
use super::{X, Y, Z};
use crate::circuit::gadget::utilities::bool_check;
use ff::Field;
use halo2::{
@ -12,10 +10,8 @@ use halo2::{
use pasta_curves::{arithmetic::FieldExt, pallas};
#[derive(Copy, Clone)]
pub(super) struct Config {
// Number of bits covered by this incomplete range.
num_bits: usize,
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(crate) struct Config<const NUM_BITS: usize> {
// Selectors used to constrain the cells used in incomplete addition.
pub(super) q_mul: (Selector, Selector, Selector),
// Cumulative sum used to decompose the scalar.
@ -32,61 +28,37 @@ pub(super) struct Config {
pub(super) lambda2: Column<Advice>,
}
// Columns used in processing the `hi` bits of the scalar.
// `x_p, y_p` are shared across the `hi` and `lo` halves.
pub(super) struct HiConfig(Config);
impl From<&EccConfig> for HiConfig {
fn from(ecc_config: &EccConfig) -> Self {
let config = Config {
num_bits: INCOMPLETE_HI_RANGE.len(),
q_mul: ecc_config.q_mul_hi,
x_p: ecc_config.advices[0],
y_p: ecc_config.advices[1],
z: ecc_config.advices[9],
x_a: ecc_config.advices[3],
lambda1: ecc_config.advices[4],
lambda2: ecc_config.advices[5],
impl<const NUM_BITS: usize> Config<NUM_BITS> {
// TODO: Make this pub(super).
pub(crate) fn configure(
meta: &mut ConstraintSystem<pallas::Base>,
z: Column<Advice>,
x_a: Column<Advice>,
x_p: Column<Advice>,
y_p: Column<Advice>,
lambda1: Column<Advice>,
lambda2: Column<Advice>,
) -> Self {
meta.enable_equality(z.into());
meta.enable_equality(lambda1.into());
let config = Self {
q_mul: (meta.selector(), meta.selector(), meta.selector()),
z,
x_a,
x_p,
y_p,
lambda1,
lambda2,
};
Self(config)
}
}
impl Deref for HiConfig {
type Target = Config;
fn deref(&self) -> &Config {
&self.0
}
}
config.create_gate(meta);
// Columns used in processing the `lo` bits of the scalar.
// `x_p, y_p` are shared across the `hi` and `lo` halves.
pub(super) struct LoConfig(Config);
impl From<&EccConfig> for LoConfig {
fn from(ecc_config: &EccConfig) -> Self {
let config = Config {
num_bits: INCOMPLETE_LO_RANGE.len(),
q_mul: ecc_config.q_mul_lo,
x_p: ecc_config.advices[0],
y_p: ecc_config.advices[1],
z: ecc_config.advices[6],
x_a: ecc_config.advices[7],
lambda1: ecc_config.advices[8],
lambda2: ecc_config.advices[2],
};
Self(config)
config
}
}
impl Deref for LoConfig {
type Target = Config;
fn deref(&self) -> &Config {
&self.0
}
}
impl Config {
// Gate for incomplete addition part of variable-base scalar multiplication.
pub(super) fn create_gate(&self, meta: &mut ConstraintSystem<pallas::Base>) {
fn create_gate(&self, meta: &mut ConstraintSystem<pallas::Base>) {
// Closure to compute x_{R,i} = λ_{1,i}^2 - x_{A,i} - x_{P,i}
let x_r = |meta: &mut VirtualCells<pallas::Base>, rotation: Rotation| {
let x_a = meta.query_advice(self.x_a, rotation);
@ -216,7 +188,7 @@ impl Config {
acc: (X<pallas::Base>, Y<pallas::Base>, Z<pallas::Base>),
) -> Result<(X<pallas::Base>, Y<pallas::Base>, Vec<Z<pallas::Base>>), Error> {
// Check that we have the correct number of bits for this double-and-add.
assert_eq!(bits.len(), self.num_bits);
assert_eq!(bits.len(), NUM_BITS);
// Handle exceptional cases
let (x_p, y_p) = (base.x.value(), base.y.value());
@ -241,12 +213,12 @@ impl Config {
let offset = offset + 1;
// q_mul_2 = 1 on all rows after offset 0, excluding the last row.
for idx in 0..(self.num_bits - 1) {
for idx in 0..(NUM_BITS - 1) {
self.q_mul.1.enable(region, offset + idx)?;
}
// q_mul_3 = 1 on the last row.
self.q_mul.2.enable(region, offset + self.num_bits - 1)?;
self.q_mul.2.enable(region, offset + NUM_BITS - 1)?;
}
// Initialise double-and-add
@ -361,7 +333,7 @@ impl Config {
let cell = region.assign_advice(
|| "y_a",
self.lambda1,
offset + self.num_bits,
offset + NUM_BITS,
|| y_a.ok_or(Error::Synthesis),
)?;
CellValue::new(cell, y_a)