From e07e8b1b9847f97daf0c31bfa6107f2b1c472729 Mon Sep 17 00:00:00 2001 From: han0110 Date: Wed, 17 Aug 2022 17:52:17 +0800 Subject: [PATCH 1/5] feat: rename `PointRepresentation::encode` to `encode_assigned` and make `encode` to take plain value --- transcript/src/transcript.rs | 168 ++++++++++++++++++++--------------- 1 file changed, 95 insertions(+), 73 deletions(-) diff --git a/transcript/src/transcript.rs b/transcript/src/transcript.rs index 797d5cfb..c4449222 100644 --- a/transcript/src/transcript.rs +++ b/transcript/src/transcript.rs @@ -1,121 +1,144 @@ use crate::{ - halo2::{arithmetic::CurveAffine, plonk::Error}, + halo2::{ + arithmetic::{CurveAffine, FieldExt}, + plonk::Error, + }, hasher::HasherChip, maingate::{AssignedValue, RegionCtx}, }; -use ecc::{halo2::circuit::Chip, AssignedPoint, BaseFieldEccChip}; +use ecc::{ + halo2::circuit::Chip, + maingate::{big_to_fe, decompose, fe_to_big}, + AssignedPoint, BaseFieldEccChip, +}; +use group::ff::PrimeField; use poseidon::Spec; -use std::marker::PhantomData; /// `PointRepresentation` will encode point with an implemented strategy +/// TODO: Generalize `ecc_chip` with `EccInstrucitons` pub trait PointRepresentation< - C: CurveAffine, + C: CurveAffine, + N: FieldExt, const NUMBER_OF_LIMBS: usize, const BIT_LEN_LIMB: usize, -> +>: Default { - fn encode( - ctx: &mut RegionCtx<'_, C::Scalar>, + fn encode_assigned( + ctx: &mut RegionCtx<'_, N>, ecc_chip: &BaseFieldEccChip, - point: &AssignedPoint, - ) -> Result>, Error>; + point: &AssignedPoint, + ) -> Result>, Error>; + + /// Returns `None` if `point` is identity + fn encode(point: C) -> Option>; } /// `LimbRepresentation` encodes point as `[[limbs_of(x)], sign_of(y)]` +#[derive(Default)] pub struct LimbRepresentation; -impl - PointRepresentation for LimbRepresentation +impl< + C: CurveAffine, + N: FieldExt, + const NUMBER_OF_LIMBS: usize, + const BIT_LEN_LIMB: usize, + > PointRepresentation for LimbRepresentation { - fn encode( - ctx: &mut RegionCtx<'_, C::Scalar>, + fn encode_assigned( + ctx: &mut RegionCtx<'_, N>, ecc_chip: &BaseFieldEccChip, - point: &AssignedPoint, - ) -> Result>, Error> { - let mut encoded: Vec> = - point.x().limbs().iter().map(|limb| limb.into()).collect(); + point: &AssignedPoint, + ) -> Result>, Error> { + let mut encoded: Vec> = point + .x() + .limbs() + .iter() + .map(|limb| limb.into()) + .collect(); encoded.push(ecc_chip.sign(ctx, point)?); Ok(encoded) } -} -impl LimbRepresentation { - // Construct new `TranscriptChip` with `LimbRepresentation` encoding strategy - pub fn new< - C: CurveAffine, - const NUMBER_OF_LIMBS: usize, - const BIT_LEN_LIMB: usize, - const T: usize, - const RATE: usize, - >( - ctx: &mut RegionCtx<'_, C::Scalar>, - spec: &Spec, - ecc_chip: BaseFieldEccChip, - ) -> Result, Error> { - TranscriptChip::new(ctx, spec, ecc_chip) + fn encode(point: C) -> Option> { + point + .coordinates() + .map(|coords| { + decompose(*coords.x(), NUMBER_OF_LIMBS, BIT_LEN_LIMB) + .into_iter() + .map(|limb| big_to_fe(fe_to_big(limb))) + .chain(Some(N::from(bool::from(coords.y().is_odd()) as u64))) + .collect() + }) + .into() } } /// `NativeRepresentation` encodes point as `[native(x), native(y)]` +#[derive(Default)] pub struct NativeRepresentation; -impl - PointRepresentation for NativeRepresentation +impl< + C: CurveAffine, + N: FieldExt, + const NUMBER_OF_LIMBS: usize, + const BIT_LEN_LIMB: usize, + > PointRepresentation for NativeRepresentation { - fn encode( - _: &mut RegionCtx<'_, C::Scalar>, + fn encode_assigned( + _: &mut RegionCtx<'_, N>, _: &BaseFieldEccChip, - point: &AssignedPoint, - ) -> Result>, Error> { - Ok(vec![point.x().native().clone(), point.y().native().clone()]) + point: &AssignedPoint, + ) -> Result>, Error> { + Ok(vec![ + point.x().native().clone(), + point.y().native().clone(), + ]) } -} -impl NativeRepresentation { - // Construct new `TranscriptChip` with `NativeRepresentation` encoding strategy - pub fn new< - C: CurveAffine, - const NUMBER_OF_LIMBS: usize, - const BIT_LEN_LIMB: usize, - const T: usize, - const RATE: usize, - >( - ctx: &mut RegionCtx<'_, C::Scalar>, - spec: &Spec, - ecc_chip: BaseFieldEccChip, - ) -> Result, Error> { - TranscriptChip::new(ctx, spec, ecc_chip) + fn encode(point: C) -> Option> { + point + .coordinates() + .map(|coords| { + [coords.x(), coords.y()] + .into_iter() + .map(|fe| big_to_fe(fe_to_big(*fe))) + .collect() + }) + .into() } } #[derive(Clone, Debug)] pub struct TranscriptChip< - E: PointRepresentation, - C: CurveAffine, + C: CurveAffine, + N: FieldExt, + E: PointRepresentation, const NUMBER_OF_LIMBS: usize, const BIT_LEN: usize, const T: usize, const RATE: usize, > { ecc_chip: BaseFieldEccChip, - hasher_chip: HasherChip, - _marker: PhantomData, + hasher_chip: HasherChip, + _point_repr: E, } impl< - E: PointRepresentation, - C: CurveAffine, + C: CurveAffine, + N: FieldExt, + E: PointRepresentation, const NUMBER_OF_LIMBS: usize, const BIT_LEN: usize, const T: usize, const RATE: usize, - > TranscriptChip + > TranscriptChip { /// Constructs the transcript chip pub fn new( - ctx: &mut RegionCtx<'_, C::Scalar>, - spec: &Spec, + ctx: &mut RegionCtx<'_, N>, + spec: &Spec, ecc_chip: BaseFieldEccChip, + _point_repr: E, ) -> Result { let main_gate = ecc_chip.main_gate(); let main_gate_config = main_gate.config(); @@ -123,31 +146,28 @@ impl< Ok(Self { ecc_chip, hasher_chip, - _marker: PhantomData, + _point_repr, }) } /// Write scalar to the transcript - pub fn write_scalar(&mut self, scalar: &AssignedValue) { + pub fn write_scalar(&mut self, scalar: &AssignedValue) { self.hasher_chip.update(&[scalar.clone()]); } /// Write point to the transcript pub fn write_point( &mut self, - ctx: &mut RegionCtx<'_, C::Scalar>, - point: &AssignedPoint, + ctx: &mut RegionCtx<'_, N>, + point: &AssignedPoint, ) -> Result<(), Error> { - let encoded = E::encode(ctx, &self.ecc_chip, point)?; + let encoded = E::encode_assigned(ctx, &self.ecc_chip, point)?; self.hasher_chip.update(&encoded[..]); Ok(()) } // Constrain squeezing new challenge - pub fn squeeze( - &mut self, - ctx: &mut RegionCtx<'_, C::Scalar>, - ) -> Result, Error> { + pub fn squeeze(&mut self, ctx: &mut RegionCtx<'_, N>) -> Result, Error> { self.hasher_chip.hash(ctx) } } @@ -164,6 +184,7 @@ mod tests { use crate::maingate::MainGateConfig; use crate::maingate::{MainGateInstructions, RegionCtx}; use crate::transcript::LimbRepresentation; + use crate::TranscriptChip; use ecc::halo2::arithmetic::CurveAffine; use ecc::halo2::circuit::Value; use ecc::integer::rns::Rns; @@ -260,10 +281,11 @@ mod tests { let ctx = &mut RegionCtx::new(region, offset); let mut transcript_chip = - LimbRepresentation::new::<_, NUMBER_OF_LIMBS, BIT_LEN_LIMB, T, RATE>( + TranscriptChip::<_, _, _, NUMBER_OF_LIMBS, BIT_LEN_LIMB, T, RATE>::new( ctx, &self.spec, ecc_chip.clone(), + LimbRepresentation::default(), )?; for e in self.inputs.as_ref().transpose_vec(self.n) { From 841d779e6868ce4793e7869ca9fcdb959298404b Mon Sep 17 00:00:00 2001 From: han0110 Date: Sat, 23 Jul 2022 13:25:37 +0800 Subject: [PATCH 2/5] feat: export advice columns of `MainGateConfig` by function `advices` --- maingate/src/main_gate.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/maingate/src/main_gate.rs b/maingate/src/main_gate.rs index 77fcb69a..2416e910 100644 --- a/maingate/src/main_gate.rs +++ b/maingate/src/main_gate.rs @@ -84,6 +84,13 @@ pub struct MainGateConfig { pub(crate) instance: Column, } +impl MainGateConfig { + /// Returns advice columns of `MainGateConfig` + pub fn advices(&self) -> [Column; WIDTH] { + [self.a, self.b, self.c, self.d, self.e] + } +} + /// MainGate implements instructions with [`MainGateConfig`] #[derive(Clone, Debug)] pub struct MainGate { From 4505bf15961cf89b60a7e0747ef6a4321ed02eb0 Mon Sep 17 00:00:00 2001 From: han0110 Date: Sat, 9 Jul 2022 12:17:42 +0800 Subject: [PATCH 3/5] feat: use tagged table to reduce # of lookup --- ecc/src/base_field_ecc.rs | 3 +- ecc/src/general_ecc.rs | 3 +- ecdsa/src/ecdsa.rs | 3 +- integer/src/chip.rs | 3 +- maingate/src/instructions.rs | 13 +- maingate/src/range.rs | 286 ++++++++++++++++++++--------------- transcript/src/transcript.rs | 16 +- 7 files changed, 175 insertions(+), 152 deletions(-) diff --git a/ecc/src/base_field_ecc.rs b/ecc/src/base_field_ecc.rs index edef6598..9269c0ad 100644 --- a/ecc/src/base_field_ecc.rs +++ b/ecc/src/base_field_ecc.rs @@ -421,8 +421,7 @@ mod tests { fn config_range(&self, layouter: &mut impl Layouter) -> Result<(), Error> { let range_chip = RangeChip::::new(self.range_config.clone()); - range_chip.load_composition_tables(layouter)?; - range_chip.load_overflow_tables(layouter)?; + range_chip.load_table(layouter)?; Ok(()) } diff --git a/ecc/src/general_ecc.rs b/ecc/src/general_ecc.rs index 818e2854..39f3ba87 100644 --- a/ecc/src/general_ecc.rs +++ b/ecc/src/general_ecc.rs @@ -492,8 +492,7 @@ mod tests { fn config_range(&self, layouter: &mut impl Layouter) -> Result<(), Error> { let range_chip = RangeChip::::new(self.range_config.clone()); - range_chip.load_composition_tables(layouter)?; - range_chip.load_overflow_tables(layouter)?; + range_chip.load_table(layouter)?; Ok(()) } diff --git a/ecdsa/src/ecdsa.rs b/ecdsa/src/ecdsa.rs index f39a5ae3..d0deeef9 100644 --- a/ecdsa/src/ecdsa.rs +++ b/ecdsa/src/ecdsa.rs @@ -200,8 +200,7 @@ mod tests { layouter: &mut impl Layouter, ) -> Result<(), Error> { let range_chip = RangeChip::::new(self.range_config.clone()); - range_chip.load_composition_tables(layouter)?; - range_chip.load_overflow_tables(layouter)?; + range_chip.load_table(layouter)?; Ok(()) } diff --git a/integer/src/chip.rs b/integer/src/chip.rs index 7774cdd1..ac732fb7 100644 --- a/integer/src/chip.rs +++ b/integer/src/chip.rs @@ -703,8 +703,7 @@ mod tests { fn config_range(&self, layouter: &mut impl Layouter) -> Result<(), Error> { let range_chip = RangeChip::::new(self.range_config.clone()); - range_chip.load_composition_tables(layouter)?; - range_chip.load_overflow_tables(layouter)?; + range_chip.load_table(layouter)?; Ok(()) } diff --git a/maingate/src/instructions.rs b/maingate/src/instructions.rs index afd00d1e..45d43076 100644 --- a/maingate/src/instructions.rs +++ b/maingate/src/instructions.rs @@ -11,7 +11,6 @@ use crate::{ AssignedCondition, AssignedValue, ColumnTags, MainGateColumn, }; use halo2wrong::{ - halo2::plonk::Selector, utils::{big_to_fe, decompose, fe_to_big, power_of_two}, RegionCtx, }; @@ -1003,12 +1002,12 @@ pub trait MainGateInstructions: Chip { /// Assigns a new witness composed of given array of terms /// `result = constant + term_0 + term_1 + ... ` /// where `term_i = a_i * q_i` - fn decompose Vec>( + fn decompose, bool) -> Result<(), Error>>( &self, ctx: &mut RegionCtx<'_, F>, terms: &[Term], constant: F, - mut fetch_tables: T, + mut enable_lookup: T, ) -> Result<(AssignedValue, Vec>), Error> { assert!(!terms.is_empty(), "At least one term is expected"); @@ -1054,11 +1053,7 @@ pub trait MainGateInstructions: Chip { CombinationOptionCommon::CombineToNextAdd(F::one()) }; - // Enable tables if there is any - let tables = fetch_tables(is_final); - for table in tables { - ctx.enable(table)?; - } + enable_lookup(ctx, is_final)?; let chunk_len = chunk.len(); let mut combined = self.apply( @@ -1098,7 +1093,7 @@ pub trait MainGateInstructions: Chip { constant: F, ) -> Result, Error> { assert!(!terms.is_empty(), "At least one term is expected"); - let (composed, _) = self.decompose(ctx, terms, constant, |_| vec![])?; + let (composed, _) = self.decompose(ctx, terms, constant, |_, _| Ok(()))?; Ok(composed) } diff --git a/maingate/src/range.rs b/maingate/src/range.rs index f92984f5..a5c48b0c 100644 --- a/maingate/src/range.rs +++ b/maingate/src/range.rs @@ -3,33 +3,33 @@ use crate::halo2::arithmetic::FieldExt; use crate::halo2::circuit::Chip; use crate::halo2::circuit::Layouter; use crate::halo2::circuit::Value; -use crate::halo2::plonk::{ConstraintSystem, Error}; +use crate::halo2::plonk::{ConstraintSystem, Error, Expression}; use crate::halo2::plonk::{Selector, TableColumn}; use crate::halo2::poly::Rotation; use crate::instructions::{MainGateInstructions, Term}; use crate::AssignedValue; +use halo2wrong::halo2::plonk::Column; +use halo2wrong::halo2::plonk::Fixed; use halo2wrong::utils::decompose; use halo2wrong::RegionCtx; use num_integer::Integer; use std::collections::BTreeMap; +use std::collections::BTreeSet; /// Maximum number of cells in one line enabled with composition selector pub const NUMBER_OF_LOOKUP_LIMBS: usize = 4; -#[derive(Clone, Debug, Eq, PartialEq, Hash)] -struct TableConfig { - selector: Selector, - column: TableColumn, -} - -impl TableConfig {} - /// Range gate configuration #[derive(Clone, Debug)] pub struct RangeConfig { main_gate_config: MainGateConfig, - composition_tables: BTreeMap, - overflow_tables: BTreeMap, + bit_len_tag: BTreeMap, + t_tag: TableColumn, + t_value: TableColumn, + s_composition: Selector, + tag_composition: Option>, + s_overflow: Option, + tag_overflow: Option>, } /// ['RangeChip'] applies binary range constraints @@ -77,10 +77,8 @@ pub trait RangeInstructions: Chip { bit_len: usize, ) -> Result<(AssignedValue, Vec>), Error>; - /// Appends base limb length table in sythnesis time - fn load_composition_tables(&self, layouter: &mut impl Layouter) -> Result<(), Error>; - /// Appends shorter range tables in sythesis time - fn load_overflow_tables(&self, layouter: &mut impl Layouter) -> Result<(), Error>; + /// Load table in sythnesis time + fn load_table(&self, layouter: &mut impl Layouter) -> Result<(), Error>; } impl RangeInstructions for RangeChip { @@ -115,72 +113,89 @@ impl RangeInstructions for RangeChip { .map(|(limb, base)| Term::Unassigned(limb, *base)) .collect(); - let composition_table = self - .config - .composition_tables - .get(&limb_bit_len) - .expect(&format!( - "composition table is not set, bit lenght: {}", - limb_bit_len, - )); self.main_gate() - .decompose(ctx, &terms[..], F::zero(), |is_last| { - if is_last && overflow_bit_len != 0 { - let overflow_table = - self.config - .overflow_tables - .get(&overflow_bit_len) - .expect(&format!( - "overflow table is not set, bit lenght: {}", - overflow_bit_len - )); - vec![composition_table.selector, overflow_table.selector] - } else { - vec![composition_table.selector] + .decompose(ctx, &terms[..], F::zero(), |ctx, is_last| { + let composition_tag = + self.config + .bit_len_tag + .get(&limb_bit_len) + .unwrap_or_else(|| { + panic!("composition table is not set, bit lenght: {limb_bit_len}") + }); + ctx.enable(self.config.s_composition)?; + if let Some(tag_composition) = self.config.tag_composition { + ctx.assign_fixed( + || "tag_composition", + tag_composition, + F::from(*composition_tag as u64), + )?; } - }) - } - fn load_composition_tables(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - for (bit_len, config) in self.config.composition_tables.iter() { - let table_values: Vec = (0..1 << bit_len).map(|e| F::from(e)).collect(); - layouter.assign_table( - || "", - |mut table| { - for (index, &value) in table_values.iter().enumerate() { - table.assign_cell( - || "composition table", - config.column, - index, - || Value::known(value), + if is_last && overflow_bit_len != 0 { + let overflow_tag = self + .config + .bit_len_tag + .get(&overflow_bit_len) + .unwrap_or_else(|| { + panic!("overflow table is not set, bit lenght: {overflow_bit_len}") + }); + ctx.enable(self.config.s_overflow.unwrap())?; + if let Some(tag_overflow) = self.config.tag_overflow { + ctx.assign_fixed( + || "tag_overflow", + tag_overflow, + F::from(*overflow_tag as u64), )?; } - Ok(()) - }, - )?; - } + } - Ok(()) + Ok(()) + }) } - fn load_overflow_tables(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - for (bit_len, config) in self.config.overflow_tables.iter() { - let table_values: Vec = (0..1 << bit_len).map(|e| F::from(e)).collect(); - layouter.assign_table( - || "", - |mut table| { - for (index, &value) in table_values.iter().enumerate() { + fn load_table(&self, layouter: &mut impl Layouter) -> Result<(), Error> { + layouter.assign_table( + || "", + |mut table| { + let mut offset = 0; + + table.assign_cell( + || "table tag", + self.config.t_tag, + offset, + || Value::known(F::zero()), + )?; + table.assign_cell( + || "table value", + self.config.t_value, + offset, + || Value::known(F::zero()), + )?; + offset += 1; + + for (bit_len, tag) in self.config.bit_len_tag.iter() { + let tag = F::from(*tag as u64); + let table_values: Vec = (0..1 << bit_len).map(|e| F::from(e)).collect(); + for value in table_values.iter() { + table.assign_cell( + || "table tag", + self.config.t_tag, + offset, + || Value::known(tag), + )?; table.assign_cell( - || "composition table", - config.column, - index, - || Value::known(value), + || "table value", + self.config.t_value, + offset, + || Value::known(*value), )?; + offset += 1; } - Ok(()) - }, - )?; - } + } + + Ok(()) + }, + )?; Ok(()) } @@ -191,13 +206,17 @@ impl RangeChip { pub fn new(config: RangeConfig) -> Self { let main_gate = MainGate::new(config.main_gate_config.clone()); let bases = config - .composition_tables + .bit_len_tag .keys() - .map(|&bit_len| { - let bases = (0..F::NUM_BITS as usize / bit_len) - .map(|i| F::from(2).pow(&[(bit_len * i) as u64, 0, 0, 0])) - .collect(); - (bit_len, bases) + .filter_map(|&bit_len| { + if bit_len == 0 { + None + } else { + let bases = (0..F::NUM_BITS as usize / bit_len) + .map(|i| F::from(2).pow(&[(bit_len * i) as u64, 0, 0, 0])) + .collect(); + Some((bit_len, bases)) + } }) .collect(); Self { @@ -215,19 +234,42 @@ impl RangeChip { composition_bit_lens: Vec, overflow_bit_lens: Vec, ) -> RangeConfig { - let mut overflow_bit_lens = overflow_bit_lens; - overflow_bit_lens.sort_unstable(); - overflow_bit_lens.dedup(); - let overflow_bit_lens: Vec = - overflow_bit_lens.into_iter().filter(|e| *e != 0).collect(); - - let mut composition_bit_lens = composition_bit_lens; - composition_bit_lens.sort_unstable(); - composition_bit_lens.dedup(); - let composition_bit_lens: Vec = composition_bit_lens - .into_iter() - .filter(|e| *e != 0) - .collect(); + let [composition_bit_lens, overflow_bit_lens] = [composition_bit_lens, overflow_bit_lens] + .map(|mut bit_lens| { + bit_lens.sort_unstable(); + bit_lens.dedup(); + bit_lens + }); + + let has_overflow_limb = !overflow_bit_lens.is_empty(); + let bit_len_tag = BTreeMap::from_iter( + BTreeSet::from_iter(composition_bit_lens.iter().chain(overflow_bit_lens.iter())) + .into_iter() + .enumerate() + .map(|(idx, bit_len)| (*bit_len, idx + 1)), + ); + + let t_tag = meta.lookup_table_column(); + let t_value = meta.lookup_table_column(); + + macro_rules! lookup { + ($prefix:literal, $selector:ident, $tag:ident, $bit_lens:ident, [$($value:ident),*]) => { + $( + meta.lookup(concat!($prefix, stringify!($value)), |meta| { + let selector = meta.query_selector($selector); + let tag = match $tag { + Some(tag) => meta.query_fixed(tag, Rotation::cur()), + None => { + let tag = F::from(bit_len_tag[&$bit_lens[0]] as u64); + selector.clone() * Expression::Constant(tag) + }, + }; + let value = meta.query_advice($value, Rotation::cur()); + vec![(tag, t_tag), (selector * value, t_value)] + }); + )* + }; + } // TODO: consider for a generic MainGateConfig let (a, b, c, d) = ( @@ -237,44 +279,43 @@ impl RangeChip { main_gate_config.d, ); - macro_rules! meta_lookup { - ($prefix:literal, $column:expr, $table_config:expr) => { - meta.lookup(concat!($prefix, "_", stringify!($column)), |meta| { - let exp = meta.query_advice($column, Rotation::cur()); - let s = meta.query_selector($table_config.selector); - vec![(exp * s, $table_config.column)] - }); - }; - } - - let mut composition_tables = BTreeMap::::new(); - let mut overflow_tables = BTreeMap::::new(); + let s_composition = meta.complex_selector(); + let tag_composition = if composition_bit_lens.len() > 1 { + Some(meta.fixed_column()) + } else { + None + }; + lookup!( + "composition", + s_composition, + tag_composition, + composition_bit_lens, + [a, b, c, d] + ); - for bit_len in composition_bit_lens.iter() { - let config = TableConfig { - selector: meta.complex_selector(), - column: meta.lookup_table_column(), - }; - meta_lookup!("composition", a, config); - meta_lookup!("composition", b, config); - meta_lookup!("composition", c, config); - meta_lookup!("composition", d, config); - composition_tables.insert(*bit_len, config); - } - for bit_len in overflow_bit_lens.iter() { - let config = TableConfig { - selector: meta.complex_selector(), - column: meta.lookup_table_column(), + let (s_overflow, tag_overflow) = if has_overflow_limb { + let s_overflow = meta.complex_selector(); + let tag_overflow = if overflow_bit_lens.len() > 1 { + Some(meta.fixed_column()) + } else { + None }; + lookup!("overflow", s_overflow, tag_overflow, overflow_bit_lens, [a]); - meta_lookup!("overflow", a, config); - overflow_tables.insert(*bit_len, config); - } + (Some(s_overflow), tag_overflow) + } else { + (None, None) + }; RangeConfig { main_gate_config: main_gate_config.clone(), - composition_tables, - overflow_tables, + bit_len_tag, + t_tag, + t_value, + s_composition, + tag_composition, + s_overflow, + tag_overflow, } } @@ -408,8 +449,7 @@ mod tests { }, )?; - range_chip.load_composition_tables(&mut layouter)?; - range_chip.load_overflow_tables(&mut layouter)?; + range_chip.load_table(&mut layouter)?; Ok(()) } diff --git a/transcript/src/transcript.rs b/transcript/src/transcript.rs index c4449222..2ec99495 100644 --- a/transcript/src/transcript.rs +++ b/transcript/src/transcript.rs @@ -49,12 +49,8 @@ impl< ecc_chip: &BaseFieldEccChip, point: &AssignedPoint, ) -> Result>, Error> { - let mut encoded: Vec> = point - .x() - .limbs() - .iter() - .map(|limb| limb.into()) - .collect(); + let mut encoded: Vec> = + point.x().limbs().iter().map(|limb| limb.into()).collect(); encoded.push(ecc_chip.sign(ctx, point)?); Ok(encoded) } @@ -89,10 +85,7 @@ impl< _: &BaseFieldEccChip, point: &AssignedPoint, ) -> Result>, Error> { - Ok(vec![ - point.x().native().clone(), - point.y().native().clone(), - ]) + Ok(vec![point.x().native().clone(), point.y().native().clone()]) } fn encode(point: C) -> Option> { @@ -234,8 +227,7 @@ mod tests { fn config_range(&self, layouter: &mut impl Layouter) -> Result<(), Error> { let range_chip = RangeChip::::new(self.range_config.clone()); - range_chip.load_composition_tables(layouter)?; - range_chip.load_overflow_tables(layouter)?; + range_chip.load_table(layouter)?; Ok(()) } From 4b5750a7ad130450e93a9b1e15dd0dfd451a483b Mon Sep 17 00:00:00 2001 From: han0110 Date: Sun, 4 Sep 2022 22:02:16 +0800 Subject: [PATCH 4/5] feat: derive `Debug` for `RegionCtx` --- halo2wrong/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/halo2wrong/src/lib.rs b/halo2wrong/src/lib.rs index 0ab38504..7d3ddecb 100644 --- a/halo2wrong/src/lib.rs +++ b/halo2wrong/src/lib.rs @@ -8,6 +8,7 @@ pub mod utils; pub use halo2; pub use halo2::halo2curves as curves; +#[derive(Debug)] pub struct RegionCtx<'a, F: FieldExt> { region: Region<'a, F>, offset: usize, From 0ca396e35d51807a87de72e776a20081540808d4 Mon Sep 17 00:00:00 2001 From: han0110 Date: Fri, 9 Sep 2022 16:55:33 +0800 Subject: [PATCH 5/5] fix: apply suggestion --- maingate/src/range.rs | 128 +++++++++++++++++++++++++---------- transcript/src/transcript.rs | 1 - 2 files changed, 91 insertions(+), 38 deletions(-) diff --git a/maingate/src/range.rs b/maingate/src/range.rs index a5c48b0c..13e16a6e 100644 --- a/maingate/src/range.rs +++ b/maingate/src/range.rs @@ -8,6 +8,7 @@ use crate::halo2::plonk::{Selector, TableColumn}; use crate::halo2::poly::Rotation; use crate::instructions::{MainGateInstructions, Term}; use crate::AssignedValue; +use halo2wrong::halo2::plonk::Advice; use halo2wrong::halo2::plonk::Column; use halo2wrong::halo2::plonk::Fixed; use halo2wrong::utils::decompose; @@ -241,7 +242,6 @@ impl RangeChip { bit_lens }); - let has_overflow_limb = !overflow_bit_lens.is_empty(); let bit_len_tag = BTreeMap::from_iter( BTreeSet::from_iter(composition_bit_lens.iter().chain(overflow_bit_lens.iter())) .into_iter() @@ -252,55 +252,75 @@ impl RangeChip { let t_tag = meta.lookup_table_column(); let t_value = meta.lookup_table_column(); - macro_rules! lookup { - ($prefix:literal, $selector:ident, $tag:ident, $bit_lens:ident, [$($value:ident),*]) => { - $( - meta.lookup(concat!($prefix, stringify!($value)), |meta| { - let selector = meta.query_selector($selector); - let tag = match $tag { - Some(tag) => meta.query_fixed(tag, Rotation::cur()), - None => { - let tag = F::from(bit_len_tag[&$bit_lens[0]] as u64); - selector.clone() * Expression::Constant(tag) - }, - }; - let value = meta.query_advice($value, Rotation::cur()); - vec![(tag, t_tag), (selector * value, t_value)] - }); - )* - }; - } - // TODO: consider for a generic MainGateConfig - let (a, b, c, d) = ( - main_gate_config.a, - main_gate_config.b, - main_gate_config.c, - main_gate_config.d, - ); + let &MainGateConfig { a, b, c, d, .. } = main_gate_config; let s_composition = meta.complex_selector(); let tag_composition = if composition_bit_lens.len() > 1 { - Some(meta.fixed_column()) + let tag = meta.fixed_column(); + for (name, value) in [ + ("composition_a", a), + ("composition_b", b), + ("composition_c", c), + ("composition_d", d), + ] { + Self::configure_lookup_with_column_tag( + meta, + name, + s_composition, + tag, + value, + t_tag, + t_value, + ) + } + Some(tag) } else { + for (name, value) in [ + ("composition_a", a), + ("composition_b", b), + ("composition_c", c), + ("composition_d", d), + ] { + Self::configure_lookup_with_constant_tag( + meta, + name, + s_composition, + bit_len_tag[&composition_bit_lens[0]], + value, + t_tag, + t_value, + ) + } None }; - lookup!( - "composition", - s_composition, - tag_composition, - composition_bit_lens, - [a, b, c, d] - ); - let (s_overflow, tag_overflow) = if has_overflow_limb { + let (s_overflow, tag_overflow) = if !overflow_bit_lens.is_empty() { let s_overflow = meta.complex_selector(); let tag_overflow = if overflow_bit_lens.len() > 1 { - Some(meta.fixed_column()) + let tag = meta.fixed_column(); + Self::configure_lookup_with_column_tag( + meta, + "overflow_a", + s_overflow, + tag, + a, + t_tag, + t_value, + ); + Some(tag) } else { + Self::configure_lookup_with_constant_tag( + meta, + "overflow_a", + s_overflow, + bit_len_tag[&overflow_bit_lens[0]], + a, + t_tag, + t_value, + ); None }; - lookup!("overflow", s_overflow, tag_overflow, overflow_bit_lens, [a]); (Some(s_overflow), tag_overflow) } else { @@ -319,6 +339,40 @@ impl RangeChip { } } + fn configure_lookup_with_column_tag( + meta: &mut ConstraintSystem, + name: &'static str, + selector: Selector, + tag: Column, + value: Column, + t_tag: TableColumn, + t_value: TableColumn, + ) { + meta.lookup(name, |meta| { + let selector = meta.query_selector(selector); + let tag = meta.query_fixed(tag, Rotation::cur()); + let value = meta.query_advice(value, Rotation::cur()); + vec![(tag, t_tag), (selector * value, t_value)] + }); + } + + fn configure_lookup_with_constant_tag( + meta: &mut ConstraintSystem, + name: &'static str, + selector: Selector, + tag: usize, + value: Column, + t_tag: TableColumn, + t_value: TableColumn, + ) { + meta.lookup(name, |meta| { + let selector = meta.query_selector(selector); + let tag = selector.clone() * Expression::Constant(F::from(tag as u64)); + let value = meta.query_advice(value, Rotation::cur()); + vec![(tag, t_tag), (selector * value, t_value)] + }); + } + fn bases(&self, limb_bit_len: usize) -> &[F] { self.bases .get(&limb_bit_len) diff --git a/transcript/src/transcript.rs b/transcript/src/transcript.rs index 2ec99495..d8cd7b62 100644 --- a/transcript/src/transcript.rs +++ b/transcript/src/transcript.rs @@ -15,7 +15,6 @@ use group::ff::PrimeField; use poseidon::Spec; /// `PointRepresentation` will encode point with an implemented strategy -/// TODO: Generalize `ecc_chip` with `EccInstrucitons` pub trait PointRepresentation< C: CurveAffine, N: FieldExt,