diff --git a/halo2_gadgets/src/ecc_opt.rs b/halo2_gadgets/src/ecc_opt.rs new file mode 100644 index 0000000000..3ef3167b1d --- /dev/null +++ b/halo2_gadgets/src/ecc_opt.rs @@ -0,0 +1 @@ +pub mod chip; diff --git a/halo2_gadgets/src/ecc_opt/chip.rs b/halo2_gadgets/src/ecc_opt/chip.rs new file mode 100644 index 0000000000..225a3ef493 --- /dev/null +++ b/halo2_gadgets/src/ecc_opt/chip.rs @@ -0,0 +1 @@ +// TODO: EccConfig has LookupRangeCheckConfig diff --git a/halo2_gadgets/src/lib.rs b/halo2_gadgets/src/lib.rs index eadea1bb65..e404097d81 100644 --- a/halo2_gadgets/src/lib.rs +++ b/halo2_gadgets/src/lib.rs @@ -22,6 +22,7 @@ #![deny(unsafe_code)] pub mod ecc; +mod ecc_opt; pub mod poseidon; #[cfg(feature = "unstable-sha256-gadget")] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-sha256-gadget")))] diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs index 7ab26bec82..9b74ef1979 100644 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ b/halo2_gadgets/src/sinsemilla/chip.rs @@ -11,8 +11,6 @@ use crate::{ }, utilities::lookup_range_check::LookupRangeCheckConfig, }; -use ff::PrimeField; -use pasta_curves::arithmetic::CurveAffine; use std::marker::PhantomData; use halo2_proofs::{ @@ -25,17 +23,12 @@ use halo2_proofs::{ }; use pasta_curves::pallas; use pasta_curves::pallas::Base; -use proptest::test_runner::Config; mod generator_table; -use crate::sinsemilla::primitives::{lebs2ip_k, INV_TWO_POW_K, SINSEMILLA_S}; use generator_table::GeneratorTableConfig; -use halo2_proofs::circuit::Region; -use halo2_proofs::plonk::Assigned; - mod hash_to_point; -/// Configuration for the Sinsemilla hash chip +/// Configuration for the Sinsemilla hash chip common parts #[derive(Eq, PartialEq, Clone, Debug)] pub struct SinsemillaConfigCommon where @@ -78,7 +71,8 @@ where /// An advice column configured to perform lookup range checks. lookup_config: LookupRangeCheckConfig, } -// TODO: add doc, rename it to SinsemillaConfigProps + +/// Trait that provides common methods for SinsemillaConfig and SinsemillaConfigOptimized pub trait SinsemillaConfigProps where Hash: HashDomains, @@ -86,6 +80,8 @@ where Commit: CommitDomains, { type LookupConfigType; + + /// Returns a reference to the `SinsemillaConfigCommon` instance. fn base(&self) -> &SinsemillaConfigCommon; /// Returns an array of all advice columns in this config, in arbitrary order. @@ -109,8 +105,12 @@ where q_s2.clone() * (q_s2 - one) } + /// querying a value 'y_q' from certain column fn get_y_q(&self, meta: &mut VirtualCells) -> Expression; + /// Configures constraints in the constraint system `meta` using the value 'y_q' + /// This function sets up various gates within the circuit to enforce the correct relationships + /// between variables according to elliptic curve arithmetic and the Sinsemilla hash function. fn configure_from_y_q(&self, meta: &mut ConstraintSystem) { let two = pallas::Base::from(2); @@ -188,7 +188,7 @@ where }); } } -// TODO: add doc + impl SinsemillaConfigProps for SinsemillaConfig where Hash: HashDomains, @@ -204,7 +204,7 @@ where self.lookup_config } - // todo: add doc + /// Query a fixed value from the circuit's fixed column using the configuration `fixed_y_q`. fn get_y_q(&self, meta: &mut VirtualCells) -> Expression { meta.query_fixed(self.base.fixed_y_q) } @@ -223,7 +223,7 @@ where config: SinsemillaConfig, } -// TODO: add doc,rename it to SinsemillaChipProps +/// Trait that provides common methods for SinsemillaChip and SinsemillaChipOptimized pub trait SinsemillaChipProps where Hash: HashDomains, @@ -246,6 +246,10 @@ where config: Self::SinsemillaConfigType, layouter: &mut impl Layouter, ) -> Result; + + /// # Side-effects + /// + /// All columns in `advices` and will be equality-enabled. fn configure( meta: &mut ConstraintSystem, advices: [Column; 5], @@ -274,12 +278,10 @@ where &self.config.base } - /// Reconstructs this chip from the given config. fn construct(config: Self::SinsemillaConfigType) -> Self { Self { config } } - /// Loads the lookup table required by this chip into the circuit. fn load( config: Self::SinsemillaConfigType, layouter: &mut impl Layouter, @@ -288,9 +290,6 @@ where config.generator_table.load(layouter) } - /// # Side-effects - /// - /// All columns in `advices` and will be equality-enabled. #[allow(clippy::too_many_arguments)] #[allow(non_snake_case)] fn configure( @@ -325,7 +324,7 @@ where } } -// TODO: add doc +/// A function to generate the common part of SinsemillaConfig 'SinsemillaConfigCommon' pub fn create_common_config( meta: &mut ConstraintSystem, advices: [Column; 5], @@ -354,7 +353,7 @@ where } } -// TODO: remove duplicate? +// TODO: remove duplicated code? impl Chip for SinsemillaChip where Hash: HashDomains, @@ -373,7 +372,7 @@ where } } -// TODO: remove duplicate? +// TODO: remove duplicated code? // Implement `SinsemillaInstructions` for `SinsemillaChip` impl SinsemillaInstructions @@ -419,7 +418,6 @@ where Ok(MessagePiece::new(cell, num_words)) } - // TODO: in the opt version: hash_message_vanilla -> hash_message #[allow(non_snake_case)] #[allow(clippy::type_complexity)] fn hash_to_point( @@ -430,6 +428,7 @@ where ) -> Result<(Self::NonIdentityPoint, Vec), Error> { layouter.assign_region( || "hash_to_point", + // TODO: in the opt version: hash_message_vanilla -> hash_message |mut region| self.hash_message_vanilla(&mut region, Q, &message), ) } diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 9ca6f448a0..6e16717150 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -58,40 +58,6 @@ where )) } - /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - fn hash_message( - &self, - region: &mut Region<'_, pallas::Base>, - Q: pallas::Affine, - message: &>::Message, - ) -> Result< - ( - NonIdentityEccPoint, - Vec>>, - ), - Error, - > { - let (offset, x_a, y_a) = self.public_initialization(region, Q)?; - - let (x_a, y_a, zs_sum) = self.hash_all_pieces(region, offset, message, x_a, y_a)?; - - // todo: add test - - x_a.value() - .zip(y_a.value()) - .error_if_known_and(|(x_a, y_a)| x_a.is_zero_vartime() || y_a.is_zero_vartime())?; - Ok(( - NonIdentityEccPoint::from_coordinates_unchecked(x_a.0, y_a), - zs_sum, - )) - } - /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). #[allow(non_snake_case)] #[allow(clippy::type_complexity)] @@ -171,7 +137,7 @@ where Q: pallas::Affine, ) -> Result<(usize, X, Y), Error> { let config = self.config().clone(); - let mut offset = 0; + let offset = 0; // Get the `x`- and `y`-coordinates of the starting `Q` base. let x_q = *Q.coordinates().unwrap().x(); @@ -179,7 +145,7 @@ where // Constrain the initial x_a, lambda_1, lambda_2, x_p using the q_sinsemilla4 // selector. - let mut y_a: Y = { + let y_a: Y = { // Enable `q_sinsemilla4` on the first row. config.base.q_sinsemilla4.enable(region, offset)?; region.assign_fixed( @@ -192,55 +158,6 @@ where Value::known(y_q.into()).into() }; - // Constrain the initial x_q to equal the x-coordinate of the domain's `Q`. - let mut x_a: X = { - let x_a = region.assign_advice_from_constant( - || "fixed x_q", - config.base.double_and_add.x_a, - offset, - x_q.into(), - )?; - - x_a.into() - }; - Ok((offset, x_a, y_a)) - } - #[allow(non_snake_case)] - /// Assign the coordinates of the initial public point `Q` - /// - /// | offset | x_A | x_P | q_sinsemilla4 | - /// -------------------------------------- - /// | 0 | | y_Q | | - /// | 1 | x_Q | | 1 | - fn public_initialization( - &self, - region: &mut Region<'_, pallas::Base>, - Q: pallas::Affine, - ) -> Result<(usize, X, Y), Error> { - let config = self.config().clone(); - let mut offset = 0; - - // Get the `x`- and `y`-coordinates of the starting `Q` base. - let x_q = *Q.coordinates().unwrap().x(); - let y_q = *Q.coordinates().unwrap().y(); - - // Constrain the initial x_a, lambda_1, lambda_2, x_p using the q_sinsemilla4 - // selector. - let y_a: Y = { - // Enable `q_sinsemilla4` on the second row. - config.base.q_sinsemilla4.enable(region, offset + 1)?; - let y_a: AssignedCell, pallas::Base> = region - .assign_advice_from_constant( - || "fixed y_q", - config.base.double_and_add.x_p, - offset, - y_q.into(), - )?; - - y_a.value_field().into() - }; - offset += 1; - // Constrain the initial x_q to equal the x-coordinate of the domain's `Q`. let x_a: X = { let x_a = region.assign_advice_from_constant( @@ -252,7 +169,6 @@ where x_a.into() }; - Ok((offset, x_a, y_a)) } diff --git a/halo2_gadgets/src/sinsemilla_opt/chip.rs b/halo2_gadgets/src/sinsemilla_opt/chip.rs index 73b29ba77a..0cb8148390 100644 --- a/halo2_gadgets/src/sinsemilla_opt/chip.rs +++ b/halo2_gadgets/src/sinsemilla_opt/chip.rs @@ -1,30 +1,21 @@ mod generator_table; mod hash_to_point; +use crate::ecc::{chip::NonIdentityEccPoint, FixedPoints}; use crate::sinsemilla::message::{Message, MessagePiece}; use crate::sinsemilla::primitives as sinsemilla; -use crate::{ - ecc::{ - chip::{DoubleAndAdd, NonIdentityEccPoint}, - FixedPoints, - }, - utilities::lookup_range_check::LookupRangeCheckConfig, -}; use halo2_proofs::{ circuit::{AssignedCell, Chip, Layouter, Value}, plonk::{ - Advice, Column, ConstraintSystem, Constraints, Error, Expression, Fixed, Selector, - TableColumn, VirtualCells, + Advice, Column, ConstraintSystem, Error, Expression, Fixed, TableColumn, VirtualCells, }, poly::Rotation, }; use pasta_curves::pallas; use pasta_curves::pallas::Base; -use std::marker::PhantomData; use crate::sinsemilla::chip::{ - create_common_config, SinsemillaChip, SinsemillaChipProps, SinsemillaConfigCommon, - SinsemillaConfigProps, + create_common_config, SinsemillaChipProps, SinsemillaConfigCommon, SinsemillaConfigProps, }; use crate::sinsemilla::{CommitDomains, HashDomains, SinsemillaInstructions}; use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; @@ -62,7 +53,7 @@ where self.lookup_config } - // todo: add doc + /// Query an advice value 'y_q' from a specific advice column `x_p` at the previous rotation. fn get_y_q(&self, meta: &mut VirtualCells) -> Expression { meta.query_advice(self.base.double_and_add.x_p, Rotation::prev()) } @@ -114,9 +105,6 @@ where config.generator_table.load(layouter) } - /// # Side-effects - /// - /// All columns in `advices` and will be equality-enabled. #[allow(clippy::too_many_arguments)] #[allow(non_snake_case)] fn configure( @@ -152,7 +140,7 @@ where } } -// TODO: remove duplicate? +// TODO: remove duplicated code? impl Chip for SinsemillaChipOptimized where Hash: HashDomains, @@ -171,7 +159,7 @@ where } } -// TODO: remove duplicate? +// TODO: remove duplicated code? // Implement `SinsemillaInstructions` for `SinsemillaChip` impl SinsemillaInstructions diff --git a/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs index e4f1558e6e..21418f8026 100644 --- a/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs @@ -1,4 +1,4 @@ -use super::{NonIdentityEccPoint, SinsemillaChip, SinsemillaChipOptimized}; +use super::{NonIdentityEccPoint, SinsemillaChipOptimized}; use crate::{ ecc::FixedPoints, sinsemilla::primitives::{self as sinsemilla, lebs2ip_k, INV_TWO_POW_K, SINSEMILLA_S}, @@ -24,39 +24,6 @@ where Commit: CommitDomains, { // TODO: simplify three hash_message functions - /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - pub(crate) fn hash_message_vanilla( - &self, - region: &mut Region<'_, pallas::Base>, - Q: pallas::Affine, - message: &>::Message, - ) -> Result< - ( - NonIdentityEccPoint, - Vec>>, - ), - Error, - > { - let (offset, x_a, y_a) = self.public_initialization_vanilla(region, Q)?; - - let (x_a, y_a, zs_sum) = self.hash_all_pieces(region, offset, message, x_a, y_a)?; - - // todo: add test - - x_a.value() - .zip(y_a.value()) - .error_if_known_and(|(x_a, y_a)| x_a.is_zero_vartime() || y_a.is_zero_vartime())?; - Ok(( - NonIdentityEccPoint::from_coordinates_unchecked(x_a.0, y_a), - zs_sum, - )) - } /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). #[allow(non_snake_case)] @@ -164,47 +131,6 @@ where )) } - #[allow(non_snake_case)] - fn public_initialization_vanilla( - &self, - region: &mut Region<'_, pallas::Base>, - Q: pallas::Affine, - ) -> Result<(usize, X, Y), Error> { - let config = self.config().clone(); - let mut offset = 0; - - // Get the `x`- and `y`-coordinates of the starting `Q` base. - let x_q = *Q.coordinates().unwrap().x(); - let y_q = *Q.coordinates().unwrap().y(); - - // Constrain the initial x_a, lambda_1, lambda_2, x_p using the q_sinsemilla4 - // selector. - let mut y_a: Y = { - // Enable `q_sinsemilla4` on the first row. - config.base.q_sinsemilla4.enable(region, offset)?; - region.assign_fixed( - || "fixed y_q", - config.base.fixed_y_q, - offset, - || Value::known(y_q), - )?; - - Value::known(y_q.into()).into() - }; - - // Constrain the initial x_q to equal the x-coordinate of the domain's `Q`. - let mut x_a: X = { - let x_a = region.assign_advice_from_constant( - || "fixed x_q", - config.base.double_and_add.x_a, - offset, - x_q.into(), - )?; - - x_a.into() - }; - Ok((offset, x_a, y_a)) - } #[allow(non_snake_case)] /// Assign the coordinates of the initial public point `Q` /// diff --git a/halo2_gadgets/src/sinsemilla_opt/merkle.rs b/halo2_gadgets/src/sinsemilla_opt/merkle.rs index 8dd8967ed6..ccc869c194 100644 --- a/halo2_gadgets/src/sinsemilla_opt/merkle.rs +++ b/halo2_gadgets/src/sinsemilla_opt/merkle.rs @@ -183,7 +183,7 @@ pub mod tests { tests::{TestCommitDomain, TestHashDomain}, HashDomains, }, - utilities::{i2lebsp, lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions}, + utilities::{i2lebsp, UtilitiesInstructions}, }; use group::ff::{Field, PrimeField, PrimeFieldBits}; diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index de9ddaa1df..896259a7a0 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -1,6 +1,7 @@ //! Make use of a K-bit lookup table to decompose a field element into K-bit //! words. +use ff::PrimeFieldBits; use halo2_proofs::{ circuit::{AssignedCell, Layouter, Region}, plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Selector, TableColumn}, @@ -8,10 +9,6 @@ use halo2_proofs::{ }; use std::{convert::TryInto, marker::PhantomData}; -use crate::sinsemilla::chip::{SinsemillaConfig, SinsemillaConfigProps}; -use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; -use ff::PrimeFieldBits; - use super::*; /// The running sum $[z_0, ..., z_W]$. If created in strict mode, $z_W = 0$. @@ -25,8 +22,8 @@ impl std::ops::Deref for RunningSum { } } -// Create a Generic Function. The function will use the LookupRangeCheck trait, -// allowing it to work with any configuration type that implements LookupRangeCheck: +/// Create a Generic Function. The function will use the LookupRangeCheck trait, +/// allowing it to work with any configuration type that implements LookupRangeCheck: pub fn witness_short_generic( lookup_config: &C, layouter: impl Layouter, @@ -64,12 +61,22 @@ pub struct LookupRangeCheckConfig { pub(crate) _marker: PhantomData, } -/// FIXME: add doc +/// Trait that provides common methods for a lookup range check. pub trait LookupRangeCheck { - /// FIXME: add doc + /// Returns a reference to the `LookupRangeCheckConfig` instance. fn base(&self) -> &LookupRangeCheckConfig; - /// FIXME: add doc + /// The `running_sum` advice column breaks the field element into `K`-bit + /// words. It is used to construct the input expression to the lookup + /// argument. + /// + /// The `table_idx` fixed column contains values from [0..2^K). Looking up + /// a value in `table_idx` constrains it to be within this range. The table + /// can be loaded outside this helper. + /// + /// # Side-effects + /// + /// Both the `running_sum` and `constants` columns will be equality-enabled. fn configure( meta: &mut ConstraintSystem, running_sum: Column, @@ -79,9 +86,15 @@ pub trait LookupRangeCheck { Self: Sized; #[cfg(test)] + // Fill `table_idx` and `table_range_check_tag`. + // This is only used in testing for now, since the Sinsemilla chip provides a pre-loaded table + // in the Orchard context. fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error>; - /// FIXME: add doc + /// Range check on an existing cell that is copied into this helper. + /// + /// Returns an error if `element` is not in a column that was passed to + /// [`ConstraintSystem::enable_equality`] during circuit configuration. fn short_range_check( &self, region: &mut Region<'_, F>, @@ -282,7 +295,6 @@ impl LookupRangeCheck for LookupRangeCh let q_running = meta.complex_selector(); let q_bitshift = meta.selector(); - // FIXME: q_range_check_4 and q_range_check_5 need to be created here // if the order of the creation makes a difference let config = LookupRangeCheckConfig { q_lookup, @@ -297,7 +309,6 @@ impl LookupRangeCheck for LookupRangeCh meta.lookup(|meta| { let q_lookup = meta.query_selector(config.q_lookup); let q_running = meta.query_selector(config.q_running); - // FIXME: q_range_check_4 and q_range_check_5 need to be created here // if the order of the creation makes a difference let z_cur = meta.query_advice(config.running_sum, Rotation::cur()); let one = Expression::Constant(F::ONE); diff --git a/halo2_gadgets/src/utilities_opt.rs b/halo2_gadgets/src/utilities_opt.rs index ddd75ce739..f3fc961d8d 100644 --- a/halo2_gadgets/src/utilities_opt.rs +++ b/halo2_gadgets/src/utilities_opt.rs @@ -1,4 +1,4 @@ //! Utility gadgets. - -pub mod cond_swap; +// TODO: after ecc_opt +//pub mod cond_swap; pub mod lookup_range_check; diff --git a/halo2_gadgets/src/utilities_opt/cond_swap.rs b/halo2_gadgets/src/utilities_opt/cond_swap.rs index 8b13789179..f219ab0296 100644 --- a/halo2_gadgets/src/utilities_opt/cond_swap.rs +++ b/halo2_gadgets/src/utilities_opt/cond_swap.rs @@ -1 +1,259 @@ +//! Gadget and chip for a conditional swap utility. + + +use crate::ecc::chip::{EccPoint, NonIdentityEccPoint}; +use group::ff::{Field, PrimeField}; +use halo2_proofs::{ + circuit::{AssignedCell, Chip, Layouter, Value}, + plonk::{self, Advice, Column, ConstraintSystem, Constraints, Error, Selector}, + poly::Rotation, +}; +use pasta_curves::pallas; +use std::marker::PhantomData; +use crate::utilities::UtilitiesInstructions; + +/// Instructions for a conditional swap gadget. + + + +#[cfg(test)] +mod tests { + use group::ff::{Field, PrimeField}; + use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner, Value}, + dev::MockProver, + plonk::{Circuit, ConstraintSystem, Error}, + }; + use pasta_curves::pallas::Base; + use rand::rngs::OsRng; + use crate::utilities::cond_swap::{CondSwapChip, CondSwapConfig}; + use crate::utilities::lookup_range_check::LookupRangeCheck; + use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; + + + #[test] + fn test_mux() { + use crate::{ + ecc::{ + chip::{EccChip, EccConfig}, + tests::TestFixedBases, + NonIdentityPoint, Point, + }, + }; + + use group::{cofactor::CofactorCurveAffine, Curve, Group}; + use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner, Value}, + dev::MockProver, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Instance}, + }; + use pasta_curves::arithmetic::CurveAffine; + use pasta_curves::{pallas, EpAffine}; + + use rand::rngs::OsRng; + + #[derive(Clone, Debug)] + pub struct MyConfig { + primary: Column, + advice: Column, + cond_swap_config: CondSwapConfig, + ecc_config: EccConfig, + } + + #[derive(Default)] + struct MyCircuit { + left_point: Value, + right_point: Value, + choice: Value, + } + + impl Circuit for MyCircuit { + type Config = MyConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let advices = [ + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + ]; + + for advice in advices.iter() { + meta.enable_equality(*advice); + } + + // Instance column used for public inputs + let primary = meta.instance_column(); + meta.enable_equality(primary); + + let cond_swap_config = + CondSwapChip::configure(meta, advices[0..5].try_into().unwrap()); + + let table_idx = meta.lookup_table_column(); + let table_range_check_tag = meta.lookup_table_column(); + + let lagrange_coeffs = [ + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + ]; + meta.enable_constant(lagrange_coeffs[0]); + + let range_check = LookupRangeCheckConfigOptimized::configure( + meta, + advices[9], + table_idx, + ); + + let ecc_config = EccChip::::configure( + meta, + advices, + lagrange_coeffs, + range_check, + ); + + MyConfig { + primary, + advice: advices[0], + cond_swap_config, + ecc_config, + } + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + // Construct a CondSwap chip + let cond_swap_chip = CondSwapChip::construct(config.cond_swap_config); + + // Construct an ECC chip + let ecc_chip = EccChip::construct(config.ecc_config); + + // Assign choice + let choice = layouter.assign_region( + || "load private", + |mut region| { + region.assign_advice(|| "load private", config.advice, 0, || self.choice) + }, + )?; + + // Test mux on non identity points + // Assign left point + let left_non_identity_point = NonIdentityPoint::new( + ecc_chip.clone(), + layouter.namespace(|| "left point"), + self.left_point.map(|left_point| left_point), + )?; + + // Assign right point + let right_non_identity_point = NonIdentityPoint::new( + ecc_chip.clone(), + layouter.namespace(|| "right point"), + self.right_point.map(|right_point| right_point), + )?; + + // Apply mux + let result_non_identity_point = cond_swap_chip.mux_on_non_identity_points( + layouter.namespace(|| "MUX"), + &choice, + left_non_identity_point.inner(), + right_non_identity_point.inner(), + )?; + + // Check equality with instance + layouter.constrain_instance( + result_non_identity_point.x().cell(), + config.primary, + 0, + )?; + layouter.constrain_instance( + result_non_identity_point.y().cell(), + config.primary, + 1, + )?; + + // Test mux on points + // Assign left point + let left_point = Point::new( + ecc_chip.clone(), + layouter.namespace(|| "left point"), + self.left_point.map(|left_point| left_point), + )?; + + // Assign right point + let right_point = Point::new( + ecc_chip, + layouter.namespace(|| "right point"), + self.right_point.map(|right_point| right_point), + )?; + + // Apply mux + let result = cond_swap_chip.mux_on_points( + layouter.namespace(|| "MUX"), + &choice, + left_point.inner(), + right_point.inner(), + )?; + + // Check equality with instance + layouter.constrain_instance(result.x().cell(), config.primary, 0)?; + layouter.constrain_instance(result.y().cell(), config.primary, 1) + } + } + + // Test different circuits + let mut circuits = vec![]; + let mut instances = vec![]; + for choice in [false, true] { + let choice_value = if choice { + pallas::Base::one() + } else { + pallas::Base::zero() + }; + let left_point = pallas::Point::random(OsRng).to_affine(); + let right_point = pallas::Point::random(OsRng).to_affine(); + circuits.push(MyCircuit { + left_point: Value::known(left_point), + right_point: Value::known(right_point), + choice: Value::known(choice_value), + }); + let expected_output = if choice { right_point } else { left_point }; + let (expected_x, expected_y) = if bool::from(expected_output.is_identity()) { + (pallas::Base::zero(), pallas::Base::zero()) + } else { + let coords = expected_output.coordinates().unwrap(); + (*coords.x(), *coords.y()) + }; + instances.push([[expected_x, expected_y]]); + } + + for (circuit, instance) in circuits.iter().zip(instances.iter()) { + let prover = MockProver::::run( + 5, + circuit, + instance.iter().map(|p| p.to_vec()).collect(), + ) + .unwrap(); + assert_eq!(prover.verify(), Ok(())); + } + } +} \ No newline at end of file diff --git a/halo2_gadgets/src/utilities_opt/lookup_range_check.rs b/halo2_gadgets/src/utilities_opt/lookup_range_check.rs index d3e17320f7..823bf07e2a 100644 --- a/halo2_gadgets/src/utilities_opt/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities_opt/lookup_range_check.rs @@ -1,9 +1,6 @@ //! Make use of a K-bit lookup table to decompose a field element into K-bit //! words. -use std::marker::PhantomData; -use std::ops::Range; - use halo2_proofs::{ circuit::{AssignedCell, Region}, plonk::{ @@ -11,6 +8,7 @@ use halo2_proofs::{ }, poly::Rotation, }; +use std::marker::PhantomData; #[cfg(test)] use halo2_proofs::circuit::{Layouter, Value}; @@ -18,7 +16,6 @@ use halo2_proofs::circuit::{Layouter, Value}; use ff::PrimeFieldBits; use crate::utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}; -use crate::utilities::{bitrange_subset, RangeConstrained}; /// Configuration that provides methods for a lookup range check. #[derive(Eq, PartialEq, Debug, Clone, Copy)] @@ -158,10 +155,6 @@ impl LookupRangeCheckConfigOptimized { config } - - pub(crate) fn table_range_check_tag(&self) -> TableColumn { - self.table_range_check_tag - } } impl LookupRangeCheck