diff --git a/halo2_gadgets/CHANGELOG.md b/halo2_gadgets/CHANGELOG.md index 25b0d0402e..f8a2732ad7 100644 --- a/halo2_gadgets/CHANGELOG.md +++ b/halo2_gadgets/CHANGELOG.md @@ -12,10 +12,16 @@ and this project adheres to Rust's notion of a shorthand for `LookupRangeCheck` specialized with `pallas::Base` and `sinsemilla::K` - `halo2_gadgets::utilities::lookup_range_check::PallasLookupRangeCheckConfig` which is a shorthand for `LookupRangeCheckConfig` specialized with `pallas::Base` and `sinsemilla::K` +- `halo2_gadgets::ecc::Point::{mul_sign, new_from_constant}` +- `halo2_gadgets::sinsemilla::CommitDomain::{blinding_factor, hash_with_private_init, q_init}` +- `halo2_gadgets::utilities::cond_swap::CondSwapChip::{mux_on_points, mux_on_non_identity_points}` ### Changed - `halo2_gadgets::utilities::lookup_range_check::witness_short` now takes a generic `Lookup` instead of directly taking a `LookupRangeCheckConfig` reference +- `halo2_gadgets::sinsemilla::merkle::chip::MerkleConfig::cond_swap_config` is now public +- `halo2_gadgets::sinsemilla::chip::SinsemillaChip::configure` has a new input + `init_from_private_point` to enable the evaluation of Sinsemilla hash from a private point. ## [0.3.1] - 2024-12-16 - `halo2_gadgets::poseidon::primitives` is now a re-export of the new `halo2_poseidon` diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 3e569416e1..98c3800f0e 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -625,6 +625,14 @@ pub(crate) mod tests { use group::{prime::PrimeCurveAffine, Curve, Group}; use std::marker::PhantomData; + use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner, Value}, + dev::MockProver, + plonk::{Circuit, ConstraintSystem, Error}, + }; + use lazy_static::lazy_static; + use pasta_curves::pallas; + use super::{ chip::{ find_zs_and_us, BaseFieldElem, EccChip, EccConfig, FixedPoint, FullScalar, ShortScalar, @@ -638,13 +646,6 @@ pub(crate) mod tests { PallasLookupRangeCheck, PallasLookupRangeCheck4_5BConfig, PallasLookupRangeCheckConfig, }, }; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::MockProver, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use lazy_static::lazy_static; - use pasta_curves::pallas; #[derive(Debug, Eq, PartialEq, Clone)] pub(crate) struct TestFixedBases; @@ -772,12 +773,12 @@ pub(crate) mod tests { type Base = BaseField; } - struct EccCircuit { + struct MyEccCircuit { test_errors: bool, _lookup_marker: PhantomData, } - impl EccCircuit { + impl MyEccCircuit { fn new(test_errors: bool) -> Self { Self { test_errors, @@ -787,12 +788,12 @@ pub(crate) mod tests { } #[allow(non_snake_case)] - impl Circuit for EccCircuit { + impl Circuit for MyEccCircuit { type Config = EccConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - EccCircuit::new(false) + MyEccCircuit::new(false) } fn configure(meta: &mut ConstraintSystem) -> Self::Config { @@ -841,7 +842,7 @@ pub(crate) mod tests { // Load 10-bit lookup table. In the Action circuit, this will be // provided by the Sinsemilla chip. - config.lookup_config.load(&mut layouter)?; + config.lookup_config.load_range_check_table(&mut layouter)?; // Generate a random non-identity point P let p_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); // P @@ -968,14 +969,14 @@ pub(crate) mod tests { #[test] fn ecc_chip() { let k = 13; - let circuit = EccCircuit::::new(true); + let circuit = MyEccCircuit::::new(true); let prover = MockProver::run(k, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())) } #[test] fn test_ecc_chip_against_stored_circuit() { - let circuit = EccCircuit::::new(false); + let circuit = MyEccCircuit::::new(false); test_against_stored_circuit(circuit, "ecc_chip", 3872); } @@ -988,7 +989,7 @@ pub(crate) mod tests { root.fill(&WHITE).unwrap(); let root = root.titled("Ecc Chip Layout", ("sans-serif", 60)).unwrap(); - let circuit = EccCircuit::::new(false); + let circuit = MyEccCircuit::::new(false); halo2_proofs::dev::CircuitLayout::default() .render(13, &circuit, &root) .unwrap(); @@ -997,7 +998,7 @@ pub(crate) mod tests { #[test] fn ecc_chip_4_5b() { let k = 13; - let circuit = EccCircuit::::new(true); + let circuit = MyEccCircuit::::new(true); let prover = MockProver::run(k, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())) @@ -1005,7 +1006,7 @@ pub(crate) mod tests { #[test] fn test_against_stored_ecc_chip_4_5b() { - let circuit = EccCircuit::::new(false); + let circuit = MyEccCircuit::::new(false); test_against_stored_circuit(circuit, "ecc_chip_4_5b", 3968); } @@ -1018,7 +1019,7 @@ pub(crate) mod tests { root.fill(&WHITE).unwrap(); let root = root.titled("Ecc Chip Layout", ("sans-serif", 60)).unwrap(); - let circuit = EccCircuit::::new(false); + let circuit = MyEccCircuit::::new(false); halo2_proofs::dev::CircuitLayout::default() .render(13, &circuit, &root) .unwrap(); diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs index d06049d3ff..af102fdbfe 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs @@ -244,7 +244,7 @@ impl> Config { /// Multiply the point by sign, using the q_mul_fixed_short gate. /// Constraints `sign` in {-1, 1} - pub fn assign_scalar_sign( + pub(crate) fn assign_scalar_sign( &self, mut layouter: impl Layouter, sign: &AssignedCell, @@ -471,7 +471,7 @@ pub mod tests { } #[derive(Default)] - struct MagnitudeSignCircuit { + struct MyMagnitudeSignCircuit { magnitude: Value, sign: Value, // For test checking @@ -480,17 +480,17 @@ pub mod tests { } impl UtilitiesInstructions - for MagnitudeSignCircuit + for MyMagnitudeSignCircuit { type Var = AssignedCell; } - impl Circuit for MagnitudeSignCircuit { + impl Circuit for MyMagnitudeSignCircuit { type Config = EccConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - MagnitudeSignCircuit { + MyMagnitudeSignCircuit { magnitude: Value::unknown(), sign: Value::unknown(), magnitude_error: Value::unknown(), @@ -584,41 +584,41 @@ pub mod tests { } } - impl MagnitudeSignCircuit { + impl MyMagnitudeSignCircuit { fn test_invalid_magnitude_sign() { // Magnitude larger than 64 bits should fail { let circuits = [ // 2^64 - MagnitudeSignCircuit:: { + MyMagnitudeSignCircuit:: { magnitude: Value::known(pallas::Base::from_u128(1 << 64)), sign: Value::known(pallas::Base::one()), magnitude_error: Value::known(pallas::Base::from(1 << 1)), _lookup_marker: PhantomData, }, // -2^64 - MagnitudeSignCircuit:: { + MyMagnitudeSignCircuit:: { magnitude: Value::known(pallas::Base::from_u128(1 << 64)), sign: Value::known(-pallas::Base::one()), magnitude_error: Value::known(pallas::Base::from(1 << 1)), _lookup_marker: PhantomData, }, // 2^66 - MagnitudeSignCircuit:: { + MyMagnitudeSignCircuit:: { magnitude: Value::known(pallas::Base::from_u128(1 << 66)), sign: Value::known(pallas::Base::one()), magnitude_error: Value::known(pallas::Base::from(1 << 3)), _lookup_marker: PhantomData, }, // -2^66 - MagnitudeSignCircuit:: { + MyMagnitudeSignCircuit:: { magnitude: Value::known(pallas::Base::from_u128(1 << 66)), sign: Value::known(-pallas::Base::one()), magnitude_error: Value::known(pallas::Base::from(1 << 3)), _lookup_marker: PhantomData, }, // 2^254 - MagnitudeSignCircuit:: { + MyMagnitudeSignCircuit:: { magnitude: Value::known(pallas::Base::from_u128(1 << 127).square()), sign: Value::known(pallas::Base::one()), magnitude_error: Value::known( @@ -627,7 +627,7 @@ pub mod tests { _lookup_marker: PhantomData, }, // -2^254 - MagnitudeSignCircuit:: { + MyMagnitudeSignCircuit:: { magnitude: Value::known(pallas::Base::from_u128(1 << 127).square()), sign: Value::known(-pallas::Base::one()), magnitude_error: Value::known( @@ -682,7 +682,7 @@ pub mod tests { // Sign that is not +/- 1 should fail { let magnitude_u64 = rand::random::(); - let circuit: MagnitudeSignCircuit = MagnitudeSignCircuit { + let circuit: MyMagnitudeSignCircuit = MyMagnitudeSignCircuit { magnitude: Value::known(pallas::Base::from(magnitude_u64)), sign: Value::known(pallas::Base::zero()), magnitude_error: Value::unknown(), @@ -744,12 +744,12 @@ pub mod tests { #[test] fn invalid_magnitude_sign() { - MagnitudeSignCircuit::::test_invalid_magnitude_sign(); + MyMagnitudeSignCircuit::::test_invalid_magnitude_sign(); } #[test] fn invalid_magnitude_sign_4_5b() { - MagnitudeSignCircuit::::test_invalid_magnitude_sign(); + MyMagnitudeSignCircuit::::test_invalid_magnitude_sign(); } pub(crate) fn test_mul_sign( @@ -819,24 +819,24 @@ pub mod tests { } #[derive(Default)] - struct MulSignCircuit { + struct MyMulSignCircuit { base: Value, sign: Value, _lookup_marker: PhantomData, } impl UtilitiesInstructions - for MulSignCircuit + for MyMulSignCircuit { type Var = AssignedCell; } - impl Circuit for MulSignCircuit { + impl Circuit for MyMulSignCircuit { type Config = EccConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - MulSignCircuit { + MyMulSignCircuit { base: Value::unknown(), sign: Value::unknown(), _lookup_marker: PhantomData, @@ -900,12 +900,12 @@ pub mod tests { } } - impl MulSignCircuit { + impl MyMulSignCircuit { fn test_invalid_magnitude_sign() { // Sign that is not +/- 1 should fail // Generate a random non-identity point let point = pallas::Point::random(rand::rngs::OsRng); - let circuit: MulSignCircuit = MulSignCircuit { + let circuit: MyMulSignCircuit = MyMulSignCircuit { base: Value::known(point.to_affine()), sign: Value::known(pallas::Base::zero()), _lookup_marker: PhantomData, @@ -954,10 +954,10 @@ pub mod tests { #[test] fn invalid_sign_in_mul_sign() { - MulSignCircuit::::test_invalid_magnitude_sign(); + MyMulSignCircuit::::test_invalid_magnitude_sign(); } #[test] fn invalid_sign_in_mul_sign_4_5b() { - MulSignCircuit::::test_invalid_magnitude_sign(); + MyMulSignCircuit::::test_invalid_magnitude_sign(); } } diff --git a/halo2_gadgets/src/poseidon/pow5.rs b/halo2_gadgets/src/poseidon/pow5.rs index 5c68a2c9ce..89f98fbd42 100644 --- a/halo2_gadgets/src/poseidon/pow5.rs +++ b/halo2_gadgets/src/poseidon/pow5.rs @@ -618,18 +618,18 @@ mod tests { use std::convert::TryInto; use std::marker::PhantomData; - struct PermuteCircuit, const WIDTH: usize, const RATE: usize>( + struct MyPermuteCircuit, const WIDTH: usize, const RATE: usize>( PhantomData, ); impl, const WIDTH: usize, const RATE: usize> Circuit - for PermuteCircuit + for MyPermuteCircuit { type Config = Pow5Config; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - PermuteCircuit::(PhantomData) + MyPermuteCircuit::(PhantomData) } fn configure(meta: &mut ConstraintSystem) -> Pow5Config { @@ -719,12 +719,12 @@ mod tests { #[test] fn poseidon_permute() { let k = 6; - let circuit = PermuteCircuit::(PhantomData); + let circuit = MyPermuteCircuit::(PhantomData); let prover = MockProver::run(k, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())) } - struct HashCircuit< + struct MyHashCircuit< S: Spec, const WIDTH: usize, const RATE: usize, @@ -738,7 +738,7 @@ mod tests { } impl, const WIDTH: usize, const RATE: usize, const L: usize> - Circuit for HashCircuit + Circuit for MyHashCircuit { type Config = Pow5Config; type FloorPlanner = SimpleFloorPlanner; @@ -824,7 +824,7 @@ mod tests { poseidon::Hash::<_, OrchardNullifier, ConstantLength<2>, 3, 2>::init().hash(message); let k = 6; - let circuit = HashCircuit:: { + let circuit = MyHashCircuit:: { message: Value::known(message), output: Value::known(output), _spec: PhantomData, @@ -842,7 +842,7 @@ mod tests { poseidon::Hash::<_, OrchardNullifier, ConstantLength<3>, 3, 2>::init().hash(message); let k = 7; - let circuit = HashCircuit:: { + let circuit = MyHashCircuit:: { message: Value::known(message), output: Value::known(output), _spec: PhantomData, @@ -884,7 +884,7 @@ mod tests { .hash(message); let k = 6; - let circuit = HashCircuit:: { + let circuit = MyHashCircuit:: { message: Value::known(message), output: Value::known(output), _spec: PhantomData, @@ -905,7 +905,7 @@ mod tests { .titled("Poseidon Chip Layout", ("sans-serif", 60)) .unwrap(); - let circuit = HashCircuit:: { + let circuit = MyHashCircuit:: { message: Value::unknown(), output: Value::unknown(), _spec: PhantomData, diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index bbd71a3d67..269c5d9153 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -586,11 +586,11 @@ pub(crate) mod tests { } } - struct SinsemillaCircuit { + struct MySinsemillaCircuit { _lookup_marker: PhantomData, } - impl SinsemillaCircuit { + impl MySinsemillaCircuit { fn new() -> Self { Self { _lookup_marker: PhantomData, @@ -808,12 +808,12 @@ pub(crate) mod tests { } } - impl Circuit for SinsemillaCircuit { + impl Circuit for MySinsemillaCircuit { type Config = EccSinsemillaConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - SinsemillaCircuit::new() + MySinsemillaCircuit::new() } #[allow(non_snake_case)] @@ -833,14 +833,14 @@ pub(crate) mod tests { #[test] fn sinsemilla_chip() { let k = 11; - let circuit = SinsemillaCircuit::::new(); + let circuit = MySinsemillaCircuit::::new(); let prover = MockProver::run(k, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())) } #[test] fn test_sinsemilla_chip_against_stored_circuit() { - let circuit = SinsemillaCircuit::::new(); + let circuit = MySinsemillaCircuit::::new(); test_against_stored_circuit(circuit, "sinsemilla_chip", 4576); } @@ -854,17 +854,17 @@ pub(crate) mod tests { root.fill(&WHITE).unwrap(); let root = root.titled("SinsemillaHash", ("sans-serif", 60)).unwrap(); - let circuit = SinsemillaCircuit::::new(); + let circuit = MySinsemillaCircuit::::new(); halo2_proofs::dev::CircuitLayout::default() .render(11, &circuit, &root) .unwrap(); } - struct SinsemillaCircuitWithHashFromPrivatePoint { + struct MySinsemillaCircuitWithHashFromPrivatePoint { _lookup_marker: PhantomData, } - impl SinsemillaCircuitWithHashFromPrivatePoint { + impl MySinsemillaCircuitWithHashFromPrivatePoint { fn new() -> Self { Self { _lookup_marker: PhantomData, @@ -873,13 +873,13 @@ pub(crate) mod tests { } impl Circuit - for SinsemillaCircuitWithHashFromPrivatePoint + for MySinsemillaCircuitWithHashFromPrivatePoint { type Config = EccSinsemillaConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - SinsemillaCircuitWithHashFromPrivatePoint::new() + MySinsemillaCircuitWithHashFromPrivatePoint::new() } #[allow(non_snake_case)] @@ -900,7 +900,7 @@ pub(crate) mod tests { fn sinsemilla_with_hash_from_private_point_chip_4_5b() { let k = 11; let circuit = - SinsemillaCircuitWithHashFromPrivatePoint::::new(); + MySinsemillaCircuitWithHashFromPrivatePoint::::new(); let prover = MockProver::run(k, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())) } @@ -908,7 +908,7 @@ pub(crate) mod tests { #[test] fn test_against_stored_sinsemilla_with_hash_from_private_point_chip_4_5b() { let circuit = - SinsemillaCircuitWithHashFromPrivatePoint::::new(); + MySinsemillaCircuitWithHashFromPrivatePoint::::new(); test_against_stored_circuit(circuit, "sinsemilla_with_private_init_chip_4_5b", 4672); } @@ -923,7 +923,7 @@ pub(crate) mod tests { let root = root.titled("SinsemillaHash", ("sans-serif", 60)).unwrap(); let circuit = - SinsemillaCircuitWithHashFromPrivatePoint::::new(); + MySinsemillaCircuitWithHashFromPrivatePoint::::new(); halo2_proofs::dev::CircuitLayout::default() .render(11, &circuit, &root) .unwrap(); diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs index ad2c54d4cc..ba7a2e4e6d 100644 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ b/halo2_gadgets/src/sinsemilla/chip.rs @@ -23,7 +23,7 @@ use halo2_proofs::{ }; use pasta_curves::pallas; -mod generator_table; +pub(crate) mod generator_table; use generator_table::GeneratorTableConfig; mod hash_to_point; @@ -153,9 +153,7 @@ where layouter: &mut impl Layouter, ) -> Result<>::Loaded, Error> { // Load the lookup table. - config - .generator_table - .load(config.lookup_config.table_range_check_tag(), layouter) + config.generator_table.load(config.lookup_config, layouter) } /// Creates the Sinsemilla chip @@ -285,6 +283,7 @@ where Constraints::with_selector(q_s1, [("Secant line", secant_line), ("y check", y_check)]) }); + config } } diff --git a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs index 6931655437..0f461ada6b 100644 --- a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs +++ b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs @@ -1,14 +1,15 @@ +use ff::PrimeFieldBits; use group::ff::PrimeField; use halo2_proofs::{ - circuit::{Layouter, Value}, + circuit::Layouter, plonk::{ConstraintSystem, Error, Expression, TableColumn}, poly::Rotation, }; use super::{CommitDomains, FixedPoints, HashDomains}; use crate::{ - sinsemilla::primitives::{self as sinsemilla, K, SINSEMILLA_S}, - utilities::lookup_range_check::PallasLookupRangeCheck, + sinsemilla::primitives::{self as sinsemilla, SINSEMILLA_S}, + utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRangeCheck}, }; use pasta_curves::pallas; @@ -82,144 +83,14 @@ impl GeneratorTableConfig { } /// Load the generator table into the circuit. - pub fn load( + pub fn load( &self, - table_range_check_tag: Option, + lookup_config: impl LookupRangeCheck, layouter: &mut impl Layouter, - ) -> Result<(), Error> { - match table_range_check_tag { - Some(tag) => self.load_with_tag(tag, layouter), - None => self.load_without_tag(layouter), - } - } - - /// Load the generator table into the circuit. - /// - /// | table_idx | table_x | table_y | - /// ------------------------------------------------ - /// | 0 | X(S\[0\]) | Y(S\[0\]) | - /// | 1 | X(S\[1\]) | Y(S\[1\]) | - /// | ... | ... | ... | - /// | 2^10-1 | X(S\[2^10-1\]) | Y(S\[2^10-1\]) | - pub fn load_without_tag( - &self, - layouter: &mut impl Layouter, - ) -> Result<(), Error> { - layouter.assign_table( - || "generator_table", - |mut table| { - for (index, (x, y)) in SINSEMILLA_S.iter().enumerate() { - table.assign_cell( - || "table_idx", - self.table_idx, - index, - || Value::known(pallas::Base::from(index as u64)), - )?; - table.assign_cell(|| "table_x", self.table_x, index, || Value::known(*x))?; - table.assign_cell(|| "table_y", self.table_y, index, || Value::known(*y))?; - } - Ok(()) - }, - ) - } - - /// Load the generator table into the circuit. - /// - /// | table_idx | table_x | table_y | table_range_check_tag | - /// ------------------------------------------------------------------- - /// | 0 | X(S\[0\]) | Y(S\[0\]) | 0 | - /// | 1 | X(S\[1\]) | Y(S\[1\]) | 0 | - /// | ... | ... | ... | 0 | - /// | 2^10-1 | X(S\[2^10-1\]) | Y(S\[2^10-1\]) | 0 | - /// | 0 | X(S\[0\]) | Y(S\[0\]) | 4 | - /// | 1 | X(S\[1\]) | Y(S\[1\]) | 4 | - /// | ... | ... | ... | 4 | - /// | 2^4-1 | X(S\[2^4-1\]) | Y(S\[2^4-1\]) | 4 | - /// | 0 | X(S\[0\]) | Y(S\[0\]) | 5 | - /// | 1 | X(S\[1\]) | Y(S\[1\]) | 5 | - /// | ... | ... | ... | 5 | - /// | 2^5-1 | X(S\[2^5-1\]) | Y(S\[2^5-1\]) | 5 | - pub fn load_with_tag( - &self, - table_range_check_tag: TableColumn, - layouter: &mut impl Layouter, - ) -> Result<(), Error> { - layouter.assign_table( - || "generator_table", - |mut table| { - for (index, (x, y)) in SINSEMILLA_S.iter().enumerate() { - table.assign_cell( - || "table_idx", - self.table_idx, - index, - || Value::known(pallas::Base::from(index as u64)), - )?; - table.assign_cell(|| "table_x", self.table_x, index, || Value::known(*x))?; - table.assign_cell(|| "table_y", self.table_y, index, || Value::known(*y))?; - - table.assign_cell( - || "table_range_check_tag", - table_range_check_tag, - index, - || Value::known(pallas::Base::zero()), - )?; - if index < (1 << 4) { - let new_index = index + (1 << K); - table.assign_cell( - || "table_idx", - self.table_idx, - new_index, - || Value::known(pallas::Base::from(index as u64)), - )?; - table.assign_cell( - || "table_x", - self.table_x, - new_index, - || Value::known(*x), - )?; - table.assign_cell( - || "table_y", - self.table_y, - new_index, - || Value::known(*y), - )?; - table.assign_cell( - || "table_range_check_tag", - table_range_check_tag, - new_index, - || Value::known(pallas::Base::from(4_u64)), - )?; - } - if index < (1 << 5) { - let new_index = index + (1 << 10) + (1 << 4); - table.assign_cell( - || "table_idx", - self.table_idx, - new_index, - || Value::known(pallas::Base::from(index as u64)), - )?; - table.assign_cell( - || "table_x", - self.table_x, - new_index, - || Value::known(*x), - )?; - table.assign_cell( - || "table_y", - self.table_y, - new_index, - || Value::known(*y), - )?; - table.assign_cell( - || "table_range_check_tag", - table_range_check_tag, - new_index, - || Value::known(pallas::Base::from(5_u64)), - )?; - } - } - Ok(()) - }, - ) + ) -> Result<(), Error> + where + F: PrimeFieldBits, + { + lookup_config.load(self, layouter) } } diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index e87bcdb7bb..15a85c9381 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -1,7 +1,7 @@ use super::super::{CommitDomains, HashDomains, SinsemillaInstructions}; +use super::{NonIdentityEccPoint, SinsemillaChip}; use crate::{ ecc::FixedPoints, - sinsemilla::chip::{NonIdentityEccPoint, SinsemillaChip}, sinsemilla::primitives::{self as sinsemilla, lebs2ip_k, INV_TWO_POW_K, SINSEMILLA_S}, utilities::lookup_range_check::PallasLookupRangeCheck, }; diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 83f20ed161..b3ca2dbc97 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -210,14 +210,14 @@ pub mod tests { const MERKLE_DEPTH: usize = 32; #[derive(Default)] - struct MerkleCircuit { + struct MyMerkleCircuit { leaf: Value, leaf_pos: Value, merkle_path: Value<[pallas::Base; MERKLE_DEPTH]>, _lookup_marker: PhantomData, } - impl MerkleCircuit { + impl MyMerkleCircuit { fn new( leaf: Value, leaf_pos: Value, @@ -296,7 +296,7 @@ pub mod tests { (config1, config2) } - impl Circuit for MerkleCircuit { + impl Circuit for MyMerkleCircuit { type Config = ( MerkleConfig, MerkleConfig, @@ -304,7 +304,7 @@ pub mod tests { type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - MerkleCircuit::new(Value::default(), Value::default(), Value::default()) + MyMerkleCircuit::new(Value::default(), Value::default(), Value::default()) } fn configure(meta: &mut ConstraintSystem) -> Self::Config { @@ -392,7 +392,7 @@ pub mod tests { } } - fn generate_circuit() -> MerkleCircuit { + fn generate_circuit() -> MyMerkleCircuit { let mut rng = OsRng; // Choose a random leaf and position @@ -405,7 +405,7 @@ pub mod tests { .collect(); // The root is provided as a public input in the Orchard circuit. - MerkleCircuit::new( + MyMerkleCircuit::new( Value::known(leaf), Value::known(pos), Value::known(path.try_into().unwrap()), @@ -414,7 +414,7 @@ pub mod tests { #[test] fn merkle_chip() { - let circuit: MerkleCircuit = generate_circuit(); + let circuit: MyMerkleCircuit = generate_circuit(); let prover = MockProver::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())) @@ -422,7 +422,7 @@ pub mod tests { #[test] fn test_merkle_chip_against_stored_circuit() { - let circuit: MerkleCircuit = generate_circuit(); + let circuit: MyMerkleCircuit = generate_circuit(); test_against_stored_circuit(circuit, "merkle_chip", 4160); } @@ -435,7 +435,7 @@ pub mod tests { root.fill(&WHITE).unwrap(); let root = root.titled("MerkleCRH Path", ("sans-serif", 60)).unwrap(); - let circuit: MerkleCircuit = MerkleCircuit { + let circuit: MyMerkleCircuit = MyMerkleCircuit { leaf: Value::default(), leaf_pos: Value::default(), merkle_path: Value::default(), @@ -448,14 +448,14 @@ pub mod tests { } #[derive(Default)] - struct MerkleCircuitWithHashFromPrivatePoint { + struct MyMerkleCircuitWithHashFromPrivatePoint { leaf: Value, leaf_pos: Value, merkle_path: Value<[pallas::Base; MERKLE_DEPTH]>, _lookup_marker: PhantomData, } - impl MerkleCircuitWithHashFromPrivatePoint { + impl MyMerkleCircuitWithHashFromPrivatePoint { fn new( leaf: Value, leaf_pos: Value, @@ -471,7 +471,7 @@ pub mod tests { } impl Circuit - for MerkleCircuitWithHashFromPrivatePoint + for MyMerkleCircuitWithHashFromPrivatePoint { type Config = ( MerkleConfig, @@ -480,7 +480,7 @@ pub mod tests { type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - MerkleCircuitWithHashFromPrivatePoint::new( + MyMerkleCircuitWithHashFromPrivatePoint::new( Value::default(), Value::default(), Value::default(), @@ -573,7 +573,7 @@ pub mod tests { } fn generate_circuit_4_5b( - ) -> MerkleCircuitWithHashFromPrivatePoint { + ) -> MyMerkleCircuitWithHashFromPrivatePoint { let mut rng = OsRng; // Choose a random leaf and position @@ -586,7 +586,7 @@ pub mod tests { .collect(); // The root is provided as a public input in the Orchard circuit. - MerkleCircuitWithHashFromPrivatePoint::new( + MyMerkleCircuitWithHashFromPrivatePoint::new( Value::known(leaf), Value::known(pos), Value::known(path.try_into().unwrap()), @@ -594,7 +594,7 @@ pub mod tests { } #[test] fn merkle_with_hash_from_private_point_chip_4_5b() { - let circuit: MerkleCircuitWithHashFromPrivatePoint = + let circuit: MyMerkleCircuitWithHashFromPrivatePoint = generate_circuit_4_5b(); let prover = MockProver::run(11, &circuit, vec![]).unwrap(); @@ -603,7 +603,7 @@ pub mod tests { #[test] fn test_against_stored_merkle_with_hash_from_private_point_chip_4_5b() { - let circuit: MerkleCircuitWithHashFromPrivatePoint = + let circuit: MyMerkleCircuitWithHashFromPrivatePoint = generate_circuit_4_5b(); test_against_stored_circuit(circuit, "merkle_with_private_init_chip_4_5b", 4160); @@ -622,8 +622,8 @@ pub mod tests { root.fill(&WHITE).unwrap(); let root = root.titled("MerkleCRH Path", ("sans-serif", 60)).unwrap(); - let circuit: MerkleCircuitWithHashFromPrivatePoint = - MerkleCircuitWithHashFromPrivatePoint::new( + let circuit: MyMerkleCircuitWithHashFromPrivatePoint = + MyMerkleCircuitWithHashFromPrivatePoint::new( Value::default(), Value::default(), Value::default(), diff --git a/halo2_gadgets/src/tests.rs b/halo2_gadgets/src/tests.rs deleted file mode 100644 index 1d00cc79b7..0000000000 --- a/halo2_gadgets/src/tests.rs +++ /dev/null @@ -1 +0,0 @@ -pub(crate) mod test_utils; diff --git a/halo2_gadgets/src/utilities/cond_swap.rs b/halo2_gadgets/src/utilities/cond_swap.rs index 43a0f791c6..3b9d051f4f 100644 --- a/halo2_gadgets/src/utilities/cond_swap.rs +++ b/halo2_gadgets/src/utilities/cond_swap.rs @@ -317,13 +317,13 @@ mod tests { #[test] fn cond_swap() { #[derive(Default)] - struct CondSwapCircuit { + struct MyCondSwapCircuit { a: Value, b: Value, swap: Value, } - impl Circuit for CondSwapCircuit { + impl Circuit for MyCondSwapCircuit { type Config = CondSwapConfig; type FloorPlanner = SimpleFloorPlanner; @@ -380,7 +380,7 @@ mod tests { // Test swap case { - let circuit: CondSwapCircuit = CondSwapCircuit { + let circuit: MyCondSwapCircuit = MyCondSwapCircuit { a: Value::known(Base::random(rng)), b: Value::known(Base::random(rng)), swap: Value::known(true), @@ -391,7 +391,7 @@ mod tests { // Test non-swap case { - let circuit: CondSwapCircuit = CondSwapCircuit { + let circuit: MyCondSwapCircuit = MyCondSwapCircuit { a: Value::known(Base::random(rng)), b: Value::known(Base::random(rng)), swap: Value::known(false), @@ -428,20 +428,20 @@ mod tests { } #[derive(Default)] - struct MuxCircuit { + struct MyMuxCircuit { left_point: Value, right_point: Value, choice: Value, _lookup_marker: PhantomData, } - impl MuxCircuit { + impl MyMuxCircuit { fn new( left_point: Value, right_point: Value, choice: Value, ) -> Self { - MuxCircuit { + MyMuxCircuit { left_point, right_point, choice, @@ -450,12 +450,12 @@ mod tests { } } - impl Circuit for MuxCircuit { + impl Circuit for MyMuxCircuit { type Config = MuxConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - MuxCircuit::::new(Value::default(), Value::default(), Value::default()) + MyMuxCircuit::::new(Value::default(), Value::default(), Value::default()) } fn configure(meta: &mut ConstraintSystem) -> Self::Config { @@ -597,7 +597,7 @@ mod tests { } } - impl MuxCircuit { + impl MyMuxCircuit { fn test_mux_circuits() { // Test different circuits let mut circuits = vec![]; @@ -610,7 +610,7 @@ mod tests { }; let left_point = pallas::Point::random(OsRng).to_affine(); let right_point = pallas::Point::random(OsRng).to_affine(); - circuits.push(MuxCircuit:: { + circuits.push(MyMuxCircuit:: { left_point: Value::known(left_point), right_point: Value::known(right_point), choice: Value::known(choice_value), @@ -638,7 +638,7 @@ mod tests { } } - MuxCircuit::::test_mux_circuits(); - MuxCircuit::::test_mux_circuits(); + MyMuxCircuit::::test_mux_circuits(); + MyMuxCircuit::::test_mux_circuits(); } } diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 7917155824..d756dd0aec 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -10,9 +10,9 @@ use std::{convert::TryInto, fmt::Debug, marker::PhantomData}; use ff::PrimeFieldBits; +use crate::sinsemilla::{chip::generator_table::GeneratorTableConfig, primitives as sinsemilla}; use pasta_curves::pallas; - -use crate::sinsemilla::primitives as sinsemilla; +use sinsemilla::SINSEMILLA_S; use super::*; @@ -58,7 +58,7 @@ impl RangeConstrained> { } } -/// Configuration that provides methods for a 10-bit lookup range check. +/// Configuration that provides methods for a lookup range check. #[derive(Eq, PartialEq, Debug, Clone, Copy)] pub struct LookupRangeCheckConfig { q_lookup: Selector, @@ -93,15 +93,19 @@ pub trait LookupRangeCheck: Eq + Copy + Debug where Self: Sized; - /// Returns the table column that contains the range check tag. - fn table_range_check_tag(&self) -> Option; + /// Load the generator table into the circuit. + fn load( + &self, + generator_table_config: &GeneratorTableConfig, + layouter: &mut impl Layouter, + ) -> Result<(), Error>; #[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>; + fn load_range_check_table(&self, layouter: &mut impl Layouter) -> Result<(), Error>; /// Constrain `x` to be a NUM_BITS word. /// @@ -382,15 +386,52 @@ impl LookupRangeCheck for LookupRangeCh config } - fn table_range_check_tag(&self) -> Option { - None + /// Load the generator table into the circuit. + /// + /// | table_idx | table_x | table_y | + /// ------------------------------------------------ + /// | 0 | X(S\[0\]) | Y(S\[0\]) | + /// | 1 | X(S\[1\]) | Y(S\[1\]) | + /// | ... | ... | ... | + /// | 2^10-1 | X(S\[2^10-1\]) | Y(S\[2^10-1\]) | + fn load( + &self, + generator_table_config: &GeneratorTableConfig, + layouter: &mut impl Layouter, + ) -> Result<(), Error> { + layouter.assign_table( + || "generator_table", + |mut table| { + for (index, (x, y)) in SINSEMILLA_S.iter().enumerate() { + table.assign_cell( + || "table_idx", + generator_table_config.table_idx, + index, + || Value::known(pallas::Base::from(index as u64)), + )?; + table.assign_cell( + || "table_x", + generator_table_config.table_x, + index, + || Value::known(*x), + )?; + table.assign_cell( + || "table_y", + generator_table_config.table_y, + index, + || Value::known(*y), + )?; + } + Ok(()) + }, + ) } #[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> { + fn load_range_check_table(&self, layouter: &mut impl Layouter) -> Result<(), Error> { layouter.assign_table( || "table_idx", |mut table| { @@ -608,15 +649,121 @@ impl LookupRangeCheck Self::configure_with_tag(meta, running_sum, table_idx, table_range_check_tag) } - fn table_range_check_tag(&self) -> Option { - Some(self.table_range_check_tag) + /// Load the generator table into the circuit. + /// + /// | table_idx | table_x | table_y | table_range_check_tag | + /// ------------------------------------------------------------------- + /// | 0 | X(S\[0\]) | Y(S\[0\]) | 0 | + /// | 1 | X(S\[1\]) | Y(S\[1\]) | 0 | + /// | ... | ... | ... | 0 | + /// | 2^10-1 | X(S\[2^10-1\]) | Y(S\[2^10-1\]) | 0 | + /// | 0 | X(S\[0\]) | Y(S\[0\]) | 4 | + /// | 1 | X(S\[1\]) | Y(S\[1\]) | 4 | + /// | ... | ... | ... | 4 | + /// | 2^4-1 | X(S\[2^4-1\]) | Y(S\[2^4-1\]) | 4 | + /// | 0 | X(S\[0\]) | Y(S\[0\]) | 5 | + /// | 1 | X(S\[1\]) | Y(S\[1\]) | 5 | + /// | ... | ... | ... | 5 | + /// | 2^5-1 | X(S\[2^5-1\]) | Y(S\[2^5-1\]) | 5 | + fn load( + &self, + generator_table_config: &GeneratorTableConfig, + layouter: &mut impl Layouter, + ) -> Result<(), Error> { + layouter.assign_table( + || "generator_table", + |mut table| { + for (index, (x, y)) in SINSEMILLA_S.iter().enumerate() { + table.assign_cell( + || "table_idx", + generator_table_config.table_idx, + index, + || Value::known(pallas::Base::from(index as u64)), + )?; + table.assign_cell( + || "table_x", + generator_table_config.table_x, + index, + || Value::known(*x), + )?; + table.assign_cell( + || "table_y", + generator_table_config.table_y, + index, + || Value::known(*y), + )?; + + table.assign_cell( + || "table_range_check_tag", + self.table_range_check_tag, + index, + || Value::known(pallas::Base::zero()), + )?; + if index < (1 << 4) { + let new_index = index + (1 << sinsemilla::K); + table.assign_cell( + || "table_idx", + generator_table_config.table_idx, + new_index, + || Value::known(pallas::Base::from(index as u64)), + )?; + table.assign_cell( + || "table_x", + generator_table_config.table_x, + new_index, + || Value::known(*x), + )?; + table.assign_cell( + || "table_y", + generator_table_config.table_y, + new_index, + || Value::known(*y), + )?; + table.assign_cell( + || "table_range_check_tag", + self.table_range_check_tag, + new_index, + || Value::known(pallas::Base::from(4_u64)), + )?; + } + if index < (1 << 5) { + let new_index = index + (1 << 10) + (1 << 4); + table.assign_cell( + || "table_idx", + generator_table_config.table_idx, + new_index, + || Value::known(pallas::Base::from(index as u64)), + )?; + table.assign_cell( + || "table_x", + generator_table_config.table_x, + new_index, + || Value::known(*x), + )?; + table.assign_cell( + || "table_y", + generator_table_config.table_y, + new_index, + || Value::known(*y), + )?; + table.assign_cell( + || "table_range_check_tag", + self.table_range_check_tag, + new_index, + || Value::known(pallas::Base::from(5_u64)), + )?; + } + } + Ok(()) + }, + ) } #[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> { + fn load_range_check_table(&self, layouter: &mut impl Layouter) -> Result<(), Error> { layouter.assign_table( || "table_idx", |mut table| { @@ -754,7 +901,7 @@ mod tests { mut layouter: impl Layouter, ) -> Result<(), Error> { // Load table_idx - config.load(&mut layouter)?; + config.load_range_check_table(&mut layouter)?; // Lookup constraining element to be no longer than num_words * K bits. let elements_and_expected_final_zs = [ @@ -877,7 +1024,7 @@ mod tests { mut layouter: impl Layouter, ) -> Result<(), Error> { // Load table_idx - config.load(&mut layouter)?; + config.load_range_check_table(&mut layouter)?; // Lookup constraining element to be no longer than num_bits. config.witness_short_check(