From 35c815d36ed271d0a6542a664465590f2362fa8f Mon Sep 17 00:00:00 2001 From: Constance Date: Tue, 21 Mar 2023 17:04:19 +0100 Subject: [PATCH 01/99] Add variable-base sign-scalar multiplication --- halo2_gadgets/src/ecc.rs | 34 ++- halo2_gadgets/src/ecc/chip.rs | 18 ++ halo2_gadgets/src/ecc/chip/mul_fixed/short.rs | 279 +++++++++++++++++- 3 files changed, 328 insertions(+), 3 deletions(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 38fab0a49a..4bf58d3ec6 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -4,7 +4,7 @@ use std::fmt::Debug; use halo2_proofs::{ arithmetic::CurveAffine, - circuit::{Chip, Layouter, Value}, + circuit::{AssignedCell, Chip, Layouter, Value}, plonk::Error, }; @@ -111,6 +111,15 @@ pub trait EccInstructions: b: &B, ) -> Result; + /// Performs variable-base sign-scalar multiplication, returning `[sign] point` + /// `sign` must be in {-1, 1}. + fn mul_sign( + &self, + layouter: &mut impl Layouter, + sign: &AssignedCell, + point: &Self::Point, + ) -> Result; + /// Performs variable-base scalar multiplication, returning `[scalar] base`. fn mul( &self, @@ -432,6 +441,21 @@ impl + Clone + Debug + Eq> Point, + sign: &AssignedCell, + ) -> Result, Error> { + self.chip + .mul_sign(&mut layouter, sign, &self.inner) + .map(|point| Point { + chip: self.chip.clone(), + inner: point, + }) + } } /// The affine short Weierstrass x-coordinate of a point on a specific elliptic curve. @@ -865,6 +889,14 @@ pub(crate) mod tests { )?; } + // Test variable-base sign-scalar multiplication + { + super::chip::mul_fixed::short::tests::test_mul_sign( + chip.clone(), + layouter.namespace(|| "variable-base sign-scalar mul"), + )?; + } + // Test full-width fixed-base scalar multiplication { super::chip::mul_fixed::full_width::tests::test_mul_fixed( diff --git a/halo2_gadgets/src/ecc/chip.rs b/halo2_gadgets/src/ecc/chip.rs index 4d12057afb..3766b454d9 100644 --- a/halo2_gadgets/src/ecc/chip.rs +++ b/halo2_gadgets/src/ecc/chip.rs @@ -532,6 +532,24 @@ where ) } + /// Performs variable-base sign-scalar multiplication, returning `[sign] point` + /// `sign` must be in {-1, 1}. + fn mul_sign( + &self, + layouter: &mut impl Layouter, + sign: &AssignedCell, + point: &Self::Point, + ) -> Result { + // Multiply point by sign, using the same gate as mul_fixed::short. + // This also constrains sign to be in {-1, 1}. + let config_short = self.config().mul_fixed_short.clone(); + config_short.assign_scalar_sign( + layouter.namespace(|| "variable-base sign-scalar mul"), + sign, + point, + ) + } + fn mul( &self, layouter: &mut impl Layouter, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs index bfdc735f70..94d61de54a 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs @@ -4,7 +4,7 @@ use super::super::{EccPoint, EccScalarFixedShort, FixedPoints, L_SCALAR_SHORT, N use crate::{ecc::chip::MagnitudeSign, utilities::bool_check}; use halo2_proofs::{ - circuit::{Layouter, Region}, + circuit::{AssignedCell, Layouter, Region}, plonk::{ConstraintSystem, Constraints, Error, Expression, Selector}, poly::Rotation, }; @@ -241,11 +241,73 @@ impl> Config { Ok((result, scalar)) } + + /// Multiply the point by sign, using the q_mul_fixed_short gate. + /// Constraints `sign` in {-1, 1} + pub fn assign_scalar_sign( + &self, + mut layouter: impl Layouter, + sign: &AssignedCell, + point: &EccPoint, + ) -> Result { + let signed_point = layouter.assign_region( + || "Signed point", + |mut region| { + let offset = 0; + + // Enable mul_fixed_short selector to check the sign logic. + self.q_mul_fixed_short.enable(&mut region, offset)?; + + // Set "last window" to 0 (this field is irrelevant here). + region.assign_advice_from_constant( + || "u=0", + self.super_config.u, + offset, + pallas::Base::zero(), + )?; + + // Copy sign to `window` column + sign.copy_advice(|| "sign", &mut region, self.super_config.window, offset)?; + + // Assign the input y-coordinate. + point.y.copy_advice( + || "unsigned y", + &mut region, + self.super_config.add_config.y_qr, + offset, + )?; + + // Conditionally negate y-coordinate according to the value of sign + let signed_y_val = sign.value().and_then(|sign| { + if sign == &-pallas::Base::one() { + -point.y.value() + } else { + point.y.value().cloned() + } + }); + + // Assign the output signed y-coordinate. + let signed_y = region.assign_advice( + || "signed y", + self.super_config.add_config.y_p, + offset, + || signed_y_val, + )?; + + Ok(EccPoint { + x: point.x.clone(), + y: signed_y, + }) + }, + )?; + + Ok(signed_point) + } } #[cfg(test)] pub mod tests { - use group::{ff::PrimeField, Curve}; + use group::{ff::PrimeField, Curve, Group}; use halo2_proofs::{ arithmetic::CurveAffine, circuit::{AssignedCell, Chip, Layouter, Value}, @@ -657,4 +719,217 @@ pub mod tests { ); } } + + pub(crate) fn test_mul_sign( + chip: EccChip, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + // Generate a random non-identity point P + let p_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); + let p = Point::new( + chip.clone(), + layouter.namespace(|| "P"), + Value::known(p_val), + )?; + + // Create -P + let p_neg_val = -p_val; + let p_neg = Point::new( + chip.clone(), + layouter.namespace(|| "-P"), + Value::known(p_neg_val), + )?; + + // Create the identity point + let identity = Point::new( + chip.clone(), + layouter.namespace(|| "identity"), + Value::known(pallas::Point::identity().to_affine()), + )?; + + // Create -1 and 1 scalars + let pos_sign = chip.load_private( + layouter.namespace(|| "positive sign"), + chip.config().advices[0], + Value::known(pallas::Base::one()), + )?; + let neg_sign = chip.load_private( + layouter.namespace(|| "negative sign"), + chip.config().advices[1], + Value::known(-pallas::Base::one()), + )?; + + // [1] P == P + { + let result = p.mul_sign(layouter.namespace(|| "[1] P"), &pos_sign)?; + result.constrain_equal(layouter.namespace(|| "constrain [1] P"), &p)?; + } + + // [-1] P == -P + { + let result = p.mul_sign(layouter.namespace(|| "[1] P"), &neg_sign)?; + result.constrain_equal(layouter.namespace(|| "constrain [1] P"), &p_neg)?; + } + + // [1] 0 == 0 + { + let result = identity.mul_sign(layouter.namespace(|| "[1] O"), &pos_sign)?; + result.constrain_equal(layouter.namespace(|| "constrain [1] 0"), &identity)?; + } + + // [-1] 0 == 0 + { + let result = identity.mul_sign(layouter.namespace(|| "[-1] O"), &neg_sign)?; + result.constrain_equal(layouter.namespace(|| "constrain [1] 0"), &identity)?; + } + + Ok(()) + } + + #[test] + fn invalid_sign_in_mul_sign() { + use crate::{ecc::chip::EccConfig, utilities::UtilitiesInstructions}; + use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner}, + dev::{FailureLocation, MockProver, VerifyFailure}, + plonk::{Circuit, ConstraintSystem, Error}, + }; + + #[derive(Default)] + struct MyCircuit { + base: Value, + sign: Value, + } + + impl UtilitiesInstructions for MyCircuit { + type Var = AssignedCell; + } + + impl Circuit for MyCircuit { + type Config = EccConfig; + 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(), + ]; + let lookup_table = 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(), + ]; + + // Shared fixed column for loading constants + let constants = meta.fixed_column(); + meta.enable_constant(constants); + + let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table); + EccChip::::configure(meta, advices, lagrange_coeffs, range_check) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let chip = EccChip::construct(config.clone()); + + let column = config.advices[0]; + + //let short_config = config.mul_fixed_short.clone(); + let base = Point::new(chip, layouter.namespace(|| "load base"), self.base)?; + + let sign = + self.load_private(layouter.namespace(|| "load sign"), column, self.sign)?; + + base.mul_sign(layouter.namespace(|| "[sign] base"), &sign)?; + + Ok(()) + } + } + + // Copied from halo2_proofs::dev::util + fn format_value(v: pallas::Base) -> String { + use ff::Field; + if v.is_zero_vartime() { + "0".into() + } else if v == pallas::Base::one() { + "1".into() + } else if v == -pallas::Base::one() { + "-1".into() + } else { + // Format value as hex. + let s = format!("{:?}", v); + // Remove leading zeroes. + let s = s.strip_prefix("0x").unwrap(); + let s = s.trim_start_matches('0'); + format!("0x{}", s) + } + } + + // Sign that is not +/- 1 should fail + // Generate a random non-identity point + let point = pallas::Point::random(rand::rngs::OsRng); + let circuit = MyCircuit { + base: Value::known(point.to_affine()), + sign: Value::known(pallas::Base::zero()), + }; + + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!( + prover.verify(), + Err(vec![ + VerifyFailure::ConstraintNotSatisfied { + constraint: ((17, "Short fixed-base mul gate").into(), 1, "sign_check").into(), + location: FailureLocation::InRegion { + region: (2, "Signed point").into(), + offset: 0, + }, + cell_values: vec![(((Any::Advice, 4).into(), 0).into(), "0".to_string())], + }, + VerifyFailure::ConstraintNotSatisfied { + constraint: ( + (17, "Short fixed-base mul gate").into(), + 3, + "negation_check" + ) + .into(), + location: FailureLocation::InRegion { + region: (2, "Signed point").into(), + offset: 0, + }, + cell_values: vec![ + ( + ((Any::Advice, 1).into(), 0).into(), + format_value(*point.to_affine().coordinates().unwrap().y()), + ), + ( + ((Any::Advice, 3).into(), 0).into(), + format_value(*point.to_affine().coordinates().unwrap().y()), + ), + (((Any::Advice, 4).into(), 0).into(), "0".to_string()), + ], + } + ]) + ); + } } From 731bc1021a000cc14b05d952571ded51bf6a15ea Mon Sep 17 00:00:00 2001 From: Constance Date: Wed, 19 Apr 2023 11:01:24 +0200 Subject: [PATCH 02/99] Add CommitDomain creation from two personalizations --- halo2_gadgets/src/sinsemilla/primitives.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/halo2_gadgets/src/sinsemilla/primitives.rs b/halo2_gadgets/src/sinsemilla/primitives.rs index 9bf6a72332..63aeec376c 100644 --- a/halo2_gadgets/src/sinsemilla/primitives.rs +++ b/halo2_gadgets/src/sinsemilla/primitives.rs @@ -200,6 +200,21 @@ impl CommitDomain { } } + /// Constructs a new `CommitDomain` from `hash_personalization` a personalization for hashing + /// and `blind_personalization` another personalization for blinding. + pub fn new_with_two_personalizations( + hash_personalization: &str, + blind_personalization: &str, + ) -> Self { + let m_prefix = format!("{}-M", hash_personalization); + let r_prefix = format!("{}-r", blind_personalization); + let hasher_r = pallas::Point::hash_to_curve(&r_prefix); + CommitDomain { + M: HashDomain::new(&m_prefix), + R: hasher_r(&[]), + } + } + /// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. /// /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit From b1e397f5b1e2e7e43741e69ebafa3a1680a2ab84 Mon Sep 17 00:00:00 2001 From: Constance Date: Wed, 19 Apr 2023 09:26:02 +0200 Subject: [PATCH 03/99] Add commit_from_hash_point --- halo2_gadgets/src/sinsemilla/primitives.rs | 44 +++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/halo2_gadgets/src/sinsemilla/primitives.rs b/halo2_gadgets/src/sinsemilla/primitives.rs index 63aeec376c..281a76d504 100644 --- a/halo2_gadgets/src/sinsemilla/primitives.rs +++ b/halo2_gadgets/src/sinsemilla/primitives.rs @@ -184,7 +184,8 @@ impl HashDomain { #[derive(Debug)] #[allow(non_snake_case)] pub struct CommitDomain { - M: HashDomain, + /// A domain in which $\mathsf{SinsemillaHashToPoint}$ and $\mathsf{SinsemillaHash}$ can be used + pub M: HashDomain, R: pallas::Point, } @@ -229,6 +230,19 @@ impl CommitDomain { .map(|p| p + Wnaf::new().scalar(r).base(self.R)) } + /// Returns `SinsemillaCommit_r(personalization, msg) = hash_point + \[r\]R` + /// where `SinsemillaHash(personalization, msg) = hash_point` + /// and `R` is derived from the `personalization`. + #[allow(non_snake_case)] + pub fn commit_from_hash_point( + &self, + hash_point: CtOption, + r: &pallas::Scalar, + ) -> CtOption { + // We use complete addition for the blinding factor. + hash_point.map(|p| p + Wnaf::new().scalar(r).base(self.R)) + } + /// $\mathsf{SinsemillaShortCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. /// /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit @@ -320,4 +334,32 @@ mod tests { assert_eq!(computed, actual); } } + + #[test] + fn commit_in_several_steps() { + use rand::{rngs::OsRng, Rng}; + + use ff::Field; + + use crate::sinsemilla::primitives::CommitDomain; + + let domain = CommitDomain::new("z.cash:ZSA-NoteCommit"); + + let mut os_rng = OsRng::default(); + let msg: Vec = (0..36).map(|_| os_rng.gen::()).collect(); + + let rcm = pallas::Scalar::random(&mut os_rng); + + // Evaluate the commitment with commit function + let commit1 = domain.commit(msg.clone().into_iter(), &rcm); + + // Evaluate the commitment with the following steps + // 1. hash msg + // 2. evaluate the commitment from the hash point + let hash_point = domain.M.hash_to_point(msg.into_iter()); + let commit2 = domain.commit_from_hash_point(hash_point, &rcm); + + // Test equality + assert_eq!(commit1.unwrap(), commit2.unwrap()); + } } From 8cfe0ae67df157868c1838321fb39d68786fbcf2 Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 20 Apr 2023 17:02:03 +0300 Subject: [PATCH 04/99] updated naming --- halo2_gadgets/src/sinsemilla/primitives.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/halo2_gadgets/src/sinsemilla/primitives.rs b/halo2_gadgets/src/sinsemilla/primitives.rs index 281a76d504..f90c63ac12 100644 --- a/halo2_gadgets/src/sinsemilla/primitives.rs +++ b/halo2_gadgets/src/sinsemilla/primitives.rs @@ -201,14 +201,10 @@ impl CommitDomain { } } - /// Constructs a new `CommitDomain` from `hash_personalization` a personalization for hashing - /// and `blind_personalization` another personalization for blinding. - pub fn new_with_two_personalizations( - hash_personalization: &str, - blind_personalization: &str, - ) -> Self { - let m_prefix = format!("{}-M", hash_personalization); - let r_prefix = format!("{}-r", blind_personalization); + /// Constructs a new `CommitDomain` from different values for `hash_domain` and `blind_domain` + pub fn new_with_personalization(hash_domain: &str, blind_domain: &str) -> Self { + let m_prefix = format!("{}-M", hash_domain); + let r_prefix = format!("{}-r", blind_domain); let hasher_r = pallas::Point::hash_to_curve(&r_prefix); CommitDomain { M: HashDomain::new(&m_prefix), @@ -230,7 +226,7 @@ impl CommitDomain { .map(|p| p + Wnaf::new().scalar(r).base(self.R)) } - /// Returns `SinsemillaCommit_r(personalization, msg) = hash_point + \[r\]R` + /// Returns `SinsemillaCommit_r(personalization, msg) = hash_point + [r]R` /// where `SinsemillaHash(personalization, msg) = hash_point` /// and `R` is derived from the `personalization`. #[allow(non_snake_case)] From 54697b22ed293fd45fe3021552b29204bd91aaeb Mon Sep 17 00:00:00 2001 From: Constance Date: Mon, 17 Apr 2023 16:51:53 +0200 Subject: [PATCH 05/99] Add hash and blinding_factor functions --- halo2_gadgets/src/sinsemilla.rs | 39 +++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 3f06315a77..ca4c14fb1d 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -412,6 +412,41 @@ where } } + #[allow(clippy::type_complexity)] + /// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. + /// + /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit + pub fn hash( + &self, + layouter: impl Layouter, + message: Message, + ) -> Result< + ( + ecc::NonIdentityPoint, + Vec, + ), + Error, + > { + assert_eq!(self.M.sinsemilla_chip, message.chip); + self.M.hash_to_point(layouter, message) + } + + #[allow(clippy::type_complexity)] + /// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. + /// + /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit + pub fn blinding_factor( + &self, + mut layouter: impl Layouter, + r: ecc::ScalarFixed, + ) -> Result< + ecc::Point, + Error, + > { + let (blind, _) = self.R.mul(layouter.namespace(|| "[r] R"), r)?; + Ok(blind) + } + #[allow(clippy::type_complexity)] /// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. /// @@ -429,8 +464,8 @@ where Error, > { assert_eq!(self.M.sinsemilla_chip, message.chip); - let (blind, _) = self.R.mul(layouter.namespace(|| "[r] R"), r)?; - let (p, zs) = self.M.hash_to_point(layouter.namespace(|| "M"), message)?; + let blind = self.blinding_factor(layouter.namespace(|| "[r] R"), r)?; + let (p, zs) = self.hash(layouter.namespace(|| "M"), message)?; let commitment = p.add(layouter.namespace(|| "M + [r] R"), &blind)?; Ok((commitment, zs)) } From 4ce262d8e7d98a9af5f3edfa9fec489b38f35f27 Mon Sep 17 00:00:00 2001 From: Constance Date: Tue, 18 Apr 2023 10:19:25 +0200 Subject: [PATCH 06/99] Add some functionalities for MuxChip --- halo2_gadgets/src/ecc/chip.rs | 2 +- halo2_proofs/src/circuit.rs | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/halo2_gadgets/src/ecc/chip.rs b/halo2_gadgets/src/ecc/chip.rs index 3766b454d9..0b6fa0d4b4 100644 --- a/halo2_gadgets/src/ecc/chip.rs +++ b/halo2_gadgets/src/ecc/chip.rs @@ -48,7 +48,7 @@ impl EccPoint { /// Constructs a point from its coordinates, without checking they are on the curve. /// /// This is an internal API that we only use where we know we have a valid curve point. - pub(crate) fn from_coordinates_unchecked( + pub fn from_coordinates_unchecked( x: AssignedCell, pallas::Base>, y: AssignedCell, pallas::Base>, ) -> Self { diff --git a/halo2_proofs/src/circuit.rs b/halo2_proofs/src/circuit.rs index 0822d8d8aa..1083339fed 100644 --- a/halo2_proofs/src/circuit.rs +++ b/halo2_proofs/src/circuit.rs @@ -139,6 +139,16 @@ impl AssignedCell, F> { } } +impl From> for AssignedCell, F> { + fn from(ac: AssignedCell) -> Self { + AssignedCell { + value: ac.value.map(|a| a.into()), + cell: ac.cell, + _marker: Default::default(), + } + } +} + impl AssignedCell where for<'v> Assigned: From<&'v V>, From 475f54daa4a15adb3920f5231d3d4a00c0ca7b45 Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Fri, 23 Jun 2023 10:31:10 +0200 Subject: [PATCH 07/99] Add Point::new_from_constant method (#17) It is now possible to create a Point from a constant. This functionality is required to evaluate the old nullifier. - for non split_notes, nf_old = Extract_P([PRF^{nfOrchard}_{nk}(rho_old) + psi_nf) mod q_P] NullifierK + cm_old) - for split notes, nf_old = Extract_P([PRF^{nfOrchard}_{nk}(rho_old) + psi_nf) mod q_P] NullifierK + cm_old + NullifierL) --- halo2_gadgets/src/ecc.rs | 19 +++++++++++ halo2_gadgets/src/ecc/chip.rs | 12 +++++++ halo2_gadgets/src/ecc/chip/witness_point.rs | 37 +++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 4bf58d3ec6..2e6e509190 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -60,6 +60,15 @@ pub trait EccInstructions: value: Value, ) -> Result; + /// Witnesses the given constant point as a private input to the circuit. + /// This allows the point to be the identity, mapped to (0, 0) in + /// affine coordinates. + fn witness_point_from_constant( + &self, + layouter: &mut impl Layouter, + value: C, + ) -> Result; + /// Witnesses the given point as a private input to the circuit. /// This returns an error if the point is the identity. fn witness_point_non_id( @@ -399,6 +408,16 @@ impl + Clone + Debug + Eq> Point, + value: C, + ) -> Result { + let point = chip.witness_point_from_constant(&mut layouter, value); + point.map(|inner| Point { chip, inner }) + } + /// Constrains this point to be equal in value to another point. pub fn constrain_equal> + Clone>( &self, diff --git a/halo2_gadgets/src/ecc/chip.rs b/halo2_gadgets/src/ecc/chip.rs index 0b6fa0d4b4..119b1670f6 100644 --- a/halo2_gadgets/src/ecc/chip.rs +++ b/halo2_gadgets/src/ecc/chip.rs @@ -453,6 +453,18 @@ where ) } + fn witness_point_from_constant( + &self, + layouter: &mut impl Layouter, + value: pallas::Affine, + ) -> Result { + let config = self.config().witness_point; + layouter.assign_region( + || "witness point (constant)", + |mut region| config.constant_point(value, 0, &mut region), + ) + } + fn witness_point_non_id( &self, layouter: &mut impl Layouter, diff --git a/halo2_gadgets/src/ecc/chip/witness_point.rs b/halo2_gadgets/src/ecc/chip/witness_point.rs index 7cba8d6f87..28e8aaf4a9 100644 --- a/halo2_gadgets/src/ecc/chip/witness_point.rs +++ b/halo2_gadgets/src/ecc/chip/witness_point.rs @@ -102,6 +102,21 @@ impl Config { Ok((x_var, y_var)) } + fn assign_xy_constant( + &self, + value: (Assigned, Assigned), + offset: usize, + region: &mut Region<'_, pallas::Base>, + ) -> Result { + // Assign `x` value + let x_var = region.assign_advice_from_constant(|| "x", self.x, offset, value.0)?; + + // Assign `y` value + let y_var = region.assign_advice_from_constant(|| "y", self.y, offset, value.1)?; + + Ok((x_var, y_var)) + } + /// Assigns a point that can be the identity. pub(super) fn point( &self, @@ -126,6 +141,28 @@ impl Config { .map(|(x, y)| EccPoint::from_coordinates_unchecked(x, y)) } + /// Assigns a constant point that can be the identity. + pub(super) fn constant_point( + &self, + value: pallas::Affine, + offset: usize, + region: &mut Region<'_, pallas::Base>, + ) -> Result { + // Enable `q_point` selector + self.q_point.enable(region, offset)?; + + let value = if value == pallas::Affine::identity() { + // Map the identity to (0, 0). + (Assigned::Zero, Assigned::Zero) + } else { + let value = value.coordinates().unwrap(); + (value.x().into(), value.y().into()) + }; + + self.assign_xy_constant(value, offset, region) + .map(|(x, y)| EccPoint::from_coordinates_unchecked(x, y)) + } + /// Assigns a non-identity point. pub(super) fn point_non_id( &self, From 4c3c00bced34bb9c86ee978c9195dbe1b71dcc05 Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Mon, 16 Oct 2023 09:27:33 +0200 Subject: [PATCH 08/99] Optimized short range check on 4 and 5 bits (#21) Short range checks on 4 and 5 bits are now performed with only one lookup (instead of 2). To do that, we added a column `table_short_range_tag` in the lookup table. This new column `table_short_range_tag` contains the value - 4 for rows used in short range check on 4 bits - 5 for rows used in short range check on 5 bits - 0 for rows used in short range check on 10 bits Disable tests on i686 and code coverage in CI --- .github/workflows/ci.yml | 114 +++++------ halo2_gadgets/src/ecc.rs | 8 +- halo2_gadgets/src/ecc/chip/mul_fixed/short.rs | 18 +- halo2_gadgets/src/sinsemilla.rs | 9 +- halo2_gadgets/src/sinsemilla/chip.rs | 3 +- .../src/sinsemilla/chip/generator_table.rs | 63 +++++- halo2_gadgets/src/sinsemilla/merkle.rs | 4 +- .../src/utilities/lookup_range_check.rs | 186 +++++++++++++++--- 8 files changed, 308 insertions(+), 97 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d2ecd3ba57..db9abdc62e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,36 +33,36 @@ jobs: ${{ steps.prepare.outputs.feature-flags }} ${{ matrix.extra_flags }} - test-32-bit: - name: Test on i686-unknown-linux-gnu${{ matrix.name_suffix }} - runs-on: ubuntu-latest - strategy: - matrix: - stage: [stable, beta, nightly] - include: - - stage: beta - name_suffix: " with beta features" - - stage: nightly - name_suffix: " with nightly features" - - steps: - - uses: actions/checkout@v3 - - id: prepare - uses: ./.github/actions/prepare - with: - beta-features: ${{ matrix.stage == 'beta' }} - nightly-features: ${{ matrix.stage == 'nightly' }} - - name: Install cross-platform support dependencies - run: sudo apt install gcc-multilib - - run: rustup target add i686-unknown-linux-gnu - - name: Run tests - run: > - cargo test - --verbose - --release - --workspace - --target i686-unknown-linux-gnu - ${{ steps.prepare.outputs.feature-flags }} +# test-32-bit: +# name: Test on i686-unknown-linux-gnu${{ matrix.name_suffix }} +# runs-on: ubuntu-latest +# strategy: +# matrix: +# stage: [stable, beta, nightly] +# include: +# - stage: beta +# name_suffix: " with beta features" +# - stage: nightly +# name_suffix: " with nightly features" +# +# steps: +# - uses: actions/checkout@v3 +# - id: prepare +# uses: ./.github/actions/prepare +# with: +# beta-features: ${{ matrix.stage == 'beta' }} +# nightly-features: ${{ matrix.stage == 'nightly' }} +# - name: Install cross-platform support dependencies +# run: sudo apt install gcc-multilib +# - run: rustup target add i686-unknown-linux-gnu +# - name: Run tests +# run: > +# cargo test +# --verbose +# --release +# --workspace +# --target i686-unknown-linux-gnu +# ${{ steps.prepare.outputs.feature-flags }} build: name: Build target ${{ matrix.target }} @@ -125,33 +125,33 @@ jobs: - name: Test halo2 book run: mdbook test -L target/debug/deps book/ - codecov: - name: Code coverage - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - # Use stable for this to ensure that cargo-tarpaulin can be built. - - id: prepare - uses: ./.github/actions/prepare - with: - toolchain: stable - nightly-features: true - - name: Install cargo-tarpaulin - uses: actions-rs/cargo@v1 - with: - command: install - args: cargo-tarpaulin - - name: Generate coverage report - uses: actions-rs/cargo@v1 - with: - command: tarpaulin - args: > - ${{ steps.prepare.outputs.feature-flags }} - --timeout 600 - --out Xml - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3.1.4 +# codecov: +# name: Code coverage +# runs-on: ubuntu-latest +# +# steps: +# - uses: actions/checkout@v3 +# # Use stable for this to ensure that cargo-tarpaulin can be built. +# - id: prepare +# uses: ./.github/actions/prepare +# with: +# toolchain: stable +# nightly-features: true +# - name: Install cargo-tarpaulin +# uses: actions-rs/cargo@v1 +# with: +# command: install +# args: cargo-tarpaulin +# - name: Generate coverage report +# uses: actions-rs/cargo@v1 +# with: +# command: tarpaulin +# args: > +# ${{ steps.prepare.outputs.feature-flags }} +# --timeout 600 +# --out Xml +# - name: Upload coverage to Codecov +# uses: codecov/codecov-action@v3.1.4 doc-links: name: Intra-doc links diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 2e6e509190..4861a20e52 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -793,6 +793,7 @@ pub(crate) mod tests { meta.advice_column(), ]; let lookup_table = meta.lookup_table_column(); + let table_range_check_tag = meta.lookup_table_column(); let lagrange_coeffs = [ meta.fixed_column(), meta.fixed_column(), @@ -807,7 +808,12 @@ pub(crate) mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table); + let range_check = LookupRangeCheckConfig::configure( + meta, + advices[9], + lookup_table, + table_range_check_tag, + ); EccChip::::configure(meta, advices, lagrange_coeffs, range_check) } diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs index 94d61de54a..a10c54c1ed 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs @@ -508,6 +508,7 @@ pub mod tests { meta.advice_column(), ]; let lookup_table = meta.lookup_table_column(); + let table_range_check_tag = meta.lookup_table_column(); let lagrange_coeffs = [ meta.fixed_column(), meta.fixed_column(), @@ -523,7 +524,12 @@ pub mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table); + let range_check = LookupRangeCheckConfig::configure( + meta, + advices[9], + lookup_table, + table_range_check_tag, + ); EccChip::::configure(meta, advices, lagrange_coeffs, range_check) } @@ -644,7 +650,7 @@ pub mod tests { )], }, VerifyFailure::Permutation { - column: (Any::Fixed, 9).into(), + column: (Any::Fixed, 10).into(), location: FailureLocation::OutsideRegion { row: 0 }, }, VerifyFailure::Permutation { @@ -827,6 +833,7 @@ pub mod tests { meta.advice_column(), ]; let lookup_table = meta.lookup_table_column(); + let table_range_check_tag = meta.lookup_table_column(); let lagrange_coeffs = [ meta.fixed_column(), meta.fixed_column(), @@ -842,7 +849,12 @@ pub mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table); + let range_check = LookupRangeCheckConfig::configure( + meta, + advices[9], + lookup_table, + table_range_check_tag, + ); EccChip::::configure(meta, advices, lagrange_coeffs, range_check) } diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index ca4c14fb1d..a1dcb9d2a2 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -586,6 +586,7 @@ pub(crate) mod tests { meta.enable_constant(constants); 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(), @@ -602,9 +603,15 @@ pub(crate) mod tests { table_idx, meta.lookup_table_column(), meta.lookup_table_column(), + table_range_check_tag, ); - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx); + let range_check = LookupRangeCheckConfig::configure( + meta, + advices[9], + table_idx, + table_range_check_tag, + ); let ecc_config = EccChip::::configure(meta, advices, lagrange_coeffs, range_check); diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs index ac4c34f781..ef76b19815 100644 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ b/halo2_gadgets/src/sinsemilla/chip.rs @@ -153,7 +153,7 @@ where advices: [Column; 5], witness_pieces: Column, fixed_y_q: Column, - lookup: (TableColumn, TableColumn, TableColumn), + lookup: (TableColumn, TableColumn, TableColumn, TableColumn), range_check: LookupRangeCheckConfig, ) -> >::Config { // Enable equality on all advice columns @@ -178,6 +178,7 @@ where table_idx: lookup.0, table_x: lookup.1, table_y: lookup.2, + table_range_check_tag: lookup.3, }, lookup_config: range_check, _marker: PhantomData, diff --git a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs index fd0ff03f91..13773a4659 100644 --- a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs +++ b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs @@ -6,7 +6,7 @@ use halo2_proofs::{ }; use super::{CommitDomains, FixedPoints, HashDomains}; -use crate::sinsemilla::primitives::{self as sinsemilla, SINSEMILLA_S}; +use crate::sinsemilla::primitives::{self as sinsemilla, K, SINSEMILLA_S}; use pasta_curves::pallas; /// Table containing independent generators S[0..2^k] @@ -15,6 +15,7 @@ pub struct GeneratorTableConfig { pub table_idx: TableColumn, pub table_x: TableColumn, pub table_y: TableColumn, + pub table_range_check_tag: TableColumn, } impl GeneratorTableConfig { @@ -90,6 +91,66 @@ impl GeneratorTableConfig { )?; 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", + self.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", + 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", + 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", + self.table_range_check_tag, + new_index, + || Value::known(pallas::Base::from(5_u64)), + )?; + } } Ok(()) }, diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 02a3bdaf7c..1eabfaa870 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -246,9 +246,11 @@ pub mod tests { meta.lookup_table_column(), meta.lookup_table_column(), meta.lookup_table_column(), + meta.lookup_table_column(), ); - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup.0); + let range_check = + LookupRangeCheckConfig::configure(meta, advices[9], lookup.0, lookup.3); let sinsemilla_config_1 = SinsemillaChip::configure( meta, diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index b26a89a884..d1173babbc 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -60,8 +60,11 @@ pub struct LookupRangeCheckConfig { q_lookup: Selector, q_running: Selector, q_bitshift: Selector, + q_range_check_4: Selector, + q_range_check_5: Selector, running_sum: Column, table_idx: TableColumn, + table_range_check_tag: TableColumn, _marker: PhantomData, } @@ -81,18 +84,24 @@ impl LookupRangeCheckConfig { meta: &mut ConstraintSystem, running_sum: Column, table_idx: TableColumn, + table_range_check_tag: TableColumn, ) -> Self { meta.enable_equality(running_sum); let q_lookup = meta.complex_selector(); let q_running = meta.complex_selector(); let q_bitshift = meta.selector(); + let q_range_check_4 = meta.complex_selector(); + let q_range_check_5 = meta.complex_selector(); let config = LookupRangeCheckConfig { q_lookup, q_running, q_bitshift, + q_range_check_4, + q_range_check_5, running_sum, table_idx, + table_range_check_tag, _marker: PhantomData, }; @@ -100,7 +109,10 @@ impl LookupRangeCheckConfig { meta.lookup(|meta| { let q_lookup = meta.query_selector(config.q_lookup); let q_running = meta.query_selector(config.q_running); + let q_range_check_4 = meta.query_selector(config.q_range_check_4); + let q_range_check_5 = meta.query_selector(config.q_range_check_5); let z_cur = meta.query_advice(config.running_sum, Rotation::cur()); + let one = Expression::Constant(F::ONE); // In the case of a running sum decomposition, we recover the word from // the difference of the running sums: @@ -117,17 +129,40 @@ impl LookupRangeCheckConfig { // In the short range check, the word is directly witnessed. let short_lookup = { - let short_word = z_cur; - let q_short = Expression::Constant(F::ONE) - q_running; + let short_word = z_cur.clone(); + let q_short = one.clone() - q_running; q_short * short_word }; + // q_range_check is equal to + // - 1 if q_range_check_4 = 1 or q_range_check_5 = 1 + // - 0 otherwise + let q_range_check = one.clone() + - (one.clone() - q_range_check_4.clone()) * (one.clone() - q_range_check_5.clone()); + + // num_bits is equal to + // - 5 if q_range_check_5 = 1 + // - 4 if q_range_check_4 = 1 and q_range_check_5 = 0 + // - 0 otherwise + let num_bits = q_range_check_5.clone() * Expression::Constant(F::from(5_u64)) + + (one.clone() - q_range_check_5) + * q_range_check_4 + * Expression::Constant(F::from(4_u64)); + // Combine the running sum and short lookups: - vec![( - q_lookup * (running_sum_lookup + short_lookup), - config.table_idx, - )] + vec![ + ( + q_lookup.clone() + * ((one - q_range_check.clone()) * (running_sum_lookup + short_lookup) + + q_range_check.clone() * z_cur), + config.table_idx, + ), + ( + q_lookup * q_range_check * num_bits, + config.table_range_check_tag, + ), + ] }); // For short lookups, check that the word has been shifted by the correct number of bits. @@ -152,9 +187,9 @@ impl LookupRangeCheckConfig { } #[cfg(test)] - // Loads the values [0..2^K) into `table_idx`. This is only used in testing - // for now, since the Sinsemilla chip provides a pre-loaded table in the - // Orchard context. + // 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. pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { layouter.assign_table( || "table_idx", @@ -167,6 +202,42 @@ impl LookupRangeCheckConfig { index, || Value::known(F::from(index as u64)), )?; + table.assign_cell( + || "table_range_check_tag", + self.table_range_check_tag, + index, + || Value::known(F::ZERO), + )?; + } + for index in 0..(1 << 4) { + let new_index = index + (1 << K); + table.assign_cell( + || "table_idx", + self.table_idx, + new_index, + || Value::known(F::from(index as u64)), + )?; + table.assign_cell( + || "table_range_check_tag", + self.table_range_check_tag, + new_index, + || Value::known(F::from(4_u64)), + )?; + } + for index in 0..(1 << 5) { + let new_index = index + (1 << K) + (1 << 4); + table.assign_cell( + || "table_idx", + self.table_idx, + new_index, + || Value::known(F::from(index as u64)), + )?; + table.assign_cell( + || "table_range_check_tag", + self.table_range_check_tag, + new_index, + || Value::known(F::from(5_u64)), + )?; } Ok(()) }, @@ -350,33 +421,43 @@ impl LookupRangeCheckConfig { element: AssignedCell, num_bits: usize, ) -> Result<(), Error> { - // Enable lookup for `element`, to constrain it to 10 bits. + // Enable lookup for `element`. self.q_lookup.enable(region, 0)?; - // Enable lookup for shifted element, to constrain it to 10 bits. - self.q_lookup.enable(region, 1)?; + match num_bits { + 4 => { + self.q_range_check_4.enable(region, 0)?; + } + 5 => { + self.q_range_check_5.enable(region, 0)?; + } + _ => { + // Enable lookup for shifted element, to constrain it to 10 bits. + self.q_lookup.enable(region, 1)?; - // Check element has been shifted by the correct number of bits. - self.q_bitshift.enable(region, 1)?; + // Check element has been shifted by the correct number of bits. + self.q_bitshift.enable(region, 1)?; - // Assign shifted `element * 2^{K - num_bits}` - let shifted = element.value().into_field() * F::from(1 << (K - num_bits)); + // Assign shifted `element * 2^{K - num_bits}` + let shifted = element.value().into_field() * F::from(1 << (K - num_bits)); - region.assign_advice( - || format!("element * 2^({}-{})", K, num_bits), - self.running_sum, - 1, - || shifted, - )?; + region.assign_advice( + || format!("element * 2^({}-{})", K, num_bits), + self.running_sum, + 1, + || shifted, + )?; - // Assign 2^{-num_bits} from a fixed column. - let inv_two_pow_s = F::from(1 << num_bits).invert().unwrap(); - region.assign_advice_from_constant( - || format!("2^(-{})", num_bits), - self.running_sum, - 2, - inv_two_pow_s, - )?; + // Assign 2^{-num_bits} from a fixed column. + let inv_two_pow_s = F::from(1 << num_bits).invert().unwrap(); + region.assign_advice_from_constant( + || format!("2^(-{})", num_bits), + self.running_sum, + 2, + inv_two_pow_s, + )?; + } + } Ok(()) } @@ -418,10 +499,16 @@ mod tests { fn configure(meta: &mut ConstraintSystem) -> Self::Config { let running_sum = meta.advice_column(); let table_idx = meta.lookup_table_column(); + let table_range_check_tag = meta.lookup_table_column(); let constants = meta.fixed_column(); meta.enable_constant(constants); - LookupRangeCheckConfig::::configure(meta, running_sum, table_idx) + LookupRangeCheckConfig::::configure( + meta, + running_sum, + table_idx, + table_range_check_tag, + ) } fn synthesize( @@ -517,10 +604,16 @@ mod tests { fn configure(meta: &mut ConstraintSystem) -> Self::Config { let running_sum = meta.advice_column(); let table_idx = meta.lookup_table_column(); + let table_range_check_tag = meta.lookup_table_column(); let constants = meta.fixed_column(); meta.enable_constant(constants); - LookupRangeCheckConfig::::configure(meta, running_sum, table_idx) + LookupRangeCheckConfig::::configure( + meta, + running_sum, + table_idx, + table_range_check_tag, + ) } fn synthesize( @@ -646,5 +739,34 @@ mod tests { }]) ); } + + // Element within 4 bits + { + let circuit: MyCircuit = MyCircuit { + element: Value::known(pallas::Base::from((1 << 4) - 1)), + num_bits: 4, + }; + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), Ok(())); + } + + // Element larger than 5 bits + { + let circuit: MyCircuit = MyCircuit { + element: Value::known(pallas::Base::from(1 << 5)), + num_bits: 5, + }; + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!( + prover.verify(), + Err(vec![VerifyFailure::Lookup { + lookup_index: 0, + location: FailureLocation::InRegion { + region: (1, "Range check 5 bits").into(), + offset: 0, + }, + }]) + ); + } } } From f51eebeb4e2a91f7763da63c72208174a4221276 Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Tue, 17 Oct 2023 09:13:40 +0200 Subject: [PATCH 09/99] Add multiplexer chip (#23) It is now possible to perform a mux between two points or between two non-identity points. `mux(choice, left, right)` will return `left` when `choice=0` and `right` when `choice=1`. `choice` must be constrained to `{0, 1}` outside the gate. It is no longer needed to expose `from_coordinates_unchecked`. --- halo2_gadgets/src/ecc/chip.rs | 2 +- halo2_gadgets/src/utilities.rs | 1 + halo2_gadgets/src/utilities/mux.rs | 450 +++++++++++++++++++++++++++++ 3 files changed, 452 insertions(+), 1 deletion(-) create mode 100644 halo2_gadgets/src/utilities/mux.rs diff --git a/halo2_gadgets/src/ecc/chip.rs b/halo2_gadgets/src/ecc/chip.rs index 119b1670f6..402020384b 100644 --- a/halo2_gadgets/src/ecc/chip.rs +++ b/halo2_gadgets/src/ecc/chip.rs @@ -48,7 +48,7 @@ impl EccPoint { /// Constructs a point from its coordinates, without checking they are on the curve. /// /// This is an internal API that we only use where we know we have a valid curve point. - pub fn from_coordinates_unchecked( + pub(crate) fn from_coordinates_unchecked( x: AssignedCell, pallas::Base>, y: AssignedCell, pallas::Base>, ) -> Self { diff --git a/halo2_gadgets/src/utilities.rs b/halo2_gadgets/src/utilities.rs index 739f4411de..b497ad2361 100644 --- a/halo2_gadgets/src/utilities.rs +++ b/halo2_gadgets/src/utilities.rs @@ -12,6 +12,7 @@ use std::ops::Range; pub mod cond_swap; pub mod decompose_running_sum; pub mod lookup_range_check; +pub mod mux; /// A type that has a value at either keygen or proving time. pub trait FieldValue { diff --git a/halo2_gadgets/src/utilities/mux.rs b/halo2_gadgets/src/utilities/mux.rs new file mode 100644 index 0000000000..82e5422397 --- /dev/null +++ b/halo2_gadgets/src/utilities/mux.rs @@ -0,0 +1,450 @@ +//! Gadget and chip for a multiplexer. +//! +//! Given an input `(choice, left, right)`, the multiplexer returns +//! - `left` if choice=0, +//! - `right` otherwise. +//! `left` and `right` are either both points or both non-identity points. +//! The output of the multiplexer has the same format as the `left` and `right` inputs. +//! If `left` and `right` are points (resp. non-identity points), the output is a point (resp. non-identity point). +//! +//! `choice` must be constrained to {0, 1} separately. + +use crate::ecc::chip::{EccPoint, NonIdentityEccPoint}; +use halo2_proofs::{ + circuit::{AssignedCell, Chip, Layouter, Value}, + plonk::{self, Advice, Column, ConstraintSystem, Constraints, Expression, Selector}, + poly::Rotation, +}; +use pasta_curves::pallas; + +/// Instructions for a multiplexer gadget. +pub trait MuxInstructions { + /// Given an input `(choice, left, right)`, returns `left` if choice=0 and `right` otherwise. + /// + /// `left` and `right` are `EccPoint` + /// `choice` must be constrained to {0, 1} separately. + fn mux_on_points( + &self, + layouter: impl Layouter, + choice: &AssignedCell, + left: &EccPoint, + right: &EccPoint, + ) -> Result; + + /// Given an input `(choice, left, right)`, returns `left` if choice=0 and `right` otherwise. + /// + /// `left` and `right` are `NonIdentityEccPoint` + /// `choice` must be constrained to {0, 1} separately. + fn mux_on_non_identity_points( + &self, + layouter: impl Layouter, + choice: &AssignedCell, + left: &NonIdentityEccPoint, + right: &NonIdentityEccPoint, + ) -> Result; +} + +/// A chip implementing a multiplexer. +#[derive(Clone, Debug)] +pub struct MuxChip { + config: MuxConfig, +} + +impl Chip for MuxChip { + type Config = MuxConfig; + type Loaded = (); + + fn config(&self) -> &Self::Config { + &self.config + } + + fn loaded(&self) -> &Self::Loaded { + &() + } +} + +/// Configuration for the [`MuxChip`]. +#[derive(Clone, Debug)] +pub struct MuxConfig { + choice: Column, + left: Column, + right: Column, + out: Column, + q_mux: Selector, +} + +impl MuxInstructions for MuxChip { + fn mux_on_points( + &self, + mut layouter: impl Layouter, + choice: &AssignedCell, + left: &EccPoint, + right: &EccPoint, + ) -> Result { + let x_cell = layouter.assign_region( + || "mux x", + |mut region| { + self.config.q_mux.enable(&mut region, 0)?; + + choice.copy_advice(|| "copy choice", &mut region, self.config.choice, 0)?; + left.x() + .copy_advice(|| "copy left_x", &mut region, self.config.left, 0)?; + right + .x() + .copy_advice(|| "copy right_x", &mut region, self.config.right, 0)?; + + let out_val = (Value::known(pallas::Base::one()) - choice.value()) + * left.x().value() + + choice.value() * right.x().value(); + + region.assign_advice(|| "out x", self.config.out, 0, || out_val) + }, + )?; + let y_cell = layouter.assign_region( + || "mux y", + |mut region| { + self.config.q_mux.enable(&mut region, 0)?; + + choice.copy_advice(|| "copy choice", &mut region, self.config.choice, 0)?; + left.y() + .copy_advice(|| "copy left_y", &mut region, self.config.left, 0)?; + right + .y() + .copy_advice(|| "copy right_y", &mut region, self.config.right, 0)?; + + let out_val = (Value::known(pallas::Base::one()) - choice.value()) + * left.y().value() + + choice.value() * right.y().value(); + + region.assign_advice(|| "out y", self.config.out, 0, || out_val) + }, + )?; + + Ok(EccPoint::from_coordinates_unchecked( + x_cell.into(), + y_cell.into(), + )) + } + + fn mux_on_non_identity_points( + &self, + mut layouter: impl Layouter, + choice: &AssignedCell, + left: &NonIdentityEccPoint, + right: &NonIdentityEccPoint, + ) -> Result { + let x_cell = layouter.assign_region( + || "mux x", + |mut region| { + self.config.q_mux.enable(&mut region, 0)?; + + choice.copy_advice(|| "copy choice", &mut region, self.config.choice, 0)?; + left.x() + .copy_advice(|| "copy left_x", &mut region, self.config.left, 0)?; + right + .x() + .copy_advice(|| "copy right_x", &mut region, self.config.right, 0)?; + + let out_val = (Value::known(pallas::Base::one()) - choice.value()) + * left.x().value() + + choice.value() * right.x().value(); + + region.assign_advice(|| "out x", self.config.out, 0, || out_val) + }, + )?; + let y_cell = layouter.assign_region( + || "mux y", + |mut region| { + self.config.q_mux.enable(&mut region, 0)?; + + choice.copy_advice(|| "copy choice", &mut region, self.config.choice, 0)?; + left.y() + .copy_advice(|| "copy left_y", &mut region, self.config.left, 0)?; + right + .y() + .copy_advice(|| "copy right_y", &mut region, self.config.right, 0)?; + + let out_val = (Value::known(pallas::Base::one()) - choice.value()) + * left.y().value() + + choice.value() * right.y().value(); + + region.assign_advice(|| "out y", self.config.out, 0, || out_val) + }, + )?; + + Ok(NonIdentityEccPoint::from_coordinates_unchecked( + x_cell.into(), + y_cell.into(), + )) + } +} + +impl MuxChip { + /// Configures this chip for use in a circuit. + pub fn configure( + meta: &mut ConstraintSystem, + choice: Column, + left: Column, + right: Column, + out: Column, + ) -> MuxConfig { + let q_mux = meta.selector(); + meta.create_gate("Field element multiplexer", |meta| { + let q_mux = meta.query_selector(q_mux); + let choice = meta.query_advice(choice, Rotation::cur()); + let left = meta.query_advice(left, Rotation::cur()); + let right = meta.query_advice(right, Rotation::cur()); + let out = meta.query_advice(out, Rotation::cur()); + + let one = Expression::Constant(pallas::Base::one()); + + let should_be_zero = (one - choice.clone()) * left + choice * right - out; + + Constraints::with_selector(q_mux, Some(should_be_zero)) + }); + + MuxConfig { + choice, + left, + right, + out, + q_mux, + } + } + + /// Constructs a [`MuxChip`] given a [`MuxConfig`]. + pub fn construct(config: MuxConfig) -> Self { + Self { config } + } +} + +#[cfg(test)] +mod tests { + use super::{MuxChip, MuxConfig, MuxInstructions}; + + use crate::{ + ecc::{ + chip::{EccChip, EccConfig}, + tests::TestFixedBases, + NonIdentityPoint, Point, + }, + utilities::lookup_range_check::LookupRangeCheckConfig, + }; + + 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, + mux_config: MuxConfig, + ecc_config: EccConfig, + } + #[derive(Default)] + struct MyCircuit { + left_point: Value, + right_point: Value, + choice: Value, + } + + #[test] + fn test_mux_on_points() { + 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 mux_config = + MuxChip::configure(meta, advices[0], advices[1], advices[2], advices[3]); + + 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 = LookupRangeCheckConfig::configure( + meta, + advices[9], + table_idx, + table_range_check_tag, + ); + + let ecc_config = EccChip::::configure( + meta, + advices, + lagrange_coeffs, + range_check, + ); + + MyConfig { + primary, + advice: advices[0], + mux_config, + ecc_config, + } + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + // Construct a MUX chip + let mux_chip = MuxChip::construct(config.mux_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 = mux_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 = mux_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(())); + } + } +} From cba30b1b8410d534dac883a045c7368ad4132412 Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Wed, 18 Oct 2023 09:46:39 +0200 Subject: [PATCH 10/99] Add functions to evaluate a Sinsemilla hash from an initial private point (#22) To share ZEC and ZSA hash computations in Orchard circuit's note commitment evaluation, we need to compute a Sinsemille hash from a private input point. --- halo2_gadgets/src/sinsemilla.rs | 60 ++++- halo2_gadgets/src/sinsemilla/chip.rs | 37 ++- .../src/sinsemilla/chip/hash_to_point.rs | 255 ++++++++++++++---- halo2_gadgets/src/sinsemilla/merkle/chip.rs | 13 + 4 files changed, 313 insertions(+), 52 deletions(-) diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index a1dcb9d2a2..2a9c92a79c 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -78,7 +78,7 @@ pub trait SinsemillaInstructions Result<(Self::NonIdentityPoint, Vec), Error>; + /// Hashes a message to an ECC curve point. + /// This returns both the resulting point, as well as the message + /// decomposition in the form of intermediate values in a cumulative + /// sum. + /// The initial point `Q` is a private point. + #[allow(non_snake_case)] + #[allow(clippy::type_complexity)] + fn hash_to_point_with_private_init( + &self, + layouter: impl Layouter, + Q: &Self::NonIdentityPoint, + message: Self::Message, + ) -> Result<(Self::NonIdentityPoint, Vec), Error>; + /// Extracts the x-coordinate of the output of a Sinsemilla hash. fn extract(point: &Self::NonIdentityPoint) -> Self::X; } @@ -329,6 +343,21 @@ where .map(|(point, zs)| (ecc::NonIdentityPoint::from_inner(self.ecc_chip.clone(), point), zs)) } + #[allow(non_snake_case)] + #[allow(clippy::type_complexity)] + /// Evaluate the Sinsemilla hash of `message` from the private initial point `Q`. + pub fn hash_to_point_with_private_init( + &self, + layouter: impl Layouter, + Q: &>::NonIdentityPoint, + message: Message, + ) -> Result<(ecc::NonIdentityPoint, Vec), Error> { + assert_eq!(self.sinsemilla_chip, message.chip); + self.sinsemilla_chip + .hash_to_point_with_private_init(layouter, Q, message.inner) + .map(|(point, zs)| (ecc::NonIdentityPoint::from_inner(self.ecc_chip.clone(), point), zs)) + } + /// $\mathsf{SinsemillaHash}$ from [§ 5.4.1.9][concretesinsemillahash]. /// /// [concretesinsemillahash]: https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash @@ -431,6 +460,35 @@ where self.M.hash_to_point(layouter, message) } + #[allow(non_snake_case)] + #[allow(clippy::type_complexity)] + /// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. + /// + /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit + pub fn hash_with_private_init( + &self, + layouter: impl Layouter, + Q: &>::NonIdentityPoint, + message: Message, + ) -> Result< + ( + ecc::NonIdentityPoint, + Vec, + ), + Error, + > { + assert_eq!(self.M.sinsemilla_chip, message.chip); + self.M.hash_to_point_with_private_init(layouter, Q, message) + } + + #[allow(clippy::type_complexity)] + /// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. + /// + /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit + pub fn q_init(&self) -> C { + self.M.Q + } + #[allow(clippy::type_complexity)] /// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. /// diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs index ef76b19815..441ba975af 100644 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ b/halo2_gadgets/src/sinsemilla/chip.rs @@ -43,8 +43,11 @@ where /// q_sinsemilla2 is used to define a synthetic selector, /// q_sinsemilla3 = (q_sinsemilla2) ⋅ (q_sinsemilla2 - 1) /// Simple selector used to constrain hash initialization to be consistent with - /// the y-coordinate of the domain $Q$. + /// the y-coordinate of the domain $Q$ when $y_Q$ is a public constant. q_sinsemilla4: Selector, + /// Simple selector used to constrain hash initialization to be consistent with + /// the y-coordinate of the domain $Q$ when $y_Q$ is a private value. + q_sinsemilla4_private: Selector, /// Fixed column used to load the y-coordinate of the domain $Q$. fixed_y_q: Column, /// Logic specific to merged double-and-add. @@ -165,6 +168,7 @@ where q_sinsemilla1: meta.complex_selector(), q_sinsemilla2: meta.fixed_column(), q_sinsemilla4: meta.selector(), + q_sinsemilla4_private: meta.selector(), fixed_y_q, double_and_add: DoubleAndAdd { x_a: advices[0], @@ -202,7 +206,7 @@ where // Check that the initial x_A, x_P, lambda_1, lambda_2 are consistent with y_Q. // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial - meta.create_gate("Initial y_Q", |meta| { + meta.create_gate("Initial y_Q (public)", |meta| { let q_s4 = meta.query_selector(config.q_sinsemilla4); let y_q = meta.query_fixed(config.fixed_y_q); @@ -215,6 +219,21 @@ where Constraints::with_selector(q_s4, Some(("init_y_q_check", init_y_q_check))) }); + // Check that the initial x_A, x_P, lambda_1, lambda_2 are consistent with y_Q. + // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial + meta.create_gate("Initial y_Q (private)", |meta| { + let q_s4 = meta.query_selector(config.q_sinsemilla4_private); + let y_q = meta.query_advice(config.double_and_add.x_p, Rotation::prev()); + + // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) + let Y_A_cur = Y_A(meta, Rotation::cur()); + + // 2 * y_q - Y_{A,0} = 0 + let init_y_q_check = y_q * two - Y_A_cur; + + Constraints::with_selector(q_s4, Some(("init_y_q_check", init_y_q_check))) + }); + // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial meta.create_gate("Sinsemilla gate", |meta| { let q_s1 = meta.query_selector(config.q_sinsemilla1); @@ -322,6 +341,20 @@ where ) } + #[allow(non_snake_case)] + #[allow(clippy::type_complexity)] + fn hash_to_point_with_private_init( + &self, + mut layouter: impl Layouter, + Q: &Self::NonIdentityPoint, + message: Self::Message, + ) -> Result<(Self::NonIdentityPoint, Vec), Error> { + layouter.assign_region( + || "hash_to_point", + |mut region| self.hash_message_with_private_init(&mut region, Q, &message), + ) + } + fn extract(point: &Self::NonIdentityPoint) -> Self::X { point.x() } diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 44beaa4259..771d2a9c5f 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -41,8 +41,143 @@ where ), 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)?; + + #[cfg(test)] + #[allow(non_snake_case)] + // Check equivalence to result from primitives::sinsemilla::hash_to_point + { + use crate::sinsemilla::primitives::{K, S_PERSONALIZATION}; + + use group::{prime::PrimeCurveAffine, Curve}; + use pasta_curves::arithmetic::CurveExt; + + let field_elems: Value> = message + .iter() + .map(|piece| piece.field_elem().map(|elem| (elem, piece.num_words()))) + .collect(); + + field_elems + .zip(x_a.value().zip(y_a.value())) + .assert_if_known(|(field_elems, (x_a, y_a))| { + // Get message as a bitstring. + let bitstring: Vec = field_elems + .iter() + .flat_map(|(elem, num_words)| { + elem.to_le_bits().into_iter().take(K * num_words) + }) + .collect(); + + let hasher_S = pallas::Point::hash_to_curve(S_PERSONALIZATION); + let S = |chunk: &[bool]| hasher_S(&lebs2ip_k(chunk).to_le_bytes()); + + // We can use complete addition here because it differs from + // incomplete addition with negligible probability. + let expected_point = bitstring + .chunks(K) + .fold(Q.to_curve(), |acc, chunk| (acc + S(chunk)) + acc); + let actual_point = + pallas::Affine::from_xy(x_a.evaluate(), y_a.evaluate()).unwrap(); + expected_point.to_affine() == actual_point + }); + } + + 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)] + pub(super) fn hash_message_with_private_init( + &self, + region: &mut Region<'_, pallas::Base>, + Q: &NonIdentityEccPoint, + message: &>::Message, + ) -> Result< + ( + NonIdentityEccPoint, + Vec>>, + ), + Error, + > { + let (offset, x_a, y_a) = self.private_initialization(region, Q)?; + + let (x_a, y_a, zs_sum) = self.hash_all_pieces(region, offset, message, x_a, y_a)?; + + #[cfg(test)] + #[allow(non_snake_case)] + // Check equivalence to result from primitives::sinsemilla::hash_to_point + { + use crate::sinsemilla::primitives::{K, S_PERSONALIZATION}; + + use group::{prime::PrimeCurveAffine, Curve}; + use pasta_curves::arithmetic::CurveExt; + + let field_elems: Value> = message + .iter() + .map(|piece| piece.field_elem().map(|elem| (elem, piece.num_words()))) + .collect(); + + field_elems + .zip(x_a.value().zip(y_a.value())) + .zip(Q.point()) + .assert_if_known(|((field_elems, (x_a, y_a)), Q)| { + // Get message as a bitstring. + let bitstring: Vec = field_elems + .iter() + .flat_map(|(elem, num_words)| { + elem.to_le_bits().into_iter().take(K * num_words) + }) + .collect(); + + let hasher_S = pallas::Point::hash_to_curve(S_PERSONALIZATION); + let S = |chunk: &[bool]| hasher_S(&lebs2ip_k(chunk).to_le_bytes()); + + // We can use complete addition here because it differs from + // incomplete addition with negligible probability. + let expected_point = bitstring + .chunks(K) + .fold(Q.to_curve(), |acc, chunk| (acc + S(chunk)) + acc); + let actual_point = + pallas::Affine::from_xy(x_a.evaluate(), y_a.evaluate()).unwrap(); + expected_point.to_affine() == actual_point + }); + } + + 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, + )) + } + + #[allow(non_snake_case)] + /// Assign the coordinates of the initial public point `Q` + /// + /// | offset | x_A | q_sinsemilla4 | fixed_y_Q | + /// -------------------------------------------- + /// | 0 | x_Q | 1 | y_Q | + 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; + let offset = 0; // Get the `x`- and `y`-coordinates of the starting `Q` base. let x_q = *Q.coordinates().unwrap().x(); @@ -50,7 +185,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.q_sinsemilla4.enable(region, offset)?; region.assign_fixed( @@ -64,7 +199,7 @@ where }; // Constrain the initial x_q to equal the x-coordinate of the domain's `Q`. - let mut x_a: X = { + let x_a: X = { let x_a = region.assign_advice_from_constant( || "fixed x_q", config.double_and_add.x_a, @@ -75,6 +210,73 @@ where x_a.into() }; + Ok((offset, x_a, y_a)) + } + + #[allow(non_snake_case)] + /// Assign the coordinates of the initial private point `Q` + /// + /// | offset | x_A | x_P | q_sinsemilla4_private | + /// ----------------------------------------------- + /// | 0 | | y_Q | | + /// | 1 | x_Q | | 1 | + fn private_initialization( + &self, + region: &mut Region<'_, pallas::Base>, + Q: &NonIdentityEccPoint, + ) -> Result<(usize, X, Y), Error> { + let config = self.config().clone(); + let mut offset = 0; + + // Assign `x_Q` and `y_Q` in the region and constrain the initial x_a, lambda_1, lambda_2, + // x_p, y_Q using the q_sinsemilla4_private selector. + let y_a: Y = { + // Enable `q_sinsemilla4_private` on the first row. + config.q_sinsemilla4_private.enable(region, offset + 1)?; + let q_y: AssignedCell, pallas::Base> = Q.y().into(); + let y_a: AssignedCell, pallas::Base> = + q_y.copy_advice(|| "fixed y_q", region, config.double_and_add.x_p, offset)?; + + y_a.value_field().into() + }; + offset += 1; + + let x_a: X = { + let q_x: AssignedCell, pallas::Base> = Q.x().into(); + let x_a = q_x.copy_advice(|| "fixed x_q", region, config.double_and_add.x_a, offset)?; + + x_a.into() + }; + + Ok((offset, x_a, y_a)) + } + + #[allow(clippy::type_complexity)] + /// Hash `message` from the initial point `Q`. + /// + /// Before this call to `hash_all_pieces()`, `x_Q` and `y_Q` MUST have been already assigned + /// within this region. + fn hash_all_pieces( + &self, + region: &mut Region<'_, pallas::Base>, + mut offset: usize, + message: &>::Message, + mut x_a: X, + mut y_a: Y, + ) -> Result< + ( + X, + AssignedCell, pallas::Base>, + Vec>>, + ), + Error, + > { + let config = self.config().clone(); + let mut zs_sum: Vec>> = Vec::new(); // Hash each piece in the message. @@ -121,52 +323,7 @@ where y_a_cell }; - #[cfg(test)] - #[allow(non_snake_case)] - // Check equivalence to result from primitives::sinsemilla::hash_to_point - { - use crate::sinsemilla::primitives::{K, S_PERSONALIZATION}; - - use group::{prime::PrimeCurveAffine, Curve}; - use pasta_curves::arithmetic::CurveExt; - - let field_elems: Value> = message - .iter() - .map(|piece| piece.field_elem().map(|elem| (elem, piece.num_words()))) - .collect(); - - field_elems - .zip(x_a.value().zip(y_a.value())) - .assert_if_known(|(field_elems, (x_a, y_a))| { - // Get message as a bitstring. - let bitstring: Vec = field_elems - .iter() - .flat_map(|(elem, num_words)| { - elem.to_le_bits().into_iter().take(K * num_words) - }) - .collect(); - - let hasher_S = pallas::Point::hash_to_curve(S_PERSONALIZATION); - let S = |chunk: &[bool]| hasher_S(&lebs2ip_k(chunk).to_le_bytes()); - - // We can use complete addition here because it differs from - // incomplete addition with negligible probability. - let expected_point = bitstring - .chunks(K) - .fold(Q.to_curve(), |acc, chunk| (acc + S(chunk)) + acc); - let actual_point = - pallas::Affine::from_xy(x_a.evaluate(), y_a.evaluate()).unwrap(); - expected_point.to_affine() == actual_point - }); - } - - 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, - )) + Ok((x_a, y_a, zs_sum)) } #[allow(clippy::type_complexity)] diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs index 2c37fe924b..45f0c5f958 100644 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla/merkle/chip.rs @@ -523,6 +523,19 @@ where chip.hash_to_point(layouter, Q, message) } + #[allow(non_snake_case)] + #[allow(clippy::type_complexity)] + fn hash_to_point_with_private_init( + &self, + layouter: impl Layouter, + Q: &Self::NonIdentityPoint, + message: Self::Message, + ) -> Result<(Self::NonIdentityPoint, Vec>), Error> { + let config = self.config().sinsemilla_config.clone(); + let chip = SinsemillaChip::::construct(config); + chip.hash_to_point_with_private_init(layouter, Q, message) + } + fn extract(point: &Self::NonIdentityPoint) -> Self::X { SinsemillaChip::::extract(point) } From 87464d4b3f1eb50e9f9e1e553c14b8a639fbb77f Mon Sep 17 00:00:00 2001 From: Constance Date: Thu, 23 Nov 2023 16:55:48 +0100 Subject: [PATCH 11/99] Update comments --- halo2_gadgets/src/sinsemilla.rs | 17 +++++------------ .../src/sinsemilla/chip/generator_table.rs | 16 ++++++++++++++++ .../src/sinsemilla/chip/hash_to_point.rs | 3 --- .../src/utilities/lookup_range_check.rs | 2 +- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 2a9c92a79c..e57c0a2129 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -442,9 +442,8 @@ where } #[allow(clippy::type_complexity)] - /// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. - /// - /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit + /// Evaluates the Sinsemilla hash of `message` from the public initial point `Q` stored + /// into `CommitDomain`. pub fn hash( &self, layouter: impl Layouter, @@ -462,9 +461,7 @@ where #[allow(non_snake_case)] #[allow(clippy::type_complexity)] - /// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. - /// - /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit + /// Evaluates the Sinsemilla hash of `message` from the private initial point `Q`. pub fn hash_with_private_init( &self, layouter: impl Layouter, @@ -482,17 +479,13 @@ where } #[allow(clippy::type_complexity)] - /// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. - /// - /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit + /// Returns the public initial point `Q` stored into `CommitDomain`. pub fn q_init(&self) -> C { self.M.Q } #[allow(clippy::type_complexity)] - /// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. - /// - /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit + /// Evaluates the blinding factor equal to $\[r\] R$ where `r` is stored in the `CommitDomain`. pub fn blinding_factor( &self, mut layouter: impl Layouter, diff --git a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs index 13773a4659..e77928b128 100644 --- a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs +++ b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs @@ -78,6 +78,22 @@ impl GeneratorTableConfig { }); } + /// 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(&self, layouter: &mut impl Layouter) -> Result<(), Error> { layouter.assign_table( || "generator_table", diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 771d2a9c5f..226e5e8a05 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -253,9 +253,6 @@ where #[allow(clippy::type_complexity)] /// Hash `message` from the initial point `Q`. - /// - /// Before this call to `hash_all_pieces()`, `x_Q` and `y_Q` MUST have been already assigned - /// within this region. fn hash_all_pieces( &self, region: &mut Region<'_, pallas::Base>, diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index d1173babbc..64b4ce4c90 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -150,7 +150,7 @@ impl LookupRangeCheckConfig { * q_range_check_4 * Expression::Constant(F::from(4_u64)); - // Combine the running sum and short lookups: + // Combine the running sum, short lookups and optimized range checks: vec![ ( q_lookup.clone() From d76d2317b75e79480eb3c7df4f28428e92643d24 Mon Sep 17 00:00:00 2001 From: Constance Date: Thu, 23 Nov 2023 21:12:08 +0100 Subject: [PATCH 12/99] Reactivate i686 CI test --- .github/workflows/ci.yml | 60 ++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db9abdc62e..7cb0e84e71 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,36 +33,36 @@ jobs: ${{ steps.prepare.outputs.feature-flags }} ${{ matrix.extra_flags }} -# test-32-bit: -# name: Test on i686-unknown-linux-gnu${{ matrix.name_suffix }} -# runs-on: ubuntu-latest -# strategy: -# matrix: -# stage: [stable, beta, nightly] -# include: -# - stage: beta -# name_suffix: " with beta features" -# - stage: nightly -# name_suffix: " with nightly features" -# -# steps: -# - uses: actions/checkout@v3 -# - id: prepare -# uses: ./.github/actions/prepare -# with: -# beta-features: ${{ matrix.stage == 'beta' }} -# nightly-features: ${{ matrix.stage == 'nightly' }} -# - name: Install cross-platform support dependencies -# run: sudo apt install gcc-multilib -# - run: rustup target add i686-unknown-linux-gnu -# - name: Run tests -# run: > -# cargo test -# --verbose -# --release -# --workspace -# --target i686-unknown-linux-gnu -# ${{ steps.prepare.outputs.feature-flags }} + test-32-bit: + name: Test on i686-unknown-linux-gnu${{ matrix.name_suffix }} + runs-on: ubuntu-latest + strategy: + matrix: + stage: [stable, beta, nightly] + include: + - stage: beta + name_suffix: " with beta features" + - stage: nightly + name_suffix: " with nightly features" + + steps: + - uses: actions/checkout@v3 + - id: prepare + uses: ./.github/actions/prepare + with: + beta-features: ${{ matrix.stage == 'beta' }} + nightly-features: ${{ matrix.stage == 'nightly' }} + - name: Install cross-platform support dependencies + run: sudo apt install gcc-multilib + - run: rustup target add i686-unknown-linux-gnu + - name: Run tests + run: > + cargo test + --verbose + --release + --workspace + --target i686-unknown-linux-gnu + ${{ steps.prepare.outputs.feature-flags }} build: name: Build target ${{ matrix.target }} From ac7a90d9ad28a4088b6b843f58a41712ab42a895 Mon Sep 17 00:00:00 2001 From: Constance Date: Tue, 28 Nov 2023 17:13:29 +0100 Subject: [PATCH 13/99] Some minor changes --- halo2_gadgets/src/ecc/chip/witness_point.rs | 4 ++-- halo2_gadgets/src/sinsemilla/primitives.rs | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/halo2_gadgets/src/ecc/chip/witness_point.rs b/halo2_gadgets/src/ecc/chip/witness_point.rs index 28e8aaf4a9..98f865a6dc 100644 --- a/halo2_gadgets/src/ecc/chip/witness_point.rs +++ b/halo2_gadgets/src/ecc/chip/witness_point.rs @@ -102,7 +102,7 @@ impl Config { Ok((x_var, y_var)) } - fn assign_xy_constant( + fn assign_xy_from_constant( &self, value: (Assigned, Assigned), offset: usize, @@ -159,7 +159,7 @@ impl Config { (value.x().into(), value.y().into()) }; - self.assign_xy_constant(value, offset, region) + self.assign_xy_from_constant(value, offset, region) .map(|(x, y)| EccPoint::from_coordinates_unchecked(x, y)) } diff --git a/halo2_gadgets/src/sinsemilla/primitives.rs b/halo2_gadgets/src/sinsemilla/primitives.rs index f90c63ac12..ad9e397b5e 100644 --- a/halo2_gadgets/src/sinsemilla/primitives.rs +++ b/halo2_gadgets/src/sinsemilla/primitives.rs @@ -185,7 +185,7 @@ impl HashDomain { #[allow(non_snake_case)] pub struct CommitDomain { /// A domain in which $\mathsf{SinsemillaHashToPoint}$ and $\mathsf{SinsemillaHash}$ can be used - pub M: HashDomain, + M: HashDomain, R: pallas::Point, } @@ -226,6 +226,13 @@ impl CommitDomain { .map(|p| p + Wnaf::new().scalar(r).base(self.R)) } + /// $\mathsf{SinsemillaHashToPoint}$ from [§ 5.4.1.9][concretesinsemillahash]. + /// + /// [concretesinsemillahash]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillahash + pub fn hash_to_point(&self, msg: impl Iterator) -> CtOption { + self.M.hash_to_point(msg) + } + /// Returns `SinsemillaCommit_r(personalization, msg) = hash_point + [r]R` /// where `SinsemillaHash(personalization, msg) = hash_point` /// and `R` is derived from the `personalization`. From 622875ead0116a0fc60c42279cafc94f1eeee351 Mon Sep 17 00:00:00 2001 From: Constance Date: Thu, 30 Nov 2023 11:17:49 +0100 Subject: [PATCH 14/99] Remove q_sinsemilla4_private --- halo2_gadgets/src/sinsemilla/chip.rs | 23 +--------- .../src/sinsemilla/chip/hash_to_point.rs | 43 ++++++++++--------- 2 files changed, 25 insertions(+), 41 deletions(-) diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs index 441ba975af..c55efd1105 100644 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ b/halo2_gadgets/src/sinsemilla/chip.rs @@ -43,11 +43,8 @@ where /// q_sinsemilla2 is used to define a synthetic selector, /// q_sinsemilla3 = (q_sinsemilla2) ⋅ (q_sinsemilla2 - 1) /// Simple selector used to constrain hash initialization to be consistent with - /// the y-coordinate of the domain $Q$ when $y_Q$ is a public constant. + /// the y-coordinate of the domain $Q$. q_sinsemilla4: Selector, - /// Simple selector used to constrain hash initialization to be consistent with - /// the y-coordinate of the domain $Q$ when $y_Q$ is a private value. - q_sinsemilla4_private: Selector, /// Fixed column used to load the y-coordinate of the domain $Q$. fixed_y_q: Column, /// Logic specific to merged double-and-add. @@ -168,7 +165,6 @@ where q_sinsemilla1: meta.complex_selector(), q_sinsemilla2: meta.fixed_column(), q_sinsemilla4: meta.selector(), - q_sinsemilla4_private: meta.selector(), fixed_y_q, double_and_add: DoubleAndAdd { x_a: advices[0], @@ -206,23 +202,8 @@ where // Check that the initial x_A, x_P, lambda_1, lambda_2 are consistent with y_Q. // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial - meta.create_gate("Initial y_Q (public)", |meta| { + meta.create_gate("Initial y_Q", |meta| { let q_s4 = meta.query_selector(config.q_sinsemilla4); - let y_q = meta.query_fixed(config.fixed_y_q); - - // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) - let Y_A_cur = Y_A(meta, Rotation::cur()); - - // 2 * y_q - Y_{A,0} = 0 - let init_y_q_check = y_q * two - Y_A_cur; - - Constraints::with_selector(q_s4, Some(("init_y_q_check", init_y_q_check))) - }); - - // Check that the initial x_A, x_P, lambda_1, lambda_2 are consistent with y_Q. - // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial - meta.create_gate("Initial y_Q (private)", |meta| { - let q_s4 = meta.query_selector(config.q_sinsemilla4_private); let y_q = meta.query_advice(config.double_and_add.x_p, Rotation::prev()); // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 226e5e8a05..165615efaa 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -168,16 +168,17 @@ where #[allow(non_snake_case)] /// Assign the coordinates of the initial public point `Q` /// - /// | offset | x_A | q_sinsemilla4 | fixed_y_Q | - /// -------------------------------------------- - /// | 0 | x_Q | 1 | y_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 offset = 0; + let mut offset = 0; // Get the `x`- and `y`-coordinates of the starting `Q` base. let x_q = *Q.coordinates().unwrap().x(); @@ -186,17 +187,19 @@ where // 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 first row. - config.q_sinsemilla4.enable(region, offset)?; - region.assign_fixed( - || "fixed y_q", - config.fixed_y_q, - offset, - || Value::known(y_q), - )?; + // Enable `q_sinsemilla4` on the second row. + config.q_sinsemilla4.enable(region, offset + 1)?; + let y_a: AssignedCell, pallas::Base> = region + .assign_advice_from_constant( + || "fixed y_q", + config.double_and_add.x_p, + offset, + y_q.into(), + )?; - Value::known(y_q.into()).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 = { @@ -216,10 +219,10 @@ where #[allow(non_snake_case)] /// Assign the coordinates of the initial private point `Q` /// - /// | offset | x_A | x_P | q_sinsemilla4_private | - /// ----------------------------------------------- - /// | 0 | | y_Q | | - /// | 1 | x_Q | | 1 | + /// | offset | x_A | x_P | q_sinsemilla4 | + /// -------------------------------------- + /// | 0 | | y_Q | | + /// | 1 | x_Q | | 1 | fn private_initialization( &self, region: &mut Region<'_, pallas::Base>, @@ -229,10 +232,10 @@ where let mut offset = 0; // Assign `x_Q` and `y_Q` in the region and constrain the initial x_a, lambda_1, lambda_2, - // x_p, y_Q using the q_sinsemilla4_private selector. + // x_p, y_Q using the q_sinsemilla4 selector. let y_a: Y = { - // Enable `q_sinsemilla4_private` on the first row. - config.q_sinsemilla4_private.enable(region, offset + 1)?; + // Enable `q_sinsemilla4` on the second row. + config.q_sinsemilla4.enable(region, offset + 1)?; let q_y: AssignedCell, pallas::Base> = Q.y().into(); let y_a: AssignedCell, pallas::Base> = q_y.copy_advice(|| "fixed y_q", region, config.double_and_add.x_p, offset)?; From 5f436dc3387665fe3201d381791a62a8233b2171 Mon Sep 17 00:00:00 2001 From: Constance Date: Thu, 30 Nov 2023 16:14:15 +0100 Subject: [PATCH 15/99] Move mux functionality into CondSwap chip --- halo2_gadgets/src/sinsemilla/merkle/chip.rs | 12 + halo2_gadgets/src/utilities.rs | 1 - halo2_gadgets/src/utilities/cond_swap.rs | 332 ++++++++++++++- halo2_gadgets/src/utilities/mux.rs | 450 -------------------- 4 files changed, 343 insertions(+), 452 deletions(-) delete mode 100644 halo2_gadgets/src/utilities/mux.rs diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs index 45f0c5f958..cb3c5be4cc 100644 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla/merkle/chip.rs @@ -441,6 +441,18 @@ where let chip = CondSwapChip::::construct(config); chip.swap(layouter, pair, swap) } + + fn mux( + &self, + layouter: &mut impl Layouter, + choice: Self::Var, + left: Self::Var, + right: Self::Var, + ) -> Result { + let config = self.config().cond_swap_config.clone(); + let chip = CondSwapChip::::construct(config); + chip.mux(layouter, choice, left, right) + } } impl SinsemillaInstructions diff --git a/halo2_gadgets/src/utilities.rs b/halo2_gadgets/src/utilities.rs index b497ad2361..739f4411de 100644 --- a/halo2_gadgets/src/utilities.rs +++ b/halo2_gadgets/src/utilities.rs @@ -12,7 +12,6 @@ use std::ops::Range; pub mod cond_swap; pub mod decompose_running_sum; pub mod lookup_range_check; -pub mod mux; /// A type that has a value at either keygen or proving time. pub trait FieldValue { diff --git a/halo2_gadgets/src/utilities/cond_swap.rs b/halo2_gadgets/src/utilities/cond_swap.rs index d733e6c4fb..78049e742a 100644 --- a/halo2_gadgets/src/utilities/cond_swap.rs +++ b/halo2_gadgets/src/utilities/cond_swap.rs @@ -2,12 +2,14 @@ use super::{bool_check, ternary, UtilitiesInstructions}; +use crate::ecc::chip::{EccPoint, NonIdentityEccPoint}; use group::ff::{Field, PrimeField}; use halo2_proofs::{ circuit::{AssignedCell, Chip, Layouter, Value}, - plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Selector}, + plonk::{self, Advice, Column, ConstraintSystem, Constraints, Error, Selector}, poly::Rotation, }; +use pasta_curves::pallas; use std::marker::PhantomData; /// Instructions for a conditional swap gadget. @@ -24,6 +26,16 @@ pub trait CondSwapInstructions: UtilitiesInstructions { pair: (Self::Var, Value), swap: Value, ) -> Result<(Self::Var, Self::Var), Error>; + + /// Given an input `(choice, left, right)` where `choice` is a boolean flag, + /// returns `left` if `choice` is not set and `right` if `choice` is set. + fn mux( + &self, + layouter: &mut impl Layouter, + choice: Self::Var, + left: Self::Var, + right: Self::Var, + ) -> Result; } /// A chip implementing a conditional swap. @@ -121,6 +133,97 @@ impl CondSwapInstructions for CondSwapChip { }, ) } + + fn mux( + &self, + layouter: &mut impl Layouter, + choice: Self::Var, + left: Self::Var, + right: Self::Var, + ) -> Result { + let config = self.config(); + + layouter.assign_region( + || "mux", + |mut region| { + // Enable `q_swap` selector + config.q_swap.enable(&mut region, 0)?; + + // Copy in `a` value + let left = left.copy_advice(|| "copy left", &mut region, config.a, 0)?; + + // Copy in `b` value + let right = right.copy_advice(|| "copy right", &mut region, config.b, 0)?; + + // Copy `choice` value + let choice = choice.copy_advice(|| "copy choice", &mut region, config.swap, 0)?; + + let a_swapped = left + .value() + .zip(right.value()) + .zip(choice.value()) + .map(|((left, right), choice)| { + if *choice == F::from(0_u64) { + left + } else { + right + } + }) + .cloned(); + let b_swapped = left + .value() + .zip(right.value()) + .zip(choice.value()) + .map(|((left, right), choice)| { + if *choice == F::from(0_u64) { + right + } else { + left + } + }) + .cloned(); + + region.assign_advice(|| "out b_swap", self.config.b_swapped, 0, || b_swapped)?; + region.assign_advice(|| "out a_swap", self.config.a_swapped, 0, || a_swapped) + }, + ) + } +} + +impl CondSwapChip { + /// Given an input `(choice, left, right)` where `choice` is a boolean flag and `left` and `right` are `EccPoint`, + /// returns `left` if `choice` is not set and `right` if `choice` is set. + pub fn mux_on_points( + &self, + mut layouter: impl Layouter, + choice: &AssignedCell, + left: &EccPoint, + right: &EccPoint, + ) -> Result { + let x_cell = self.mux(&mut layouter, choice.clone(), left.x(), right.x())?; + let y_cell = self.mux(&mut layouter, choice.clone(), left.y(), right.y())?; + Ok(EccPoint::from_coordinates_unchecked( + x_cell.into(), + y_cell.into(), + )) + } + + /// Given an input `(choice, left, right)` where `choice` is a boolean flag and `left` and `right` are + /// `NonIdentityEccPoint`, returns `left` if `choice` is not set and `right` if `choice` is set. + pub fn mux_on_non_identity_points( + &self, + mut layouter: impl Layouter, + choice: &AssignedCell, + left: &NonIdentityEccPoint, + right: &NonIdentityEccPoint, + ) -> Result { + let x_cell = self.mux(&mut layouter, choice.clone(), left.x(), right.x())?; + let y_cell = self.mux(&mut layouter, choice.clone(), left.y(), right.y())?; + Ok(NonIdentityEccPoint::from_coordinates_unchecked( + x_cell.into(), + y_cell.into(), + )) + } } impl CondSwapChip { @@ -291,4 +394,231 @@ mod tests { assert_eq!(prover.verify(), Ok(())); } } + + #[test] + fn test_mux() { + use crate::{ + ecc::{ + chip::{EccChip, EccConfig}, + tests::TestFixedBases, + NonIdentityPoint, Point, + }, + utilities::lookup_range_check::LookupRangeCheckConfig, + }; + + 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 = LookupRangeCheckConfig::configure( + meta, + advices[9], + table_idx, + table_range_check_tag, + ); + + 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(())); + } + } } diff --git a/halo2_gadgets/src/utilities/mux.rs b/halo2_gadgets/src/utilities/mux.rs deleted file mode 100644 index 82e5422397..0000000000 --- a/halo2_gadgets/src/utilities/mux.rs +++ /dev/null @@ -1,450 +0,0 @@ -//! Gadget and chip for a multiplexer. -//! -//! Given an input `(choice, left, right)`, the multiplexer returns -//! - `left` if choice=0, -//! - `right` otherwise. -//! `left` and `right` are either both points or both non-identity points. -//! The output of the multiplexer has the same format as the `left` and `right` inputs. -//! If `left` and `right` are points (resp. non-identity points), the output is a point (resp. non-identity point). -//! -//! `choice` must be constrained to {0, 1} separately. - -use crate::ecc::chip::{EccPoint, NonIdentityEccPoint}; -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Layouter, Value}, - plonk::{self, Advice, Column, ConstraintSystem, Constraints, Expression, Selector}, - poly::Rotation, -}; -use pasta_curves::pallas; - -/// Instructions for a multiplexer gadget. -pub trait MuxInstructions { - /// Given an input `(choice, left, right)`, returns `left` if choice=0 and `right` otherwise. - /// - /// `left` and `right` are `EccPoint` - /// `choice` must be constrained to {0, 1} separately. - fn mux_on_points( - &self, - layouter: impl Layouter, - choice: &AssignedCell, - left: &EccPoint, - right: &EccPoint, - ) -> Result; - - /// Given an input `(choice, left, right)`, returns `left` if choice=0 and `right` otherwise. - /// - /// `left` and `right` are `NonIdentityEccPoint` - /// `choice` must be constrained to {0, 1} separately. - fn mux_on_non_identity_points( - &self, - layouter: impl Layouter, - choice: &AssignedCell, - left: &NonIdentityEccPoint, - right: &NonIdentityEccPoint, - ) -> Result; -} - -/// A chip implementing a multiplexer. -#[derive(Clone, Debug)] -pub struct MuxChip { - config: MuxConfig, -} - -impl Chip for MuxChip { - type Config = MuxConfig; - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -/// Configuration for the [`MuxChip`]. -#[derive(Clone, Debug)] -pub struct MuxConfig { - choice: Column, - left: Column, - right: Column, - out: Column, - q_mux: Selector, -} - -impl MuxInstructions for MuxChip { - fn mux_on_points( - &self, - mut layouter: impl Layouter, - choice: &AssignedCell, - left: &EccPoint, - right: &EccPoint, - ) -> Result { - let x_cell = layouter.assign_region( - || "mux x", - |mut region| { - self.config.q_mux.enable(&mut region, 0)?; - - choice.copy_advice(|| "copy choice", &mut region, self.config.choice, 0)?; - left.x() - .copy_advice(|| "copy left_x", &mut region, self.config.left, 0)?; - right - .x() - .copy_advice(|| "copy right_x", &mut region, self.config.right, 0)?; - - let out_val = (Value::known(pallas::Base::one()) - choice.value()) - * left.x().value() - + choice.value() * right.x().value(); - - region.assign_advice(|| "out x", self.config.out, 0, || out_val) - }, - )?; - let y_cell = layouter.assign_region( - || "mux y", - |mut region| { - self.config.q_mux.enable(&mut region, 0)?; - - choice.copy_advice(|| "copy choice", &mut region, self.config.choice, 0)?; - left.y() - .copy_advice(|| "copy left_y", &mut region, self.config.left, 0)?; - right - .y() - .copy_advice(|| "copy right_y", &mut region, self.config.right, 0)?; - - let out_val = (Value::known(pallas::Base::one()) - choice.value()) - * left.y().value() - + choice.value() * right.y().value(); - - region.assign_advice(|| "out y", self.config.out, 0, || out_val) - }, - )?; - - Ok(EccPoint::from_coordinates_unchecked( - x_cell.into(), - y_cell.into(), - )) - } - - fn mux_on_non_identity_points( - &self, - mut layouter: impl Layouter, - choice: &AssignedCell, - left: &NonIdentityEccPoint, - right: &NonIdentityEccPoint, - ) -> Result { - let x_cell = layouter.assign_region( - || "mux x", - |mut region| { - self.config.q_mux.enable(&mut region, 0)?; - - choice.copy_advice(|| "copy choice", &mut region, self.config.choice, 0)?; - left.x() - .copy_advice(|| "copy left_x", &mut region, self.config.left, 0)?; - right - .x() - .copy_advice(|| "copy right_x", &mut region, self.config.right, 0)?; - - let out_val = (Value::known(pallas::Base::one()) - choice.value()) - * left.x().value() - + choice.value() * right.x().value(); - - region.assign_advice(|| "out x", self.config.out, 0, || out_val) - }, - )?; - let y_cell = layouter.assign_region( - || "mux y", - |mut region| { - self.config.q_mux.enable(&mut region, 0)?; - - choice.copy_advice(|| "copy choice", &mut region, self.config.choice, 0)?; - left.y() - .copy_advice(|| "copy left_y", &mut region, self.config.left, 0)?; - right - .y() - .copy_advice(|| "copy right_y", &mut region, self.config.right, 0)?; - - let out_val = (Value::known(pallas::Base::one()) - choice.value()) - * left.y().value() - + choice.value() * right.y().value(); - - region.assign_advice(|| "out y", self.config.out, 0, || out_val) - }, - )?; - - Ok(NonIdentityEccPoint::from_coordinates_unchecked( - x_cell.into(), - y_cell.into(), - )) - } -} - -impl MuxChip { - /// Configures this chip for use in a circuit. - pub fn configure( - meta: &mut ConstraintSystem, - choice: Column, - left: Column, - right: Column, - out: Column, - ) -> MuxConfig { - let q_mux = meta.selector(); - meta.create_gate("Field element multiplexer", |meta| { - let q_mux = meta.query_selector(q_mux); - let choice = meta.query_advice(choice, Rotation::cur()); - let left = meta.query_advice(left, Rotation::cur()); - let right = meta.query_advice(right, Rotation::cur()); - let out = meta.query_advice(out, Rotation::cur()); - - let one = Expression::Constant(pallas::Base::one()); - - let should_be_zero = (one - choice.clone()) * left + choice * right - out; - - Constraints::with_selector(q_mux, Some(should_be_zero)) - }); - - MuxConfig { - choice, - left, - right, - out, - q_mux, - } - } - - /// Constructs a [`MuxChip`] given a [`MuxConfig`]. - pub fn construct(config: MuxConfig) -> Self { - Self { config } - } -} - -#[cfg(test)] -mod tests { - use super::{MuxChip, MuxConfig, MuxInstructions}; - - use crate::{ - ecc::{ - chip::{EccChip, EccConfig}, - tests::TestFixedBases, - NonIdentityPoint, Point, - }, - utilities::lookup_range_check::LookupRangeCheckConfig, - }; - - 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, - mux_config: MuxConfig, - ecc_config: EccConfig, - } - #[derive(Default)] - struct MyCircuit { - left_point: Value, - right_point: Value, - choice: Value, - } - - #[test] - fn test_mux_on_points() { - 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 mux_config = - MuxChip::configure(meta, advices[0], advices[1], advices[2], advices[3]); - - 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 = LookupRangeCheckConfig::configure( - meta, - advices[9], - table_idx, - table_range_check_tag, - ); - - let ecc_config = EccChip::::configure( - meta, - advices, - lagrange_coeffs, - range_check, - ); - - MyConfig { - primary, - advice: advices[0], - mux_config, - ecc_config, - } - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // Construct a MUX chip - let mux_chip = MuxChip::construct(config.mux_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 = mux_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 = mux_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(())); - } - } -} From 80dfd60052e503eb1e250e31aaf9ed276d5bbeb0 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Tue, 23 Apr 2024 22:31:23 +0200 Subject: [PATCH 16/99] add initial doc --- halo2_gadgets/src/ecc.rs | 80 +- halo2_gadgets/src/ecc/chip.rs | 117 ++- halo2_gadgets/src/ecc/chip/mul.rs | 23 +- halo2_gadgets/src/ecc/chip/mul/overflow.rs | 10 +- halo2_gadgets/src/ecc/chip/mul_fixed.rs | 6 +- .../src/ecc/chip/mul_fixed/base_field_elem.rs | 44 +- .../src/ecc/chip/mul_fixed/full_width.rs | 17 +- halo2_gadgets/src/ecc/chip/mul_fixed/short.rs | 327 +------- halo2_gadgets/src/ecc/chip/witness_point.rs | 41 +- halo2_gadgets/src/ecc_opt.rs | 419 ++++++++++ halo2_gadgets/src/ecc_opt/chip.rs | 61 ++ halo2_gadgets/src/ecc_opt/chip/mul_fixed.rs | 1 + .../src/ecc_opt/chip/mul_fixed/short.rs | 744 ++++++++++++++++++ .../src/ecc_opt/chip/witness_point.rs | 50 ++ halo2_gadgets/src/lib.rs | 3 + halo2_gadgets/src/sinsemilla.rs | 194 ++--- halo2_gadgets/src/sinsemilla/chip.rs | 263 +++++-- .../src/sinsemilla/chip/generator_table.rs | 123 +-- .../src/sinsemilla/chip/hash_to_point.rs | 224 ++---- halo2_gadgets/src/sinsemilla/merkle.rs | 55 +- halo2_gadgets/src/sinsemilla/merkle/chip.rs | 198 +++-- halo2_gadgets/src/sinsemilla/primitives.rs | 66 +- halo2_gadgets/src/sinsemilla_opt.rs | 478 +++++++++++ halo2_gadgets/src/sinsemilla_opt/chip.rs | 56 ++ .../sinsemilla_opt/chip/generator_table.rs | 136 ++++ .../src/sinsemilla_opt/chip/hash_to_point.rs | 146 ++++ halo2_gadgets/src/sinsemilla_opt/merkle.rs | 3 + .../src/sinsemilla_opt/merkle/chip.rs | 75 ++ .../src/sinsemilla_opt/primitives.rs | 74 ++ halo2_gadgets/src/utilities/cond_swap.rs | 346 +------- .../src/utilities/lookup_range_check.rs | 712 +++++------------ halo2_gadgets/src/utilities_opt.rs | 4 + halo2_gadgets/src/utilities_opt/cond_swap.rs | 448 +++++++++++ .../src/utilities_opt/lookup_range_check.rs | 570 ++++++++++++++ 34 files changed, 4149 insertions(+), 1965 deletions(-) create mode 100644 halo2_gadgets/src/ecc_opt.rs create mode 100644 halo2_gadgets/src/ecc_opt/chip.rs create mode 100644 halo2_gadgets/src/ecc_opt/chip/mul_fixed.rs create mode 100644 halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs create mode 100644 halo2_gadgets/src/ecc_opt/chip/witness_point.rs create mode 100644 halo2_gadgets/src/sinsemilla_opt.rs create mode 100644 halo2_gadgets/src/sinsemilla_opt/chip.rs create mode 100644 halo2_gadgets/src/sinsemilla_opt/chip/generator_table.rs create mode 100644 halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs create mode 100644 halo2_gadgets/src/sinsemilla_opt/merkle.rs create mode 100644 halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs create mode 100644 halo2_gadgets/src/sinsemilla_opt/primitives.rs create mode 100644 halo2_gadgets/src/utilities_opt.rs create mode 100644 halo2_gadgets/src/utilities_opt/cond_swap.rs create mode 100644 halo2_gadgets/src/utilities_opt/lookup_range_check.rs diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 4861a20e52..2bd1491565 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -4,7 +4,7 @@ use std::fmt::Debug; use halo2_proofs::{ arithmetic::CurveAffine, - circuit::{AssignedCell, Chip, Layouter, Value}, + circuit::{Chip, Layouter, Value}, plonk::Error, }; @@ -60,15 +60,6 @@ pub trait EccInstructions: value: Value, ) -> Result; - /// Witnesses the given constant point as a private input to the circuit. - /// This allows the point to be the identity, mapped to (0, 0) in - /// affine coordinates. - fn witness_point_from_constant( - &self, - layouter: &mut impl Layouter, - value: C, - ) -> Result; - /// Witnesses the given point as a private input to the circuit. /// This returns an error if the point is the identity. fn witness_point_non_id( @@ -120,15 +111,6 @@ pub trait EccInstructions: b: &B, ) -> Result; - /// Performs variable-base sign-scalar multiplication, returning `[sign] point` - /// `sign` must be in {-1, 1}. - fn mul_sign( - &self, - layouter: &mut impl Layouter, - sign: &AssignedCell, - point: &Self::Point, - ) -> Result; - /// Performs variable-base scalar multiplication, returning `[scalar] base`. fn mul( &self, @@ -249,7 +231,7 @@ impl> ScalarFixed { #[derive(Debug)] pub struct ScalarFixedShort> { chip: EccChip, - inner: EccChip::ScalarFixedShort, + pub(crate) inner: EccChip::ScalarFixedShort, } impl> ScalarFixedShort { @@ -393,8 +375,8 @@ impl + Clone + Debug + Eq> /// A point on a specific elliptic curve. #[derive(Copy, Clone, Debug)] pub struct Point + Clone + Debug + Eq> { - chip: EccChip, - inner: EccChip::Point, + pub(crate) chip: EccChip, + pub(crate) inner: EccChip::Point, } impl + Clone + Debug + Eq> Point { @@ -408,16 +390,6 @@ impl + Clone + Debug + Eq> Point, - value: C, - ) -> Result { - let point = chip.witness_point_from_constant(&mut layouter, value); - point.map(|inner| Point { chip, inner }) - } - /// Constrains this point to be equal in value to another point. pub fn constrain_equal> + Clone>( &self, @@ -460,21 +432,6 @@ impl + Clone + Debug + Eq> Point, - sign: &AssignedCell, - ) -> Result, Error> { - self.chip - .mul_sign(&mut layouter, sign, &self.inner) - .map(|point| Point { - chip: self.chip.clone(), - inner: point, - }) - } } /// The affine short Weierstrass x-coordinate of a point on a specific elliptic curve. @@ -617,7 +574,6 @@ impl> FixedPointShort { Self { chip, inner } } } - #[cfg(test)] pub(crate) mod tests { use ff::PrimeField; @@ -638,7 +594,7 @@ pub(crate) mod tests { }, FixedPoints, }; - use crate::utilities::lookup_range_check::LookupRangeCheckConfig; + use crate::utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}; #[derive(Debug, Eq, PartialEq, Clone)] pub(crate) struct TestFixedBases; @@ -772,7 +728,10 @@ pub(crate) mod tests { #[allow(non_snake_case)] impl Circuit for MyCircuit { - type Config = EccConfig; + type Config = EccConfig< + TestFixedBases, + LookupRangeCheckConfig, + >; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -793,7 +752,6 @@ pub(crate) mod tests { meta.advice_column(), ]; let lookup_table = meta.lookup_table_column(); - let table_range_check_tag = meta.lookup_table_column(); let lagrange_coeffs = [ meta.fixed_column(), meta.fixed_column(), @@ -808,13 +766,11 @@ pub(crate) mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); - let range_check = LookupRangeCheckConfig::configure( - meta, - advices[9], - lookup_table, - table_range_check_tag, - ); - EccChip::::configure(meta, advices, lagrange_coeffs, range_check) + let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table); + EccChip::< + TestFixedBases, + LookupRangeCheckConfig, + >::configure(meta, advices, lagrange_coeffs, range_check) } fn synthesize( @@ -914,14 +870,6 @@ pub(crate) mod tests { )?; } - // Test variable-base sign-scalar multiplication - { - super::chip::mul_fixed::short::tests::test_mul_sign( - chip.clone(), - layouter.namespace(|| "variable-base sign-scalar mul"), - )?; - } - // Test full-width fixed-base scalar multiplication { super::chip::mul_fixed::full_width::tests::test_mul_fixed( diff --git a/halo2_gadgets/src/ecc/chip.rs b/halo2_gadgets/src/ecc/chip.rs index 402020384b..f581e625c6 100644 --- a/halo2_gadgets/src/ecc/chip.rs +++ b/halo2_gadgets/src/ecc/chip.rs @@ -1,10 +1,7 @@ //! Chip implementations for the ECC gadgets. use super::{BaseFitsInScalarInstructions, EccInstructions, FixedPoints}; -use crate::{ - sinsemilla::primitives as sinsemilla, - utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions}, -}; +use crate::utilities::{lookup_range_check::DefaultLookupRangeCheck, UtilitiesInstructions}; use arrayvec::ArrayVec; use ff::PrimeField; @@ -17,12 +14,12 @@ use pasta_curves::{arithmetic::CurveAffine, pallas}; use std::convert::TryInto; -pub(super) mod add; -pub(super) mod add_incomplete; +pub(crate) mod add; +pub(crate) mod add_incomplete; pub mod constants; -pub(super) mod mul; -pub(super) mod mul_fixed; -pub(super) mod witness_point; +pub(crate) mod mul; +pub(crate) mod mul_fixed; +pub(crate) mod witness_point; pub use constants::*; @@ -37,11 +34,11 @@ pub struct EccPoint { /// x-coordinate /// /// Stored as an `Assigned` to enable batching inversions. - x: AssignedCell, pallas::Base>, + pub(crate) x: AssignedCell, pallas::Base>, /// y-coordinate /// /// Stored as an `Assigned` to enable batching inversions. - y: AssignedCell, pallas::Base>, + pub(crate) y: AssignedCell, pallas::Base>, } impl EccPoint { @@ -77,7 +74,7 @@ impl EccPoint { } #[cfg(test)] - fn is_identity(&self) -> Value { + pub(crate) fn is_identity(&self) -> Value { self.x.value().map(|x| x.is_zero_vartime()) } } @@ -137,7 +134,10 @@ impl From for EccPoint { /// Configuration for [`EccChip`]. #[derive(Clone, Debug, Eq, PartialEq)] #[allow(non_snake_case)] -pub struct EccConfig> { +pub struct EccConfig< + FixedPoints: super::FixedPoints, + LookupRangeCheckConfig: DefaultLookupRangeCheck, +> { /// Advice columns needed by instructions in the ECC chip. pub advices: [Column; 10], @@ -148,20 +148,20 @@ pub struct EccConfig> { add: add::Config, /// Variable-base scalar multiplication - mul: mul::Config, + mul: mul::Config, /// Fixed-base full-width scalar multiplication mul_fixed_full: mul_fixed::full_width::Config, /// Fixed-base signed short scalar multiplication - mul_fixed_short: mul_fixed::short::Config, + pub(crate) mul_fixed_short: mul_fixed::short::Config, /// Fixed-base mul using a base field element as a scalar - mul_fixed_base_field: mul_fixed::base_field_elem::Config, + mul_fixed_base_field: mul_fixed::base_field_elem::Config, /// Witness point - witness_point: witness_point::Config, + pub(crate) witness_point: witness_point::Config, /// Lookup range check using 10-bit lookup table - pub lookup_config: LookupRangeCheckConfig, + pub lookup_config: LookupRangeCheckConfig, } /// A trait representing the kind of scalar used with a particular `FixedPoint`. @@ -227,12 +227,19 @@ pub trait FixedPoint: std::fmt::Debug + Eq + Clone { /// An [`EccInstructions`] chip that uses 10 advice columns. #[derive(Clone, Debug, Eq, PartialEq)] -pub struct EccChip> { - config: EccConfig, +pub struct EccChip< + FixedPoints: super::FixedPoints, + LookupRangeCheckConfig: DefaultLookupRangeCheck, +> { + config: EccConfig, } -impl> Chip for EccChip { - type Config = EccConfig; +impl< + FixedPoints: super::FixedPoints, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + > Chip for EccChip +{ + type Config = EccConfig; type Loaded = (); fn config(&self) -> &Self::Config { @@ -244,13 +251,19 @@ impl> Chip for Ecc } } -impl> UtilitiesInstructions - for EccChip +impl< + Fixed: super::FixedPoints, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + > UtilitiesInstructions for EccChip { type Var = AssignedCell; } -impl> EccChip { +impl< + FixedPoints: super::FixedPoints, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + > EccChip +{ /// Reconstructs this chip from the given config. pub fn construct(config: >::Config) -> Self { Self { config } @@ -264,7 +277,7 @@ impl> EccChip { meta: &mut ConstraintSystem, advices: [Column; 10], lagrange_coeffs: [Column; 8], - range_check: LookupRangeCheckConfig, + range_check: LookupRangeCheckConfig, ) -> >::Config { // Create witness point gate let witness_point = witness_point::Config::configure(meta, advices[0], advices[1]); @@ -301,12 +314,13 @@ impl> EccChip { mul_fixed::short::Config::::configure(meta, mul_fixed.clone()); // Create gate that is only used in fixed-base mul using a base field element. - let mul_fixed_base_field = mul_fixed::base_field_elem::Config::::configure( - meta, - advices[6..9].try_into().unwrap(), - range_check, - mul_fixed, - ); + let mul_fixed_base_field = + mul_fixed::base_field_elem::Config::::configure( + meta, + advices[6..9].try_into().unwrap(), + range_check, + mul_fixed, + ); EccConfig { advices, @@ -339,7 +353,7 @@ pub struct EccScalarFixed { type MagnitudeCell = AssignedCell; // TODO: Make V an enum Sign { Positive, Negative } type SignCell = AssignedCell; -type MagnitudeSign = (MagnitudeCell, SignCell); +pub(crate) type MagnitudeSign = (MagnitudeCell, SignCell); /// A signed short scalar used for fixed-base scalar multiplication. /// A short scalar must have magnitude in the range [0..2^64), with @@ -407,7 +421,8 @@ pub enum ScalarVar { FullWidth, } -impl> EccInstructions for EccChip +impl, LookupRangeCheckConfig: DefaultLookupRangeCheck> + EccInstructions for EccChip where >::Base: FixedPoint, @@ -453,18 +468,6 @@ where ) } - fn witness_point_from_constant( - &self, - layouter: &mut impl Layouter, - value: pallas::Affine, - ) -> Result { - let config = self.config().witness_point; - layouter.assign_region( - || "witness point (constant)", - |mut region| config.constant_point(value, 0, &mut region), - ) - } - fn witness_point_non_id( &self, layouter: &mut impl Layouter, @@ -544,24 +547,6 @@ where ) } - /// Performs variable-base sign-scalar multiplication, returning `[sign] point` - /// `sign` must be in {-1, 1}. - fn mul_sign( - &self, - layouter: &mut impl Layouter, - sign: &AssignedCell, - point: &Self::Point, - ) -> Result { - // Multiply point by sign, using the same gate as mul_fixed::short. - // This also constrains sign to be in {-1, 1}. - let config_short = self.config().mul_fixed_short.clone(); - config_short.assign_scalar_sign( - layouter.namespace(|| "variable-base sign-scalar mul"), - sign, - point, - ) - } - fn mul( &self, layouter: &mut impl Layouter, @@ -624,8 +609,8 @@ where } } -impl> BaseFitsInScalarInstructions - for EccChip +impl, LookupRangeCheckConfig: DefaultLookupRangeCheck> + BaseFitsInScalarInstructions for EccChip where >::Base: FixedPoint, diff --git a/halo2_gadgets/src/ecc/chip/mul.rs b/halo2_gadgets/src/ecc/chip/mul.rs index 8e857ae442..85677da520 100644 --- a/halo2_gadgets/src/ecc/chip/mul.rs +++ b/halo2_gadgets/src/ecc/chip/mul.rs @@ -1,7 +1,7 @@ use super::{add, EccPoint, NonIdentityEccPoint, ScalarVar, T_Q}; -use crate::{ - sinsemilla::primitives as sinsemilla, - utilities::{bool_check, lookup_range_check::LookupRangeCheckConfig, ternary}, +use crate::utilities::{ + lookup_range_check::DefaultLookupRangeCheck, + {bool_check, ternary}, }; use std::{ convert::TryInto, @@ -46,7 +46,7 @@ const INCOMPLETE_LO_LEN: usize = INCOMPLETE_LEN - INCOMPLETE_HI_LEN; const COMPLETE_RANGE: Range = INCOMPLETE_LEN..(INCOMPLETE_LEN + NUM_COMPLETE_BITS); #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { +pub struct Config { // Selector used to check switching logic on LSB q_mul_lsb: Selector, // Configuration used in complete addition @@ -58,14 +58,14 @@ pub struct Config { // Configuration used for complete addition part of double-and-add algorithm complete_config: complete::Config, // Configuration used to check for overflow - overflow_config: overflow::Config, + overflow_config: overflow::Config, } -impl Config { +impl Config { pub(super) fn configure( meta: &mut ConstraintSystem, add_config: add::Config, - lookup_config: LookupRangeCheckConfig, + lookup_config: LookupRangeCheckConfig, advices: [Column; 10], ) -> Self { let hi_config = incomplete::Config::configure( @@ -467,6 +467,7 @@ pub mod tests { use pasta_curves::pallas; use rand::rngs::OsRng; + use crate::utilities::lookup_range_check::DefaultLookupRangeCheck; use crate::{ ecc::{ chip::{EccChip, EccPoint}, @@ -476,13 +477,13 @@ pub mod tests { utilities::UtilitiesInstructions, }; - pub(crate) fn test_mul( - chip: EccChip, + pub(crate) fn test_mul( + chip: EccChip, mut layouter: impl Layouter, - p: &NonIdentityPoint>, + p: &NonIdentityPoint>, p_val: pallas::Affine, ) -> Result<(), Error> { - let column = chip.config().advices[0]; + let column = chip.config.advices[0]; fn constrain_equal_non_id< EccChip: EccInstructions + Clone + Eq + std::fmt::Debug, diff --git a/halo2_gadgets/src/ecc/chip/mul/overflow.rs b/halo2_gadgets/src/ecc/chip/mul/overflow.rs index 12101ae82e..8adaefa311 100644 --- a/halo2_gadgets/src/ecc/chip/mul/overflow.rs +++ b/halo2_gadgets/src/ecc/chip/mul/overflow.rs @@ -1,6 +1,6 @@ use super::{T_Q, Z}; use crate::{ - sinsemilla::primitives as sinsemilla, utilities::lookup_range_check::LookupRangeCheckConfig, + sinsemilla::primitives as sinsemilla, utilities::lookup_range_check::DefaultLookupRangeCheck, }; use group::ff::PrimeField; @@ -15,19 +15,19 @@ use pasta_curves::pallas; use std::iter; #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { +pub struct Config { // Selector to check z_0 = alpha + t_q (mod p) q_mul_overflow: Selector, // 10-bit lookup table - lookup_config: LookupRangeCheckConfig, + lookup_config: LookupRangeCheckConfig, // Advice columns advices: [Column; 3], } -impl Config { +impl Config { pub(super) fn configure( meta: &mut ConstraintSystem, - lookup_config: LookupRangeCheckConfig, + lookup_config: LookupRangeCheckConfig, advices: [Column; 3], ) -> Self { for advice in advices.iter() { diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed.rs b/halo2_gadgets/src/ecc/chip/mul_fixed.rs index d0781056b8..686cb6203e 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed.rs @@ -41,11 +41,11 @@ pub struct Config> { fixed_z: Column, // Decomposition of an `n-1`-bit scalar into `k`-bit windows: // a = a_0 + 2^k(a_1) + 2^{2k}(a_2) + ... + 2^{(n-1)k}(a_{n-1}) - window: Column, + pub(crate) window: Column, // y-coordinate of accumulator (only used in the final row). - u: Column, + pub(crate) u: Column, // Configuration for `add` - add_config: add::Config, + pub(crate) add_config: add::Config, // Configuration for `add_incomplete` add_incomplete_config: add_incomplete::Config, _marker: PhantomData, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs index 9a2b0c76ce..254ba6804c 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs @@ -1,10 +1,8 @@ use super::super::{EccBaseFieldElemFixed, EccPoint, FixedPoints, NUM_WINDOWS, T_P}; use super::H_BASE; -use crate::utilities::bool_check; -use crate::{ - sinsemilla::primitives as sinsemilla, - utilities::{bitrange_subset, lookup_range_check::LookupRangeCheckConfig, range_check}, +use crate::utilities::{ + bitrange_subset, bool_check, lookup_range_check::DefaultLookupRangeCheck, range_check, }; use group::ff::PrimeField; @@ -18,18 +16,23 @@ use pasta_curves::pallas; use std::convert::TryInto; #[derive(Clone, Debug, Eq, PartialEq)] -pub struct Config> { +pub struct Config< + Fixed: FixedPoints, + LookupRangeCheckConfig: DefaultLookupRangeCheck, +> { q_mul_fixed_base_field: Selector, canon_advices: [Column; 3], - lookup_config: LookupRangeCheckConfig, + lookup_config: LookupRangeCheckConfig, super_config: super::Config, } -impl> Config { +impl, LookupRangeCheckConfig: DefaultLookupRangeCheck> + Config +{ pub(crate) fn configure( meta: &mut ConstraintSystem, canon_advices: [Column; 3], - lookup_config: LookupRangeCheckConfig, + lookup_config: LookupRangeCheckConfig, super_config: super::Config, ) -> Self { for advice in canon_advices.iter() { @@ -388,6 +391,7 @@ pub mod tests { use pasta_curves::pallas; use rand::rngs::OsRng; + use crate::utilities::lookup_range_check::DefaultLookupRangeCheck; use crate::{ ecc::{ chip::{EccChip, FixedPoint, H}, @@ -397,8 +401,8 @@ pub mod tests { utilities::UtilitiesInstructions, }; - pub(crate) fn test_mul_fixed_base_field( - chip: EccChip, + pub(crate) fn test_mul_fixed_base_field( + chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { test_single_base( @@ -410,22 +414,22 @@ pub mod tests { } #[allow(clippy::op_ref)] - fn test_single_base( - chip: EccChip, + fn test_single_base( + chip: EccChip, mut layouter: impl Layouter, - base: FixedPointBaseField>, + base: FixedPointBaseField>, base_val: pallas::Affine, ) -> Result<(), Error> { let rng = OsRng; let column = chip.config().advices[0]; - fn constrain_equal_non_id( - chip: EccChip, + fn constrain_equal_non_id( + chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, scalar_val: pallas::Base, - result: Point>, + result: Point>, ) -> Result<(), Error> { // Move scalar from base field into scalar field (which always fits for Pallas). let scalar = pallas::Scalar::from_repr(scalar_val.to_repr()).unwrap(); @@ -464,10 +468,10 @@ pub mod tests { { let h = pallas::Base::from(H as u64); let scalar_fixed = "1333333333333333333333333333333333333333333333333333333333333333333333333333333333334" - .chars() - .fold(pallas::Base::zero(), |acc, c| { - acc * &h + &pallas::Base::from(c.to_digit(8).unwrap() as u64) - }); + .chars() + .fold(pallas::Base::zero(), |acc, c| { + acc * &h + &pallas::Base::from(c.to_digit(8).unwrap() as u64) + }); let result = { let scalar_fixed = chip.load_private( layouter.namespace(|| "mul with double"), diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs index 886f86bbba..a06b1b9394 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs @@ -192,9 +192,10 @@ pub mod tests { tests::{FullWidth, TestFixedBases}, FixedPoint, NonIdentityPoint, Point, ScalarFixed, }; + use crate::utilities::lookup_range_check::DefaultLookupRangeCheck; - pub(crate) fn test_mul_fixed( - chip: EccChip, + pub(crate) fn test_mul_fixed( + chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { let test_base = FullWidth::from_pallas_generator(); @@ -209,18 +210,18 @@ pub mod tests { } #[allow(clippy::op_ref)] - fn test_single_base( - chip: EccChip, + fn test_single_base( + chip: EccChip, mut layouter: impl Layouter, - base: FixedPoint>, + base: FixedPoint>, base_val: pallas::Affine, ) -> Result<(), Error> { - fn constrain_equal_non_id( - chip: EccChip, + fn constrain_equal_non_id( + chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, scalar_val: pallas::Scalar, - result: Point>, + result: Point>, ) -> Result<(), Error> { let expected = NonIdentityPoint::new( chip, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs index a10c54c1ed..8ce73ca3c6 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs @@ -4,7 +4,7 @@ use super::super::{EccPoint, EccScalarFixedShort, FixedPoints, L_SCALAR_SHORT, N use crate::{ecc::chip::MagnitudeSign, utilities::bool_check}; use halo2_proofs::{ - circuit::{AssignedCell, Layouter, Region}, + circuit::{Layouter, Region}, plonk::{ConstraintSystem, Constraints, Error, Expression, Selector}, poly::Rotation, }; @@ -13,8 +13,8 @@ use pasta_curves::pallas; #[derive(Clone, Debug, Eq, PartialEq)] pub struct Config> { // Selector used for fixed-base scalar mul with short signed exponent. - q_mul_fixed_short: Selector, - super_config: super::Config, + pub(crate) q_mul_fixed_short: Selector, + pub(crate) super_config: super::Config, } impl> Config { @@ -241,80 +241,20 @@ impl> Config { Ok((result, scalar)) } - - /// Multiply the point by sign, using the q_mul_fixed_short gate. - /// Constraints `sign` in {-1, 1} - pub fn assign_scalar_sign( - &self, - mut layouter: impl Layouter, - sign: &AssignedCell, - point: &EccPoint, - ) -> Result { - let signed_point = layouter.assign_region( - || "Signed point", - |mut region| { - let offset = 0; - - // Enable mul_fixed_short selector to check the sign logic. - self.q_mul_fixed_short.enable(&mut region, offset)?; - - // Set "last window" to 0 (this field is irrelevant here). - region.assign_advice_from_constant( - || "u=0", - self.super_config.u, - offset, - pallas::Base::zero(), - )?; - - // Copy sign to `window` column - sign.copy_advice(|| "sign", &mut region, self.super_config.window, offset)?; - - // Assign the input y-coordinate. - point.y.copy_advice( - || "unsigned y", - &mut region, - self.super_config.add_config.y_qr, - offset, - )?; - - // Conditionally negate y-coordinate according to the value of sign - let signed_y_val = sign.value().and_then(|sign| { - if sign == &-pallas::Base::one() { - -point.y.value() - } else { - point.y.value().cloned() - } - }); - - // Assign the output signed y-coordinate. - let signed_y = region.assign_advice( - || "signed y", - self.super_config.add_config.y_p, - offset, - || signed_y_val, - )?; - - Ok(EccPoint { - x: point.x.clone(), - y: signed_y, - }) - }, - )?; - - Ok(signed_point) - } } #[cfg(test)] pub mod tests { - use group::{ff::PrimeField, Curve, Group}; + use group::{ff::PrimeField, Curve}; use halo2_proofs::{ arithmetic::CurveAffine, circuit::{AssignedCell, Chip, Layouter, Value}, plonk::{Any, Error}, }; use pasta_curves::pallas; + use std::marker::PhantomData; + use crate::utilities::lookup_range_check::{DefaultLookupRangeCheck, LookupRangeCheck}; use crate::{ ecc::{ chip::{EccChip, FixedPoint, MagnitudeSign}, @@ -325,16 +265,16 @@ pub mod tests { }; #[allow(clippy::op_ref)] - pub(crate) fn test_mul_fixed_short( - chip: EccChip, + pub(crate) fn test_mul_fixed_short( + chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { // test_short let base_val = Short.generator(); let test_short = FixedPointShort::from_inner(chip.clone(), Short); - fn load_magnitude_sign( - chip: EccChip, + fn load_magnitude_sign( + chip: EccChip, mut layouter: impl Layouter, magnitude: pallas::Base, sign: pallas::Base, @@ -351,12 +291,12 @@ pub mod tests { Ok((magnitude, sign)) } - fn constrain_equal_non_id( - chip: EccChip, + fn constrain_equal_non_id( + chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, scalar_val: pallas::Scalar, - result: Point>, + result: Point>, ) -> Result<(), Error> { let expected = NonIdentityPoint::new( chip, @@ -462,6 +402,8 @@ pub mod tests { Ok(()) } + // todo: fixit + #[test] fn invalid_magnitude_sign() { use crate::{ @@ -487,7 +429,10 @@ pub mod tests { } impl Circuit for MyCircuit { - type Config = EccConfig; + type Config = EccConfig< + TestFixedBases, + LookupRangeCheckConfig, + >; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -508,7 +453,6 @@ pub mod tests { meta.advice_column(), ]; let lookup_table = meta.lookup_table_column(); - let table_range_check_tag = meta.lookup_table_column(); let lagrange_coeffs = [ meta.fixed_column(), meta.fixed_column(), @@ -524,13 +468,11 @@ pub mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); - let range_check = LookupRangeCheckConfig::configure( - meta, - advices[9], - lookup_table, - table_range_check_tag, - ); - EccChip::::configure(meta, advices, lagrange_coeffs, range_check) + let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table); + EccChip::< + TestFixedBases, + LookupRangeCheckConfig, + >::configure(meta, advices, lagrange_coeffs, range_check) } fn synthesize( @@ -650,7 +592,7 @@ pub mod tests { )], }, VerifyFailure::Permutation { - column: (Any::Fixed, 10).into(), + column: (Any::Fixed, 9).into(), location: FailureLocation::OutsideRegion { row: 0 }, }, VerifyFailure::Permutation { @@ -725,223 +667,4 @@ pub mod tests { ); } } - - pub(crate) fn test_mul_sign( - chip: EccChip, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // Generate a random non-identity point P - let p_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); - let p = Point::new( - chip.clone(), - layouter.namespace(|| "P"), - Value::known(p_val), - )?; - - // Create -P - let p_neg_val = -p_val; - let p_neg = Point::new( - chip.clone(), - layouter.namespace(|| "-P"), - Value::known(p_neg_val), - )?; - - // Create the identity point - let identity = Point::new( - chip.clone(), - layouter.namespace(|| "identity"), - Value::known(pallas::Point::identity().to_affine()), - )?; - - // Create -1 and 1 scalars - let pos_sign = chip.load_private( - layouter.namespace(|| "positive sign"), - chip.config().advices[0], - Value::known(pallas::Base::one()), - )?; - let neg_sign = chip.load_private( - layouter.namespace(|| "negative sign"), - chip.config().advices[1], - Value::known(-pallas::Base::one()), - )?; - - // [1] P == P - { - let result = p.mul_sign(layouter.namespace(|| "[1] P"), &pos_sign)?; - result.constrain_equal(layouter.namespace(|| "constrain [1] P"), &p)?; - } - - // [-1] P == -P - { - let result = p.mul_sign(layouter.namespace(|| "[1] P"), &neg_sign)?; - result.constrain_equal(layouter.namespace(|| "constrain [1] P"), &p_neg)?; - } - - // [1] 0 == 0 - { - let result = identity.mul_sign(layouter.namespace(|| "[1] O"), &pos_sign)?; - result.constrain_equal(layouter.namespace(|| "constrain [1] 0"), &identity)?; - } - - // [-1] 0 == 0 - { - let result = identity.mul_sign(layouter.namespace(|| "[-1] O"), &neg_sign)?; - result.constrain_equal(layouter.namespace(|| "constrain [1] 0"), &identity)?; - } - - Ok(()) - } - - #[test] - fn invalid_sign_in_mul_sign() { - use crate::{ecc::chip::EccConfig, utilities::UtilitiesInstructions}; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - dev::{FailureLocation, MockProver, VerifyFailure}, - plonk::{Circuit, ConstraintSystem, Error}, - }; - - #[derive(Default)] - struct MyCircuit { - base: Value, - sign: Value, - } - - impl UtilitiesInstructions for MyCircuit { - type Var = AssignedCell; - } - - impl Circuit for MyCircuit { - type Config = EccConfig; - 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(), - ]; - let lookup_table = 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(), - ]; - - // Shared fixed column for loading constants - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - let range_check = LookupRangeCheckConfig::configure( - meta, - advices[9], - lookup_table, - table_range_check_tag, - ); - EccChip::::configure(meta, advices, lagrange_coeffs, range_check) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let chip = EccChip::construct(config.clone()); - - let column = config.advices[0]; - - //let short_config = config.mul_fixed_short.clone(); - let base = Point::new(chip, layouter.namespace(|| "load base"), self.base)?; - - let sign = - self.load_private(layouter.namespace(|| "load sign"), column, self.sign)?; - - base.mul_sign(layouter.namespace(|| "[sign] base"), &sign)?; - - Ok(()) - } - } - - // Copied from halo2_proofs::dev::util - fn format_value(v: pallas::Base) -> String { - use ff::Field; - if v.is_zero_vartime() { - "0".into() - } else if v == pallas::Base::one() { - "1".into() - } else if v == -pallas::Base::one() { - "-1".into() - } else { - // Format value as hex. - let s = format!("{:?}", v); - // Remove leading zeroes. - let s = s.strip_prefix("0x").unwrap(); - let s = s.trim_start_matches('0'); - format!("0x{}", s) - } - } - - // Sign that is not +/- 1 should fail - // Generate a random non-identity point - let point = pallas::Point::random(rand::rngs::OsRng); - let circuit = MyCircuit { - base: Value::known(point.to_affine()), - sign: Value::known(pallas::Base::zero()), - }; - - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![ - VerifyFailure::ConstraintNotSatisfied { - constraint: ((17, "Short fixed-base mul gate").into(), 1, "sign_check").into(), - location: FailureLocation::InRegion { - region: (2, "Signed point").into(), - offset: 0, - }, - cell_values: vec![(((Any::Advice, 4).into(), 0).into(), "0".to_string())], - }, - VerifyFailure::ConstraintNotSatisfied { - constraint: ( - (17, "Short fixed-base mul gate").into(), - 3, - "negation_check" - ) - .into(), - location: FailureLocation::InRegion { - region: (2, "Signed point").into(), - offset: 0, - }, - cell_values: vec![ - ( - ((Any::Advice, 1).into(), 0).into(), - format_value(*point.to_affine().coordinates().unwrap().y()), - ), - ( - ((Any::Advice, 3).into(), 0).into(), - format_value(*point.to_affine().coordinates().unwrap().y()), - ), - (((Any::Advice, 4).into(), 0).into(), "0".to_string()), - ], - } - ]) - ); - } } diff --git a/halo2_gadgets/src/ecc/chip/witness_point.rs b/halo2_gadgets/src/ecc/chip/witness_point.rs index 98f865a6dc..580a07ca1d 100644 --- a/halo2_gadgets/src/ecc/chip/witness_point.rs +++ b/halo2_gadgets/src/ecc/chip/witness_point.rs @@ -12,14 +12,14 @@ use halo2_proofs::{ }; use pasta_curves::{arithmetic::CurveAffine, pallas}; -type Coordinates = ( +pub(crate) type Coordinates = ( AssignedCell, pallas::Base>, AssignedCell, pallas::Base>, ); #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct Config { - q_point: Selector, + pub(crate) q_point: Selector, q_point_non_id: Selector, // x-coordinate pub x: Column, @@ -102,21 +102,6 @@ impl Config { Ok((x_var, y_var)) } - fn assign_xy_from_constant( - &self, - value: (Assigned, Assigned), - offset: usize, - region: &mut Region<'_, pallas::Base>, - ) -> Result { - // Assign `x` value - let x_var = region.assign_advice_from_constant(|| "x", self.x, offset, value.0)?; - - // Assign `y` value - let y_var = region.assign_advice_from_constant(|| "y", self.y, offset, value.1)?; - - Ok((x_var, y_var)) - } - /// Assigns a point that can be the identity. pub(super) fn point( &self, @@ -141,28 +126,6 @@ impl Config { .map(|(x, y)| EccPoint::from_coordinates_unchecked(x, y)) } - /// Assigns a constant point that can be the identity. - pub(super) fn constant_point( - &self, - value: pallas::Affine, - offset: usize, - region: &mut Region<'_, pallas::Base>, - ) -> Result { - // Enable `q_point` selector - self.q_point.enable(region, offset)?; - - let value = if value == pallas::Affine::identity() { - // Map the identity to (0, 0). - (Assigned::Zero, Assigned::Zero) - } else { - let value = value.coordinates().unwrap(); - (value.x().into(), value.y().into()) - }; - - self.assign_xy_from_constant(value, offset, region) - .map(|(x, y)| EccPoint::from_coordinates_unchecked(x, y)) - } - /// Assigns a non-identity point. pub(super) fn point_non_id( &self, diff --git a/halo2_gadgets/src/ecc_opt.rs b/halo2_gadgets/src/ecc_opt.rs new file mode 100644 index 0000000000..a8ed313c10 --- /dev/null +++ b/halo2_gadgets/src/ecc_opt.rs @@ -0,0 +1,419 @@ +//! Elliptic curve operations. + +use std::fmt::Debug; + +use halo2_proofs::{ + arithmetic::CurveAffine, + circuit::{AssignedCell, Layouter}, + plonk::Error, +}; + +use crate::ecc::{EccInstructions, Point}; + +pub(crate) mod chip; + +/// The set of circuit instructions required to use the ECC gadgets. +pub trait EccInstructionsOptimized: EccInstructions { + /// Witnesses the given constant point as a private input to the circuit. + /// This allows the point to be the identity, mapped to (0, 0) in + /// affine coordinates. + fn witness_point_from_constant( + &self, + layouter: &mut impl Layouter, + value: C, + ) -> Result; + + /// Performs variable-base sign-scalar multiplication, returning `[sign] point` + /// `sign` must be in {-1, 1}. + fn mul_sign( + &self, + layouter: &mut impl Layouter, + sign: &AssignedCell, + point: &Self::Point, + ) -> Result; +} + +impl + Clone + Debug + Eq> Point { + /// Constructs a new point with the given fixed value. + pub fn new_from_constant( + chip: EccChip, + mut layouter: impl Layouter, + value: C, + ) -> Result { + let point = chip.witness_point_from_constant(&mut layouter, value); + point.map(|inner| Point { chip, inner }) + } + + /// Returns `[sign] self`. + /// `sign` must be in {-1, 1}. + pub fn mul_sign( + &self, + mut layouter: impl Layouter, + sign: &AssignedCell, + ) -> Result, Error> { + self.chip + .mul_sign(&mut layouter, sign, &self.inner) + .map(|point| Point { + chip: self.chip.clone(), + inner: point, + }) + } +} + +#[cfg(test)] +pub(crate) mod tests { + use ff::PrimeField; + use group::{prime::PrimeCurveAffine, Curve, Group}; + + use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner, Value}, + dev::MockProver, + plonk::{Circuit, ConstraintSystem, Error}, + }; + use lazy_static::lazy_static; + use pasta_curves::pallas; + + use crate::ecc::{ + chip::{ + find_zs_and_us, BaseFieldElem, EccChip, EccConfig, FixedPoint, FullScalar, ShortScalar, + H, NUM_WINDOWS, NUM_WINDOWS_SHORT, + }, + FixedPoints, + }; + use crate::utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}; + use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; + + #[derive(Debug, Eq, PartialEq, Clone)] + pub(crate) struct TestFixedBases; + #[derive(Debug, Eq, PartialEq, Clone)] + pub(crate) struct FullWidth(pallas::Affine, &'static [(u64, [pallas::Base; H])]); + #[derive(Debug, Eq, PartialEq, Clone)] + pub(crate) struct BaseField; + #[derive(Debug, Eq, PartialEq, Clone)] + pub(crate) struct Short; + + lazy_static! { + static ref BASE: pallas::Affine = pallas::Point::generator().to_affine(); + static ref ZS_AND_US: Vec<(u64, [pallas::Base; H])> = + find_zs_and_us(*BASE, NUM_WINDOWS).unwrap(); + static ref ZS_AND_US_SHORT: Vec<(u64, [pallas::Base; H])> = + find_zs_and_us(*BASE, NUM_WINDOWS_SHORT).unwrap(); + } + + impl FullWidth { + pub(crate) fn from_pallas_generator() -> Self { + FullWidth(*BASE, &ZS_AND_US) + } + + pub(crate) fn from_parts( + base: pallas::Affine, + zs_and_us: &'static [(u64, [pallas::Base; H])], + ) -> Self { + FullWidth(base, zs_and_us) + } + } + + impl FixedPoint for FullWidth { + type FixedScalarKind = FullScalar; + + fn generator(&self) -> pallas::Affine { + self.0 + } + + fn u(&self) -> Vec<[[u8; 32]; H]> { + self.1 + .iter() + .map(|(_, us)| { + [ + us[0].to_repr(), + us[1].to_repr(), + us[2].to_repr(), + us[3].to_repr(), + us[4].to_repr(), + us[5].to_repr(), + us[6].to_repr(), + us[7].to_repr(), + ] + }) + .collect() + } + + fn z(&self) -> Vec { + self.1.iter().map(|(z, _)| *z).collect() + } + } + + impl FixedPoint for BaseField { + type FixedScalarKind = BaseFieldElem; + + fn generator(&self) -> pallas::Affine { + *BASE + } + + fn u(&self) -> Vec<[[u8; 32]; H]> { + ZS_AND_US + .iter() + .map(|(_, us)| { + [ + us[0].to_repr(), + us[1].to_repr(), + us[2].to_repr(), + us[3].to_repr(), + us[4].to_repr(), + us[5].to_repr(), + us[6].to_repr(), + us[7].to_repr(), + ] + }) + .collect() + } + + fn z(&self) -> Vec { + ZS_AND_US.iter().map(|(z, _)| *z).collect() + } + } + + impl FixedPoint for Short { + type FixedScalarKind = ShortScalar; + + fn generator(&self) -> pallas::Affine { + *BASE + } + + fn u(&self) -> Vec<[[u8; 32]; H]> { + ZS_AND_US_SHORT + .iter() + .map(|(_, us)| { + [ + us[0].to_repr(), + us[1].to_repr(), + us[2].to_repr(), + us[3].to_repr(), + us[4].to_repr(), + us[5].to_repr(), + us[6].to_repr(), + us[7].to_repr(), + ] + }) + .collect() + } + + fn z(&self) -> Vec { + ZS_AND_US_SHORT.iter().map(|(z, _)| *z).collect() + } + } + + impl FixedPoints for TestFixedBases { + type FullScalar = FullWidth; + type ShortScalar = Short; + type Base = BaseField; + } + + struct MyCircuit { + test_errors: bool, + } + + #[allow(non_snake_case)] + impl Circuit for MyCircuit { + type Config = EccConfig< + crate::ecc::tests::TestFixedBases, + LookupRangeCheckConfigOptimized, + >; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + MyCircuit { test_errors: false } + } + + 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(), + ]; + let lookup_table = 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(), + ]; + // Shared fixed column for loading constants + let constants = meta.fixed_column(); + meta.enable_constant(constants); + + let range_check = + LookupRangeCheckConfigOptimized::configure(meta, advices[9], lookup_table); + EccChip::< + crate::ecc::tests::TestFixedBases, + LookupRangeCheckConfigOptimized, + >::configure(meta, advices, lagrange_coeffs, range_check) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let chip = EccChip::construct(config.clone()); + + // Load 10-bit lookup table. In the Action circuit, this will be + // provided by the Sinsemilla chip. + config.lookup_config.load(&mut layouter)?; + + // Generate a random non-identity point P + let p_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); // P + let p = crate::ecc::NonIdentityPoint::new( + chip.clone(), + layouter.namespace(|| "P"), + Value::known(p_val), + )?; + let p_neg = -p_val; + let p_neg = crate::ecc::NonIdentityPoint::new( + chip.clone(), + layouter.namespace(|| "-P"), + Value::known(p_neg), + )?; + + // Generate a random non-identity point Q + let q_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); // Q + let q = crate::ecc::NonIdentityPoint::new( + chip.clone(), + layouter.namespace(|| "Q"), + Value::known(q_val), + )?; + + // Make sure P and Q are not the same point. + assert_ne!(p_val, q_val); + + // Test that we can witness the identity as a point, but not as a non-identity point. + { + let _ = super::Point::new( + chip.clone(), + layouter.namespace(|| "identity"), + Value::known(pallas::Affine::identity()), + )?; + + crate::ecc::NonIdentityPoint::new( + chip.clone(), + layouter.namespace(|| "identity"), + Value::known(pallas::Affine::identity()), + ) + .expect_err("Trying to witness the identity should return an error"); + } + + // Test witness non-identity point + { + crate::ecc::chip::witness_point::tests::test_witness_non_id( + chip.clone(), + layouter.namespace(|| "witness non-identity point"), + ) + } + + // Test complete addition + { + crate::ecc::chip::add::tests::test_add( + chip.clone(), + layouter.namespace(|| "complete addition"), + p_val, + &p, + q_val, + &q, + &p_neg, + )?; + } + + // Test incomplete addition + { + crate::ecc::chip::add_incomplete::tests::test_add_incomplete( + chip.clone(), + layouter.namespace(|| "incomplete addition"), + p_val, + &p, + q_val, + &q, + &p_neg, + self.test_errors, + )?; + } + + // Test variable-base scalar multiplication + { + crate::ecc::chip::mul::tests::test_mul( + chip.clone(), + layouter.namespace(|| "variable-base scalar mul"), + &p, + p_val, + )?; + } + + // Test variable-base sign-scalar multiplication + { + super::chip::mul_fixed::short::tests::test_mul_sign( + chip.clone(), + layouter.namespace(|| "variable-base sign-scalar mul"), + )?; + } + + // Test full-width fixed-base scalar multiplication + { + crate::ecc::chip::mul_fixed::full_width::tests::test_mul_fixed( + chip.clone(), + layouter.namespace(|| "full-width fixed-base scalar mul"), + )?; + } + + // Test signed short fixed-base scalar multiplication + { + crate::ecc::chip::mul_fixed::short::tests::test_mul_fixed_short( + chip.clone(), + layouter.namespace(|| "signed short fixed-base scalar mul"), + )?; + } + + // Test fixed-base scalar multiplication with a base field element + { + crate::ecc::chip::mul_fixed::base_field_elem::tests::test_mul_fixed_base_field( + chip, + layouter.namespace(|| "fixed-base scalar mul with base field element"), + )?; + } + + Ok(()) + } + } + + #[test] + fn ecc_chip() { + let k = 13; + let circuit = MyCircuit { test_errors: true }; + let prover = MockProver::run(k, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), Ok(())) + } + + #[cfg(feature = "test-dev-graph")] + #[test] + fn print_ecc_chip() { + use plotters::prelude::*; + + let root = BitMapBackend::new("ecc-chip-layout.png", (1024, 7680)).into_drawing_area(); + root.fill(&WHITE).unwrap(); + let root = root.titled("Ecc Chip Layout", ("sans-serif", 60)).unwrap(); + + let circuit = MyCircuit { test_errors: false }; + halo2_proofs::dev::CircuitLayout::default() + .render(13, &circuit, &root) + .unwrap(); + } +} diff --git a/halo2_gadgets/src/ecc_opt/chip.rs b/halo2_gadgets/src/ecc_opt/chip.rs new file mode 100644 index 0000000000..ed391881b3 --- /dev/null +++ b/halo2_gadgets/src/ecc_opt/chip.rs @@ -0,0 +1,61 @@ +//! Chip implementations for the ECC gadgets. + +use halo2_proofs::{ + circuit::{AssignedCell, Chip, Layouter}, + plonk::Error, +}; +use pasta_curves::pallas; + +use crate::{ + ecc::{ + chip::{BaseFieldElem, EccChip, FixedPoint, FullScalar, ShortScalar}, + FixedPoints, + }, + utilities::lookup_range_check::DefaultLookupRangeCheck, +}; + +use super::EccInstructionsOptimized; + +pub(crate) mod mul_fixed; +pub(super) mod witness_point; + +impl, LookupRangeCheckConfig: DefaultLookupRangeCheck> + EccInstructionsOptimized for EccChip +where + >::Base: + FixedPoint, + >::FullScalar: + FixedPoint, + >::ShortScalar: + FixedPoint, +{ + fn witness_point_from_constant( + &self, + layouter: &mut impl Layouter, + value: pallas::Affine, + ) -> Result { + let config = self.config().witness_point; + layouter.assign_region( + || "witness point (constant)", + |mut region| config.constant_point(value, 0, &mut region), + ) + } + + /// Performs variable-base sign-scalar multiplication, returning `[sign] point` + /// `sign` must be in {-1, 1}. + fn mul_sign( + &self, + layouter: &mut impl Layouter, + sign: &AssignedCell, + point: &Self::Point, + ) -> Result { + // Multiply point by sign, using the same gate as mul_fixed::short. + // This also constrains sign to be in {-1, 1}. + let config_short = self.config().mul_fixed_short.clone(); + config_short.assign_scalar_sign( + layouter.namespace(|| "variable-base sign-scalar mul"), + sign, + point, + ) + } +} diff --git a/halo2_gadgets/src/ecc_opt/chip/mul_fixed.rs b/halo2_gadgets/src/ecc_opt/chip/mul_fixed.rs new file mode 100644 index 0000000000..d1dea74e22 --- /dev/null +++ b/halo2_gadgets/src/ecc_opt/chip/mul_fixed.rs @@ -0,0 +1 @@ +pub mod short; diff --git a/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs new file mode 100644 index 0000000000..679bd5d2be --- /dev/null +++ b/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs @@ -0,0 +1,744 @@ +use crate::ecc::chip::EccPoint; + +use super::super::FixedPoints; + +use halo2_proofs::{ + circuit::{AssignedCell, Layouter}, + plonk::Error, +}; +use pasta_curves::pallas; + +use crate::ecc::chip::mul_fixed::short::Config; + +impl> Config { + /// Multiply the point by sign, using the q_mul_fixed_short gate. + /// Constraints `sign` in {-1, 1} + pub fn assign_scalar_sign( + &self, + mut layouter: impl Layouter, + sign: &AssignedCell, + point: &EccPoint, + ) -> Result { + let signed_point = layouter.assign_region( + || "Signed point", + |mut region| { + let offset = 0; + + // Enable mul_fixed_short selector to check the sign logic. + self.q_mul_fixed_short.enable(&mut region, offset)?; + + // Set "last window" to 0 (this field is irrelevant here). + region.assign_advice_from_constant( + || "u=0", + self.super_config.u, + offset, + pallas::Base::zero(), + )?; + + // Copy sign to `window` column + sign.copy_advice(|| "sign", &mut region, self.super_config.window, offset)?; + + // Assign the input y-coordinate. + point.y.copy_advice( + || "unsigned y", + &mut region, + self.super_config.add_config.y_qr, + offset, + )?; + + // Conditionally negate y-coordinate according to the value of sign + let signed_y_val = sign.value().and_then(|sign| { + if sign == &-pallas::Base::one() { + -point.y.value() + } else { + point.y.value().cloned() + } + }); + + // Assign the output signed y-coordinate. + let signed_y = region.assign_advice( + || "signed y", + self.super_config.add_config.y_p, + offset, + || signed_y_val, + )?; + + Ok(EccPoint { + x: point.x.clone(), + y: signed_y, + }) + }, + )?; + + Ok(signed_point) + } +} + +#[cfg(test)] +pub mod tests { + use group::{ff::PrimeField, Curve, Group}; + use halo2_proofs::{ + arithmetic::CurveAffine, + circuit::{AssignedCell, Chip, Layouter, Value}, + plonk::{Any, Error}, + }; + use pasta_curves::pallas; + + use crate::utilities::lookup_range_check::{DefaultLookupRangeCheck, LookupRangeCheck}; + use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; + use crate::{ + ecc::{ + chip::{EccChip, FixedPoint, MagnitudeSign}, + tests::{Short, TestFixedBases}, + FixedPointShort, NonIdentityPoint, Point, ScalarFixedShort, + }, + utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions}, + }; + + #[allow(clippy::op_ref)] + pub(crate) fn test_mul_fixed_short( + chip: EccChip< + TestFixedBases, + LookupRangeCheckConfigOptimized, + >, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + // test_short + let base_val = Short.generator(); + let test_short = FixedPointShort::from_inner(chip.clone(), Short); + + fn load_magnitude_sign( + chip: EccChip< + TestFixedBases, + LookupRangeCheckConfigOptimized, + >, + mut layouter: impl Layouter, + magnitude: pallas::Base, + sign: pallas::Base, + ) -> Result { + let column = chip.config().advices[0]; + let magnitude = chip.load_private( + layouter.namespace(|| "magnitude"), + column, + Value::known(magnitude), + )?; + let sign = + chip.load_private(layouter.namespace(|| "sign"), column, Value::known(sign))?; + + Ok((magnitude, sign)) + } + + fn constrain_equal_non_id( + chip: EccChip< + TestFixedBases, + LookupRangeCheckConfigOptimized, + >, + mut layouter: impl Layouter, + base_val: pallas::Affine, + scalar_val: pallas::Scalar, + result: Point< + pallas::Affine, + EccChip< + TestFixedBases, + LookupRangeCheckConfigOptimized< + pallas::Base, + { crate::sinsemilla::primitives::K }, + >, + >, + >, + ) -> Result<(), Error> { + let expected = NonIdentityPoint::new( + chip, + layouter.namespace(|| "expected point"), + Value::known((base_val * scalar_val).to_affine()), + )?; + result.constrain_equal(layouter.namespace(|| "constrain result"), &expected) + } + + let magnitude_signs = [ + ("random [a]B", pallas::Base::from(rand::random::()), { + let mut random_sign = pallas::Base::one(); + if rand::random::() { + random_sign = -random_sign; + } + random_sign + }), + ( + "[2^64 - 1]B", + pallas::Base::from(0xFFFF_FFFF_FFFF_FFFFu64), + pallas::Base::one(), + ), + ( + "-[2^64 - 1]B", + pallas::Base::from(0xFFFF_FFFF_FFFF_FFFFu64), + -pallas::Base::one(), + ), + // There is a single canonical sequence of window values for which a doubling occurs on the last step: + // 1333333333333333333334 in octal. + // [0xB6DB_6DB6_DB6D_B6DC] B + ( + "mul_with_double", + pallas::Base::from(0xB6DB_6DB6_DB6D_B6DCu64), + pallas::Base::one(), + ), + ( + "mul_with_double negative", + pallas::Base::from(0xB6DB_6DB6_DB6D_B6DCu64), + -pallas::Base::one(), + ), + ]; + + for (name, magnitude, sign) in magnitude_signs.iter() { + let (result, _) = { + let magnitude_sign = load_magnitude_sign( + chip.clone(), + layouter.namespace(|| *name), + *magnitude, + *sign, + )?; + let by = ScalarFixedShort::new( + chip.clone(), + layouter.namespace(|| "signed short scalar"), + magnitude_sign, + )?; + test_short.mul(layouter.namespace(|| *name), by)? + }; + // Move from base field into scalar field + let scalar = { + let magnitude = pallas::Scalar::from_repr(magnitude.to_repr()).unwrap(); + let sign = if *sign == pallas::Base::one() { + pallas::Scalar::one() + } else { + -pallas::Scalar::one() + }; + magnitude * sign + }; + constrain_equal_non_id( + chip.clone(), + layouter.namespace(|| *name), + base_val, + scalar, + result, + )?; + } + + let zero_magnitude_signs = [ + ("mul by +zero", pallas::Base::zero(), pallas::Base::one()), + ("mul by -zero", pallas::Base::zero(), -pallas::Base::one()), + ]; + + for (name, magnitude, sign) in zero_magnitude_signs.iter() { + let (result, _) = { + let magnitude_sign = load_magnitude_sign( + chip.clone(), + layouter.namespace(|| *name), + *magnitude, + *sign, + )?; + let by = ScalarFixedShort::new( + chip.clone(), + layouter.namespace(|| "signed short scalar"), + magnitude_sign, + )?; + test_short.mul(layouter.namespace(|| *name), by)? + }; + result + .inner() + .is_identity() + .assert_if_known(|is_identity| *is_identity); + } + + Ok(()) + } + + #[test] + fn invalid_magnitude_sign() { + use crate::{ + ecc::chip::{EccConfig, FixedPoint}, + utilities::UtilitiesInstructions, + }; + use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner}, + dev::{FailureLocation, MockProver, VerifyFailure}, + plonk::{Circuit, ConstraintSystem, Error}, + }; + + #[derive(Default)] + struct MyCircuit { + magnitude: Value, + sign: Value, + // For test checking + magnitude_error: Value, + } + + impl UtilitiesInstructions for MyCircuit { + type Var = AssignedCell; + } + + impl Circuit for MyCircuit { + type Config = EccConfig< + TestFixedBases, + LookupRangeCheckConfigOptimized, + >; + 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(), + ]; + let lookup_table = 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(), + ]; + + // Shared fixed column for loading constants + let constants = meta.fixed_column(); + meta.enable_constant(constants); + + let range_check = + LookupRangeCheckConfigOptimized::configure(meta, advices[9], lookup_table); + EccChip::< + TestFixedBases, + LookupRangeCheckConfigOptimized< + pallas::Base, + { crate::sinsemilla::primitives::K }, + >, + >::configure(meta, advices, lagrange_coeffs, range_check) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let column = config.advices[0]; + + let short_config = config.mul_fixed_short.clone(); + let magnitude_sign = { + let magnitude = self.load_private( + layouter.namespace(|| "load magnitude"), + column, + self.magnitude, + )?; + let sign = + self.load_private(layouter.namespace(|| "load sign"), column, self.sign)?; + ScalarFixedShort::new( + EccChip::construct(config), + layouter.namespace(|| "signed short scalar"), + (magnitude, sign), + )? + }; + + short_config.assign(layouter, &magnitude_sign.inner, &Short)?; + + Ok(()) + } + } + + // Copied from halo2_proofs::dev::util + fn format_value(v: pallas::Base) -> String { + use ff::Field; + if v.is_zero_vartime() { + "0".into() + } else if v == pallas::Base::one() { + "1".into() + } else if v == -pallas::Base::one() { + "-1".into() + } else { + // Format value as hex. + let s = format!("{:?}", v); + // Remove leading zeroes. + let s = s.strip_prefix("0x").unwrap(); + let s = s.trim_start_matches('0'); + format!("0x{}", s) + } + } + + // Magnitude larger than 64 bits should fail + { + let circuits = [ + // 2^64 + MyCircuit { + magnitude: Value::known(pallas::Base::from_u128(1 << 64)), + sign: Value::known(pallas::Base::one()), + magnitude_error: Value::known(pallas::Base::from(1 << 1)), + }, + // -2^64 + MyCircuit { + magnitude: Value::known(pallas::Base::from_u128(1 << 64)), + sign: Value::known(-pallas::Base::one()), + magnitude_error: Value::known(pallas::Base::from(1 << 1)), + }, + // 2^66 + MyCircuit { + magnitude: Value::known(pallas::Base::from_u128(1 << 66)), + sign: Value::known(pallas::Base::one()), + magnitude_error: Value::known(pallas::Base::from(1 << 3)), + }, + // -2^66 + MyCircuit { + magnitude: Value::known(pallas::Base::from_u128(1 << 66)), + sign: Value::known(-pallas::Base::one()), + magnitude_error: Value::known(pallas::Base::from(1 << 3)), + }, + // 2^254 + MyCircuit { + magnitude: Value::known(pallas::Base::from_u128(1 << 127).square()), + sign: Value::known(pallas::Base::one()), + magnitude_error: Value::known( + pallas::Base::from_u128(1 << 95).square() * pallas::Base::from(2), + ), + }, + // -2^254 + MyCircuit { + magnitude: Value::known(pallas::Base::from_u128(1 << 127).square()), + sign: Value::known(-pallas::Base::one()), + magnitude_error: Value::known( + pallas::Base::from_u128(1 << 95).square() * pallas::Base::from(2), + ), + }, + ]; + + for circuit in circuits.iter() { + let prover = MockProver::::run(11, circuit, vec![]).unwrap(); + circuit.magnitude_error.assert_if_known(|magnitude_error| { + assert_eq!( + prover.verify(), + Err(vec![ + VerifyFailure::ConstraintNotSatisfied { + constraint: ( + (17, "Short fixed-base mul gate").into(), + 0, + "last_window_check", + ) + .into(), + location: FailureLocation::InRegion { + region: (3, "Short fixed-base mul (most significant word)") + .into(), + offset: 1, + }, + cell_values: vec![( + ((Any::Advice, 5).into(), 0).into(), + format_value(*magnitude_error), + )], + }, + VerifyFailure::Permutation { + column: (Any::Fixed, 10).into(), + location: FailureLocation::OutsideRegion { row: 0 }, + }, + VerifyFailure::Permutation { + column: (Any::Advice, 4).into(), + location: FailureLocation::InRegion { + region: (2, "Short fixed-base mul (incomplete addition)") + .into(), + offset: 22, + }, + }, + ]) + ); + true + }); + } + } + + // Sign that is not +/- 1 should fail + { + let magnitude_u64 = rand::random::(); + let circuit = MyCircuit { + magnitude: Value::known(pallas::Base::from(magnitude_u64)), + sign: Value::known(pallas::Base::zero()), + magnitude_error: Value::unknown(), + }; + + let negation_check_y = { + *(Short.generator() * pallas::Scalar::from(magnitude_u64)) + .to_affine() + .coordinates() + .unwrap() + .y() + }; + + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!( + prover.verify(), + Err(vec![ + VerifyFailure::ConstraintNotSatisfied { + constraint: ((17, "Short fixed-base mul gate").into(), 1, "sign_check") + .into(), + location: FailureLocation::InRegion { + region: (3, "Short fixed-base mul (most significant word)").into(), + offset: 1, + }, + cell_values: vec![(((Any::Advice, 4).into(), 0).into(), "0".to_string())], + }, + VerifyFailure::ConstraintNotSatisfied { + constraint: ( + (17, "Short fixed-base mul gate").into(), + 3, + "negation_check" + ) + .into(), + location: FailureLocation::InRegion { + region: (3, "Short fixed-base mul (most significant word)").into(), + offset: 1, + }, + cell_values: vec![ + ( + ((Any::Advice, 1).into(), 0).into(), + format_value(negation_check_y), + ), + ( + ((Any::Advice, 3).into(), 0).into(), + format_value(negation_check_y), + ), + (((Any::Advice, 4).into(), 0).into(), "0".to_string()), + ], + } + ]) + ); + } + } + + pub(crate) fn test_mul_sign( + chip: EccChip, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + // Generate a random non-identity point P + let p_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); + let p = Point::new( + chip.clone(), + layouter.namespace(|| "P"), + Value::known(p_val), + )?; + + // Create -P + let p_neg_val = -p_val; + let p_neg = Point::new( + chip.clone(), + layouter.namespace(|| "-P"), + Value::known(p_neg_val), + )?; + + // Create the identity point + let identity = Point::new( + chip.clone(), + layouter.namespace(|| "identity"), + Value::known(pallas::Point::identity().to_affine()), + )?; + + // Create -1 and 1 scalars + let pos_sign = chip.load_private( + layouter.namespace(|| "positive sign"), + chip.config().advices[0], + Value::known(pallas::Base::one()), + )?; + let neg_sign = chip.load_private( + layouter.namespace(|| "negative sign"), + chip.config().advices[1], + Value::known(-pallas::Base::one()), + )?; + + // [1] P == P + { + let result = p.mul_sign(layouter.namespace(|| "[1] P"), &pos_sign)?; + result.constrain_equal(layouter.namespace(|| "constrain [1] P"), &p)?; + } + + // [-1] P == -P + { + let result = p.mul_sign(layouter.namespace(|| "[1] P"), &neg_sign)?; + result.constrain_equal(layouter.namespace(|| "constrain [1] P"), &p_neg)?; + } + + // [1] 0 == 0 + { + let result = identity.mul_sign(layouter.namespace(|| "[1] O"), &pos_sign)?; + result.constrain_equal(layouter.namespace(|| "constrain [1] 0"), &identity)?; + } + + // [-1] 0 == 0 + { + let result = identity.mul_sign(layouter.namespace(|| "[-1] O"), &neg_sign)?; + result.constrain_equal(layouter.namespace(|| "constrain [1] 0"), &identity)?; + } + + Ok(()) + } + + #[test] + fn invalid_sign_in_mul_sign() { + use crate::{ecc::chip::EccConfig, utilities::UtilitiesInstructions}; + use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner}, + dev::{FailureLocation, MockProver, VerifyFailure}, + plonk::{Circuit, ConstraintSystem, Error}, + }; + + #[derive(Default)] + struct MyCircuit { + base: Value, + sign: Value, + } + + impl UtilitiesInstructions for MyCircuit { + type Var = AssignedCell; + } + + impl Circuit for MyCircuit { + type Config = EccConfig< + TestFixedBases, + LookupRangeCheckConfigOptimized, + >; + 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(), + ]; + let lookup_table = 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(), + ]; + + // Shared fixed column for loading constants + let constants = meta.fixed_column(); + meta.enable_constant(constants); + + let range_check = + LookupRangeCheckConfigOptimized::configure(meta, advices[9], lookup_table); + EccChip::< + TestFixedBases, + LookupRangeCheckConfigOptimized< + pallas::Base, + { crate::sinsemilla::primitives::K }, + >, + >::configure(meta, advices, lagrange_coeffs, range_check) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let chip = EccChip::construct(config.clone()); + + let column = config.advices[0]; + + //let short_config = config.mul_fixed_short.clone(); + let base = Point::new(chip, layouter.namespace(|| "load base"), self.base)?; + + let sign = + self.load_private(layouter.namespace(|| "load sign"), column, self.sign)?; + + base.mul_sign(layouter.namespace(|| "[sign] base"), &sign)?; + + Ok(()) + } + } + + // Copied from halo2_proofs::dev::util + fn format_value(v: pallas::Base) -> String { + use ff::Field; + if v.is_zero_vartime() { + "0".into() + } else if v == pallas::Base::one() { + "1".into() + } else if v == -pallas::Base::one() { + "-1".into() + } else { + // Format value as hex. + let s = format!("{:?}", v); + // Remove leading zeroes. + let s = s.strip_prefix("0x").unwrap(); + let s = s.trim_start_matches('0'); + format!("0x{}", s) + } + } + + // Sign that is not +/- 1 should fail + // Generate a random non-identity point + let point = pallas::Point::random(rand::rngs::OsRng); + let circuit = MyCircuit { + base: Value::known(point.to_affine()), + sign: Value::known(pallas::Base::zero()), + }; + + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!( + prover.verify(), + Err(vec![ + VerifyFailure::ConstraintNotSatisfied { + constraint: ((17, "Short fixed-base mul gate").into(), 1, "sign_check").into(), + location: FailureLocation::InRegion { + region: (2, "Signed point").into(), + offset: 0, + }, + cell_values: vec![(((Any::Advice, 4).into(), 0).into(), "0".to_string())], + }, + VerifyFailure::ConstraintNotSatisfied { + constraint: ( + (17, "Short fixed-base mul gate").into(), + 3, + "negation_check" + ) + .into(), + location: FailureLocation::InRegion { + region: (2, "Signed point").into(), + offset: 0, + }, + cell_values: vec![ + ( + ((Any::Advice, 1).into(), 0).into(), + format_value(*point.to_affine().coordinates().unwrap().y()), + ), + ( + ((Any::Advice, 3).into(), 0).into(), + format_value(*point.to_affine().coordinates().unwrap().y()), + ), + (((Any::Advice, 4).into(), 0).into(), "0".to_string()), + ], + } + ]) + ); + } +} diff --git a/halo2_gadgets/src/ecc_opt/chip/witness_point.rs b/halo2_gadgets/src/ecc_opt/chip/witness_point.rs new file mode 100644 index 0000000000..9e1bfeae6d --- /dev/null +++ b/halo2_gadgets/src/ecc_opt/chip/witness_point.rs @@ -0,0 +1,50 @@ +use crate::ecc::chip::EccPoint; + +use group::prime::PrimeCurveAffine; + +use halo2_proofs::{ + circuit::Region, + plonk::{Assigned, Error}, +}; +use pasta_curves::{arithmetic::CurveAffine, pallas}; + +use crate::ecc::chip::witness_point::{Config, Coordinates}; + +impl Config { + fn assign_xy_from_constant( + &self, + value: (Assigned, Assigned), + offset: usize, + region: &mut Region<'_, pallas::Base>, + ) -> Result { + // Assign `x` value + let x_var = region.assign_advice_from_constant(|| "x", self.x, offset, value.0)?; + + // Assign `y` value + let y_var = region.assign_advice_from_constant(|| "y", self.y, offset, value.1)?; + + Ok((x_var, y_var)) + } + + /// Assigns a constant point that can be the identity. + pub(crate) fn constant_point( + &self, + value: pallas::Affine, + offset: usize, + region: &mut Region<'_, pallas::Base>, + ) -> Result { + // Enable `q_point` selector + self.q_point.enable(region, offset)?; + + let value = if value == pallas::Affine::identity() { + // Map the identity to (0, 0). + (Assigned::Zero, Assigned::Zero) + } else { + let value = value.coordinates().unwrap(); + (value.x().into(), value.y().into()) + }; + + self.assign_xy_from_constant(value, offset, region) + .map(|(x, y)| EccPoint::from_coordinates_unchecked(x, y)) + } +} diff --git a/halo2_gadgets/src/lib.rs b/halo2_gadgets/src/lib.rs index 2ac2623a99..33ffcfa6b8 100644 --- a/halo2_gadgets/src/lib.rs +++ b/halo2_gadgets/src/lib.rs @@ -22,9 +22,12 @@ #![deny(unsafe_code)] pub mod ecc; +pub mod ecc_opt; pub mod poseidon; #[cfg(feature = "unstable-sha256-gadget")] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-sha256-gadget")))] pub mod sha256; pub mod sinsemilla; +pub mod sinsemilla_opt; pub mod utilities; +pub mod utilities_opt; diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index e57c0a2129..d518c341cc 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -15,7 +15,7 @@ use std::fmt::Debug; pub mod chip; pub mod merkle; -mod message; +pub(crate) mod message; pub mod primitives; /// The set of circuit instructions required to use the [`Sinsemilla`](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html) gadget. @@ -78,30 +78,17 @@ pub trait SinsemillaInstructions, + is_Q_public: bool, Q: C, message: Self::Message, ) -> Result<(Self::NonIdentityPoint, Vec), Error>; - /// Hashes a message to an ECC curve point. - /// This returns both the resulting point, as well as the message - /// decomposition in the form of intermediate values in a cumulative - /// sum. - /// The initial point `Q` is a private point. - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - fn hash_to_point_with_private_init( - &self, - layouter: impl Layouter, - Q: &Self::NonIdentityPoint, - message: Self::Message, - ) -> Result<(Self::NonIdentityPoint, Vec), Error>; - /// Extracts the x-coordinate of the output of a Sinsemilla hash. fn extract(point: &Self::NonIdentityPoint) -> Self::X; } @@ -116,8 +103,8 @@ pub struct Message + Clone + Debug + Eq, { - chip: SinsemillaChip, - inner: SinsemillaChip::Message, + pub(crate) chip: SinsemillaChip, + pub(crate) inner: SinsemillaChip::Message, } impl @@ -126,7 +113,7 @@ where SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, { #![allow(dead_code)] - fn from_bitstring( + pub(crate) fn from_bitstring( chip: SinsemillaChip, mut layouter: impl Layouter, bitstring: Vec>, @@ -200,7 +187,7 @@ where SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, { #![allow(dead_code)] - fn from_bitstring( + pub(crate) fn from_bitstring( chip: SinsemillaChip, layouter: impl Layouter, bitstring: &[Value], @@ -297,9 +284,9 @@ pub struct HashDomain< + Debug + Eq, { - sinsemilla_chip: SinsemillaChip, - ecc_chip: EccChip, - Q: C, + pub(crate) sinsemilla_chip: SinsemillaChip, + pub(crate) ecc_chip: EccChip, + pub(crate) Q: C, } impl @@ -335,26 +322,12 @@ where pub fn hash_to_point( &self, layouter: impl Layouter, + is_Q_public: bool, message: Message, ) -> Result<(ecc::NonIdentityPoint, Vec), Error> { assert_eq!(self.sinsemilla_chip, message.chip); self.sinsemilla_chip - .hash_to_point(layouter, self.Q, message.inner) - .map(|(point, zs)| (ecc::NonIdentityPoint::from_inner(self.ecc_chip.clone(), point), zs)) - } - - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - /// Evaluate the Sinsemilla hash of `message` from the private initial point `Q`. - pub fn hash_to_point_with_private_init( - &self, - layouter: impl Layouter, - Q: &>::NonIdentityPoint, - message: Message, - ) -> Result<(ecc::NonIdentityPoint, Vec), Error> { - assert_eq!(self.sinsemilla_chip, message.chip); - self.sinsemilla_chip - .hash_to_point_with_private_init(layouter, Q, message.inner) + .hash_to_point(layouter, is_Q_public, self.Q, message.inner) .map(|(point, zs)| (ecc::NonIdentityPoint::from_inner(self.ecc_chip.clone(), point), zs)) } @@ -365,10 +338,11 @@ where pub fn hash( &self, layouter: impl Layouter, + is_Q_public: bool, message: Message, ) -> Result<(ecc::X, Vec), Error> { assert_eq!(self.sinsemilla_chip, message.chip); - let (p, zs) = self.hash_to_point(layouter, message)?; + let (p, zs) = self.hash_to_point(layouter, is_Q_public, message)?; Ok((p.extract_p(), zs)) } } @@ -412,8 +386,8 @@ pub struct CommitDomain< + Debug + Eq, { - M: HashDomain, - R: ecc::FixedPoint, + pub(crate) M: HashDomain, + pub(crate) R: ecc::FixedPoint, } impl @@ -441,63 +415,6 @@ where } } - #[allow(clippy::type_complexity)] - /// Evaluates the Sinsemilla hash of `message` from the public initial point `Q` stored - /// into `CommitDomain`. - pub fn hash( - &self, - layouter: impl Layouter, - message: Message, - ) -> Result< - ( - ecc::NonIdentityPoint, - Vec, - ), - Error, - > { - assert_eq!(self.M.sinsemilla_chip, message.chip); - self.M.hash_to_point(layouter, message) - } - - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - /// Evaluates the Sinsemilla hash of `message` from the private initial point `Q`. - pub fn hash_with_private_init( - &self, - layouter: impl Layouter, - Q: &>::NonIdentityPoint, - message: Message, - ) -> Result< - ( - ecc::NonIdentityPoint, - Vec, - ), - Error, - > { - assert_eq!(self.M.sinsemilla_chip, message.chip); - self.M.hash_to_point_with_private_init(layouter, Q, message) - } - - #[allow(clippy::type_complexity)] - /// Returns the public initial point `Q` stored into `CommitDomain`. - pub fn q_init(&self) -> C { - self.M.Q - } - - #[allow(clippy::type_complexity)] - /// Evaluates the blinding factor equal to $\[r\] R$ where `r` is stored in the `CommitDomain`. - pub fn blinding_factor( - &self, - mut layouter: impl Layouter, - r: ecc::ScalarFixed, - ) -> Result< - ecc::Point, - Error, - > { - let (blind, _) = self.R.mul(layouter.namespace(|| "[r] R"), r)?; - Ok(blind) - } - #[allow(clippy::type_complexity)] /// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. /// @@ -505,6 +422,7 @@ where pub fn commit( &self, mut layouter: impl Layouter, + is_Q_public: bool, message: Message, r: ecc::ScalarFixed, ) -> Result< @@ -515,8 +433,15 @@ where Error, > { assert_eq!(self.M.sinsemilla_chip, message.chip); - let blind = self.blinding_factor(layouter.namespace(|| "[r] R"), r)?; - let (p, zs) = self.hash(layouter.namespace(|| "M"), message)?; + + // FIXME: consider returning ZSA version of the following lines. + // It's not a breaking change because `blinding_factor` simply wraps `R.mul` + // and `hash` simply wraps `M.hash_to_point` - are those wrapper really needed? + //let blind = self.blinding_factor(layouter.namespace(|| "[r] R"), r)?; + //let (p, zs) = self.hash(layouter.namespace(|| "M"), message)?; + let (blind, _) = self.R.mul(layouter.namespace(|| "[r] R"), r)?; + let (p, zs) = self.M.hash_to_point(layouter.namespace(|| "M"), is_Q_public, message)?; + let commitment = p.add(layouter.namespace(|| "M + [r] R"), &blind)?; Ok((commitment, zs)) } @@ -528,11 +453,12 @@ where pub fn short_commit( &self, mut layouter: impl Layouter, + is_Q_public: bool, message: Message, r: ecc::ScalarFixed, ) -> Result<(ecc::X, Vec), Error> { assert_eq!(self.M.sinsemilla_chip, message.chip); - let (p, zs) = self.commit(layouter.namespace(|| "commit"), message, r)?; + let (p, zs) = self.commit(layouter.namespace(|| "commit"), is_Q_public, message, r)?; Ok((p.extract_p(), zs)) } } @@ -568,6 +494,8 @@ pub(crate) mod tests { use lazy_static::lazy_static; use pasta_curves::pallas; + use crate::sinsemilla::chip::generator_table::GeneratorTableConfig; + use crate::utilities::lookup_range_check::LookupRangeCheck; use std::convert::TryInto; pub(crate) const PERSONALIZATION: &str = "MerkleCRH"; @@ -607,9 +535,24 @@ pub(crate) mod tests { impl Circuit for MyCircuit { #[allow(clippy::type_complexity)] type Config = ( - EccConfig, - SinsemillaConfig, - SinsemillaConfig, + EccConfig< + TestFixedBases, + LookupRangeCheckConfig, + >, + SinsemillaConfig< + TestHashDomain, + TestCommitDomain, + TestFixedBases, + LookupRangeCheckConfig, + GeneratorTableConfig, + >, + SinsemillaConfig< + TestHashDomain, + TestCommitDomain, + TestFixedBases, + LookupRangeCheckConfig, + GeneratorTableConfig, + >, ); type FloorPlanner = SimpleFloorPlanner; @@ -637,7 +580,6 @@ pub(crate) mod tests { meta.enable_constant(constants); 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(), @@ -654,33 +596,36 @@ pub(crate) mod tests { table_idx, meta.lookup_table_column(), meta.lookup_table_column(), - table_range_check_tag, ); - let range_check = LookupRangeCheckConfig::configure( - meta, - advices[9], - table_idx, - table_range_check_tag, - ); + let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx); + let table = GeneratorTableConfig { + table_idx: lookup.0, + table_x: lookup.1, + table_y: lookup.2, + }; - let ecc_config = - EccChip::::configure(meta, advices, lagrange_coeffs, range_check); + let ecc_config = EccChip::< + TestFixedBases, + LookupRangeCheckConfig, + >::configure(meta, advices, lagrange_coeffs, range_check); let config1 = SinsemillaChip::configure( + true, meta, advices[..5].try_into().unwrap(), advices[2], lagrange_coeffs[0], - lookup, + table, range_check, ); let config2 = SinsemillaChip::configure( + true, meta, advices[5..].try_into().unwrap(), advices[7], lagrange_coeffs[1], - lookup, + table, range_check, ); (ecc_config, config1, config2) @@ -696,10 +641,13 @@ pub(crate) mod tests { let ecc_chip = EccChip::construct(config.0); // The two `SinsemillaChip`s share the same lookup table. - SinsemillaChip::::load( - config.1.clone(), - &mut layouter, - )?; + SinsemillaChip::< + TestHashDomain, + TestCommitDomain, + TestFixedBases, + LookupRangeCheckConfig, + GeneratorTableConfig, + >::load(config.1.clone(), &mut layouter)?; // This MerkleCRH example is purely for illustrative purposes. // It is not an implementation of the Orchard protocol spec. @@ -766,7 +714,7 @@ pub(crate) mod tests { // Parent let (parent, _) = { let message = Message::from_pieces(chip1, vec![l, left, right]); - merkle_crh.hash_to_point(layouter.namespace(|| "parent"), message)? + merkle_crh.hash_to_point(layouter.namespace(|| "parent"), true, message)? }; parent.constrain_equal( @@ -796,7 +744,7 @@ pub(crate) mod tests { layouter.namespace(|| "witness message"), message.clone(), )?; - test_commit.commit(layouter.namespace(|| "commit"), message, r)? + test_commit.commit(layouter.namespace(|| "commit"), true, message, r)? }; // Witness expected result. diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs index c55efd1105..07ad5323f9 100644 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ b/halo2_gadgets/src/sinsemilla/chip.rs @@ -9,7 +9,7 @@ use crate::{ chip::{DoubleAndAdd, NonIdentityEccPoint}, FixedPoints, }, - utilities::lookup_range_check::LookupRangeCheckConfig, + utilities::lookup_range_check::DefaultLookupRangeCheck, }; use std::marker::PhantomData; @@ -22,51 +22,60 @@ use halo2_proofs::{ poly::Rotation, }; use pasta_curves::pallas; +use pasta_curves::pallas::Base; -mod generator_table; +pub(crate) mod generator_table; +use crate::sinsemilla::chip::generator_table::{DefaultGeneratorTable, GeneratorTable}; +use crate::sinsemilla_opt::chip::generator_table::GeneratorTableConfigOptimized; +use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; use generator_table::GeneratorTableConfig; -mod hash_to_point; +pub(crate) mod hash_to_point; /// Configuration for the Sinsemilla hash chip #[derive(Eq, PartialEq, Clone, Debug)] -pub struct SinsemillaConfig +pub struct SinsemillaConfig where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, { /// Binary selector used in lookup argument and in the body of the Sinsemilla hash. - q_sinsemilla1: Selector, + pub(crate) q_sinsemilla1: Selector, /// Non-binary selector used in lookup argument and in the body of the Sinsemilla hash. - q_sinsemilla2: Column, + pub(crate) q_sinsemilla2: Column, /// q_sinsemilla2 is used to define a synthetic selector, /// q_sinsemilla3 = (q_sinsemilla2) ⋅ (q_sinsemilla2 - 1) /// Simple selector used to constrain hash initialization to be consistent with /// the y-coordinate of the domain $Q$. - q_sinsemilla4: Selector, + pub(crate) q_sinsemilla4: Selector, /// Fixed column used to load the y-coordinate of the domain $Q$. - fixed_y_q: Column, + pub(crate) fixed_y_q: Column, /// Logic specific to merged double-and-add. - double_and_add: DoubleAndAdd, + pub(crate) double_and_add: DoubleAndAdd, /// Advice column used to load the message. - bits: Column, + pub(crate) bits: Column, /// Advice column used to witness message pieces. This may or may not be the same /// column as `bits`. - witness_pieces: Column, + pub(crate) witness_pieces: Column, /// The lookup table where $(\mathsf{idx}, x_p, y_p)$ are loaded for the $2^K$ /// generators of the Sinsemilla hash. - pub(super) generator_table: GeneratorTableConfig, + pub(crate) generator_table: GeneratorTableConfigType, /// An advice column configured to perform lookup range checks. - lookup_config: LookupRangeCheckConfig, + pub(crate) lookup_config: LookupRangeCheckConfig, _marker: PhantomData<(Hash, Commit, F)>, } -impl SinsemillaConfig +impl + SinsemillaConfig where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, { /// Returns an array of all advice columns in this config, in arbitrary order. pub(super) fn advices(&self) -> [Column; 5] { @@ -80,7 +89,7 @@ where } /// Returns the lookup range check config used in this config. - pub fn lookup_config(&self) -> LookupRangeCheckConfig { + pub fn lookup_config(&self) -> LookupRangeCheckConfig { self.lookup_config } @@ -96,22 +105,28 @@ where /// /// [Chip description](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html#plonk--halo-2-constraints). #[derive(Eq, PartialEq, Clone, Debug)] -pub struct SinsemillaChip +pub struct SinsemillaChip where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, { - config: SinsemillaConfig, + config: SinsemillaConfig, } -impl Chip for SinsemillaChip +impl Chip + for SinsemillaChip where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, { - type Config = SinsemillaConfig; + type Config = + SinsemillaConfig; type Loaded = (); fn config(&self) -> &Self::Config { @@ -123,11 +138,14 @@ where } } -impl SinsemillaChip +impl + SinsemillaChip where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, { /// Reconstructs this chip from the given config. pub fn construct(config: >::Config) -> Self { @@ -136,65 +154,55 @@ where /// Loads the lookup table required by this chip into the circuit. pub fn load( - config: SinsemillaConfig, + config: SinsemillaConfig, layouter: &mut impl Layouter, ) -> Result<>::Loaded, Error> { // Load the lookup table. 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)] - pub fn configure( - meta: &mut ConstraintSystem, - advices: [Column; 5], - witness_pieces: Column, - fixed_y_q: Column, - lookup: (TableColumn, TableColumn, TableColumn, TableColumn), - range_check: LookupRangeCheckConfig, - ) -> >::Config { - // Enable equality on all advice columns - for advice in advices.iter() { - meta.enable_equality(*advice); - } - - let config = SinsemillaConfig:: { - q_sinsemilla1: meta.complex_selector(), - q_sinsemilla2: meta.fixed_column(), - q_sinsemilla4: meta.selector(), - fixed_y_q, - double_and_add: DoubleAndAdd { - x_a: advices[0], - x_p: advices[1], - lambda_1: advices[3], - lambda_2: advices[4], - }, - bits: advices[2], - witness_pieces, - generator_table: GeneratorTableConfig { - table_idx: lookup.0, - table_x: lookup.1, - table_y: lookup.2, - table_range_check_tag: lookup.3, - }, - lookup_config: range_check, - _marker: PhantomData, - }; + /// Query a fixed value from the circuit's fixed column using the configuration `fixed_y_q`. + fn get_y_q_fixed( + meta: &mut VirtualCells, + config: &SinsemillaConfig< + Hash, + Commit, + F, + LookupRangeCheckConfig, + GeneratorTableConfigType, + >, + ) -> Expression { + meta.query_fixed(config.fixed_y_q) + } - // Set up lookup argument - GeneratorTableConfig::configure(meta, config.clone()); + /// Query an advice value 'y_q' from a specific advice column `x_p` at the previous rotation. + fn get_y_q_advice( + meta: &mut VirtualCells, + config: &SinsemillaConfig< + Hash, + Commit, + F, + LookupRangeCheckConfig, + GeneratorTableConfigType, + >, + ) -> Expression { + meta.query_advice(config.double_and_add.x_p, Rotation::prev()) + } + #[allow(non_snake_case)] + pub(crate) fn create_initial_y_q_gate( + is_Q_public: bool, + meta: &mut ConstraintSystem, + config: &SinsemillaConfig< + Hash, + Commit, + F, + LookupRangeCheckConfig, + GeneratorTableConfigType, + >, + ) { let two = pallas::Base::from(2); - // Closures for expressions that are derived multiple times - // x_r = lambda_1^2 - x_a - x_p - let x_r = |meta: &mut VirtualCells, rotation| { - config.double_and_add.x_r(meta, rotation) - }; - // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) let Y_A = |meta: &mut VirtualCells, rotation| { config.double_and_add.Y_A(meta, rotation) @@ -204,7 +212,12 @@ where // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial meta.create_gate("Initial y_Q", |meta| { let q_s4 = meta.query_selector(config.q_sinsemilla4); - let y_q = meta.query_advice(config.double_and_add.x_p, Rotation::prev()); + // fixme: how to change to optimized get_y_q in a simple way? + let y_q = if is_Q_public { + Self::get_y_q_fixed(meta, &config) + } else { + Self::get_y_q_advice(meta, &config) + }; // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) let Y_A_cur = Y_A(meta, Rotation::cur()); @@ -214,6 +227,31 @@ where Constraints::with_selector(q_s4, Some(("init_y_q_check", init_y_q_check))) }); + } + + #[allow(non_snake_case)] + pub(crate) fn create_sinsemilla_gate( + meta: &mut ConstraintSystem, + config: &SinsemillaConfig< + Hash, + Commit, + F, + LookupRangeCheckConfig, + GeneratorTableConfigType, + >, + ) { + let two = pallas::Base::from(2); + + // Closures for expressions that are derived multiple times + // x_r = lambda_1^2 - x_a - x_p + let x_r = |meta: &mut VirtualCells, rotation| { + config.double_and_add.x_r(meta, rotation) + }; + + // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) + let Y_A = |meta: &mut VirtualCells, rotation| { + config.double_and_add.Y_A(meta, rotation) + }; // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial meta.create_gate("Sinsemilla gate", |meta| { @@ -259,18 +297,82 @@ where Constraints::with_selector(q_s1, [("Secant line", secant_line), ("y check", y_check)]) }); + } + + pub(crate) fn create_config( + meta: &mut ConstraintSystem, + advices: [Column; 5], + witness_pieces: Column, + fixed_y_q: Column, + table: GeneratorTableConfigType, + range_check: LookupRangeCheckConfig, + ) -> >::Config { + // Enable equality on all advice columns + for advice in advices.iter() { + meta.enable_equality(*advice); + } + + let config = + SinsemillaConfig:: { + q_sinsemilla1: meta.complex_selector(), + q_sinsemilla2: meta.fixed_column(), + q_sinsemilla4: meta.selector(), + fixed_y_q, + double_and_add: DoubleAndAdd { + x_a: advices[0], + x_p: advices[1], + lambda_1: advices[3], + lambda_2: advices[4], + }, + bits: advices[2], + witness_pieces, + // todo: check + generator_table: table, + lookup_config: range_check, + _marker: PhantomData, + }; + + // Set up lookup argument + config.generator_table.configure(meta, &config); + + config + } + + /// # Side-effects + /// + /// All columns in `advices` and will be equality-enabled. + #[allow(clippy::too_many_arguments)] + #[allow(non_snake_case)] + pub fn configure( + is_Q_public: bool, + meta: &mut ConstraintSystem, + advices: [Column; 5], + witness_pieces: Column, + fixed_y_q: Column, + table: GeneratorTableConfigType, + range_check: LookupRangeCheckConfig, + ) -> >::Config { + let config = + Self::create_config(meta, advices, witness_pieces, fixed_y_q, table, range_check); + + Self::create_initial_y_q_gate(is_Q_public, meta, &config); + + Self::create_sinsemilla_gate(meta, &config); config } } // Implement `SinsemillaInstructions` for `SinsemillaChip` -impl SinsemillaInstructions - for SinsemillaChip +impl + SinsemillaInstructions + for SinsemillaChip where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, { type CellValue = AssignedCell; @@ -313,26 +415,13 @@ where fn hash_to_point( &self, mut layouter: impl Layouter, + is_Q_public: bool, Q: pallas::Affine, message: Self::Message, ) -> Result<(Self::NonIdentityPoint, Vec), Error> { layouter.assign_region( || "hash_to_point", - |mut region| self.hash_message(&mut region, Q, &message), - ) - } - - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - fn hash_to_point_with_private_init( - &self, - mut layouter: impl Layouter, - Q: &Self::NonIdentityPoint, - message: Self::Message, - ) -> Result<(Self::NonIdentityPoint, Vec), Error> { - layouter.assign_region( - || "hash_to_point", - |mut region| self.hash_message_with_private_init(&mut region, Q, &message), + |mut region| self.hash_message(is_Q_public, &mut region, Q, &message), ) } diff --git a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs index e77928b128..5c09500554 100644 --- a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs +++ b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs @@ -1,12 +1,18 @@ +use ff::PrimeFieldBits; use group::ff::PrimeField; use halo2_proofs::{ circuit::{Layouter, Value}, plonk::{ConstraintSystem, Error, Expression, TableColumn}, poly::Rotation, }; +use std::fmt::Debug; use super::{CommitDomains, FixedPoints, HashDomains}; -use crate::sinsemilla::primitives::{self as sinsemilla, K, SINSEMILLA_S}; +use crate::utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}; +use crate::{ + sinsemilla::primitives::{self as sinsemilla, SINSEMILLA_S}, + utilities::lookup_range_check::DefaultLookupRangeCheck, +}; use pasta_curves::pallas; /// Table containing independent generators S[0..2^k] @@ -15,27 +21,38 @@ pub struct GeneratorTableConfig { pub table_idx: TableColumn, pub table_x: TableColumn, pub table_y: TableColumn, - pub table_range_check_tag: TableColumn, } -impl GeneratorTableConfig { +/// FIXME: add doc +pub trait GeneratorTable { + fn config(&self) -> &GeneratorTableConfig; + #[allow(clippy::too_many_arguments)] #[allow(non_snake_case)] /// Even though the lookup table can be used in other parts of the circuit, /// this specific configuration sets up Sinsemilla-specific constraints /// controlled by `q_sinsemilla`, and would likely not apply to other chips. - pub fn configure( + fn configure( + &self, meta: &mut ConstraintSystem, - config: super::SinsemillaConfig, + config: &super::SinsemillaConfig< + Hash, + Commit, + F, + LookupRangeCheckConfig, + GeneratorTableConfigType, + >, ) where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, { let (table_idx, table_x, table_y) = ( - config.generator_table.table_idx, - config.generator_table.table_x, - config.generator_table.table_y, + self.config().table_idx, + self.config().table_x, + self.config().table_y, ); // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial @@ -78,23 +95,14 @@ impl GeneratorTableConfig { }); } - /// 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(&self, layouter: &mut impl Layouter) -> Result<(), Error> { + fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error>; +} +impl GeneratorTable for GeneratorTableConfig { + fn config(&self) -> &GeneratorTableConfig { + self + } + + fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { layouter.assign_table( || "generator_table", |mut table| { @@ -107,69 +115,14 @@ impl GeneratorTableConfig { )?; 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", - self.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", - 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", - 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", - self.table_range_check_tag, - new_index, - || Value::known(pallas::Base::from(5_u64)), - )?; - } } Ok(()) }, ) } } + +/// FIXME: add doc +pub trait DefaultGeneratorTable: GeneratorTable + Eq + PartialEq + Clone + Copy + Debug {} + +impl DefaultGeneratorTable for GeneratorTableConfig {} diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 165615efaa..6c0bc392e5 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -3,6 +3,7 @@ use super::{NonIdentityEccPoint, SinsemillaChip}; use crate::{ ecc::FixedPoints, sinsemilla::primitives::{self as sinsemilla, lebs2ip_k, INV_TWO_POW_K, SINSEMILLA_S}, + utilities::lookup_range_check::DefaultLookupRangeCheck, }; use ff::Field; @@ -14,19 +15,31 @@ use halo2_proofs::{ use group::ff::{PrimeField, PrimeFieldBits}; use pasta_curves::{arithmetic::CurveAffine, pallas}; +use crate::sinsemilla::chip::generator_table::DefaultGeneratorTable; use std::ops::Deref; -impl SinsemillaChip +/// Define an enum that can hold either type +#[derive(Debug, Clone)] +pub enum EccPointQ<'a> { + PublicPoint(pallas::Affine), + PrivatePoint(&'a NonIdentityEccPoint), +} + +impl + SinsemillaChip where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, { /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). #[allow(non_snake_case)] #[allow(clippy::type_complexity)] pub(super) fn hash_message( &self, + is_Q_public: bool, region: &mut Region<'_, pallas::Base>, Q: pallas::Affine, message: & { - let (offset, x_a, y_a) = self.public_initialization(region, Q)?; + // todo: add doc about is_Q_public + let (offset, x_a, y_a) = if is_Q_public { + self.public_initialization_vanilla(region, Q)? + } else { + self.public_initialization(region, Q)? + }; let (x_a, y_a, zs_sum) = self.hash_all_pieces(region, offset, message, x_a, y_a)?; #[cfg(test)] - #[allow(non_snake_case)] - // Check equivalence to result from primitives::sinsemilla::hash_to_point - { - use crate::sinsemilla::primitives::{K, S_PERSONALIZATION}; - - use group::{prime::PrimeCurveAffine, Curve}; - use pasta_curves::arithmetic::CurveExt; - - let field_elems: Value> = message - .iter() - .map(|piece| piece.field_elem().map(|elem| (elem, piece.num_words()))) - .collect(); - - field_elems - .zip(x_a.value().zip(y_a.value())) - .assert_if_known(|(field_elems, (x_a, y_a))| { - // Get message as a bitstring. - let bitstring: Vec = field_elems - .iter() - .flat_map(|(elem, num_words)| { - elem.to_le_bits().into_iter().take(K * num_words) - }) - .collect(); - - let hasher_S = pallas::Point::hash_to_curve(S_PERSONALIZATION); - let S = |chunk: &[bool]| hasher_S(&lebs2ip_k(chunk).to_le_bytes()); - - // We can use complete addition here because it differs from - // incomplete addition with negligible probability. - let expected_point = bitstring - .chunks(K) - .fold(Q.to_curve(), |acc, chunk| (acc + S(chunk)) + acc); - let actual_point = - pallas::Affine::from_xy(x_a.evaluate(), y_a.evaluate()).unwrap(); - expected_point.to_affine() == actual_point - }); - } - - 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, - )) + self.check_hash_result(EccPointQ::PublicPoint(Q), message, x_a, y_a, zs_sum) } - /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). + #[cfg(test)] #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - pub(super) fn hash_message_with_private_init( + // Check equivalence to result from primitives::sinsemilla::hash_to_point + pub(crate) fn check_hash_result( &self, - region: &mut Region<'_, pallas::Base>, - Q: &NonIdentityEccPoint, + Q: EccPointQ, message: &>::Message, + x_a: X, + y_a: AssignedCell, pallas::Base>, + zs_sum: Vec>>, ) -> Result< ( NonIdentityEccPoint, @@ -112,49 +88,42 @@ where ), Error, > { - let (offset, x_a, y_a) = self.private_initialization(region, Q)?; + use crate::sinsemilla::primitives::{K, S_PERSONALIZATION}; - let (x_a, y_a, zs_sum) = self.hash_all_pieces(region, offset, message, x_a, y_a)?; + use group::{prime::PrimeCurveAffine, Curve}; + use pasta_curves::arithmetic::CurveExt; - #[cfg(test)] - #[allow(non_snake_case)] - // Check equivalence to result from primitives::sinsemilla::hash_to_point - { - use crate::sinsemilla::primitives::{K, S_PERSONALIZATION}; + let field_elems: Value> = message + .iter() + .map(|piece| piece.field_elem().map(|elem| (elem, piece.num_words()))) + .collect(); - use group::{prime::PrimeCurveAffine, Curve}; - use pasta_curves::arithmetic::CurveExt; + let value_Q = match Q { + EccPointQ::PublicPoint(p) => Value::known(p), + EccPointQ::PrivatePoint(p) => p.point(), + }; - let field_elems: Value> = message - .iter() - .map(|piece| piece.field_elem().map(|elem| (elem, piece.num_words()))) - .collect(); - - field_elems - .zip(x_a.value().zip(y_a.value())) - .zip(Q.point()) - .assert_if_known(|((field_elems, (x_a, y_a)), Q)| { - // Get message as a bitstring. - let bitstring: Vec = field_elems - .iter() - .flat_map(|(elem, num_words)| { - elem.to_le_bits().into_iter().take(K * num_words) - }) - .collect(); - - let hasher_S = pallas::Point::hash_to_curve(S_PERSONALIZATION); - let S = |chunk: &[bool]| hasher_S(&lebs2ip_k(chunk).to_le_bytes()); - - // We can use complete addition here because it differs from - // incomplete addition with negligible probability. - let expected_point = bitstring - .chunks(K) - .fold(Q.to_curve(), |acc, chunk| (acc + S(chunk)) + acc); - let actual_point = - pallas::Affine::from_xy(x_a.evaluate(), y_a.evaluate()).unwrap(); - expected_point.to_affine() == actual_point - }); - } + field_elems + .zip(x_a.value().zip(y_a.value())) + .zip(value_Q) + .assert_if_known(|((field_elems, (x_a, y_a)), value_Q)| { + // Get message as a bitstring. + let bitstring: Vec = field_elems + .iter() + .flat_map(|(elem, num_words)| elem.to_le_bits().into_iter().take(K * num_words)) + .collect(); + + let hasher_S = pallas::Point::hash_to_curve(S_PERSONALIZATION); + let S = |chunk: &[bool]| hasher_S(&lebs2ip_k(chunk).to_le_bytes()); + + // We can use complete addition here because it differs from + // incomplete addition with negligible probability. + let expected_point = bitstring + .chunks(K) + .fold(value_Q.to_curve(), |acc, chunk| (acc + S(chunk)) + acc); + let actual_point = pallas::Affine::from_xy(x_a.evaluate(), y_a.evaluate()).unwrap(); + expected_point.to_affine() == actual_point + }); x_a.value() .zip(y_a.value()) @@ -168,17 +137,16 @@ where #[allow(non_snake_case)] /// Assign the coordinates of the initial public point `Q` /// - /// | offset | x_A | x_P | q_sinsemilla4 | + /// | offset | x_A | q_sinsemilla4 | fixed_y_q | /// -------------------------------------- - /// | 0 | | y_Q | | - /// | 1 | x_Q | | 1 | - fn public_initialization( + /// | 0 | x_Q | 1 | y_Q | + pub(crate) 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; + let offset = 0; // Get the `x`- and `y`-coordinates of the starting `Q` base. let x_q = *Q.coordinates().unwrap().x(); @@ -187,19 +155,17 @@ where // 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.q_sinsemilla4.enable(region, offset + 1)?; - let y_a: AssignedCell, pallas::Base> = region - .assign_advice_from_constant( - || "fixed y_q", - config.double_and_add.x_p, - offset, - y_q.into(), - )?; + // Enable `q_sinsemilla4` on the first row. + config.q_sinsemilla4.enable(region, offset)?; + region.assign_fixed( + || "fixed y_q", + config.fixed_y_q, + offset, + || Value::known(y_q), + )?; - y_a.value_field().into() + Value::known(y_q.into()).into() }; - offset += 1; // Constrain the initial x_q to equal the x-coordinate of the domain's `Q`. let x_a: X = { @@ -216,47 +182,9 @@ where Ok((offset, x_a, y_a)) } - #[allow(non_snake_case)] - /// Assign the coordinates of the initial private point `Q` - /// - /// | offset | x_A | x_P | q_sinsemilla4 | - /// -------------------------------------- - /// | 0 | | y_Q | | - /// | 1 | x_Q | | 1 | - fn private_initialization( - &self, - region: &mut Region<'_, pallas::Base>, - Q: &NonIdentityEccPoint, - ) -> Result<(usize, X, Y), Error> { - let config = self.config().clone(); - let mut offset = 0; - - // Assign `x_Q` and `y_Q` in the region and constrain the initial x_a, lambda_1, lambda_2, - // x_p, y_Q using the q_sinsemilla4 selector. - let y_a: Y = { - // Enable `q_sinsemilla4` on the second row. - config.q_sinsemilla4.enable(region, offset + 1)?; - let q_y: AssignedCell, pallas::Base> = Q.y().into(); - let y_a: AssignedCell, pallas::Base> = - q_y.copy_advice(|| "fixed y_q", region, config.double_and_add.x_p, offset)?; - - y_a.value_field().into() - }; - offset += 1; - - let x_a: X = { - let q_x: AssignedCell, pallas::Base> = Q.x().into(); - let x_a = q_x.copy_advice(|| "fixed x_q", region, config.double_and_add.x_a, offset)?; - - x_a.into() - }; - - Ok((offset, x_a, y_a)) - } - #[allow(clippy::type_complexity)] /// Hash `message` from the initial point `Q`. - fn hash_all_pieces( + pub(crate) fn hash_all_pieces( &self, region: &mut Region<'_, pallas::Base>, mut offset: usize, @@ -534,7 +462,7 @@ where } /// The x-coordinate of the accumulator in a Sinsemilla hash instance. -struct X(AssignedCell, F>); +pub(crate) struct X(pub(crate) AssignedCell, F>); impl From, F>> for X { fn from(cell_value: AssignedCell, F>) -> Self { @@ -555,7 +483,7 @@ impl Deref for X { /// This is never actually witnessed until the last round, since it /// can be derived from other variables. Thus it only exists as a field /// element, not a `CellValue`. -struct Y(Value>); +pub(crate) struct Y(pub(crate) Value>); impl From>> for Y { fn from(value: Value>) -> Self { diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 1eabfaa870..3b85ac807c 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -36,6 +36,7 @@ pub trait MerkleInstructions< fn hash_layer( &self, layouter: impl Layouter, + is_Q_public: bool, Q: C, l: usize, left: Self::Var, @@ -117,6 +118,7 @@ where pub fn calculate_root( &self, mut layouter: impl Layouter, + is_Q_public: bool, leaf: MerkleChip::Var, ) -> Result { // Each chip processes `ceil(PATH_LENGTH / PAR)` layers. @@ -159,6 +161,7 @@ where // M^l_i = MerkleCRH(l, M^{l+1}_{2i}, M^{l+1}_{2i+1}) node = chip.hash_layer( layouter.namespace(|| format!("MerkleCRH({}, left, right)", l)), + is_Q_public, Q, l, pair.0, @@ -184,7 +187,11 @@ pub mod tests { tests::{TestCommitDomain, TestHashDomain}, HashDomains, }, - utilities::{i2lebsp, lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions}, + utilities::{ + i2lebsp, + lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, + UtilitiesInstructions, + }, }; use group::ff::{Field, PrimeField, PrimeFieldBits}; @@ -195,6 +202,7 @@ pub mod tests { plonk::{Circuit, ConstraintSystem, Error}, }; + use crate::sinsemilla::chip::generator_table::GeneratorTableConfig; use rand::{rngs::OsRng, RngCore}; use std::{convert::TryInto, iter}; @@ -209,8 +217,20 @@ pub mod tests { impl Circuit for MyCircuit { type Config = ( - MerkleConfig, - MerkleConfig, + MerkleConfig< + TestHashDomain, + TestCommitDomain, + TestFixedBases, + LookupRangeCheckConfig, + GeneratorTableConfig, + >, + MerkleConfig< + TestHashDomain, + TestCommitDomain, + TestFixedBases, + LookupRangeCheckConfig, + GeneratorTableConfig, + >, ); type FloorPlanner = SimpleFloorPlanner; @@ -246,28 +266,34 @@ pub mod tests { meta.lookup_table_column(), meta.lookup_table_column(), meta.lookup_table_column(), - meta.lookup_table_column(), ); - let range_check = - LookupRangeCheckConfig::configure(meta, advices[9], lookup.0, lookup.3); + let table = GeneratorTableConfig { + table_idx: lookup.0, + table_x: lookup.1, + table_y: lookup.2, + }; + + let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup.0); let sinsemilla_config_1 = SinsemillaChip::configure( + true, meta, advices[5..].try_into().unwrap(), advices[7], fixed_y_q_1, - lookup, + table, range_check, ); let config1 = MerkleChip::configure(meta, sinsemilla_config_1); let sinsemilla_config_2 = SinsemillaChip::configure( + true, meta, advices[..5].try_into().unwrap(), advices[2], fixed_y_q_2, - lookup, + table, range_check, ); let config2 = MerkleChip::configure(meta, sinsemilla_config_2); @@ -281,10 +307,13 @@ pub mod tests { mut layouter: impl Layouter, ) -> Result<(), Error> { // Load generator table (shared across both configs) - SinsemillaChip::::load( - config.0.sinsemilla_config.clone(), - &mut layouter, - )?; + SinsemillaChip::< + TestHashDomain, + TestCommitDomain, + TestFixedBases, + LookupRangeCheckConfig, + GeneratorTableConfig, + >::load(config.0.sinsemilla_config.clone(), &mut layouter)?; // Construct Merkle chips which will be placed side-by-side in the circuit. let chip_1 = MerkleChip::construct(config.0.clone()); @@ -304,7 +333,7 @@ pub mod tests { }; let computed_final_root = - path.calculate_root(layouter.namespace(|| "calculate root"), leaf)?; + path.calculate_root(layouter.namespace(|| "calculate root"), true, leaf)?; self.leaf .zip(self.leaf_pos) diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs index cb3c5be4cc..ebfe08a701 100644 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla/merkle/chip.rs @@ -9,9 +9,10 @@ use pasta_curves::pallas; use super::MerkleInstructions; +use crate::sinsemilla::chip::generator_table::{DefaultGeneratorTable, GeneratorTableConfig}; use crate::{ sinsemilla::{primitives as sinsemilla, MessagePiece}, - utilities::RangeConstrained, + utilities::{lookup_range_check::DefaultLookupRangeCheck, RangeConstrained}, { ecc::FixedPoints, sinsemilla::{ @@ -28,16 +29,19 @@ use group::ff::PrimeField; /// Configuration for the `MerkleChip` implementation. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct MerkleConfig +pub struct MerkleConfig where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, { advices: [Column; 5], q_decompose: Selector, - pub(super) cond_swap_config: CondSwapConfig, - pub(super) sinsemilla_config: SinsemillaConfig, + pub(crate) cond_swap_config: CondSwapConfig, + pub(crate) sinsemilla_config: + SinsemillaConfig, } /// Chip implementing `MerkleInstructions`. @@ -51,22 +55,28 @@ where /// This chip does **NOT** constrain `left⋆` and `right⋆` to be canonical encodings of /// `left` and `right`. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct MerkleChip +pub struct MerkleChip where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, { - config: MerkleConfig, + config: MerkleConfig, } -impl Chip for MerkleChip +impl Chip + for MerkleChip where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, { - type Config = MerkleConfig; + type Config = + MerkleConfig; type Loaded = (); fn config(&self) -> &Self::Config { @@ -78,17 +88,26 @@ where } } -impl MerkleChip +impl + MerkleChip where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, { /// Configures the [`MerkleChip`]. pub fn configure( meta: &mut ConstraintSystem, - sinsemilla_config: SinsemillaConfig, - ) -> MerkleConfig { + sinsemilla_config: SinsemillaConfig< + Hash, + Commit, + F, + LookupRangeCheckConfig, + GeneratorTableConfigType, + >, + ) -> MerkleConfig { // All five advice columns are equality-enabled by SinsemillaConfig. let advices = sinsemilla_config.advices(); let cond_swap_config = CondSwapChip::configure(meta, advices); @@ -191,23 +210,34 @@ where } /// Constructs a [`MerkleChip`] given a [`MerkleConfig`]. - pub fn construct(config: MerkleConfig) -> Self { + pub fn construct( + config: MerkleConfig, + ) -> Self { MerkleChip { config } } } -impl - MerkleInstructions - for MerkleChip +impl< + Hash, + Commit, + F, + LookupRangeCheckConfig, + GeneratorTableConfigType, + const MERKLE_DEPTH: usize, + > MerkleInstructions + for MerkleChip where Hash: HashDomains + Eq, F: FixedPoints, Commit: CommitDomains + Eq, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, { #[allow(non_snake_case)] fn hash_layer( &self, mut layouter: impl Layouter, + is_Q_public: bool, Q: pallas::Affine, // l = MERKLE_DEPTH - layer - 1 l: usize, @@ -299,6 +329,7 @@ where // https://p.z.cash/proto:merkle-crh-orchard let (point, zs) = self.hash_to_point( layouter.namespace(|| format!("hash at l = {}", l)), + is_Q_public, Q, vec![a.inner(), b.inner(), c.inner()].into(), )?; @@ -415,20 +446,28 @@ where } } -impl UtilitiesInstructions for MerkleChip +impl + UtilitiesInstructions + for MerkleChip where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, { type Var = AssignedCell; } -impl CondSwapInstructions for MerkleChip +impl + CondSwapInstructions + for MerkleChip where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, { #[allow(clippy::type_complexity)] fn swap( @@ -441,71 +480,106 @@ where let chip = CondSwapChip::::construct(config); chip.swap(layouter, pair, swap) } - - fn mux( - &self, - layouter: &mut impl Layouter, - choice: Self::Var, - left: Self::Var, - right: Self::Var, - ) -> Result { - let config = self.config().cond_swap_config.clone(); - let chip = CondSwapChip::::construct(config); - chip.mux(layouter, choice, left, right) - } } -impl SinsemillaInstructions - for MerkleChip +impl + SinsemillaInstructions + for MerkleChip where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, { - type CellValue = as SinsemillaInstructions< + type CellValue = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::CellValue; - type Message = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::Message; - type MessagePiece = as SinsemillaInstructions< + type Message = as SinsemillaInstructions>::Message; + type MessagePiece = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::MessagePiece; - type RunningSum = as SinsemillaInstructions< + type RunningSum = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::RunningSum; - type X = as SinsemillaInstructions< + type X = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::X; - type NonIdentityPoint = as SinsemillaInstructions< + type NonIdentityPoint = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::NonIdentityPoint; - type FixedPoints = as SinsemillaInstructions< + type FixedPoints = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::FixedPoints; - type HashDomains = as SinsemillaInstructions< + type HashDomains = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::HashDomains; - type CommitDomains = as SinsemillaInstructions< + type CommitDomains = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, @@ -518,7 +592,13 @@ where num_words: usize, ) -> Result { let config = self.config().sinsemilla_config.clone(); - let chip = SinsemillaChip::::construct(config); + let chip = SinsemillaChip::< + Hash, + Commit, + F, + LookupRangeCheckConfig, + GeneratorTableConfigType, + >::construct(config); chip.witness_message_piece(layouter, value, num_words) } @@ -527,28 +607,24 @@ where fn hash_to_point( &self, layouter: impl Layouter, + is_Q_public: bool, Q: pallas::Affine, message: Self::Message, ) -> Result<(Self::NonIdentityPoint, Vec>), Error> { let config = self.config().sinsemilla_config.clone(); - let chip = SinsemillaChip::::construct(config); - chip.hash_to_point(layouter, Q, message) - } - - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - fn hash_to_point_with_private_init( - &self, - layouter: impl Layouter, - Q: &Self::NonIdentityPoint, - message: Self::Message, - ) -> Result<(Self::NonIdentityPoint, Vec>), Error> { - let config = self.config().sinsemilla_config.clone(); - let chip = SinsemillaChip::::construct(config); - chip.hash_to_point_with_private_init(layouter, Q, message) + let chip = SinsemillaChip::< + Hash, + Commit, + F, + LookupRangeCheckConfig, + GeneratorTableConfigType, + >::construct(config); + chip.hash_to_point(layouter, is_Q_public, Q, message) } fn extract(point: &Self::NonIdentityPoint) -> Self::X { - SinsemillaChip::::extract(point) + SinsemillaChip::::extract( + point, + ) } } diff --git a/halo2_gadgets/src/sinsemilla/primitives.rs b/halo2_gadgets/src/sinsemilla/primitives.rs index ad9e397b5e..2ebde8faf4 100644 --- a/halo2_gadgets/src/sinsemilla/primitives.rs +++ b/halo2_gadgets/src/sinsemilla/primitives.rs @@ -56,7 +56,7 @@ fn extract_p_bottom(point: CtOption) -> CtOption { /// Pads the given iterator (which MUST have length $\leq K * C$) with zero-bits to a /// multiple of $K$ bits. -struct Pad> { +pub(crate) struct Pad> { /// The iterator we are padding. inner: I, /// The measured length of the inner iterator. @@ -184,9 +184,10 @@ impl HashDomain { #[derive(Debug)] #[allow(non_snake_case)] pub struct CommitDomain { + // FIXME: THis comment came from ZSA version /// A domain in which $\mathsf{SinsemillaHashToPoint}$ and $\mathsf{SinsemillaHash}$ can be used - M: HashDomain, - R: pallas::Point, + pub(crate) M: HashDomain, + pub(crate) R: pallas::Point, } impl CommitDomain { @@ -201,17 +202,6 @@ impl CommitDomain { } } - /// Constructs a new `CommitDomain` from different values for `hash_domain` and `blind_domain` - pub fn new_with_personalization(hash_domain: &str, blind_domain: &str) -> Self { - let m_prefix = format!("{}-M", hash_domain); - let r_prefix = format!("{}-r", blind_domain); - let hasher_r = pallas::Point::hash_to_curve(&r_prefix); - CommitDomain { - M: HashDomain::new(&m_prefix), - R: hasher_r(&[]), - } - } - /// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. /// /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit @@ -226,26 +216,6 @@ impl CommitDomain { .map(|p| p + Wnaf::new().scalar(r).base(self.R)) } - /// $\mathsf{SinsemillaHashToPoint}$ from [§ 5.4.1.9][concretesinsemillahash]. - /// - /// [concretesinsemillahash]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillahash - pub fn hash_to_point(&self, msg: impl Iterator) -> CtOption { - self.M.hash_to_point(msg) - } - - /// Returns `SinsemillaCommit_r(personalization, msg) = hash_point + [r]R` - /// where `SinsemillaHash(personalization, msg) = hash_point` - /// and `R` is derived from the `personalization`. - #[allow(non_snake_case)] - pub fn commit_from_hash_point( - &self, - hash_point: CtOption, - r: &pallas::Scalar, - ) -> CtOption { - // We use complete addition for the blinding factor. - hash_point.map(|p| p + Wnaf::new().scalar(r).base(self.R)) - } - /// $\mathsf{SinsemillaShortCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. /// /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit @@ -337,32 +307,4 @@ mod tests { assert_eq!(computed, actual); } } - - #[test] - fn commit_in_several_steps() { - use rand::{rngs::OsRng, Rng}; - - use ff::Field; - - use crate::sinsemilla::primitives::CommitDomain; - - let domain = CommitDomain::new("z.cash:ZSA-NoteCommit"); - - let mut os_rng = OsRng::default(); - let msg: Vec = (0..36).map(|_| os_rng.gen::()).collect(); - - let rcm = pallas::Scalar::random(&mut os_rng); - - // Evaluate the commitment with commit function - let commit1 = domain.commit(msg.clone().into_iter(), &rcm); - - // Evaluate the commitment with the following steps - // 1. hash msg - // 2. evaluate the commitment from the hash point - let hash_point = domain.M.hash_to_point(msg.into_iter()); - let commit2 = domain.commit_from_hash_point(hash_point, &rcm); - - // Test equality - assert_eq!(commit1.unwrap(), commit2.unwrap()); - } } diff --git a/halo2_gadgets/src/sinsemilla_opt.rs b/halo2_gadgets/src/sinsemilla_opt.rs new file mode 100644 index 0000000000..1103a73705 --- /dev/null +++ b/halo2_gadgets/src/sinsemilla_opt.rs @@ -0,0 +1,478 @@ +//! The [Sinsemilla] hash function. +//! +//! [Sinsemilla]: https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash + +use std::fmt::Debug; + +use pasta_curves::arithmetic::CurveAffine; + +use halo2_proofs::{circuit::Layouter, plonk::Error}; + +use crate::{ + ecc::{self, EccInstructions}, + sinsemilla::{CommitDomain, HashDomain, Message, SinsemillaInstructions}, +}; + +pub mod chip; +pub mod merkle; +pub mod primitives; + +/// FIXME: add a doc +pub trait SinsemillaInstructionsOptimized: + SinsemillaInstructions +{ + /// Hashes a message to an ECC curve point. + /// This returns both the resulting point, as well as the message + /// decomposition in the form of intermediate values in a cumulative + /// sum. + /// The initial point `Q` is a private point. + #[allow(non_snake_case)] + #[allow(clippy::type_complexity)] + fn hash_to_point_with_private_init( + &self, + layouter: impl Layouter, + Q: &Self::NonIdentityPoint, + message: Self::Message, + ) -> Result<(Self::NonIdentityPoint, Vec), Error>; +} + +impl + HashDomain +where + SinsemillaChip: SinsemillaInstructionsOptimized + Clone + Debug + Eq, + EccChip: EccInstructions< + C, + NonIdentityPoint = >::NonIdentityPoint, + FixedPoints = >::FixedPoints, + > + Clone + + Debug + + Eq, +{ + #[allow(non_snake_case)] + #[allow(clippy::type_complexity)] + /// Evaluate the Sinsemilla hash of `message` from the private initial point `Q`. + pub fn hash_to_point_with_private_init( + &self, + layouter: impl Layouter, + Q: &>::NonIdentityPoint, + message: Message, + ) -> Result<(ecc::NonIdentityPoint, Vec), Error> { + assert_eq!(self.sinsemilla_chip, message.chip); + self.sinsemilla_chip + .hash_to_point_with_private_init(layouter, Q, message.inner) + .map(|(point, zs)| (ecc::NonIdentityPoint::from_inner(self.ecc_chip.clone(), point), zs)) + } + +} + +impl + CommitDomain +where + SinsemillaChip: SinsemillaInstructionsOptimized + Clone + Debug + Eq, + EccChip: EccInstructions< + C, + NonIdentityPoint = >::NonIdentityPoint, + FixedPoints = >::FixedPoints, + > + Clone + + Debug + + Eq, +{ + #[allow(clippy::type_complexity)] + /// Evaluates the Sinsemilla hash of `message` from the public initial point `Q` stored + /// into `CommitDomain`. + pub fn hash( + &self, + layouter: impl Layouter, + is_Q_public: bool, + message: Message, + ) -> Result< + ( + ecc::NonIdentityPoint, + Vec, + ), + Error, + > { + assert_eq!(self.M.sinsemilla_chip, message.chip); + self.M.hash_to_point(layouter, is_Q_public, message) + } + + #[allow(non_snake_case)] + #[allow(clippy::type_complexity)] + /// Evaluates the Sinsemilla hash of `message` from the private initial point `Q`. + pub fn hash_with_private_init( + &self, + layouter: impl Layouter, + Q: &>::NonIdentityPoint, + message: Message, + ) -> Result< + ( + ecc::NonIdentityPoint, + Vec, + ), + Error, + > { + assert_eq!(self.M.sinsemilla_chip, message.chip); + self.M.hash_to_point_with_private_init(layouter, Q, message) + } + + #[allow(clippy::type_complexity)] + /// Returns the public initial point `Q` stored into `CommitDomain`. + pub fn q_init(&self) -> C { + self.M.Q + } + + #[allow(clippy::type_complexity)] + /// Evaluates the blinding factor equal to $\[r\] R$ where `r` is stored in the `CommitDomain`. + pub fn blinding_factor( + &self, + mut layouter: impl Layouter, + r: ecc::ScalarFixed, + ) -> Result< + ecc::Point, + Error, + > { + let (blind, _) = self.R.mul(layouter.namespace(|| "[r] R"), r)?; + Ok(blind) + } +} + +#[cfg(test)] +pub(crate) mod tests { + use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner, Value}, + dev::MockProver, + plonk::{Circuit, ConstraintSystem, Error}, + }; + use rand::rngs::OsRng; + + use crate::sinsemilla::{ + chip::{SinsemillaChip, SinsemillaConfig}, + CommitDomain, CommitDomains, HashDomain, HashDomains, Message, MessagePiece, + }; + + use crate::{ + ecc::ScalarFixed, + sinsemilla::primitives::{self as sinsemilla, K}, + { + ecc::{ + chip::{find_zs_and_us, EccChip, EccConfig, H, NUM_WINDOWS}, + tests::{FullWidth, TestFixedBases}, + NonIdentityPoint, + }, + utilities::lookup_range_check::LookupRangeCheckConfig, + }, + }; + + use group::{ff::Field, Curve}; + use lazy_static::lazy_static; + use pasta_curves::pallas; + + use crate::sinsemilla::chip::generator_table::GeneratorTableConfig; + use crate::sinsemilla_opt::chip::generator_table::GeneratorTableConfigOptimized; + use crate::utilities::lookup_range_check::LookupRangeCheck; + use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; + use std::convert::TryInto; + + pub(crate) const PERSONALIZATION: &str = "MerkleCRH"; + + lazy_static! { + static ref COMMIT_DOMAIN: sinsemilla::CommitDomain = + sinsemilla::CommitDomain::new(PERSONALIZATION); + static ref Q: pallas::Affine = COMMIT_DOMAIN.Q().to_affine(); + static ref R: pallas::Affine = COMMIT_DOMAIN.R().to_affine(); + static ref R_ZS_AND_US: Vec<(u64, [pallas::Base; H])> = + find_zs_and_us(*R, NUM_WINDOWS).unwrap(); + } + + #[derive(Debug, Clone, Eq, PartialEq)] + pub(crate) struct TestHashDomain; + impl HashDomains for TestHashDomain { + fn Q(&self) -> pallas::Affine { + *Q + } + } + + // This test does not make use of the CommitDomain. + #[derive(Debug, Clone, Eq, PartialEq)] + pub(crate) struct TestCommitDomain; + impl CommitDomains for TestCommitDomain { + fn r(&self) -> FullWidth { + FullWidth::from_parts(*R, &R_ZS_AND_US) + } + + fn hash_domain(&self) -> TestHashDomain { + TestHashDomain + } + } + + struct MyCircuit {} + + impl Circuit for MyCircuit { + #[allow(clippy::type_complexity)] + type Config = ( + EccConfig< + TestFixedBases, + LookupRangeCheckConfigOptimized, + >, + SinsemillaConfig< + TestHashDomain, + TestCommitDomain, + TestFixedBases, + LookupRangeCheckConfigOptimized, + GeneratorTableConfigOptimized, + >, + SinsemillaConfig< + TestHashDomain, + TestCommitDomain, + TestFixedBases, + LookupRangeCheckConfigOptimized, + GeneratorTableConfigOptimized, + >, + ); + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + MyCircuit {} + } + + #[allow(non_snake_case)] + 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(), + ]; + + // Shared fixed column for loading constants + let constants = meta.fixed_column(); + meta.enable_constant(constants); + + let table_idx = 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(), + ]; + + // todo: check the lookup.3 and LookupRangeCheckConfigOptimized::configure, to see if one more column is created + // Fixed columns for the Sinsemilla generator lookup table + let lookup = ( + table_idx, + meta.lookup_table_column(), + meta.lookup_table_column(), + meta.lookup_table_column(), + ); + + let range_check = + LookupRangeCheckConfigOptimized::configure(meta, advices[9], table_idx); + let table = GeneratorTableConfigOptimized { + base: GeneratorTableConfig { + table_idx: lookup.0, + table_x: lookup.1, + table_y: lookup.2, + }, + table_range_check_tag: lookup.3, + }; + + let ecc_config = EccChip::< + TestFixedBases, + LookupRangeCheckConfigOptimized, + >::configure(meta, advices, lagrange_coeffs, range_check); + + let config1 = SinsemillaChip::configure( + false, + meta, + advices[..5].try_into().unwrap(), + advices[2], + lagrange_coeffs[0], + table, + range_check, + ); + let config2 = SinsemillaChip::configure( + false, + meta, + advices[5..].try_into().unwrap(), + advices[7], + lagrange_coeffs[1], + table, + range_check, + ); + (ecc_config, config1, config2) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let rng = OsRng; + + let ecc_chip = EccChip::construct(config.0); + + // The two `SinsemillaChip`s share the same lookup table. + SinsemillaChip::< + TestHashDomain, + TestCommitDomain, + TestFixedBases, + LookupRangeCheckConfigOptimized, + GeneratorTableConfigOptimized, + >::load(config.1.clone(), &mut layouter)?; + + // This MerkleCRH example is purely for illustrative purposes. + // It is not an implementation of the Orchard protocol spec. + { + let chip1 = SinsemillaChip::construct(config.1); + + let merkle_crh = HashDomain::new(chip1.clone(), ecc_chip.clone(), &TestHashDomain); + + // Layer 31, l = MERKLE_DEPTH - 1 - layer = 0 + let l_bitstring = vec![Value::known(false); K]; + let l = MessagePiece::from_bitstring( + chip1.clone(), + layouter.namespace(|| "l"), + &l_bitstring, + )?; + + // Left leaf + let left_bitstring: Vec> = (0..250) + .map(|_| Value::known(rand::random::())) + .collect(); + let left = MessagePiece::from_bitstring( + chip1.clone(), + layouter.namespace(|| "left"), + &left_bitstring, + )?; + + // Right leaf + let right_bitstring: Vec> = (0..250) + .map(|_| Value::known(rand::random::())) + .collect(); + let right = MessagePiece::from_bitstring( + chip1.clone(), + layouter.namespace(|| "right"), + &right_bitstring, + )?; + + let l_bitstring: Value> = l_bitstring.into_iter().collect(); + let left_bitstring: Value> = left_bitstring.into_iter().collect(); + let right_bitstring: Value> = right_bitstring.into_iter().collect(); + + // Witness expected parent + let expected_parent = { + let expected_parent = l_bitstring.zip(left_bitstring.zip(right_bitstring)).map( + |(l, (left, right))| { + let merkle_crh = sinsemilla::HashDomain::from_Q((*Q).into()); + let point = merkle_crh + .hash_to_point( + l.into_iter() + .chain(left.into_iter()) + .chain(right.into_iter()), + ) + .unwrap(); + point.to_affine() + }, + ); + + NonIdentityPoint::new( + ecc_chip.clone(), + layouter.namespace(|| "Witness expected parent"), + expected_parent, + )? + }; + + // Parent + let (parent, _) = { + let message = Message::from_pieces(chip1, vec![l, left, right]); + merkle_crh.hash_to_point(layouter.namespace(|| "parent"), false, message)? + }; + + parent.constrain_equal( + layouter.namespace(|| "parent == expected parent"), + &expected_parent, + )?; + } + + { + let chip2 = SinsemillaChip::construct(config.2); + + let test_commit = + CommitDomain::new(chip2.clone(), ecc_chip.clone(), &TestCommitDomain); + let r_val = pallas::Scalar::random(rng); + let message: Vec> = (0..500) + .map(|_| Value::known(rand::random::())) + .collect(); + + let (result, _) = { + let r = ScalarFixed::new( + ecc_chip.clone(), + layouter.namespace(|| "r"), + Value::known(r_val), + )?; + let message = Message::from_bitstring( + chip2, + layouter.namespace(|| "witness message"), + message.clone(), + )?; + test_commit.commit(layouter.namespace(|| "commit"), false, message, r)? + }; + + // Witness expected result. + let expected_result = { + let message: Value> = message.into_iter().collect(); + let expected_result = message.map(|message| { + let domain = sinsemilla::CommitDomain::new(PERSONALIZATION); + let point = domain.commit(message.into_iter(), &r_val).unwrap(); + point.to_affine() + }); + + NonIdentityPoint::new( + ecc_chip, + layouter.namespace(|| "Witness expected result"), + expected_result, + )? + }; + + result.constrain_equal( + layouter.namespace(|| "result == expected result"), + &expected_result, + ) + } + } + } + + #[test] + fn sinsemilla_chip() { + let k = 11; + let circuit = MyCircuit {}; + let prover = MockProver::run(k, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), Ok(())) + } + + #[cfg(feature = "test-dev-graph")] + #[test] + fn print_sinsemilla_chip() { + use plotters::prelude::*; + + let root = + BitMapBackend::new("sinsemilla-hash-layout.png", (1024, 7680)).into_drawing_area(); + root.fill(&WHITE).unwrap(); + let root = root.titled("SinsemillaHash", ("sans-serif", 60)).unwrap(); + + let circuit = MyCircuit {}; + halo2_proofs::dev::CircuitLayout::default() + .render(11, &circuit, &root) + .unwrap(); + } +} diff --git a/halo2_gadgets/src/sinsemilla_opt/chip.rs b/halo2_gadgets/src/sinsemilla_opt/chip.rs new file mode 100644 index 0000000000..790a7c9484 --- /dev/null +++ b/halo2_gadgets/src/sinsemilla_opt/chip.rs @@ -0,0 +1,56 @@ +//! Chip implementations for the Sinsemilla gadgets. + +use super::SinsemillaInstructionsOptimized; +use crate::sinsemilla::chip::generator_table::{DefaultGeneratorTable, GeneratorTableConfig}; +use crate::sinsemilla_opt::chip::generator_table::GeneratorTableConfigOptimized; +use crate::utilities::lookup_range_check::{DefaultLookupRangeCheck, LookupRangeCheckConfig}; +use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; +use crate::{ + ecc::{chip::NonIdentityEccPoint, FixedPoints}, + sinsemilla::{ + chip::{SinsemillaChip, SinsemillaConfig}, + message::{Message, MessagePiece}, + primitives as sinsemilla, CommitDomains, HashDomains, SinsemillaInstructions, + }, + utilities_opt::lookup_range_check::DefaultLookupRangeCheckConfigOptimized, +}; +use halo2_proofs::plonk::Expression; +use halo2_proofs::{ + circuit::{AssignedCell, Chip, Layouter, Value}, + plonk::{ + Advice, Column, ConstraintSystem, Constraints, Error, Fixed, TableColumn, VirtualCells, + }, + poly::Rotation, +}; +use pasta_curves::pallas; +use pasta_curves::pallas::Base; + +pub(crate) mod generator_table; + +mod hash_to_point; + +// Implement `SinsemillaInstructionsOptimized` for `SinsemillaChip` +impl + SinsemillaInstructionsOptimized + for SinsemillaChip +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, +{ + #[allow(non_snake_case)] + #[allow(clippy::type_complexity)] + fn hash_to_point_with_private_init( + &self, + mut layouter: impl Layouter, + Q: &Self::NonIdentityPoint, + message: Self::Message, + ) -> Result<(Self::NonIdentityPoint, Vec), Error> { + layouter.assign_region( + || "hash_to_point", + |mut region| self.hash_message_with_private_init(&mut region, Q, &message), + ) + } +} diff --git a/halo2_gadgets/src/sinsemilla_opt/chip/generator_table.rs b/halo2_gadgets/src/sinsemilla_opt/chip/generator_table.rs new file mode 100644 index 0000000000..d721778427 --- /dev/null +++ b/halo2_gadgets/src/sinsemilla_opt/chip/generator_table.rs @@ -0,0 +1,136 @@ +use halo2_proofs::{ + circuit::{Layouter, Value}, + plonk::{Error, TableColumn}, +}; +use std::fmt::Debug; + +use pasta_curves::pallas; + +use crate::sinsemilla::chip::generator_table::{DefaultGeneratorTable, GeneratorTable}; +use crate::sinsemilla::{ + chip::generator_table::GeneratorTableConfig, + primitives::{K, SINSEMILLA_S}, +}; +use crate::utilities::lookup_range_check::{DefaultLookupRangeCheck, LookupRangeCheckConfig}; +use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; + +/// Table containing independent generators S[0..2^k] +#[derive(Eq, PartialEq, Copy, Clone, Debug)] +pub struct GeneratorTableConfigOptimized { + pub(crate) base: GeneratorTableConfig, + pub(crate) table_range_check_tag: TableColumn, +} +impl GeneratorTable for GeneratorTableConfigOptimized { + fn config(&self) -> &GeneratorTableConfig { + &self.base + } + + /// 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, 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.config().table_idx, + index, + || Value::known(pallas::Base::from(index as u64)), + )?; + table.assign_cell( + || "table_x", + self.config().table_x, + index, + || Value::known(*x), + )?; + table.assign_cell( + || "table_y", + self.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 << K); + table.assign_cell( + || "table_idx", + self.config().table_idx, + new_index, + || Value::known(pallas::Base::from(index as u64)), + )?; + table.assign_cell( + || "table_x", + self.config().table_x, + new_index, + || Value::known(*x), + )?; + table.assign_cell( + || "table_y", + self.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", + self.config().table_idx, + new_index, + || Value::known(pallas::Base::from(index as u64)), + )?; + table.assign_cell( + || "table_x", + self.config().table_x, + new_index, + || Value::known(*x), + )?; + table.assign_cell( + || "table_y", + self.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(()) + }, + ) + } +} + +pub(crate) type DefaultGeneratorTableConfigOptimized = GeneratorTableConfigOptimized; + +impl DefaultGeneratorTable for DefaultGeneratorTableConfigOptimized {} diff --git a/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs new file mode 100644 index 0000000000..b62a8ae152 --- /dev/null +++ b/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs @@ -0,0 +1,146 @@ +use pasta_curves::{arithmetic::CurveAffine, pallas}; + +use halo2_proofs::{ + circuit::{AssignedCell, Chip, Region}, + plonk::{Assigned, Error}, +}; + +use crate::sinsemilla::chip::generator_table::DefaultGeneratorTable; +use crate::sinsemilla::chip::hash_to_point::EccPointQ; +use crate::sinsemilla::chip::SinsemillaChip; +use crate::utilities::lookup_range_check::DefaultLookupRangeCheck; +use crate::{ + ecc::{chip::NonIdentityEccPoint, FixedPoints}, + sinsemilla::{ + chip::hash_to_point::{X, Y}, + primitives::{self as sinsemilla}, + CommitDomains, HashDomains, SinsemillaInstructions, + }, +}; + +impl + SinsemillaChip +where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, +{ + /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). + #[allow(non_snake_case)] + #[allow(clippy::type_complexity)] + pub(crate) fn hash_message_with_private_init( + &self, + region: &mut Region<'_, pallas::Base>, + Q: &NonIdentityEccPoint, + message: &>::Message, + ) -> Result< + ( + NonIdentityEccPoint, + Vec>>, + ), + Error, + > { + let (offset, x_a, y_a) = self.private_initialization(region, Q)?; + + // FIXME: calling construct_base is possibly(!) non-optimal + let (x_a, y_a, zs_sum) = self.hash_all_pieces(region, offset, message, x_a, y_a)?; + + #[cfg(test)] + self.check_hash_result(EccPointQ::PrivatePoint(Q), message, x_a, y_a, zs_sum) + } + + #[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 | + pub(crate) 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.q_sinsemilla4.enable(region, offset + 1)?; + let y_a: AssignedCell, pallas::Base> = region + .assign_advice_from_constant( + || "fixed y_q", + config.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( + || "fixed x_q", + config.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 private point `Q` + /// + /// | offset | x_A | x_P | q_sinsemilla4 | + /// -------------------------------------- + /// | 0 | | y_Q | | + /// | 1 | x_Q | | 1 | + fn private_initialization( + &self, + region: &mut Region<'_, pallas::Base>, + Q: &NonIdentityEccPoint, + ) -> Result<(usize, X, Y), Error> { + let config = self.config().clone(); + let mut offset = 0; + + // Assign `x_Q` and `y_Q` in the region and constrain the initial x_a, lambda_1, lambda_2, + // x_p, y_Q using the q_sinsemilla4 selector. + let y_a: Y = { + // Enable `q_sinsemilla4` on the second row. + config.q_sinsemilla4.enable(region, offset + 1)?; + let q_y: AssignedCell, pallas::Base> = Q.y().into(); + let y_a: AssignedCell, pallas::Base> = + q_y.copy_advice(|| "fixed y_q", region, config.double_and_add.x_p, offset)?; + + y_a.value_field().into() + }; + offset += 1; + + let x_a: X = { + let q_x: AssignedCell, pallas::Base> = Q.x().into(); + let x_a = q_x.copy_advice(|| "fixed x_q", region, config.double_and_add.x_a, offset)?; + + x_a.into() + }; + + Ok((offset, x_a, y_a)) + } +} diff --git a/halo2_gadgets/src/sinsemilla_opt/merkle.rs b/halo2_gadgets/src/sinsemilla_opt/merkle.rs new file mode 100644 index 0000000000..2927585229 --- /dev/null +++ b/halo2_gadgets/src/sinsemilla_opt/merkle.rs @@ -0,0 +1,3 @@ +//! Gadgets for implementing a Merkle tree with Sinsemilla. + +pub mod chip; diff --git a/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs b/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs new file mode 100644 index 0000000000..48f078cb38 --- /dev/null +++ b/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs @@ -0,0 +1,75 @@ +//! Chip implementing a Merkle hash using Sinsemilla as the hash function. + +use halo2_proofs::{ + circuit::{Chip, Layouter}, + plonk::Error, +}; +use pasta_curves::pallas; + +use crate::sinsemilla::chip::generator_table::DefaultGeneratorTable; +use crate::sinsemilla::chip::SinsemillaChip; +use crate::utilities::lookup_range_check::DefaultLookupRangeCheck; +use crate::{ + sinsemilla::{merkle::chip::MerkleChip, primitives as sinsemilla}, + sinsemilla_opt::SinsemillaInstructionsOptimized, + utilities_opt::lookup_range_check::DefaultLookupRangeCheckConfigOptimized, + { + ecc::FixedPoints, + sinsemilla::{CommitDomains, HashDomains}, + utilities::cond_swap::CondSwapChip, + utilities_opt::cond_swap::CondSwapInstructionsOptimized, + }, +}; + +impl + CondSwapInstructionsOptimized + for MerkleChip +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, +{ + fn mux( + &self, + layouter: &mut impl Layouter, + choice: Self::Var, + left: Self::Var, + right: Self::Var, + ) -> Result { + let config = self.config().cond_swap_config.clone(); + let chip = CondSwapChip::::construct(config); + chip.mux(layouter, choice, left, right) + } +} + +impl + SinsemillaInstructionsOptimized + for MerkleChip +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, + LookupRangeCheckConfig: DefaultLookupRangeCheck, + GeneratorTableConfigType: DefaultGeneratorTable, +{ + #[allow(non_snake_case)] + #[allow(clippy::type_complexity)] + fn hash_to_point_with_private_init( + &self, + layouter: impl Layouter, + Q: &Self::NonIdentityPoint, + message: Self::Message, + ) -> Result<(Self::NonIdentityPoint, Vec>), Error> { + let config = self.config().sinsemilla_config.clone(); + let chip = SinsemillaChip::< + Hash, + Commit, + F, + LookupRangeCheckConfig, + GeneratorTableConfigType, + >::construct(config); + chip.hash_to_point_with_private_init(layouter, Q, message) + } +} diff --git a/halo2_gadgets/src/sinsemilla_opt/primitives.rs b/halo2_gadgets/src/sinsemilla_opt/primitives.rs new file mode 100644 index 0000000000..dd2930d6d2 --- /dev/null +++ b/halo2_gadgets/src/sinsemilla_opt/primitives.rs @@ -0,0 +1,74 @@ +//! Implementation of Sinsemilla outside the circuit. + +use group::Wnaf; +use halo2_proofs::arithmetic::CurveExt; +use pasta_curves::pallas; +use subtle::CtOption; + +use crate::sinsemilla::primitives::{CommitDomain, HashDomain}; + +impl CommitDomain { + /// Constructs a new `CommitDomain` from different values for `hash_domain` and `blind_domain` + pub fn new_with_personalization(hash_domain: &str, blind_domain: &str) -> Self { + let m_prefix = format!("{}-M", hash_domain); + let r_prefix = format!("{}-r", blind_domain); + let hasher_r = pallas::Point::hash_to_curve(&r_prefix); + CommitDomain { + M: HashDomain::new(&m_prefix), + R: hasher_r(&[]), + } + } + + /// $\mathsf{SinsemillaHashToPoint}$ from [§ 5.4.1.9][concretesinsemillahash]. + /// + /// [concretesinsemillahash]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillahash + pub fn hash_to_point(&self, msg: impl Iterator) -> CtOption { + self.M.hash_to_point(msg) + } + + /// Returns `SinsemillaCommit_r(personalization, msg) = hash_point + [r]R` + /// where `SinsemillaHash(personalization, msg) = hash_point` + /// and `R` is derived from the `personalization`. + #[allow(non_snake_case)] + pub fn commit_from_hash_point( + &self, + hash_point: CtOption, + r: &pallas::Scalar, + ) -> CtOption { + // We use complete addition for the blinding factor. + hash_point.map(|p| p + Wnaf::new().scalar(r).base(self.R)) + } +} + +#[cfg(test)] +mod tests { + use pasta_curves::pallas; + + #[test] + fn commit_in_several_steps() { + use rand::{rngs::OsRng, Rng}; + + use ff::Field; + + use crate::sinsemilla::primitives::CommitDomain; + + let domain = CommitDomain::new("z.cash:ZSA-NoteCommit"); + + let mut os_rng = OsRng::default(); + let msg: Vec = (0..36).map(|_| os_rng.gen::()).collect(); + + let rcm = pallas::Scalar::random(&mut os_rng); + + // Evaluate the commitment with commit function + let commit1 = domain.commit(msg.clone().into_iter(), &rcm); + + // Evaluate the commitment with the following steps + // 1. hash msg + // 2. evaluate the commitment from the hash point + let hash_point = domain.M.hash_to_point(msg.into_iter()); + let commit2 = domain.commit_from_hash_point(hash_point, &rcm); + + // Test equality + assert_eq!(commit1.unwrap(), commit2.unwrap()); + } +} diff --git a/halo2_gadgets/src/utilities/cond_swap.rs b/halo2_gadgets/src/utilities/cond_swap.rs index 78049e742a..7712c89b2a 100644 --- a/halo2_gadgets/src/utilities/cond_swap.rs +++ b/halo2_gadgets/src/utilities/cond_swap.rs @@ -2,14 +2,12 @@ use super::{bool_check, ternary, UtilitiesInstructions}; -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}, + plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Selector}, poly::Rotation, }; -use pasta_curves::pallas; use std::marker::PhantomData; /// Instructions for a conditional swap gadget. @@ -26,22 +24,12 @@ pub trait CondSwapInstructions: UtilitiesInstructions { pair: (Self::Var, Value), swap: Value, ) -> Result<(Self::Var, Self::Var), Error>; - - /// Given an input `(choice, left, right)` where `choice` is a boolean flag, - /// returns `left` if `choice` is not set and `right` if `choice` is set. - fn mux( - &self, - layouter: &mut impl Layouter, - choice: Self::Var, - left: Self::Var, - right: Self::Var, - ) -> Result; } /// A chip implementing a conditional swap. #[derive(Clone, Debug)] pub struct CondSwapChip { - config: CondSwapConfig, + pub(crate) config: CondSwapConfig, _marker: PhantomData, } @@ -61,12 +49,12 @@ impl Chip for CondSwapChip { /// Configuration for the [`CondSwapChip`]. #[derive(Clone, Debug, PartialEq, Eq)] pub struct CondSwapConfig { - q_swap: Selector, - a: Column, - b: Column, - a_swapped: Column, - b_swapped: Column, - swap: Column, + pub(crate) q_swap: Selector, + pub(crate) a: Column, + pub(crate) b: Column, + pub(crate) a_swapped: Column, + pub(crate) b_swapped: Column, + pub(crate) swap: Column, } #[cfg(test)] @@ -133,97 +121,6 @@ impl CondSwapInstructions for CondSwapChip { }, ) } - - fn mux( - &self, - layouter: &mut impl Layouter, - choice: Self::Var, - left: Self::Var, - right: Self::Var, - ) -> Result { - let config = self.config(); - - layouter.assign_region( - || "mux", - |mut region| { - // Enable `q_swap` selector - config.q_swap.enable(&mut region, 0)?; - - // Copy in `a` value - let left = left.copy_advice(|| "copy left", &mut region, config.a, 0)?; - - // Copy in `b` value - let right = right.copy_advice(|| "copy right", &mut region, config.b, 0)?; - - // Copy `choice` value - let choice = choice.copy_advice(|| "copy choice", &mut region, config.swap, 0)?; - - let a_swapped = left - .value() - .zip(right.value()) - .zip(choice.value()) - .map(|((left, right), choice)| { - if *choice == F::from(0_u64) { - left - } else { - right - } - }) - .cloned(); - let b_swapped = left - .value() - .zip(right.value()) - .zip(choice.value()) - .map(|((left, right), choice)| { - if *choice == F::from(0_u64) { - right - } else { - left - } - }) - .cloned(); - - region.assign_advice(|| "out b_swap", self.config.b_swapped, 0, || b_swapped)?; - region.assign_advice(|| "out a_swap", self.config.a_swapped, 0, || a_swapped) - }, - ) - } -} - -impl CondSwapChip { - /// Given an input `(choice, left, right)` where `choice` is a boolean flag and `left` and `right` are `EccPoint`, - /// returns `left` if `choice` is not set and `right` if `choice` is set. - pub fn mux_on_points( - &self, - mut layouter: impl Layouter, - choice: &AssignedCell, - left: &EccPoint, - right: &EccPoint, - ) -> Result { - let x_cell = self.mux(&mut layouter, choice.clone(), left.x(), right.x())?; - let y_cell = self.mux(&mut layouter, choice.clone(), left.y(), right.y())?; - Ok(EccPoint::from_coordinates_unchecked( - x_cell.into(), - y_cell.into(), - )) - } - - /// Given an input `(choice, left, right)` where `choice` is a boolean flag and `left` and `right` are - /// `NonIdentityEccPoint`, returns `left` if `choice` is not set and `right` if `choice` is set. - pub fn mux_on_non_identity_points( - &self, - mut layouter: impl Layouter, - choice: &AssignedCell, - left: &NonIdentityEccPoint, - right: &NonIdentityEccPoint, - ) -> Result { - let x_cell = self.mux(&mut layouter, choice.clone(), left.x(), right.x())?; - let y_cell = self.mux(&mut layouter, choice.clone(), left.y(), right.y())?; - Ok(NonIdentityEccPoint::from_coordinates_unchecked( - x_cell.into(), - y_cell.into(), - )) - } } impl CondSwapChip { @@ -394,231 +291,4 @@ mod tests { assert_eq!(prover.verify(), Ok(())); } } - - #[test] - fn test_mux() { - use crate::{ - ecc::{ - chip::{EccChip, EccConfig}, - tests::TestFixedBases, - NonIdentityPoint, Point, - }, - utilities::lookup_range_check::LookupRangeCheckConfig, - }; - - 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 = LookupRangeCheckConfig::configure( - meta, - advices[9], - table_idx, - table_range_check_tag, - ); - - 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(())); - } - } } diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 64b4ce4c90..09369c04f1 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -6,10 +6,14 @@ use halo2_proofs::{ plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Selector, TableColumn}, poly::Rotation, }; -use std::{convert::TryInto, marker::PhantomData}; +use std::{convert::TryInto, fmt::Debug, marker::PhantomData}; use ff::PrimeFieldBits; +use pasta_curves::pallas; + +use crate::sinsemilla::primitives as sinsemilla; + use super::*; /// The running sum $[z_0, ..., z_W]$. If created in strict mode, $z_W = 0$. @@ -30,8 +34,8 @@ impl RangeConstrained> { /// # Panics /// /// Panics if `bitrange.len() >= K`. - pub fn witness_short( - lookup_config: &LookupRangeCheckConfig, + pub fn witness_short>( + lookup_config: &L, layouter: impl Layouter, value: Value<&F>, bitrange: Range, @@ -49,7 +53,7 @@ impl RangeConstrained> { .map(|inner| Self { inner, num_bits, - _phantom: PhantomData::default(), + _phantom: PhantomData, }) } } @@ -57,198 +61,44 @@ impl RangeConstrained> { /// Configuration that provides methods for a lookup range check. #[derive(Eq, PartialEq, Debug, Clone, Copy)] pub struct LookupRangeCheckConfig { - q_lookup: Selector, - q_running: Selector, - q_bitshift: Selector, - q_range_check_4: Selector, - q_range_check_5: Selector, - running_sum: Column, - table_idx: TableColumn, - table_range_check_tag: TableColumn, - _marker: PhantomData, + pub(crate) q_lookup: Selector, + pub(crate) q_running: Selector, + pub(crate) q_bitshift: Selector, + pub(crate) running_sum: Column, + pub(crate) table_idx: TableColumn, + pub(crate) _marker: PhantomData, } -impl LookupRangeCheckConfig { - /// 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. - pub fn configure( +/// FIXME: add doc +pub trait LookupRangeCheck { + /// FIXME: add doc + fn config(&self) -> &LookupRangeCheckConfig; + + /// FIXME: add doc + fn configure( meta: &mut ConstraintSystem, running_sum: Column, table_idx: TableColumn, - table_range_check_tag: TableColumn, - ) -> Self { - meta.enable_equality(running_sum); - - let q_lookup = meta.complex_selector(); - let q_running = meta.complex_selector(); - let q_bitshift = meta.selector(); - let q_range_check_4 = meta.complex_selector(); - let q_range_check_5 = meta.complex_selector(); - let config = LookupRangeCheckConfig { - q_lookup, - q_running, - q_bitshift, - q_range_check_4, - q_range_check_5, - running_sum, - table_idx, - table_range_check_tag, - _marker: PhantomData, - }; - - // https://p.z.cash/halo2-0.1:decompose-combined-lookup - meta.lookup(|meta| { - let q_lookup = meta.query_selector(config.q_lookup); - let q_running = meta.query_selector(config.q_running); - let q_range_check_4 = meta.query_selector(config.q_range_check_4); - let q_range_check_5 = meta.query_selector(config.q_range_check_5); - let z_cur = meta.query_advice(config.running_sum, Rotation::cur()); - let one = Expression::Constant(F::ONE); - - // In the case of a running sum decomposition, we recover the word from - // the difference of the running sums: - // z_i = 2^{K}⋅z_{i + 1} + a_i - // => a_i = z_i - 2^{K}⋅z_{i + 1} - let running_sum_lookup = { - let running_sum_word = { - let z_next = meta.query_advice(config.running_sum, Rotation::next()); - z_cur.clone() - z_next * F::from(1 << K) - }; - - q_running.clone() * running_sum_word - }; - - // In the short range check, the word is directly witnessed. - let short_lookup = { - let short_word = z_cur.clone(); - let q_short = one.clone() - q_running; - - q_short * short_word - }; - - // q_range_check is equal to - // - 1 if q_range_check_4 = 1 or q_range_check_5 = 1 - // - 0 otherwise - let q_range_check = one.clone() - - (one.clone() - q_range_check_4.clone()) * (one.clone() - q_range_check_5.clone()); - - // num_bits is equal to - // - 5 if q_range_check_5 = 1 - // - 4 if q_range_check_4 = 1 and q_range_check_5 = 0 - // - 0 otherwise - let num_bits = q_range_check_5.clone() * Expression::Constant(F::from(5_u64)) - + (one.clone() - q_range_check_5) - * q_range_check_4 - * Expression::Constant(F::from(4_u64)); - - // Combine the running sum, short lookups and optimized range checks: - vec![ - ( - q_lookup.clone() - * ((one - q_range_check.clone()) * (running_sum_lookup + short_lookup) - + q_range_check.clone() * z_cur), - config.table_idx, - ), - ( - q_lookup * q_range_check * num_bits, - config.table_range_check_tag, - ), - ] - }); - - // For short lookups, check that the word has been shifted by the correct number of bits. - // https://p.z.cash/halo2-0.1:decompose-short-lookup - meta.create_gate("Short lookup bitshift", |meta| { - let q_bitshift = meta.query_selector(config.q_bitshift); - let word = meta.query_advice(config.running_sum, Rotation::prev()); - let shifted_word = meta.query_advice(config.running_sum, Rotation::cur()); - let inv_two_pow_s = meta.query_advice(config.running_sum, Rotation::next()); - - let two_pow_k = F::from(1 << K); - - // shifted_word = word * 2^{K-s} - // = word * 2^K * inv_two_pow_s - Constraints::with_selector( - q_bitshift, - Some(word * two_pow_k * inv_two_pow_s - shifted_word), - ) - }); - - config - } + ) -> Self + where + 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. - pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - layouter.assign_table( - || "table_idx", - |mut table| { - // We generate the row values lazily (we only need them during keygen). - for index in 0..(1 << K) { - table.assign_cell( - || "table_idx", - self.table_idx, - index, - || Value::known(F::from(index as u64)), - )?; - table.assign_cell( - || "table_range_check_tag", - self.table_range_check_tag, - index, - || Value::known(F::ZERO), - )?; - } - for index in 0..(1 << 4) { - let new_index = index + (1 << K); - table.assign_cell( - || "table_idx", - self.table_idx, - new_index, - || Value::known(F::from(index as u64)), - )?; - table.assign_cell( - || "table_range_check_tag", - self.table_range_check_tag, - new_index, - || Value::known(F::from(4_u64)), - )?; - } - for index in 0..(1 << 5) { - let new_index = index + (1 << K) + (1 << 4); - table.assign_cell( - || "table_idx", - self.table_idx, - new_index, - || Value::known(F::from(index as u64)), - )?; - table.assign_cell( - || "table_range_check_tag", - self.table_range_check_tag, - new_index, - || Value::known(F::from(5_u64)), - )?; - } - Ok(()) - }, - ) - } + fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error>; + + /// FIXME: add doc + fn short_range_check( + &self, + region: &mut Region<'_, F>, + element: AssignedCell, + num_bits: usize, + ) -> Result<(), Error>; /// 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. - pub fn copy_check( + fn copy_check( &self, mut layouter: impl Layouter, element: AssignedCell, @@ -259,14 +109,15 @@ impl LookupRangeCheckConfig { || format!("{:?} words range check", num_words), |mut region| { // Copy `element` and initialize running sum `z_0 = element` to decompose it. - let z_0 = element.copy_advice(|| "z_0", &mut region, self.running_sum, 0)?; + let z_0 = + element.copy_advice(|| "z_0", &mut region, self.config().running_sum, 0)?; self.range_check(&mut region, z_0, num_words, strict) }, ) } /// Range check on a value that is witnessed in this helper. - pub fn witness_check( + fn witness_check( &self, mut layouter: impl Layouter, value: Value, @@ -276,8 +127,12 @@ impl LookupRangeCheckConfig { layouter.assign_region( || "Witness element", |mut region| { - let z_0 = - region.assign_advice(|| "Witness element", self.running_sum, 0, || value)?; + let z_0 = region.assign_advice( + || "Witness element", + self.config().running_sum, + 0, + || value, + )?; self.range_check(&mut region, z_0, num_words, strict) }, ) @@ -332,9 +187,9 @@ impl LookupRangeCheckConfig { let inv_two_pow_k = F::from(1u64 << K).invert().unwrap(); for (idx, word) in words.iter().enumerate() { // Enable q_lookup on this row - self.q_lookup.enable(region, idx)?; + self.config().q_lookup.enable(region, idx)?; // Enable q_running on this row - self.q_running.enable(region, idx)?; + self.config().q_running.enable(region, idx)?; // z_next = (z_cur - m_cur) / 2^K z = { @@ -346,7 +201,7 @@ impl LookupRangeCheckConfig { // Assign z_next region.assign_advice( || format!("z_{:?}", idx + 1), - self.running_sum, + self.config().running_sum, idx + 1, || z_val, )? @@ -367,7 +222,7 @@ impl LookupRangeCheckConfig { /// # Panics /// /// Panics if NUM_BITS is equal to or larger than K. - pub fn copy_short_check( + fn copy_short_check( &self, mut layouter: impl Layouter, element: AssignedCell, @@ -379,7 +234,7 @@ impl LookupRangeCheckConfig { |mut region| { // Copy `element` to use in the k-bit lookup. let element = - element.copy_advice(|| "element", &mut region, self.running_sum, 0)?; + element.copy_advice(|| "element", &mut region, self.config().running_sum, 0)?; self.short_range_check(&mut region, element, num_bits) }, @@ -391,7 +246,7 @@ impl LookupRangeCheckConfig { /// # Panics /// /// Panics if num_bits is larger than K. - pub fn witness_short_check( + fn witness_short_check( &self, mut layouter: impl Layouter, element: Value, @@ -402,8 +257,12 @@ impl LookupRangeCheckConfig { || format!("Range check {:?} bits", num_bits), |mut region| { // Witness `element` to use in the k-bit lookup. - let element = - region.assign_advice(|| "Witness element", self.running_sum, 0, || element)?; + let element = region.assign_advice( + || "Witness element", + self.config().running_sum, + 0, + || element, + )?; self.short_range_check(&mut region, element.clone(), num_bits)?; @@ -411,362 +270,159 @@ impl LookupRangeCheckConfig { }, ) } +} - /// Constrain `x` to be a NUM_BITS word. - /// - /// `element` must have been assigned to `self.running_sum` at offset 0. - fn short_range_check( - &self, - region: &mut Region<'_, F>, - element: AssignedCell, - num_bits: usize, - ) -> Result<(), Error> { - // Enable lookup for `element`. - self.q_lookup.enable(region, 0)?; - - match num_bits { - 4 => { - self.q_range_check_4.enable(region, 0)?; - } - 5 => { - self.q_range_check_5.enable(region, 0)?; - } - _ => { - // Enable lookup for shifted element, to constrain it to 10 bits. - self.q_lookup.enable(region, 1)?; +impl LookupRangeCheck for LookupRangeCheckConfig { + fn config(&self) -> &LookupRangeCheckConfig { + self + } - // Check element has been shifted by the correct number of bits. - self.q_bitshift.enable(region, 1)?; + fn configure( + meta: &mut ConstraintSystem, + running_sum: Column, + table_idx: TableColumn, + ) -> Self { + meta.enable_equality(running_sum); - // Assign shifted `element * 2^{K - num_bits}` - let shifted = element.value().into_field() * F::from(1 << (K - num_bits)); + let q_lookup = meta.complex_selector(); + let q_running = meta.complex_selector(); + let q_bitshift = meta.selector(); - region.assign_advice( - || format!("element * 2^({}-{})", K, num_bits), - self.running_sum, - 1, - || shifted, - )?; + // 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, + q_running, + q_bitshift, + running_sum, + table_idx, + _marker: PhantomData, + }; - // Assign 2^{-num_bits} from a fixed column. - let inv_two_pow_s = F::from(1 << num_bits).invert().unwrap(); - region.assign_advice_from_constant( - || format!("2^(-{})", num_bits), - self.running_sum, - 2, - inv_two_pow_s, - )?; - } - } + // https://p.z.cash/halo2-0.1:decompose-combined-lookup + 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); - Ok(()) - } -} + // In the case of a running sum decomposition, we recover the word from + // the difference of the running sums: + // z_i = 2^{K}⋅z_{i + 1} + a_i + // => a_i = z_i - 2^{K}⋅z_{i + 1} + let running_sum_lookup = { + let running_sum_word = { + let z_next = meta.query_advice(config.running_sum, Rotation::next()); + z_cur.clone() - z_next * F::from(1 << K) + }; -#[cfg(test)] -mod tests { - use super::LookupRangeCheckConfig; - - use super::super::lebs2ip; - use crate::sinsemilla::primitives::K; - - use ff::{Field, PrimeFieldBits}; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::{FailureLocation, MockProver, VerifyFailure}, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use pasta_curves::pallas; - - use std::{convert::TryInto, marker::PhantomData}; - - #[test] - fn lookup_range_check() { - #[derive(Clone, Copy)] - struct MyCircuit { - num_words: usize, - _marker: PhantomData, - } + q_running.clone() * running_sum_word + }; - impl Circuit for MyCircuit { - type Config = LookupRangeCheckConfig; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - *self - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let running_sum = meta.advice_column(); - let table_idx = meta.lookup_table_column(); - let table_range_check_tag = meta.lookup_table_column(); - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - LookupRangeCheckConfig::::configure( - meta, - running_sum, - table_idx, - table_range_check_tag, - ) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // Load table_idx - config.load(&mut layouter)?; - - // Lookup constraining element to be no longer than num_words * K bits. - let elements_and_expected_final_zs = [ - (F::from((1 << (self.num_words * K)) - 1), F::ZERO, true), // a word that is within self.num_words * K bits long - (F::from(1 << (self.num_words * K)), F::ONE, false), // a word that is just over self.num_words * K bits long - ]; - - fn expected_zs( - element: F, - num_words: usize, - ) -> Vec { - let chunks = { - element - .to_le_bits() - .iter() - .by_vals() - .take(num_words * K) - .collect::>() - .chunks_exact(K) - .map(|chunk| F::from(lebs2ip::(chunk.try_into().unwrap()))) - .collect::>() - }; - let expected_zs = { - let inv_two_pow_k = F::from(1 << K).invert().unwrap(); - chunks.iter().fold(vec![element], |mut zs, a_i| { - // z_{i + 1} = (z_i - a_i) / 2^{K} - let z = (zs[zs.len() - 1] - a_i) * inv_two_pow_k; - zs.push(z); - zs - }) - }; - expected_zs - } + // In the short range check, the word is directly witnessed. + let short_lookup = { + let short_word = z_cur.clone(); + let q_short = one.clone() - q_running; - for (element, expected_final_z, strict) in elements_and_expected_final_zs.iter() { - let expected_zs = expected_zs::(*element, self.num_words); + q_short * short_word + }; - let zs = config.witness_check( - layouter.namespace(|| format!("Lookup {:?}", self.num_words)), - Value::known(*element), - self.num_words, - *strict, - )?; + vec![( + q_lookup * (running_sum_lookup + short_lookup), + config.table_idx, + )] + }); - assert_eq!(*expected_zs.last().unwrap(), *expected_final_z); + // For short lookups, check that the word has been shifted by the correct number of bits. + // https://p.z.cash/halo2-0.1:decompose-short-lookup + meta.create_gate("Short lookup bitshift", |meta| { + let q_bitshift = meta.query_selector(config.q_bitshift); + let word = meta.query_advice(config.running_sum, Rotation::prev()); + let shifted_word = meta.query_advice(config.running_sum, Rotation::cur()); + let inv_two_pow_s = meta.query_advice(config.running_sum, Rotation::next()); - for (expected_z, z) in expected_zs.into_iter().zip(zs.iter()) { - z.value().assert_if_known(|z| &&expected_z == z); - } - } - Ok(()) - } - } + let two_pow_k = F::from(1 << K); - { - let circuit: MyCircuit = MyCircuit { - num_words: 6, - _marker: PhantomData, - }; + // shifted_word = word * 2^{K-s} + // = word * 2^K * inv_two_pow_s + Constraints::with_selector( + q_bitshift, + Some(word * two_pow_k * inv_two_pow_s - shifted_word), + ) + }); - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } + config } - #[test] - fn short_range_check() { - struct MyCircuit { - element: Value, - num_bits: usize, - } - - impl Circuit for MyCircuit { - type Config = LookupRangeCheckConfig; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - MyCircuit { - element: Value::unknown(), - num_bits: self.num_bits, + #[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> { + layouter.assign_table( + || "table_idx", + |mut table| { + // We generate the row values lazily (we only need them during keygen). + for index in 0..(1 << K) { + table.assign_cell( + || "table_idx", + self.table_idx, + index, + || Value::known(F::from(index as u64)), + )?; } - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let running_sum = meta.advice_column(); - let table_idx = meta.lookup_table_column(); - let table_range_check_tag = meta.lookup_table_column(); - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - LookupRangeCheckConfig::::configure( - meta, - running_sum, - table_idx, - table_range_check_tag, - ) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // Load table_idx - config.load(&mut layouter)?; - - // Lookup constraining element to be no longer than num_bits. - config.witness_short_check( - layouter.namespace(|| format!("Lookup {:?} bits", self.num_bits)), - self.element, - self.num_bits, - )?; - Ok(()) - } - } - - // Edge case: zero bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::ZERO), - num_bits: 0, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } + }, + ) + } - // Edge case: K bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from((1 << K) - 1)), - num_bits: K, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } + /// Constrain `x` to be a NUM_BITS word. + /// + /// `element` must have been assigned to `self.running_sum` at offset 0. + fn short_range_check( + &self, + region: &mut Region<'_, F>, + element: AssignedCell, + num_bits: usize, + ) -> Result<(), Error> { + // Enable lookup for `element`. + self.q_lookup.enable(region, 0)?; - // Element within `num_bits` - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from((1 << 6) - 1)), - num_bits: 6, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } + // Enable lookup for shifted element, to constrain it to 10 bits. + self.q_lookup.enable(region, 1)?; - // Element larger than `num_bits` but within K bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from(1 << 6)), - num_bits: 6, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![VerifyFailure::Lookup { - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 1, - }, - }]) - ); - } + // Check element has been shifted by the correct number of bits. + self.q_bitshift.enable(region, 1)?; - // Element larger than K bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from(1 << K)), - num_bits: 6, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![ - VerifyFailure::Lookup { - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 0, - }, - }, - VerifyFailure::Lookup { - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 1, - }, - }, - ]) - ); - } + // Assign shifted `element * 2^{K - num_bits}` + let shifted = element.value().into_field() * F::from(1 << (K - num_bits)); - // Element which is not within `num_bits`, but which has a shifted value within - // num_bits - { - let num_bits = 6; - let shifted = pallas::Base::from((1 << num_bits) - 1); - // Recall that shifted = element * 2^{K-s} - // => element = shifted * 2^{s-K} - let element = shifted - * pallas::Base::from(1 << (K as u64 - num_bits)) - .invert() - .unwrap(); - let circuit: MyCircuit = MyCircuit { - element: Value::known(element), - num_bits: num_bits as usize, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![VerifyFailure::Lookup { - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 0, - }, - }]) - ); - } + region.assign_advice( + || format!("element * 2^({}-{})", K, num_bits), + self.running_sum, + 1, + || shifted, + )?; - // Element within 4 bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from((1 << 4) - 1)), - num_bits: 4, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } + // Assign 2^{-num_bits} from a fixed column. + let inv_two_pow_s = F::from(1 << num_bits).invert().unwrap(); + region.assign_advice_from_constant( + || format!("2^(-{})", num_bits), + self.running_sum, + 2, + inv_two_pow_s, + )?; - // Element larger than 5 bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from(1 << 5)), - num_bits: 5, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![VerifyFailure::Lookup { - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 5 bits").into(), - offset: 0, - }, - }]) - ); - } + Ok(()) } } + +/// FIXME: add doc +pub trait DefaultLookupRangeCheck: + LookupRangeCheck + Eq + PartialEq + Clone + Copy + Debug +{ +} + +impl DefaultLookupRangeCheck for LookupRangeCheckConfig {} diff --git a/halo2_gadgets/src/utilities_opt.rs b/halo2_gadgets/src/utilities_opt.rs new file mode 100644 index 0000000000..ddd75ce739 --- /dev/null +++ b/halo2_gadgets/src/utilities_opt.rs @@ -0,0 +1,4 @@ +//! Utility gadgets. + +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 new file mode 100644 index 0000000000..13b169ec2e --- /dev/null +++ b/halo2_gadgets/src/utilities_opt/cond_swap.rs @@ -0,0 +1,448 @@ +//! Gadget and chip for a conditional swap utility. + +use group::ff::{Field, PrimeField}; +use pasta_curves::pallas; + +use halo2_proofs::{ + circuit::{AssignedCell, Chip, Layouter}, + plonk::{self, Error}, +}; + +use crate::ecc::chip::{EccPoint, NonIdentityEccPoint}; + +use crate::utilities::cond_swap::{CondSwapChip, CondSwapInstructions}; + +/// Instructions for a conditional swap gadget. +pub trait CondSwapInstructionsOptimized: CondSwapInstructions { + /// Given an input `(choice, left, right)` where `choice` is a boolean flag, + /// returns `left` if `choice` is not set and `right` if `choice` is set. + fn mux( + &self, + layouter: &mut impl Layouter, + choice: Self::Var, + left: Self::Var, + right: Self::Var, + ) -> Result; +} + +impl CondSwapInstructionsOptimized for CondSwapChip { + fn mux( + &self, + layouter: &mut impl Layouter, + choice: Self::Var, + left: Self::Var, + right: Self::Var, + ) -> Result { + let config = self.config(); + + layouter.assign_region( + || "mux", + |mut region| { + // Enable `q_swap` selector + config.q_swap.enable(&mut region, 0)?; + + // Copy in `a` value + let left = left.copy_advice(|| "copy left", &mut region, config.a, 0)?; + + // Copy in `b` value + let right = right.copy_advice(|| "copy right", &mut region, config.b, 0)?; + + // Copy `choice` value + let choice = choice.copy_advice(|| "copy choice", &mut region, config.swap, 0)?; + + let a_swapped = left + .value() + .zip(right.value()) + .zip(choice.value()) + .map(|((left, right), choice)| { + if *choice == F::from(0_u64) { + left + } else { + right + } + }) + .cloned(); + let b_swapped = left + .value() + .zip(right.value()) + .zip(choice.value()) + .map(|((left, right), choice)| { + if *choice == F::from(0_u64) { + right + } else { + left + } + }) + .cloned(); + + region.assign_advice(|| "out b_swap", self.config.b_swapped, 0, || b_swapped)?; + region.assign_advice(|| "out a_swap", self.config.a_swapped, 0, || a_swapped) + }, + ) + } +} + +impl CondSwapChip { + /// Given an input `(choice, left, right)` where `choice` is a boolean flag and `left` and `right` are `EccPoint`, + /// returns `left` if `choice` is not set and `right` if `choice` is set. + pub fn mux_on_points( + &self, + mut layouter: impl Layouter, + choice: &AssignedCell, + left: &EccPoint, + right: &EccPoint, + ) -> Result { + let x_cell = self.mux(&mut layouter, choice.clone(), left.x(), right.x())?; + let y_cell = self.mux(&mut layouter, choice.clone(), left.y(), right.y())?; + Ok(EccPoint::from_coordinates_unchecked( + x_cell.into(), + y_cell.into(), + )) + } + + /// Given an input `(choice, left, right)` where `choice` is a boolean flag and `left` and `right` are + /// `NonIdentityEccPoint`, returns `left` if `choice` is not set and `right` if `choice` is set. + pub fn mux_on_non_identity_points( + &self, + mut layouter: impl Layouter, + choice: &AssignedCell, + left: &NonIdentityEccPoint, + right: &NonIdentityEccPoint, + ) -> Result { + let x_cell = self.mux(&mut layouter, choice.clone(), left.x(), right.x())?; + let y_cell = self.mux(&mut layouter, choice.clone(), left.y(), right.y())?; + Ok(NonIdentityEccPoint::from_coordinates_unchecked( + x_cell.into(), + y_cell.into(), + )) + } +} + +#[cfg(test)] +mod tests { + use super::{CondSwapChip, CondSwapInstructions}; + use crate::utilities::cond_swap::CondSwapConfig; + use crate::utilities::lookup_range_check::LookupRangeCheck; + use crate::utilities::UtilitiesInstructions; + use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; + 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; + + #[test] + fn cond_swap() { + #[derive(Default)] + struct MyCircuit { + a: Value, + b: Value, + swap: Value, + } + + impl Circuit for MyCircuit { + type Config = CondSwapConfig; + 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(), + ]; + + CondSwapChip::::configure(meta, advices) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let chip = CondSwapChip::::construct(config.clone()); + + // Load the pair and the swap flag into the circuit. + let a = chip.load_private(layouter.namespace(|| "a"), config.a, self.a)?; + // Return the swapped pair. + let swapped_pair = chip.swap( + layouter.namespace(|| "swap"), + (a.clone(), self.b), + self.swap, + )?; + + self.swap + .zip(a.value().zip(self.b.as_ref())) + .zip(swapped_pair.0.value().zip(swapped_pair.1.value())) + .assert_if_known(|((swap, (a, b)), (a_swapped, b_swapped))| { + if *swap { + // Check that `a` and `b` have been swapped + (a_swapped == b) && (b_swapped == a) + } else { + // Check that `a` and `b` have not been swapped + (a_swapped == a) && (b_swapped == b) + } + }); + + Ok(()) + } + } + + let rng = OsRng; + + // Test swap case + { + let circuit: MyCircuit = MyCircuit { + a: Value::known(Base::random(rng)), + b: Value::known(Base::random(rng)), + swap: Value::known(true), + }; + let prover = MockProver::::run(3, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), Ok(())); + } + + // Test non-swap case + { + let circuit: MyCircuit = MyCircuit { + a: Value::known(Base::random(rng)), + b: Value::known(Base::random(rng)), + swap: Value::known(false), + }; + let prover = MockProver::::run(3, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), Ok(())); + } + } + + #[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< + TestFixedBases, + LookupRangeCheckConfigOptimized, + >, + } + + #[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::< + TestFixedBases, + LookupRangeCheckConfigOptimized< + pallas::Base, + { crate::sinsemilla::primitives::K }, + >, + >::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(())); + } + } +} diff --git a/halo2_gadgets/src/utilities_opt/lookup_range_check.rs b/halo2_gadgets/src/utilities_opt/lookup_range_check.rs new file mode 100644 index 0000000000..13d278f834 --- /dev/null +++ b/halo2_gadgets/src/utilities_opt/lookup_range_check.rs @@ -0,0 +1,570 @@ +//! Make use of a K-bit lookup table to decompose a field element into K-bit +//! words. + +use std::marker::PhantomData; + +use halo2_proofs::{ + circuit::{AssignedCell, Region}, + plonk::{ + Advice, Column, ConstraintSystem, Constraints, Error, Expression, Selector, TableColumn, + }, + poly::Rotation, +}; + +#[cfg(test)] +use halo2_proofs::circuit::{Layouter, Value}; + +use ff::PrimeFieldBits; + +use pasta_curves::pallas; + +use crate::{ + sinsemilla::primitives as sinsemilla, + utilities::lookup_range_check::{ + DefaultLookupRangeCheck, LookupRangeCheck, LookupRangeCheckConfig, + }, +}; + +/// Configuration that provides methods for a lookup range check. +#[derive(Eq, PartialEq, Debug, Clone, Copy)] +pub struct LookupRangeCheckConfigOptimized { + base: LookupRangeCheckConfig, + q_range_check_4: Selector, + q_range_check_5: Selector, + // FIXME: Instead of making it pub, add a method in LookupRangeCheckConfig that returns table_range_check_tag + //pub(crate) + table_range_check_tag: TableColumn, +} + +impl LookupRangeCheckConfigOptimized { + /// 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_with_tag( + meta: &mut ConstraintSystem, + running_sum: Column, + table_idx: TableColumn, + table_range_check_tag: TableColumn, + ) -> Self { + meta.enable_equality(running_sum); + + let q_lookup = meta.complex_selector(); + let q_running = meta.complex_selector(); + let q_bitshift = meta.selector(); + + let q_range_check_4 = meta.complex_selector(); + let q_range_check_5 = meta.complex_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 = LookupRangeCheckConfigOptimized { + base: LookupRangeCheckConfig { + q_lookup, + q_running, + q_bitshift, + running_sum, + table_idx, + _marker: PhantomData, + }, + q_range_check_4, + q_range_check_5, + table_range_check_tag, + }; + + // https://p.z.cash/halo2-0.1:decompose-combined-lookup + meta.lookup(|meta| { + let q_lookup = meta.query_selector(config.base.q_lookup); + let q_running = meta.query_selector(config.base.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.base.running_sum, Rotation::cur()); + let one = Expression::Constant(F::ONE); + + // In the case of a running sum decomposition, we recover the word from + // the difference of the running sums: + // z_i = 2^{K}⋅z_{i + 1} + a_i + // => a_i = z_i - 2^{K}⋅z_{i + 1} + let running_sum_lookup = { + let running_sum_word = { + let z_next = meta.query_advice(config.base.running_sum, Rotation::next()); + z_cur.clone() - z_next * F::from(1 << K) + }; + + q_running.clone() * running_sum_word + }; + + // In the short range check, the word is directly witnessed. + let short_lookup = { + let short_word = z_cur.clone(); + let q_short = one.clone() - q_running; + + q_short * short_word + }; + + let q_range_check_4 = meta.query_selector(config.q_range_check_4); + let q_range_check_5 = meta.query_selector(config.q_range_check_5); + + // q_range_check is equal to + // - 1 if q_range_check_4 = 1 or q_range_check_5 = 1 + // - 0 otherwise + let q_range_check = one.clone() + - (one.clone() - q_range_check_4.clone()) * (one.clone() - q_range_check_5.clone()); + + // num_bits is equal to + // - 5 if q_range_check_5 = 1 + // - 4 if q_range_check_4 = 1 and q_range_check_5 = 0 + // - 0 otherwise + let num_bits = q_range_check_5.clone() * Expression::Constant(F::from(5_u64)) + + (one.clone() - q_range_check_5) + * q_range_check_4 + * Expression::Constant(F::from(4_u64)); + + // Combine the running sum, short lookups and optimized range checks: + vec![ + ( + q_lookup.clone() + * ((one - q_range_check.clone()) * (running_sum_lookup + short_lookup) + + q_range_check.clone() * z_cur), + config.base.table_idx, + ), + ( + q_lookup * q_range_check * num_bits, + config.table_range_check_tag, + ), + ] + }); + + // For short lookups, check that the word has been shifted by the correct number of bits. + // https://p.z.cash/halo2-0.1:decompose-short-lookup + meta.create_gate("Short lookup bitshift", |meta| { + let q_bitshift = meta.query_selector(config.base.q_bitshift); + let word = meta.query_advice(config.base.running_sum, Rotation::prev()); + let shifted_word = meta.query_advice(config.base.running_sum, Rotation::cur()); + let inv_two_pow_s = meta.query_advice(config.base.running_sum, Rotation::next()); + + let two_pow_k = F::from(1 << K); + + // shifted_word = word * 2^{K-s} + // = word * 2^K * inv_two_pow_s + Constraints::with_selector( + q_bitshift, + Some(word * two_pow_k * inv_two_pow_s - shifted_word), + ) + }); + + config + } + + pub(crate) fn table_range_check_tag(&self) -> TableColumn { + self.table_range_check_tag + } +} + +impl LookupRangeCheck + for LookupRangeCheckConfigOptimized +{ + fn config(&self) -> &LookupRangeCheckConfig { + &self.base + } + + fn configure( + meta: &mut ConstraintSystem, + running_sum: Column, + table_idx: TableColumn, + ) -> Self { + let table_range_check_tag = meta.lookup_table_column(); + Self::configure_with_tag(meta, running_sum, table_idx, table_range_check_tag) + } + + #[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> { + layouter.assign_table( + || "table_idx", + |mut table| { + let mut assign_cells = + |offset: usize, table_size, value: u64| -> Result { + for index in 0..table_size { + let new_index = index + offset; + table.assign_cell( + || "table_idx", + self.base.table_idx, + new_index, + || Value::known(F::from(index as u64)), + )?; + table.assign_cell( + || "table_range_check_tag", + self.table_range_check_tag, + new_index, + || Value::known(F::from(value)), + )?; + } + Ok(offset + table_size) + }; + + // We generate the row values lazily (we only need them during keygen). + let mut offset = 0; + + //annotation: &'v (dyn Fn() -> String + 'v), + //column: TableColumn, + //offset: usize, + //to: &'v mut (dyn FnMut() -> Value> + 'v), + + offset = assign_cells(offset, 1 << K, 0)?; + offset = assign_cells(offset, 1 << 4, 4)?; + assign_cells(offset, 1 << 5, 5)?; + + Ok(()) + }, + ) + } + + /// Constrain `x` to be a NUM_BITS word. + /// + /// `element` must have been assigned to `self.running_sum` at offset 0. + fn short_range_check( + &self, + region: &mut Region<'_, F>, + element: AssignedCell, + num_bits: usize, + ) -> Result<(), Error> { + match num_bits { + 4 => { + self.base.q_lookup.enable(region, 0)?; + self.q_range_check_4.enable(region, 0)?; + Ok(()) + } + + 5 => { + self.base.q_lookup.enable(region, 0)?; + self.q_range_check_5.enable(region, 0)?; + Ok(()) + } + + _ => self.base.short_range_check(region, element, num_bits), + } + } +} + +#[cfg(test)] +mod tests { + use super::{LookupRangeCheck, LookupRangeCheckConfigOptimized}; + + use crate::sinsemilla::primitives::K; + use crate::utilities::lebs2ip; + + use ff::{Field, PrimeFieldBits}; + use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner, Value}, + dev::{FailureLocation, MockProver, VerifyFailure}, + plonk::{Circuit, ConstraintSystem, Error}, + }; + use pasta_curves::pallas; + + use std::{convert::TryInto, marker::PhantomData}; + + #[test] + fn lookup_range_check() { + #[derive(Clone, Copy)] + struct MyCircuit { + num_words: usize, + _marker: PhantomData, + } + + impl Circuit for MyCircuit { + type Config = LookupRangeCheckConfigOptimized; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + *self + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let running_sum = meta.advice_column(); + let table_idx = meta.lookup_table_column(); + let table_range_check_tag = meta.lookup_table_column(); + let constants = meta.fixed_column(); + meta.enable_constant(constants); + + LookupRangeCheckConfigOptimized::::configure_with_tag( + meta, + running_sum, + table_idx, + table_range_check_tag, + ) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + // Load table_idx + config.load(&mut layouter)?; + + // Lookup constraining element to be no longer than num_words * K bits. + let elements_and_expected_final_zs = [ + (F::from((1 << (self.num_words * K)) - 1), F::ZERO, true), // a word that is within self.num_words * K bits long + (F::from(1 << (self.num_words * K)), F::ONE, false), // a word that is just over self.num_words * K bits long + ]; + + fn expected_zs( + element: F, + num_words: usize, + ) -> Vec { + let chunks = { + element + .to_le_bits() + .iter() + .by_vals() + .take(num_words * K) + .collect::>() + .chunks_exact(K) + .map(|chunk| F::from(lebs2ip::(chunk.try_into().unwrap()))) + .collect::>() + }; + let expected_zs = { + let inv_two_pow_k = F::from(1 << K).invert().unwrap(); + chunks.iter().fold(vec![element], |mut zs, a_i| { + // z_{i + 1} = (z_i - a_i) / 2^{K} + let z = (zs[zs.len() - 1] - a_i) * inv_two_pow_k; + zs.push(z); + zs + }) + }; + expected_zs + } + + for (element, expected_final_z, strict) in elements_and_expected_final_zs.iter() { + let expected_zs = expected_zs::(*element, self.num_words); + + let zs = config.witness_check( + layouter.namespace(|| format!("Lookup {:?}", self.num_words)), + Value::known(*element), + self.num_words, + *strict, + )?; + + assert_eq!(*expected_zs.last().unwrap(), *expected_final_z); + + for (expected_z, z) in expected_zs.into_iter().zip(zs.iter()) { + z.value().assert_if_known(|z| &&expected_z == z); + } + } + Ok(()) + } + } + + { + let circuit: MyCircuit = MyCircuit { + num_words: 6, + _marker: PhantomData, + }; + + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), Ok(())); + } + } + + #[test] + fn short_range_check() { + struct MyCircuit { + element: Value, + num_bits: usize, + } + + impl Circuit for MyCircuit { + type Config = LookupRangeCheckConfigOptimized; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + MyCircuit { + element: Value::unknown(), + num_bits: self.num_bits, + } + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let running_sum = meta.advice_column(); + let table_idx = meta.lookup_table_column(); + let table_range_check_tag = meta.lookup_table_column(); + let constants = meta.fixed_column(); + meta.enable_constant(constants); + + LookupRangeCheckConfigOptimized::::configure_with_tag( + meta, + running_sum, + table_idx, + table_range_check_tag, + ) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + // Load table_idx + config.load(&mut layouter)?; + + // Lookup constraining element to be no longer than num_bits. + config.witness_short_check( + layouter.namespace(|| format!("Lookup {:?} bits", self.num_bits)), + self.element, + self.num_bits, + )?; + + Ok(()) + } + } + + // Edge case: zero bits + { + let circuit: MyCircuit = MyCircuit { + element: Value::known(pallas::Base::ZERO), + num_bits: 0, + }; + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), Ok(())); + } + + // Edge case: K bits + { + let circuit: MyCircuit = MyCircuit { + element: Value::known(pallas::Base::from((1 << K) - 1)), + num_bits: K, + }; + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), Ok(())); + } + + // Element within `num_bits` + { + let circuit: MyCircuit = MyCircuit { + element: Value::known(pallas::Base::from((1 << 6) - 1)), + num_bits: 6, + }; + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), Ok(())); + } + + // Element larger than `num_bits` but within K bits + { + let circuit: MyCircuit = MyCircuit { + element: Value::known(pallas::Base::from(1 << 6)), + num_bits: 6, + }; + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!( + prover.verify(), + Err(vec![VerifyFailure::Lookup { + lookup_index: 0, + location: FailureLocation::InRegion { + region: (1, "Range check 6 bits").into(), + offset: 1, + }, + }]) + ); + } + + // Element larger than K bits + { + let circuit: MyCircuit = MyCircuit { + element: Value::known(pallas::Base::from(1 << K)), + num_bits: 6, + }; + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!( + prover.verify(), + Err(vec![ + VerifyFailure::Lookup { + lookup_index: 0, + location: FailureLocation::InRegion { + region: (1, "Range check 6 bits").into(), + offset: 0, + }, + }, + VerifyFailure::Lookup { + lookup_index: 0, + location: FailureLocation::InRegion { + region: (1, "Range check 6 bits").into(), + offset: 1, + }, + }, + ]) + ); + } + + // Element which is not within `num_bits`, but which has a shifted value within + // num_bits + { + let num_bits = 6; + let shifted = pallas::Base::from((1 << num_bits) - 1); + // Recall that shifted = element * 2^{K-s} + // => element = shifted * 2^{s-K} + let element = shifted + * pallas::Base::from(1 << (K as u64 - num_bits)) + .invert() + .unwrap(); + let circuit: MyCircuit = MyCircuit { + element: Value::known(element), + num_bits: num_bits as usize, + }; + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!( + prover.verify(), + Err(vec![VerifyFailure::Lookup { + lookup_index: 0, + location: FailureLocation::InRegion { + region: (1, "Range check 6 bits").into(), + offset: 0, + }, + }]) + ); + } + + // Element within 4 bits + { + let circuit: MyCircuit = MyCircuit { + element: Value::known(pallas::Base::from((1 << 4) - 1)), + num_bits: 4, + }; + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), Ok(())); + } + + // Element larger than 5 bits + { + let circuit: MyCircuit = MyCircuit { + element: Value::known(pallas::Base::from(1 << 5)), + num_bits: 5, + }; + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!( + prover.verify(), + Err(vec![VerifyFailure::Lookup { + lookup_index: 0, + location: FailureLocation::InRegion { + region: (1, "Range check 5 bits").into(), + offset: 0, + }, + }]) + ); + } + } +} + +pub(crate) type DefaultLookupRangeCheckConfigOptimized = + LookupRangeCheckConfigOptimized; + +impl DefaultLookupRangeCheck for DefaultLookupRangeCheckConfigOptimized {} From d3a6f4239c21d8c2249664a308d10754186ff2a8 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Wed, 24 Apr 2024 11:29:41 +0200 Subject: [PATCH 17/99] clean up code --- halo2_gadgets/src/ecc/chip/mul.rs | 2 +- halo2_gadgets/src/ecc/chip/mul_fixed/short.rs | 1 - halo2_gadgets/src/ecc_opt.rs | 15 +- .../src/ecc_opt/chip/mul_fixed/short.rs | 162 +----------------- halo2_gadgets/src/sinsemilla.rs | 6 +- halo2_gadgets/src/sinsemilla/chip.rs | 8 +- .../src/sinsemilla/chip/generator_table.rs | 2 - .../src/sinsemilla/chip/hash_to_point.rs | 70 ++++---- halo2_gadgets/src/sinsemilla/merkle/chip.rs | 2 +- halo2_gadgets/src/sinsemilla_opt.rs | 2 +- halo2_gadgets/src/sinsemilla_opt/chip.rs | 23 +-- .../sinsemilla_opt/chip/generator_table.rs | 2 - .../src/sinsemilla_opt/merkle/chip.rs | 1 - halo2_gadgets/src/utilities_opt/cond_swap.rs | 1 - .../src/utilities_opt/lookup_range_check.rs | 3 - 15 files changed, 58 insertions(+), 242 deletions(-) diff --git a/halo2_gadgets/src/ecc/chip/mul.rs b/halo2_gadgets/src/ecc/chip/mul.rs index 85677da520..6408ae6a44 100644 --- a/halo2_gadgets/src/ecc/chip/mul.rs +++ b/halo2_gadgets/src/ecc/chip/mul.rs @@ -461,7 +461,7 @@ pub mod tests { Curve, }; use halo2_proofs::{ - circuit::{Chip, Layouter, Value}, + circuit::{Layouter, Value}, plonk::Error, }; use pasta_curves::pallas; diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs index 8ce73ca3c6..c746bd5f97 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs @@ -252,7 +252,6 @@ pub mod tests { plonk::{Any, Error}, }; use pasta_curves::pallas; - use std::marker::PhantomData; use crate::utilities::lookup_range_check::{DefaultLookupRangeCheck, LookupRangeCheck}; use crate::{ diff --git a/halo2_gadgets/src/ecc_opt.rs b/halo2_gadgets/src/ecc_opt.rs index a8ed313c10..6f0203c384 100644 --- a/halo2_gadgets/src/ecc_opt.rs +++ b/halo2_gadgets/src/ecc_opt.rs @@ -80,7 +80,7 @@ pub(crate) mod tests { }, FixedPoints, }; - use crate::utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}; + use crate::utilities::lookup_range_check::LookupRangeCheck; use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; #[derive(Debug, Eq, PartialEq, Clone)] @@ -100,19 +100,6 @@ pub(crate) mod tests { find_zs_and_us(*BASE, NUM_WINDOWS_SHORT).unwrap(); } - impl FullWidth { - pub(crate) fn from_pallas_generator() -> Self { - FullWidth(*BASE, &ZS_AND_US) - } - - pub(crate) fn from_parts( - base: pallas::Affine, - zs_and_us: &'static [(u64, [pallas::Base; H])], - ) -> Self { - FullWidth(base, zs_and_us) - } - } - impl FixedPoint for FullWidth { type FixedScalarKind = FullScalar; diff --git a/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs index 679bd5d2be..65abba6291 100644 --- a/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs +++ b/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs @@ -88,169 +88,13 @@ pub mod tests { use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; use crate::{ ecc::{ - chip::{EccChip, FixedPoint, MagnitudeSign}, + chip::{EccChip}, tests::{Short, TestFixedBases}, - FixedPointShort, NonIdentityPoint, Point, ScalarFixedShort, + Point, ScalarFixedShort, }, - utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions}, + utilities::UtilitiesInstructions, }; - #[allow(clippy::op_ref)] - pub(crate) fn test_mul_fixed_short( - chip: EccChip< - TestFixedBases, - LookupRangeCheckConfigOptimized, - >, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // test_short - let base_val = Short.generator(); - let test_short = FixedPointShort::from_inner(chip.clone(), Short); - - fn load_magnitude_sign( - chip: EccChip< - TestFixedBases, - LookupRangeCheckConfigOptimized, - >, - mut layouter: impl Layouter, - magnitude: pallas::Base, - sign: pallas::Base, - ) -> Result { - let column = chip.config().advices[0]; - let magnitude = chip.load_private( - layouter.namespace(|| "magnitude"), - column, - Value::known(magnitude), - )?; - let sign = - chip.load_private(layouter.namespace(|| "sign"), column, Value::known(sign))?; - - Ok((magnitude, sign)) - } - - fn constrain_equal_non_id( - chip: EccChip< - TestFixedBases, - LookupRangeCheckConfigOptimized, - >, - mut layouter: impl Layouter, - base_val: pallas::Affine, - scalar_val: pallas::Scalar, - result: Point< - pallas::Affine, - EccChip< - TestFixedBases, - LookupRangeCheckConfigOptimized< - pallas::Base, - { crate::sinsemilla::primitives::K }, - >, - >, - >, - ) -> Result<(), Error> { - let expected = NonIdentityPoint::new( - chip, - layouter.namespace(|| "expected point"), - Value::known((base_val * scalar_val).to_affine()), - )?; - result.constrain_equal(layouter.namespace(|| "constrain result"), &expected) - } - - let magnitude_signs = [ - ("random [a]B", pallas::Base::from(rand::random::()), { - let mut random_sign = pallas::Base::one(); - if rand::random::() { - random_sign = -random_sign; - } - random_sign - }), - ( - "[2^64 - 1]B", - pallas::Base::from(0xFFFF_FFFF_FFFF_FFFFu64), - pallas::Base::one(), - ), - ( - "-[2^64 - 1]B", - pallas::Base::from(0xFFFF_FFFF_FFFF_FFFFu64), - -pallas::Base::one(), - ), - // There is a single canonical sequence of window values for which a doubling occurs on the last step: - // 1333333333333333333334 in octal. - // [0xB6DB_6DB6_DB6D_B6DC] B - ( - "mul_with_double", - pallas::Base::from(0xB6DB_6DB6_DB6D_B6DCu64), - pallas::Base::one(), - ), - ( - "mul_with_double negative", - pallas::Base::from(0xB6DB_6DB6_DB6D_B6DCu64), - -pallas::Base::one(), - ), - ]; - - for (name, magnitude, sign) in magnitude_signs.iter() { - let (result, _) = { - let magnitude_sign = load_magnitude_sign( - chip.clone(), - layouter.namespace(|| *name), - *magnitude, - *sign, - )?; - let by = ScalarFixedShort::new( - chip.clone(), - layouter.namespace(|| "signed short scalar"), - magnitude_sign, - )?; - test_short.mul(layouter.namespace(|| *name), by)? - }; - // Move from base field into scalar field - let scalar = { - let magnitude = pallas::Scalar::from_repr(magnitude.to_repr()).unwrap(); - let sign = if *sign == pallas::Base::one() { - pallas::Scalar::one() - } else { - -pallas::Scalar::one() - }; - magnitude * sign - }; - constrain_equal_non_id( - chip.clone(), - layouter.namespace(|| *name), - base_val, - scalar, - result, - )?; - } - - let zero_magnitude_signs = [ - ("mul by +zero", pallas::Base::zero(), pallas::Base::one()), - ("mul by -zero", pallas::Base::zero(), -pallas::Base::one()), - ]; - - for (name, magnitude, sign) in zero_magnitude_signs.iter() { - let (result, _) = { - let magnitude_sign = load_magnitude_sign( - chip.clone(), - layouter.namespace(|| *name), - *magnitude, - *sign, - )?; - let by = ScalarFixedShort::new( - chip.clone(), - layouter.namespace(|| "signed short scalar"), - magnitude_sign, - )?; - test_short.mul(layouter.namespace(|| *name), by)? - }; - result - .inner() - .is_identity() - .assert_if_known(|is_identity| *is_identity); - } - - Ok(()) - } - #[test] fn invalid_magnitude_sign() { use crate::{ diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index d518c341cc..7cbedd7a15 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -78,7 +78,7 @@ pub trait SinsemillaInstructions, @@ -416,6 +418,7 @@ where } #[allow(clippy::type_complexity)] + #[allow(non_snake_case)] /// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. /// /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit @@ -447,6 +450,7 @@ where } #[allow(clippy::type_complexity)] + #[allow(non_snake_case)] /// $\mathsf{SinsemillaShortCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. /// /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs index 07ad5323f9..d1e03c044d 100644 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ b/halo2_gadgets/src/sinsemilla/chip.rs @@ -17,18 +17,14 @@ use halo2_proofs::{ circuit::{AssignedCell, Chip, Layouter, Value}, plonk::{ Advice, Column, ConstraintSystem, Constraints, Error, Expression, Fixed, Selector, - TableColumn, VirtualCells, + VirtualCells, }, poly::Rotation, }; use pasta_curves::pallas; use pasta_curves::pallas::Base; - pub(crate) mod generator_table; -use crate::sinsemilla::chip::generator_table::{DefaultGeneratorTable, GeneratorTable}; -use crate::sinsemilla_opt::chip::generator_table::GeneratorTableConfigOptimized; -use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; -use generator_table::GeneratorTableConfig; +use crate::sinsemilla::chip::generator_table::{DefaultGeneratorTable}; pub(crate) mod hash_to_point; diff --git a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs index 5c09500554..463cc4f323 100644 --- a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs +++ b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs @@ -1,4 +1,3 @@ -use ff::PrimeFieldBits; use group::ff::PrimeField; use halo2_proofs::{ circuit::{Layouter, Value}, @@ -8,7 +7,6 @@ use halo2_proofs::{ use std::fmt::Debug; use super::{CommitDomains, FixedPoints, HashDomains}; -use crate::utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}; use crate::{ sinsemilla::primitives::{self as sinsemilla, SINSEMILLA_S}, utilities::lookup_range_check::DefaultLookupRangeCheck, diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 6c0bc392e5..c7ca71a4c8 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -63,7 +63,6 @@ where let (x_a, y_a, zs_sum) = self.hash_all_pieces(region, offset, message, x_a, y_a)?; - #[cfg(test)] self.check_hash_result(EccPointQ::PublicPoint(Q), message, x_a, y_a, zs_sum) } @@ -88,42 +87,47 @@ where ), Error, > { - use crate::sinsemilla::primitives::{K, S_PERSONALIZATION}; + #[cfg(test)] + #[allow(non_snake_case)] + { + use crate::sinsemilla::primitives::{K, S_PERSONALIZATION}; + + use group::{prime::PrimeCurveAffine, Curve}; + use pasta_curves::arithmetic::CurveExt; - use group::{prime::PrimeCurveAffine, Curve}; - use pasta_curves::arithmetic::CurveExt; + let field_elems: Value> = message + .iter() + .map(|piece| piece.field_elem().map(|elem| (elem, piece.num_words()))) + .collect(); - let field_elems: Value> = message - .iter() - .map(|piece| piece.field_elem().map(|elem| (elem, piece.num_words()))) - .collect(); + let value_Q = match Q { + EccPointQ::PublicPoint(p) => Value::known(p), + EccPointQ::PrivatePoint(p) => p.point(), + }; - let value_Q = match Q { - EccPointQ::PublicPoint(p) => Value::known(p), - EccPointQ::PrivatePoint(p) => p.point(), - }; + field_elems + .zip(x_a.value().zip(y_a.value())) + .zip(value_Q) + .assert_if_known(|((field_elems, (x_a, y_a)), value_Q)| { + // Get message as a bitstring. + let bitstring: Vec = field_elems + .iter() + .flat_map(|(elem, num_words)| elem.to_le_bits().into_iter().take(K * num_words)) + .collect(); + + let hasher_S = pallas::Point::hash_to_curve(S_PERSONALIZATION); + let S = |chunk: &[bool]| hasher_S(&lebs2ip_k(chunk).to_le_bytes()); + + // We can use complete addition here because it differs from + // incomplete addition with negligible probability. + let expected_point = bitstring + .chunks(K) + .fold(value_Q.to_curve(), |acc, chunk| (acc + S(chunk)) + acc); + let actual_point = pallas::Affine::from_xy(x_a.evaluate(), y_a.evaluate()).unwrap(); + expected_point.to_affine() == actual_point + }); + } - field_elems - .zip(x_a.value().zip(y_a.value())) - .zip(value_Q) - .assert_if_known(|((field_elems, (x_a, y_a)), value_Q)| { - // Get message as a bitstring. - let bitstring: Vec = field_elems - .iter() - .flat_map(|(elem, num_words)| elem.to_le_bits().into_iter().take(K * num_words)) - .collect(); - - let hasher_S = pallas::Point::hash_to_curve(S_PERSONALIZATION); - let S = |chunk: &[bool]| hasher_S(&lebs2ip_k(chunk).to_le_bytes()); - - // We can use complete addition here because it differs from - // incomplete addition with negligible probability. - let expected_point = bitstring - .chunks(K) - .fold(value_Q.to_curve(), |acc, chunk| (acc + S(chunk)) + acc); - let actual_point = pallas::Affine::from_xy(x_a.evaluate(), y_a.evaluate()).unwrap(); - expected_point.to_affine() == actual_point - }); x_a.value() .zip(y_a.value()) diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs index ebfe08a701..685d338490 100644 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla/merkle/chip.rs @@ -9,7 +9,7 @@ use pasta_curves::pallas; use super::MerkleInstructions; -use crate::sinsemilla::chip::generator_table::{DefaultGeneratorTable, GeneratorTableConfig}; +use crate::sinsemilla::chip::generator_table::{DefaultGeneratorTable}; use crate::{ sinsemilla::{primitives as sinsemilla, MessagePiece}, utilities::{lookup_range_check::DefaultLookupRangeCheck, RangeConstrained}, diff --git a/halo2_gadgets/src/sinsemilla_opt.rs b/halo2_gadgets/src/sinsemilla_opt.rs index 1103a73705..8948283c62 100644 --- a/halo2_gadgets/src/sinsemilla_opt.rs +++ b/halo2_gadgets/src/sinsemilla_opt.rs @@ -78,6 +78,7 @@ where + Eq, { #[allow(clippy::type_complexity)] + #[allow(non_snake_case)] /// Evaluates the Sinsemilla hash of `message` from the public initial point `Q` stored /// into `CommitDomain`. pub fn hash( @@ -159,7 +160,6 @@ pub(crate) mod tests { tests::{FullWidth, TestFixedBases}, NonIdentityPoint, }, - utilities::lookup_range_check::LookupRangeCheckConfig, }, }; diff --git a/halo2_gadgets/src/sinsemilla_opt/chip.rs b/halo2_gadgets/src/sinsemilla_opt/chip.rs index 790a7c9484..1fa6bc582f 100644 --- a/halo2_gadgets/src/sinsemilla_opt/chip.rs +++ b/halo2_gadgets/src/sinsemilla_opt/chip.rs @@ -1,29 +1,20 @@ //! Chip implementations for the Sinsemilla gadgets. use super::SinsemillaInstructionsOptimized; -use crate::sinsemilla::chip::generator_table::{DefaultGeneratorTable, GeneratorTableConfig}; -use crate::sinsemilla_opt::chip::generator_table::GeneratorTableConfigOptimized; -use crate::utilities::lookup_range_check::{DefaultLookupRangeCheck, LookupRangeCheckConfig}; -use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; +use crate::sinsemilla::chip::generator_table::{DefaultGeneratorTable}; +use crate::utilities::lookup_range_check::{DefaultLookupRangeCheck}; use crate::{ - ecc::{chip::NonIdentityEccPoint, FixedPoints}, + ecc::{FixedPoints}, sinsemilla::{ - chip::{SinsemillaChip, SinsemillaConfig}, - message::{Message, MessagePiece}, - primitives as sinsemilla, CommitDomains, HashDomains, SinsemillaInstructions, + chip::{SinsemillaChip}, + primitives as sinsemilla, CommitDomains, HashDomains, }, - utilities_opt::lookup_range_check::DefaultLookupRangeCheckConfigOptimized, }; -use halo2_proofs::plonk::Expression; use halo2_proofs::{ - circuit::{AssignedCell, Chip, Layouter, Value}, - plonk::{ - Advice, Column, ConstraintSystem, Constraints, Error, Fixed, TableColumn, VirtualCells, - }, - poly::Rotation, + circuit::{Layouter}, + plonk::Error, }; use pasta_curves::pallas; -use pasta_curves::pallas::Base; pub(crate) mod generator_table; diff --git a/halo2_gadgets/src/sinsemilla_opt/chip/generator_table.rs b/halo2_gadgets/src/sinsemilla_opt/chip/generator_table.rs index d721778427..6a582dddde 100644 --- a/halo2_gadgets/src/sinsemilla_opt/chip/generator_table.rs +++ b/halo2_gadgets/src/sinsemilla_opt/chip/generator_table.rs @@ -11,8 +11,6 @@ use crate::sinsemilla::{ chip::generator_table::GeneratorTableConfig, primitives::{K, SINSEMILLA_S}, }; -use crate::utilities::lookup_range_check::{DefaultLookupRangeCheck, LookupRangeCheckConfig}; -use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; /// Table containing independent generators S[0..2^k] #[derive(Eq, PartialEq, Copy, Clone, Debug)] diff --git a/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs b/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs index 48f078cb38..7b9d160e9c 100644 --- a/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs @@ -12,7 +12,6 @@ use crate::utilities::lookup_range_check::DefaultLookupRangeCheck; use crate::{ sinsemilla::{merkle::chip::MerkleChip, primitives as sinsemilla}, sinsemilla_opt::SinsemillaInstructionsOptimized, - utilities_opt::lookup_range_check::DefaultLookupRangeCheckConfigOptimized, { ecc::FixedPoints, sinsemilla::{CommitDomains, HashDomains}, diff --git a/halo2_gadgets/src/utilities_opt/cond_swap.rs b/halo2_gadgets/src/utilities_opt/cond_swap.rs index 13b169ec2e..4ba03e5eea 100644 --- a/halo2_gadgets/src/utilities_opt/cond_swap.rs +++ b/halo2_gadgets/src/utilities_opt/cond_swap.rs @@ -292,7 +292,6 @@ mod tests { 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(), diff --git a/halo2_gadgets/src/utilities_opt/lookup_range_check.rs b/halo2_gadgets/src/utilities_opt/lookup_range_check.rs index 13d278f834..115d8ea811 100644 --- a/halo2_gadgets/src/utilities_opt/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities_opt/lookup_range_check.rs @@ -163,9 +163,6 @@ impl LookupRangeCheckConfigOptimized { config } - pub(crate) fn table_range_check_tag(&self) -> TableColumn { - self.table_range_check_tag - } } impl LookupRangeCheck From 86bd33f49d3170620de5038077a5c11860411bdf Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Wed, 24 Apr 2024 11:31:47 +0200 Subject: [PATCH 18/99] remove cfg[test] --- halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs | 1 - 1 file changed, 1 deletion(-) 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 b62a8ae152..282ef6dc9a 100644 --- a/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs @@ -51,7 +51,6 @@ where // FIXME: calling construct_base is possibly(!) non-optimal let (x_a, y_a, zs_sum) = self.hash_all_pieces(region, offset, message, x_a, y_a)?; - #[cfg(test)] self.check_hash_result(EccPointQ::PrivatePoint(Q), message, x_a, y_a, zs_sum) } From 989f29bae96d974e1d3f0de77e95648108ac692f Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Thu, 25 Apr 2024 11:55:31 +0200 Subject: [PATCH 19/99] remove generator table trait, fix hash_to_point --- halo2_gadgets/Cargo.toml | 1 + halo2_gadgets/src/ecc.rs | 6 +- halo2_gadgets/src/ecc/chip.rs | 2 +- halo2_gadgets/src/ecc/chip/mul.rs | 6 +- halo2_gadgets/src/ecc_opt.rs | 23 +- .../src/ecc_opt/chip/mul_fixed/short.rs | 166 ++++++------ halo2_gadgets/src/sinsemilla.rs | 42 +-- halo2_gadgets/src/sinsemilla/chip.rs | 228 ++++++---------- .../src/sinsemilla/chip/generator_table.rs | 39 +-- .../src/sinsemilla/chip/hash_to_point.rs | 31 ++- halo2_gadgets/src/sinsemilla/merkle.rs | 31 +-- halo2_gadgets/src/sinsemilla/merkle/chip.rs | 233 ++++++----------- halo2_gadgets/src/sinsemilla_opt.rs | 53 ++-- halo2_gadgets/src/sinsemilla_opt/chip.rs | 78 +++++- .../sinsemilla_opt/chip/generator_table.rs | 185 ++++++------- .../src/sinsemilla_opt/chip/hash_to_point.rs | 8 +- halo2_gadgets/src/sinsemilla_opt/merkle.rs | 244 ++++++++++++++++++ .../src/sinsemilla_opt/merkle/chip.rs | 21 +- .../src/utilities/lookup_range_check.rs | 7 +- halo2_gadgets/src/utilities_opt/cond_swap.rs | 111 +------- .../src/utilities_opt/lookup_range_check.rs | 9 +- rust-toolchain.toml | 2 +- 22 files changed, 755 insertions(+), 771 deletions(-) diff --git a/halo2_gadgets/Cargo.toml b/halo2_gadgets/Cargo.toml index 09ab4efc84..1aa754264e 100644 --- a/halo2_gadgets/Cargo.toml +++ b/halo2_gadgets/Cargo.toml @@ -49,6 +49,7 @@ pprof = { version = "0.8", features = ["criterion", "flamegraph"] } # MSRV 1.56 bench = false [features] +default = ["test-dev-graph"] test-dev-graph = [ "halo2_proofs/dev-graph", "plotters", diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 2bd1491565..a03eaa141a 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -574,6 +574,7 @@ impl> FixedPointShort { Self { chip, inner } } } + #[cfg(test)] pub(crate) mod tests { use ff::PrimeField; @@ -594,7 +595,10 @@ pub(crate) mod tests { }, FixedPoints, }; - use crate::utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}; + use crate::{ + sinsemilla::primitives as sinsemilla, + utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, + }; #[derive(Debug, Eq, PartialEq, Clone)] pub(crate) struct TestFixedBases; diff --git a/halo2_gadgets/src/ecc/chip.rs b/halo2_gadgets/src/ecc/chip.rs index f581e625c6..df8e1bb124 100644 --- a/halo2_gadgets/src/ecc/chip.rs +++ b/halo2_gadgets/src/ecc/chip.rs @@ -74,7 +74,7 @@ impl EccPoint { } #[cfg(test)] - pub(crate) fn is_identity(&self) -> Value { + fn is_identity(&self) -> Value { self.x.value().map(|x| x.is_zero_vartime()) } } diff --git a/halo2_gadgets/src/ecc/chip/mul.rs b/halo2_gadgets/src/ecc/chip/mul.rs index 6408ae6a44..b4b6d55518 100644 --- a/halo2_gadgets/src/ecc/chip/mul.rs +++ b/halo2_gadgets/src/ecc/chip/mul.rs @@ -62,7 +62,7 @@ pub struct Config { } impl Config { - pub(super) fn configure( + pub(crate) fn configure( meta: &mut ConstraintSystem, add_config: add::Config, lookup_config: LookupRangeCheckConfig, @@ -461,13 +461,13 @@ pub mod tests { Curve, }; use halo2_proofs::{ - circuit::{Layouter, Value}, + circuit::{Chip, Layouter, Value}, plonk::Error, }; use pasta_curves::pallas; use rand::rngs::OsRng; - use crate::utilities::lookup_range_check::DefaultLookupRangeCheck; + use crate::utilities::lookup_range_check::{DefaultLookupRangeCheck, LookupRangeCheckConfig}; use crate::{ ecc::{ chip::{EccChip, EccPoint}, diff --git a/halo2_gadgets/src/ecc_opt.rs b/halo2_gadgets/src/ecc_opt.rs index 6f0203c384..253662a7ca 100644 --- a/halo2_gadgets/src/ecc_opt.rs +++ b/halo2_gadgets/src/ecc_opt.rs @@ -59,7 +59,6 @@ impl + Clone + Debug + Eq> }) } } - #[cfg(test)] pub(crate) mod tests { use ff::PrimeField; @@ -100,6 +99,19 @@ pub(crate) mod tests { find_zs_and_us(*BASE, NUM_WINDOWS_SHORT).unwrap(); } + impl FullWidth { + pub(crate) fn from_pallas_generator() -> Self { + FullWidth(*BASE, &ZS_AND_US) + } + + pub(crate) fn from_parts( + base: pallas::Affine, + zs_and_us: &'static [(u64, [pallas::Base; H])], + ) -> Self { + FullWidth(base, zs_and_us) + } + } + impl FixedPoint for FullWidth { type FixedScalarKind = FullScalar; @@ -226,6 +238,7 @@ pub(crate) mod tests { meta.advice_column(), ]; let lookup_table = meta.lookup_table_column(); + let table_range_check_tag = meta.lookup_table_column(); let lagrange_coeffs = [ meta.fixed_column(), meta.fixed_column(), @@ -240,8 +253,12 @@ pub(crate) mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); - let range_check = - LookupRangeCheckConfigOptimized::configure(meta, advices[9], lookup_table); + let range_check = LookupRangeCheckConfigOptimized::configure_with_tag( + meta, + advices[9], + lookup_table, + table_range_check_tag, + ); EccChip::< crate::ecc::tests::TestFixedBases, LookupRangeCheckConfigOptimized, diff --git a/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs index 65abba6291..927aea4858 100644 --- a/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs +++ b/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs @@ -76,7 +76,8 @@ impl> Config { #[cfg(test)] pub mod tests { - use group::{ff::PrimeField, Curve, Group}; + use ff::PrimeField; + use group::{Curve, Group}; use halo2_proofs::{ arithmetic::CurveAffine, circuit::{AssignedCell, Chip, Layouter, Value}, @@ -84,17 +85,84 @@ pub mod tests { }; use pasta_curves::pallas; - use crate::utilities::lookup_range_check::{DefaultLookupRangeCheck, LookupRangeCheck}; + use crate::ecc::tests::Short; + use crate::ecc::ScalarFixedShort; + use crate::utilities::lookup_range_check::DefaultLookupRangeCheck; use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; use crate::{ - ecc::{ - chip::{EccChip}, - tests::{Short, TestFixedBases}, - Point, ScalarFixedShort, + ecc::{chip::EccChip, tests::TestFixedBases, Point}, + utilities::{ + lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, + UtilitiesInstructions, }, - utilities::UtilitiesInstructions, }; + pub(crate) fn test_mul_sign( + chip: EccChip, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + // Generate a random non-identity point P + let p_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); + let p = Point::new( + chip.clone(), + layouter.namespace(|| "P"), + Value::known(p_val), + )?; + + // Create -P + let p_neg_val = -p_val; + let p_neg = Point::new( + chip.clone(), + layouter.namespace(|| "-P"), + Value::known(p_neg_val), + )?; + + // Create the identity point + let identity = Point::new( + chip.clone(), + layouter.namespace(|| "identity"), + Value::known(pallas::Point::identity().to_affine()), + )?; + + // Create -1 and 1 scalars + let pos_sign = chip.load_private( + layouter.namespace(|| "positive sign"), + chip.config().advices[0], + Value::known(pallas::Base::one()), + )?; + let neg_sign = chip.load_private( + layouter.namespace(|| "negative sign"), + chip.config().advices[1], + Value::known(-pallas::Base::one()), + )?; + + // [1] P == P + { + let result = p.mul_sign(layouter.namespace(|| "[1] P"), &pos_sign)?; + result.constrain_equal(layouter.namespace(|| "constrain [1] P"), &p)?; + } + + // [-1] P == -P + { + let result = p.mul_sign(layouter.namespace(|| "[1] P"), &neg_sign)?; + result.constrain_equal(layouter.namespace(|| "constrain [1] P"), &p_neg)?; + } + + // [1] 0 == 0 + { + let result = identity.mul_sign(layouter.namespace(|| "[1] O"), &pos_sign)?; + result.constrain_equal(layouter.namespace(|| "constrain [1] 0"), &identity)?; + } + + // [-1] 0 == 0 + { + let result = identity.mul_sign(layouter.namespace(|| "[-1] O"), &neg_sign)?; + result.constrain_equal(layouter.namespace(|| "constrain [1] 0"), &identity)?; + } + + Ok(()) + } + #[test] fn invalid_magnitude_sign() { use crate::{ @@ -144,6 +212,7 @@ pub mod tests { meta.advice_column(), ]; let lookup_table = meta.lookup_table_column(); + let table_range_check_tag = meta.lookup_table_column(); let lagrange_coeffs = [ meta.fixed_column(), meta.fixed_column(), @@ -159,8 +228,12 @@ pub mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); - let range_check = - LookupRangeCheckConfigOptimized::configure(meta, advices[9], lookup_table); + let range_check = LookupRangeCheckConfigOptimized::configure_with_tag( + meta, + advices[9], + lookup_table, + table_range_check_tag, + ); EccChip::< TestFixedBases, LookupRangeCheckConfigOptimized< @@ -363,72 +436,6 @@ pub mod tests { } } - pub(crate) fn test_mul_sign( - chip: EccChip, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // Generate a random non-identity point P - let p_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); - let p = Point::new( - chip.clone(), - layouter.namespace(|| "P"), - Value::known(p_val), - )?; - - // Create -P - let p_neg_val = -p_val; - let p_neg = Point::new( - chip.clone(), - layouter.namespace(|| "-P"), - Value::known(p_neg_val), - )?; - - // Create the identity point - let identity = Point::new( - chip.clone(), - layouter.namespace(|| "identity"), - Value::known(pallas::Point::identity().to_affine()), - )?; - - // Create -1 and 1 scalars - let pos_sign = chip.load_private( - layouter.namespace(|| "positive sign"), - chip.config().advices[0], - Value::known(pallas::Base::one()), - )?; - let neg_sign = chip.load_private( - layouter.namespace(|| "negative sign"), - chip.config().advices[1], - Value::known(-pallas::Base::one()), - )?; - - // [1] P == P - { - let result = p.mul_sign(layouter.namespace(|| "[1] P"), &pos_sign)?; - result.constrain_equal(layouter.namespace(|| "constrain [1] P"), &p)?; - } - - // [-1] P == -P - { - let result = p.mul_sign(layouter.namespace(|| "[1] P"), &neg_sign)?; - result.constrain_equal(layouter.namespace(|| "constrain [1] P"), &p_neg)?; - } - - // [1] 0 == 0 - { - let result = identity.mul_sign(layouter.namespace(|| "[1] O"), &pos_sign)?; - result.constrain_equal(layouter.namespace(|| "constrain [1] 0"), &identity)?; - } - - // [-1] 0 == 0 - { - let result = identity.mul_sign(layouter.namespace(|| "[-1] O"), &neg_sign)?; - result.constrain_equal(layouter.namespace(|| "constrain [1] 0"), &identity)?; - } - - Ok(()) - } - #[test] fn invalid_sign_in_mul_sign() { use crate::{ecc::chip::EccConfig, utilities::UtilitiesInstructions}; @@ -473,6 +480,7 @@ pub mod tests { meta.advice_column(), ]; let lookup_table = meta.lookup_table_column(); + let table_range_check_tag = meta.lookup_table_column(); let lagrange_coeffs = [ meta.fixed_column(), meta.fixed_column(), @@ -488,8 +496,12 @@ pub mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); - let range_check = - LookupRangeCheckConfigOptimized::configure(meta, advices[9], lookup_table); + let range_check = LookupRangeCheckConfigOptimized::configure_with_tag( + meta, + advices[9], + lookup_table, + table_range_check_tag, + ); EccChip::< TestFixedBases, LookupRangeCheckConfigOptimized< diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 7cbedd7a15..a3e2dc892b 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -78,13 +78,12 @@ pub trait SinsemillaInstructions, - is_Q_public: bool, Q: C, message: Self::Message, ) -> Result<(Self::NonIdentityPoint, Vec), Error>; @@ -316,19 +315,17 @@ where } #[allow(clippy::type_complexity)] - #[allow(non_snake_case)] /// $\mathsf{SinsemillaHashToPoint}$ from [§ 5.4.1.9][concretesinsemillahash]. /// /// [concretesinsemillahash]: https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash pub fn hash_to_point( &self, layouter: impl Layouter, - is_Q_public: bool, message: Message, ) -> Result<(ecc::NonIdentityPoint, Vec), Error> { assert_eq!(self.sinsemilla_chip, message.chip); self.sinsemilla_chip - .hash_to_point(layouter, is_Q_public, self.Q, message.inner) + .hash_to_point(layouter, self.Q, message.inner) .map(|(point, zs)| (ecc::NonIdentityPoint::from_inner(self.ecc_chip.clone(), point), zs)) } @@ -336,15 +333,13 @@ where /// /// [concretesinsemillahash]: https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash #[allow(clippy::type_complexity)] - #[allow(non_snake_case)] pub fn hash( &self, layouter: impl Layouter, - is_Q_public: bool, message: Message, ) -> Result<(ecc::X, Vec), Error> { assert_eq!(self.sinsemilla_chip, message.chip); - let (p, zs) = self.hash_to_point(layouter, is_Q_public, message)?; + let (p, zs) = self.hash_to_point(layouter, message)?; Ok((p.extract_p(), zs)) } } @@ -418,14 +413,12 @@ where } #[allow(clippy::type_complexity)] - #[allow(non_snake_case)] /// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. /// /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit pub fn commit( &self, mut layouter: impl Layouter, - is_Q_public: bool, message: Message, r: ecc::ScalarFixed, ) -> Result< @@ -443,26 +436,23 @@ where //let blind = self.blinding_factor(layouter.namespace(|| "[r] R"), r)?; //let (p, zs) = self.hash(layouter.namespace(|| "M"), message)?; let (blind, _) = self.R.mul(layouter.namespace(|| "[r] R"), r)?; - let (p, zs) = self.M.hash_to_point(layouter.namespace(|| "M"), is_Q_public, message)?; - + let (p, zs) = self.M.hash_to_point(layouter.namespace(|| "M"), message)?; let commitment = p.add(layouter.namespace(|| "M + [r] R"), &blind)?; Ok((commitment, zs)) } #[allow(clippy::type_complexity)] - #[allow(non_snake_case)] /// $\mathsf{SinsemillaShortCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. /// /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit pub fn short_commit( &self, mut layouter: impl Layouter, - is_Q_public: bool, message: Message, r: ecc::ScalarFixed, ) -> Result<(ecc::X, Vec), Error> { assert_eq!(self.M.sinsemilla_chip, message.chip); - let (p, zs) = self.commit(layouter.namespace(|| "commit"), is_Q_public, message, r)?; + let (p, zs) = self.commit(layouter.namespace(|| "commit"), message, r)?; Ok((p.extract_p(), zs)) } } @@ -490,7 +480,7 @@ pub(crate) mod tests { tests::{FullWidth, TestFixedBases}, NonIdentityPoint, }, - utilities::lookup_range_check::LookupRangeCheckConfig, + utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, }, }; @@ -498,8 +488,6 @@ pub(crate) mod tests { use lazy_static::lazy_static; use pasta_curves::pallas; - use crate::sinsemilla::chip::generator_table::GeneratorTableConfig; - use crate::utilities::lookup_range_check::LookupRangeCheck; use std::convert::TryInto; pub(crate) const PERSONALIZATION: &str = "MerkleCRH"; @@ -548,14 +536,12 @@ pub(crate) mod tests { TestCommitDomain, TestFixedBases, LookupRangeCheckConfig, - GeneratorTableConfig, >, SinsemillaConfig< TestHashDomain, TestCommitDomain, TestFixedBases, LookupRangeCheckConfig, - GeneratorTableConfig, >, ); type FloorPlanner = SimpleFloorPlanner; @@ -603,11 +589,6 @@ pub(crate) mod tests { ); let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx); - let table = GeneratorTableConfig { - table_idx: lookup.0, - table_x: lookup.1, - table_y: lookup.2, - }; let ecc_config = EccChip::< TestFixedBases, @@ -615,21 +596,19 @@ pub(crate) mod tests { >::configure(meta, advices, lagrange_coeffs, range_check); let config1 = SinsemillaChip::configure( - true, meta, advices[..5].try_into().unwrap(), advices[2], lagrange_coeffs[0], - table, + lookup, range_check, ); let config2 = SinsemillaChip::configure( - true, meta, advices[5..].try_into().unwrap(), advices[7], lagrange_coeffs[1], - table, + lookup, range_check, ); (ecc_config, config1, config2) @@ -650,7 +629,6 @@ pub(crate) mod tests { TestCommitDomain, TestFixedBases, LookupRangeCheckConfig, - GeneratorTableConfig, >::load(config.1.clone(), &mut layouter)?; // This MerkleCRH example is purely for illustrative purposes. @@ -718,7 +696,7 @@ pub(crate) mod tests { // Parent let (parent, _) = { let message = Message::from_pieces(chip1, vec![l, left, right]); - merkle_crh.hash_to_point(layouter.namespace(|| "parent"), true, message)? + merkle_crh.hash_to_point(layouter.namespace(|| "parent"), message)? }; parent.constrain_equal( @@ -748,7 +726,7 @@ pub(crate) mod tests { layouter.namespace(|| "witness message"), message.clone(), )?; - test_commit.commit(layouter.namespace(|| "commit"), true, message, r)? + test_commit.commit(layouter.namespace(|| "commit"), message, r)? }; // Witness expected result. diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs index d1e03c044d..4793a99da2 100644 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ b/halo2_gadgets/src/sinsemilla/chip.rs @@ -17,26 +17,25 @@ use halo2_proofs::{ circuit::{AssignedCell, Chip, Layouter, Value}, plonk::{ Advice, Column, ConstraintSystem, Constraints, Error, Expression, Fixed, Selector, - VirtualCells, + TableColumn, VirtualCells, }, poly::Rotation, }; use pasta_curves::pallas; -use pasta_curves::pallas::Base; + pub(crate) mod generator_table; -use crate::sinsemilla::chip::generator_table::{DefaultGeneratorTable}; +use generator_table::GeneratorTableConfig; pub(crate) mod hash_to_point; /// Configuration for the Sinsemilla hash chip #[derive(Eq, PartialEq, Clone, Debug)] -pub struct SinsemillaConfig +pub struct SinsemillaConfig where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { /// Binary selector used in lookup argument and in the body of the Sinsemilla hash. pub(crate) q_sinsemilla1: Selector, @@ -58,20 +57,19 @@ where pub(crate) witness_pieces: Column, /// The lookup table where $(\mathsf{idx}, x_p, y_p)$ are loaded for the $2^K$ /// generators of the Sinsemilla hash. - pub(crate) generator_table: GeneratorTableConfigType, + pub(crate) generator_table: GeneratorTableConfig, /// An advice column configured to perform lookup range checks. pub(crate) lookup_config: LookupRangeCheckConfig, - _marker: PhantomData<(Hash, Commit, F)>, + pub(crate) _marker: PhantomData<(Hash, Commit, F)>, } -impl - SinsemillaConfig +impl + SinsemillaConfig where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { /// Returns an array of all advice columns in this config, in arbitrary order. pub(super) fn advices(&self) -> [Column; 5] { @@ -101,28 +99,25 @@ where /// /// [Chip description](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html#plonk--halo-2-constraints). #[derive(Eq, PartialEq, Clone, Debug)] -pub struct SinsemillaChip +pub struct SinsemillaChip where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { - config: SinsemillaConfig, + config: SinsemillaConfig, } -impl Chip - for SinsemillaChip +impl Chip + for SinsemillaChip where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { - type Config = - SinsemillaConfig; + type Config = SinsemillaConfig; type Loaded = (); fn config(&self) -> &Self::Config { @@ -134,14 +129,13 @@ where } } -impl - SinsemillaChip +impl + SinsemillaChip where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { /// Reconstructs this chip from the given config. pub fn construct(config: >::Config) -> Self { @@ -150,55 +144,67 @@ where /// Loads the lookup table required by this chip into the circuit. pub fn load( - config: SinsemillaConfig, + config: SinsemillaConfig, layouter: &mut impl Layouter, ) -> Result<>::Loaded, Error> { // Load the lookup table. - config.generator_table.load(layouter) - } - /// Query a fixed value from the circuit's fixed column using the configuration `fixed_y_q`. - fn get_y_q_fixed( - meta: &mut VirtualCells, - config: &SinsemillaConfig< - Hash, - Commit, - F, - LookupRangeCheckConfig, - GeneratorTableConfigType, - >, - ) -> Expression { - meta.query_fixed(config.fixed_y_q) - } - - /// Query an advice value 'y_q' from a specific advice column `x_p` at the previous rotation. - fn get_y_q_advice( - meta: &mut VirtualCells, - config: &SinsemillaConfig< - Hash, - Commit, - F, - LookupRangeCheckConfig, - GeneratorTableConfigType, - >, - ) -> Expression { - meta.query_advice(config.double_and_add.x_p, Rotation::prev()) + 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)] - pub(crate) fn create_initial_y_q_gate( - is_Q_public: bool, + pub fn configure( meta: &mut ConstraintSystem, - config: &SinsemillaConfig< - Hash, - Commit, - F, - LookupRangeCheckConfig, - GeneratorTableConfigType, - >, - ) { + advices: [Column; 5], + witness_pieces: Column, + fixed_y_q: Column, + lookup: (TableColumn, TableColumn, TableColumn), + range_check: LookupRangeCheckConfig, + ) -> >::Config { + // FIXME: add comments + + // Enable equality on all advice columns + for advice in advices.iter() { + meta.enable_equality(*advice); + } + + let config = SinsemillaConfig:: { + q_sinsemilla1: meta.complex_selector(), + q_sinsemilla2: meta.fixed_column(), + q_sinsemilla4: meta.selector(), + fixed_y_q, + double_and_add: DoubleAndAdd { + x_a: advices[0], + x_p: advices[1], + lambda_1: advices[3], + lambda_2: advices[4], + }, + bits: advices[2], + witness_pieces, + generator_table: GeneratorTableConfig { + table_idx: lookup.0, + table_x: lookup.1, + table_y: lookup.2, + }, + lookup_config: range_check, + _marker: PhantomData, + }; + + // Set up lookup argument + GeneratorTableConfig::configure(meta, &config); + let two = pallas::Base::from(2); + // Closures for expressions that are derived multiple times + // x_r = lambda_1^2 - x_a - x_p + let x_r = |meta: &mut VirtualCells, rotation| { + config.double_and_add.x_r(meta, rotation) + }; + // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) let Y_A = |meta: &mut VirtualCells, rotation| { config.double_and_add.Y_A(meta, rotation) @@ -208,13 +214,11 @@ where // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial meta.create_gate("Initial y_Q", |meta| { let q_s4 = meta.query_selector(config.q_sinsemilla4); - // fixme: how to change to optimized get_y_q in a simple way? - let y_q = if is_Q_public { - Self::get_y_q_fixed(meta, &config) + let y_q = if LookupRangeCheckConfig::is_optimized() { + meta.query_advice(config.double_and_add.x_p, Rotation::prev()) } else { - Self::get_y_q_advice(meta, &config) + meta.query_fixed(config.fixed_y_q) }; - // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) let Y_A_cur = Y_A(meta, Rotation::cur()); @@ -223,31 +227,6 @@ where Constraints::with_selector(q_s4, Some(("init_y_q_check", init_y_q_check))) }); - } - - #[allow(non_snake_case)] - pub(crate) fn create_sinsemilla_gate( - meta: &mut ConstraintSystem, - config: &SinsemillaConfig< - Hash, - Commit, - F, - LookupRangeCheckConfig, - GeneratorTableConfigType, - >, - ) { - let two = pallas::Base::from(2); - - // Closures for expressions that are derived multiple times - // x_r = lambda_1^2 - x_a - x_p - let x_r = |meta: &mut VirtualCells, rotation| { - config.double_and_add.x_r(meta, rotation) - }; - - // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) - let Y_A = |meta: &mut VirtualCells, rotation| { - config.double_and_add.Y_A(meta, rotation) - }; // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial meta.create_gate("Sinsemilla gate", |meta| { @@ -293,82 +272,20 @@ where Constraints::with_selector(q_s1, [("Secant line", secant_line), ("y check", y_check)]) }); - } - - pub(crate) fn create_config( - meta: &mut ConstraintSystem, - advices: [Column; 5], - witness_pieces: Column, - fixed_y_q: Column, - table: GeneratorTableConfigType, - range_check: LookupRangeCheckConfig, - ) -> >::Config { - // Enable equality on all advice columns - for advice in advices.iter() { - meta.enable_equality(*advice); - } - - let config = - SinsemillaConfig:: { - q_sinsemilla1: meta.complex_selector(), - q_sinsemilla2: meta.fixed_column(), - q_sinsemilla4: meta.selector(), - fixed_y_q, - double_and_add: DoubleAndAdd { - x_a: advices[0], - x_p: advices[1], - lambda_1: advices[3], - lambda_2: advices[4], - }, - bits: advices[2], - witness_pieces, - // todo: check - generator_table: table, - lookup_config: range_check, - _marker: PhantomData, - }; - - // Set up lookup argument - config.generator_table.configure(meta, &config); - - config - } - - /// # Side-effects - /// - /// All columns in `advices` and will be equality-enabled. - #[allow(clippy::too_many_arguments)] - #[allow(non_snake_case)] - pub fn configure( - is_Q_public: bool, - meta: &mut ConstraintSystem, - advices: [Column; 5], - witness_pieces: Column, - fixed_y_q: Column, - table: GeneratorTableConfigType, - range_check: LookupRangeCheckConfig, - ) -> >::Config { - let config = - Self::create_config(meta, advices, witness_pieces, fixed_y_q, table, range_check); - - Self::create_initial_y_q_gate(is_Q_public, meta, &config); - - Self::create_sinsemilla_gate(meta, &config); config } } // Implement `SinsemillaInstructions` for `SinsemillaChip` -impl +impl SinsemillaInstructions - for SinsemillaChip + for SinsemillaChip where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { type CellValue = AssignedCell; @@ -411,13 +328,12 @@ where fn hash_to_point( &self, mut layouter: impl Layouter, - is_Q_public: bool, Q: pallas::Affine, message: Self::Message, ) -> Result<(Self::NonIdentityPoint, Vec), Error> { layouter.assign_region( || "hash_to_point", - |mut region| self.hash_message(is_Q_public, &mut region, Q, &message), + |mut region| self.hash_message(&mut region, Q, &message), ) } diff --git a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs index 463cc4f323..ed7cc9e554 100644 --- a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs +++ b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs @@ -4,9 +4,9 @@ use halo2_proofs::{ plonk::{ConstraintSystem, Error, Expression, TableColumn}, poly::Rotation, }; -use std::fmt::Debug; use super::{CommitDomains, FixedPoints, HashDomains}; +use crate::utilities::lookup_range_check::LookupRangeCheckConfig; use crate::{ sinsemilla::primitives::{self as sinsemilla, SINSEMILLA_S}, utilities::lookup_range_check::DefaultLookupRangeCheck, @@ -21,36 +21,25 @@ pub struct GeneratorTableConfig { pub table_y: TableColumn, } -/// FIXME: add doc -pub trait GeneratorTable { - fn config(&self) -> &GeneratorTableConfig; - +impl GeneratorTableConfig { #[allow(clippy::too_many_arguments)] #[allow(non_snake_case)] /// Even though the lookup table can be used in other parts of the circuit, /// this specific configuration sets up Sinsemilla-specific constraints /// controlled by `q_sinsemilla`, and would likely not apply to other chips. - fn configure( - &self, + pub fn configure( meta: &mut ConstraintSystem, - config: &super::SinsemillaConfig< - Hash, - Commit, - F, - LookupRangeCheckConfig, - GeneratorTableConfigType, - >, + config: &super::SinsemillaConfig, ) where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { let (table_idx, table_x, table_y) = ( - self.config().table_idx, - self.config().table_x, - self.config().table_y, + config.generator_table.table_idx, + config.generator_table.table_x, + config.generator_table.table_y, ); // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial @@ -93,14 +82,7 @@ pub trait GeneratorTable { }); } - fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error>; -} -impl GeneratorTable for GeneratorTableConfig { - fn config(&self) -> &GeneratorTableConfig { - self - } - - fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { + pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { layouter.assign_table( || "generator_table", |mut table| { @@ -119,8 +101,3 @@ impl GeneratorTable for GeneratorTableConfig { ) } } - -/// FIXME: add doc -pub trait DefaultGeneratorTable: GeneratorTable + Eq + PartialEq + Clone + Copy + Debug {} - -impl DefaultGeneratorTable for GeneratorTableConfig {} diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index c7ca71a4c8..1bb1ce9ed6 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -1,5 +1,5 @@ use super::super::{CommitDomains, HashDomains, SinsemillaInstructions}; -use super::{NonIdentityEccPoint, SinsemillaChip}; +use super::{NonIdentityEccPoint, SinsemillaChip, SinsemillaConfig}; use crate::{ ecc::FixedPoints, sinsemilla::primitives::{self as sinsemilla, lebs2ip_k, INV_TWO_POW_K, SINSEMILLA_S}, @@ -15,7 +15,6 @@ use halo2_proofs::{ use group::ff::{PrimeField, PrimeFieldBits}; use pasta_curves::{arithmetic::CurveAffine, pallas}; -use crate::sinsemilla::chip::generator_table::DefaultGeneratorTable; use std::ops::Deref; /// Define an enum that can hold either type @@ -25,21 +24,19 @@ pub enum EccPointQ<'a> { PrivatePoint(&'a NonIdentityEccPoint), } -impl - SinsemillaChip +impl + SinsemillaChip where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). #[allow(non_snake_case)] #[allow(clippy::type_complexity)] pub(super) fn hash_message( &self, - is_Q_public: bool, region: &mut Region<'_, pallas::Base>, Q: pallas::Affine, message: & { - // todo: add doc about is_Q_public - let (offset, x_a, y_a) = if is_Q_public { - self.public_initialization_vanilla(region, Q)? - } else { + // todo: add doc about LookupRangeCheckConfig::is_optimized() + //let (offset, x_a, y_a) = self.public_initialization(region, Q)?; + let (offset, x_a, y_a) = if LookupRangeCheckConfig::is_optimized() { self.public_initialization(region, Q)? + } else { + self.public_initialization_vanilla(region, Q)? }; let (x_a, y_a, zs_sum) = self.hash_all_pieces(region, offset, message, x_a, y_a)?; @@ -66,7 +64,6 @@ where self.check_hash_result(EccPointQ::PublicPoint(Q), message, x_a, y_a, zs_sum) } - #[cfg(test)] #[allow(non_snake_case)] // Check equivalence to result from primitives::sinsemilla::hash_to_point pub(crate) fn check_hash_result( @@ -88,7 +85,6 @@ where Error, > { #[cfg(test)] - #[allow(non_snake_case)] { use crate::sinsemilla::primitives::{K, S_PERSONALIZATION}; @@ -112,7 +108,9 @@ where // Get message as a bitstring. let bitstring: Vec = field_elems .iter() - .flat_map(|(elem, num_words)| elem.to_le_bits().into_iter().take(K * num_words)) + .flat_map(|(elem, num_words)| { + elem.to_le_bits().into_iter().take(K * num_words) + }) .collect(); let hasher_S = pallas::Point::hash_to_curve(S_PERSONALIZATION); @@ -123,12 +121,12 @@ where let expected_point = bitstring .chunks(K) .fold(value_Q.to_curve(), |acc, chunk| (acc + S(chunk)) + acc); - let actual_point = pallas::Affine::from_xy(x_a.evaluate(), y_a.evaluate()).unwrap(); + let actual_point = + pallas::Affine::from_xy(x_a.evaluate(), y_a.evaluate()).unwrap(); expected_point.to_affine() == actual_point }); } - 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())?; @@ -139,7 +137,8 @@ where } #[allow(non_snake_case)] - /// Assign the coordinates of the initial public point `Q` + /// Assign the coordinates of the initial public point `Q`, + /// y_Q to a fixed column /// /// | offset | x_A | q_sinsemilla4 | fixed_y_q | /// -------------------------------------- diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 3b85ac807c..1485c466f1 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -36,7 +36,6 @@ pub trait MerkleInstructions< fn hash_layer( &self, layouter: impl Layouter, - is_Q_public: bool, Q: C, l: usize, left: Self::Var, @@ -57,11 +56,11 @@ pub struct MerklePath< > where MerkleChip: MerkleInstructions + Clone, { - chips: [MerkleChip; PAR], - domain: MerkleChip::HashDomains, - leaf_pos: Value, + pub(crate) chips: [MerkleChip; PAR], + pub(crate) domain: MerkleChip::HashDomains, + pub(crate) leaf_pos: Value, // The Merkle path is ordered from leaves to root. - path: Value<[C::Base; PATH_LENGTH]>, + pub(crate) path: Value<[C::Base; PATH_LENGTH]>, } impl< @@ -118,7 +117,6 @@ where pub fn calculate_root( &self, mut layouter: impl Layouter, - is_Q_public: bool, leaf: MerkleChip::Var, ) -> Result { // Each chip processes `ceil(PATH_LENGTH / PAR)` layers. @@ -161,7 +159,6 @@ where // M^l_i = MerkleCRH(l, M^{l+1}_{2i}, M^{l+1}_{2i+1}) node = chip.hash_layer( layouter.namespace(|| format!("MerkleCRH({}, left, right)", l)), - is_Q_public, Q, l, pair.0, @@ -202,7 +199,6 @@ pub mod tests { plonk::{Circuit, ConstraintSystem, Error}, }; - use crate::sinsemilla::chip::generator_table::GeneratorTableConfig; use rand::{rngs::OsRng, RngCore}; use std::{convert::TryInto, iter}; @@ -222,14 +218,12 @@ pub mod tests { TestCommitDomain, TestFixedBases, LookupRangeCheckConfig, - GeneratorTableConfig, >, MerkleConfig< TestHashDomain, TestCommitDomain, TestFixedBases, LookupRangeCheckConfig, - GeneratorTableConfig, >, ); type FloorPlanner = SimpleFloorPlanner; @@ -268,32 +262,24 @@ pub mod tests { meta.lookup_table_column(), ); - let table = GeneratorTableConfig { - table_idx: lookup.0, - table_x: lookup.1, - table_y: lookup.2, - }; - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup.0); let sinsemilla_config_1 = SinsemillaChip::configure( - true, meta, advices[5..].try_into().unwrap(), advices[7], fixed_y_q_1, - table, + lookup, range_check, ); let config1 = MerkleChip::configure(meta, sinsemilla_config_1); let sinsemilla_config_2 = SinsemillaChip::configure( - true, meta, advices[..5].try_into().unwrap(), advices[2], fixed_y_q_2, - table, + lookup, range_check, ); let config2 = MerkleChip::configure(meta, sinsemilla_config_2); @@ -312,7 +298,6 @@ pub mod tests { TestCommitDomain, TestFixedBases, LookupRangeCheckConfig, - GeneratorTableConfig, >::load(config.0.sinsemilla_config.clone(), &mut layouter)?; // Construct Merkle chips which will be placed side-by-side in the circuit. @@ -333,7 +318,7 @@ pub mod tests { }; let computed_final_root = - path.calculate_root(layouter.namespace(|| "calculate root"), true, leaf)?; + path.calculate_root(layouter.namespace(|| "calculate root"), leaf)?; self.leaf .zip(self.leaf_pos) @@ -422,7 +407,7 @@ pub mod tests { let circuit = MyCircuit::default(); halo2_proofs::dev::CircuitLayout::default() - .show_labels(false) + .show_labels(true) .render(11, &circuit, &root) .unwrap(); } diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs index 685d338490..dc7fb3f6f8 100644 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla/merkle/chip.rs @@ -9,7 +9,6 @@ use pasta_curves::pallas; use super::MerkleInstructions; -use crate::sinsemilla::chip::generator_table::{DefaultGeneratorTable}; use crate::{ sinsemilla::{primitives as sinsemilla, MessagePiece}, utilities::{lookup_range_check::DefaultLookupRangeCheck, RangeConstrained}, @@ -29,19 +28,17 @@ use group::ff::PrimeField; /// Configuration for the `MerkleChip` implementation. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct MerkleConfig +pub struct MerkleConfig where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { advices: [Column; 5], q_decompose: Selector, pub(crate) cond_swap_config: CondSwapConfig, - pub(crate) sinsemilla_config: - SinsemillaConfig, + pub(crate) sinsemilla_config: SinsemillaConfig, } /// Chip implementing `MerkleInstructions`. @@ -55,28 +52,25 @@ where /// This chip does **NOT** constrain `left⋆` and `right⋆` to be canonical encodings of /// `left` and `right`. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct MerkleChip +pub struct MerkleChip where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { - config: MerkleConfig, + config: MerkleConfig, } -impl Chip - for MerkleChip +impl Chip + for MerkleChip where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { - type Config = - MerkleConfig; + type Config = MerkleConfig; type Loaded = (); fn config(&self) -> &Self::Config { @@ -88,26 +82,18 @@ where } } -impl - MerkleChip +impl MerkleChip where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { /// Configures the [`MerkleChip`]. pub fn configure( meta: &mut ConstraintSystem, - sinsemilla_config: SinsemillaConfig< - Hash, - Commit, - F, - LookupRangeCheckConfig, - GeneratorTableConfigType, - >, - ) -> MerkleConfig { + sinsemilla_config: SinsemillaConfig, + ) -> MerkleConfig { // All five advice columns are equality-enabled by SinsemillaConfig. let advices = sinsemilla_config.advices(); let cond_swap_config = CondSwapChip::configure(meta, advices); @@ -210,34 +196,24 @@ where } /// Constructs a [`MerkleChip`] given a [`MerkleConfig`]. - pub fn construct( - config: MerkleConfig, - ) -> Self { + pub fn construct(config: MerkleConfig) -> Self { MerkleChip { config } } } -impl< - Hash, - Commit, - F, - LookupRangeCheckConfig, - GeneratorTableConfigType, - const MERKLE_DEPTH: usize, - > MerkleInstructions - for MerkleChip +impl + MerkleInstructions + for MerkleChip where Hash: HashDomains + Eq, F: FixedPoints, Commit: CommitDomains + Eq, LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { #[allow(non_snake_case)] fn hash_layer( &self, mut layouter: impl Layouter, - is_Q_public: bool, Q: pallas::Affine, // l = MERKLE_DEPTH - layer - 1 l: usize, @@ -329,7 +305,6 @@ where // https://p.z.cash/proto:merkle-crh-orchard let (point, zs) = self.hash_to_point( layouter.namespace(|| format!("hash at l = {}", l)), - is_Q_public, Q, vec![a.inner(), b.inner(), c.inner()].into(), )?; @@ -446,28 +421,24 @@ where } } -impl - UtilitiesInstructions - for MerkleChip +impl UtilitiesInstructions + for MerkleChip where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { type Var = AssignedCell; } -impl - CondSwapInstructions - for MerkleChip +impl CondSwapInstructions + for MerkleChip where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { #[allow(clippy::type_complexity)] fn swap( @@ -482,108 +453,71 @@ where } } -impl +impl SinsemillaInstructions - for MerkleChip + for MerkleChip where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { - type CellValue = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::CellValue; - - type Message = as SinsemillaInstructions>::Message; - type MessagePiece = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::MessagePiece; - type RunningSum = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::RunningSum; - - type X = as SinsemillaInstructions< + type CellValue = + as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::CellValue; + + type Message = + as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::Message; + type MessagePiece = + as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::MessagePiece; + type RunningSum = + as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::RunningSum; + + type X = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::X; - type NonIdentityPoint = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::NonIdentityPoint; - type FixedPoints = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::FixedPoints; - - type HashDomains = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::HashDomains; - type CommitDomains = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::CommitDomains; + type NonIdentityPoint = + as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::NonIdentityPoint; + type FixedPoints = + as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::FixedPoints; + + type HashDomains = + as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::HashDomains; + type CommitDomains = + as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::CommitDomains; fn witness_message_piece( &self, @@ -592,13 +526,7 @@ where num_words: usize, ) -> Result { let config = self.config().sinsemilla_config.clone(); - let chip = SinsemillaChip::< - Hash, - Commit, - F, - LookupRangeCheckConfig, - GeneratorTableConfigType, - >::construct(config); + let chip = SinsemillaChip::::construct(config); chip.witness_message_piece(layouter, value, num_words) } @@ -607,24 +535,15 @@ where fn hash_to_point( &self, layouter: impl Layouter, - is_Q_public: bool, Q: pallas::Affine, message: Self::Message, ) -> Result<(Self::NonIdentityPoint, Vec>), Error> { let config = self.config().sinsemilla_config.clone(); - let chip = SinsemillaChip::< - Hash, - Commit, - F, - LookupRangeCheckConfig, - GeneratorTableConfigType, - >::construct(config); - chip.hash_to_point(layouter, is_Q_public, Q, message) + let chip = SinsemillaChip::::construct(config); + chip.hash_to_point(layouter, Q, message) } fn extract(point: &Self::NonIdentityPoint) -> Self::X { - SinsemillaChip::::extract( - point, - ) + SinsemillaChip::::extract(point) } } diff --git a/halo2_gadgets/src/sinsemilla_opt.rs b/halo2_gadgets/src/sinsemilla_opt.rs index 8948283c62..cca2af19f8 100644 --- a/halo2_gadgets/src/sinsemilla_opt.rs +++ b/halo2_gadgets/src/sinsemilla_opt.rs @@ -5,6 +5,7 @@ use std::fmt::Debug; use pasta_curves::arithmetic::CurveAffine; +use pasta_curves::pallas; use halo2_proofs::{circuit::Layouter, plonk::Error}; @@ -78,13 +79,11 @@ where + Eq, { #[allow(clippy::type_complexity)] - #[allow(non_snake_case)] /// Evaluates the Sinsemilla hash of `message` from the public initial point `Q` stored /// into `CommitDomain`. pub fn hash( &self, layouter: impl Layouter, - is_Q_public: bool, message: Message, ) -> Result< ( @@ -94,7 +93,7 @@ where Error, > { assert_eq!(self.M.sinsemilla_chip, message.chip); - self.M.hash_to_point(layouter, is_Q_public, message) + self.M.hash_to_point(layouter, message) } #[allow(non_snake_case)] @@ -160,6 +159,7 @@ pub(crate) mod tests { tests::{FullWidth, TestFixedBases}, NonIdentityPoint, }, + utilities::lookup_range_check::LookupRangeCheckConfig, }, }; @@ -167,9 +167,7 @@ pub(crate) mod tests { use lazy_static::lazy_static; use pasta_curves::pallas; - use crate::sinsemilla::chip::generator_table::GeneratorTableConfig; - use crate::sinsemilla_opt::chip::generator_table::GeneratorTableConfigOptimized; - use crate::utilities::lookup_range_check::LookupRangeCheck; + use crate::sinsemilla_opt::chip::SinsemillaChipOptimized; use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; use std::convert::TryInto; @@ -219,14 +217,12 @@ pub(crate) mod tests { TestCommitDomain, TestFixedBases, LookupRangeCheckConfigOptimized, - GeneratorTableConfigOptimized, >, SinsemillaConfig< TestHashDomain, TestCommitDomain, TestFixedBases, LookupRangeCheckConfigOptimized, - GeneratorTableConfigOptimized, >, ); type FloorPlanner = SimpleFloorPlanner; @@ -255,6 +251,7 @@ pub(crate) mod tests { meta.enable_constant(constants); 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(), @@ -266,25 +263,19 @@ pub(crate) mod tests { meta.fixed_column(), ]; - // todo: check the lookup.3 and LookupRangeCheckConfigOptimized::configure, to see if one more column is created // Fixed columns for the Sinsemilla generator lookup table let lookup = ( table_idx, meta.lookup_table_column(), meta.lookup_table_column(), - meta.lookup_table_column(), ); - let range_check = - LookupRangeCheckConfigOptimized::configure(meta, advices[9], table_idx); - let table = GeneratorTableConfigOptimized { - base: GeneratorTableConfig { - table_idx: lookup.0, - table_x: lookup.1, - table_y: lookup.2, - }, - table_range_check_tag: lookup.3, - }; + let range_check = LookupRangeCheckConfigOptimized::configure_with_tag( + meta, + advices[9], + table_idx, + table_range_check_tag, + ); let ecc_config = EccChip::< TestFixedBases, @@ -292,21 +283,19 @@ pub(crate) mod tests { >::configure(meta, advices, lagrange_coeffs, range_check); let config1 = SinsemillaChip::configure( - false, meta, advices[..5].try_into().unwrap(), advices[2], lagrange_coeffs[0], - table, + lookup, range_check, ); let config2 = SinsemillaChip::configure( - false, meta, advices[5..].try_into().unwrap(), advices[7], lagrange_coeffs[1], - table, + lookup, range_check, ); (ecc_config, config1, config2) @@ -321,14 +310,12 @@ pub(crate) mod tests { let ecc_chip = EccChip::construct(config.0); + // todo: check SinsemillaChipOptimized::load // The two `SinsemillaChip`s share the same lookup table. - SinsemillaChip::< - TestHashDomain, - TestCommitDomain, - TestFixedBases, - LookupRangeCheckConfigOptimized, - GeneratorTableConfigOptimized, - >::load(config.1.clone(), &mut layouter)?; + SinsemillaChipOptimized::::load( + config.1.clone(), + &mut layouter, + )?; // This MerkleCRH example is purely for illustrative purposes. // It is not an implementation of the Orchard protocol spec. @@ -395,7 +382,7 @@ pub(crate) mod tests { // Parent let (parent, _) = { let message = Message::from_pieces(chip1, vec![l, left, right]); - merkle_crh.hash_to_point(layouter.namespace(|| "parent"), false, message)? + merkle_crh.hash_to_point(layouter.namespace(|| "parent"), message)? }; parent.constrain_equal( @@ -425,7 +412,7 @@ pub(crate) mod tests { layouter.namespace(|| "witness message"), message.clone(), )?; - test_commit.commit(layouter.namespace(|| "commit"), false, message, r)? + test_commit.commit(layouter.namespace(|| "commit"), message, r)? }; // Witness expected result. diff --git a/halo2_gadgets/src/sinsemilla_opt/chip.rs b/halo2_gadgets/src/sinsemilla_opt/chip.rs index 1fa6bc582f..909ad21f7c 100644 --- a/halo2_gadgets/src/sinsemilla_opt/chip.rs +++ b/halo2_gadgets/src/sinsemilla_opt/chip.rs @@ -1,35 +1,40 @@ //! Chip implementations for the Sinsemilla gadgets. use super::SinsemillaInstructionsOptimized; -use crate::sinsemilla::chip::generator_table::{DefaultGeneratorTable}; -use crate::utilities::lookup_range_check::{DefaultLookupRangeCheck}; +use crate::utilities::lookup_range_check::DefaultLookupRangeCheck; use crate::{ - ecc::{FixedPoints}, + ecc::{chip::NonIdentityEccPoint, FixedPoints}, sinsemilla::{ - chip::{SinsemillaChip}, - primitives as sinsemilla, CommitDomains, HashDomains, + chip::{SinsemillaChip, SinsemillaConfig}, + message::{Message, MessagePiece}, + primitives as sinsemilla, CommitDomains, HashDomains, SinsemillaInstructions, }, + utilities_opt::lookup_range_check::DefaultLookupRangeCheckConfigOptimized, }; +use halo2_proofs::plonk::Expression; use halo2_proofs::{ - circuit::{Layouter}, - plonk::Error, + circuit::{AssignedCell, Chip, Layouter, Value}, + plonk::{ + Advice, Column, ConstraintSystem, Constraints, Error, Fixed, TableColumn, VirtualCells, + }, + poly::Rotation, }; use pasta_curves::pallas; +use pasta_curves::pallas::Base; pub(crate) mod generator_table; mod hash_to_point; // Implement `SinsemillaInstructionsOptimized` for `SinsemillaChip` -impl +impl SinsemillaInstructionsOptimized - for SinsemillaChip + for SinsemillaChip where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { #[allow(non_snake_case)] #[allow(clippy::type_complexity)] @@ -45,3 +50,56 @@ where ) } } + +/// A chip that implements 10-bit Sinsemilla using a lookup table and 5 advice columns. +/// +/// [Chip description](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html#plonk--halo-2-constraints). +#[derive(Eq, PartialEq, Clone, Debug)] +pub struct SinsemillaChipOptimized +where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, +{ + inner: SinsemillaChip, +} + +// FIXME: is this needed? +impl Chip for SinsemillaChipOptimized +where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, +{ + type Config = SinsemillaConfig; + type Loaded = (); + + fn config(&self) -> &Self::Config { + self.inner.config() + } + + fn loaded(&self) -> &Self::Loaded { + &() + } +} + +impl SinsemillaChipOptimized +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, +{ + /// Loads the lookup table required by this chip into the circuit. + pub fn load( + config: SinsemillaConfig, + layouter: &mut impl Layouter, + ) -> Result<>::Loaded, Error> { + // Load the lookup table. + generator_table::load_with_tag( + &config.generator_table, + // FIXME: consider to remove Option arount tag + config.lookup_config.table_range_check_tag(), + layouter, + ) + } +} diff --git a/halo2_gadgets/src/sinsemilla_opt/chip/generator_table.rs b/halo2_gadgets/src/sinsemilla_opt/chip/generator_table.rs index 6a582dddde..fc87e48c07 100644 --- a/halo2_gadgets/src/sinsemilla_opt/chip/generator_table.rs +++ b/halo2_gadgets/src/sinsemilla_opt/chip/generator_table.rs @@ -2,133 +2,110 @@ use halo2_proofs::{ circuit::{Layouter, Value}, plonk::{Error, TableColumn}, }; -use std::fmt::Debug; use pasta_curves::pallas; -use crate::sinsemilla::chip::generator_table::{DefaultGeneratorTable, GeneratorTable}; use crate::sinsemilla::{ chip::generator_table::GeneratorTableConfig, primitives::{K, SINSEMILLA_S}, }; -/// Table containing independent generators S[0..2^k] -#[derive(Eq, PartialEq, Copy, Clone, Debug)] -pub struct GeneratorTableConfigOptimized { - pub(crate) base: GeneratorTableConfig, - pub(crate) table_range_check_tag: TableColumn, -} -impl GeneratorTable for GeneratorTableConfigOptimized { - fn config(&self) -> &GeneratorTableConfig { - &self.base - } +/// 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( + config: &GeneratorTableConfig, + 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", + config.table_idx, + index, + || Value::known(pallas::Base::from(index as u64)), + )?; + table.assign_cell(|| "table_x", config.table_x, index, || Value::known(*x))?; + table.assign_cell(|| "table_y", config.table_y, index, || Value::known(*y))?; - /// 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, 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_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.config().table_idx, - index, + config.table_idx, + new_index, || Value::known(pallas::Base::from(index as u64)), )?; table.assign_cell( || "table_x", - self.config().table_x, - index, + config.table_x, + new_index, || Value::known(*x), )?; table.assign_cell( || "table_y", - self.config().table_y, - index, + config.table_y, + new_index, || Value::known(*y), )?; table.assign_cell( || "table_range_check_tag", - self.table_range_check_tag, - index, - || Value::known(pallas::Base::zero()), + table_range_check_tag, + new_index, + || Value::known(pallas::Base::from(4_u64)), )?; - if index < (1 << 4) { - let new_index = index + (1 << K); - table.assign_cell( - || "table_idx", - self.config().table_idx, - new_index, - || Value::known(pallas::Base::from(index as u64)), - )?; - table.assign_cell( - || "table_x", - self.config().table_x, - new_index, - || Value::known(*x), - )?; - table.assign_cell( - || "table_y", - self.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", - self.config().table_idx, - new_index, - || Value::known(pallas::Base::from(index as u64)), - )?; - table.assign_cell( - || "table_x", - self.config().table_x, - new_index, - || Value::known(*x), - )?; - table.assign_cell( - || "table_y", - self.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(()) - }, - ) - } + if index < (1 << 5) { + let new_index = index + (1 << 10) + (1 << 4); + table.assign_cell( + || "table_idx", + config.table_idx, + new_index, + || Value::known(pallas::Base::from(index as u64)), + )?; + table.assign_cell( + || "table_x", + config.table_x, + new_index, + || Value::known(*x), + )?; + table.assign_cell( + || "table_y", + config.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(()) + }, + ) } - -pub(crate) type DefaultGeneratorTableConfigOptimized = GeneratorTableConfigOptimized; - -impl DefaultGeneratorTable for DefaultGeneratorTableConfigOptimized {} 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 282ef6dc9a..469a5991e1 100644 --- a/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs @@ -5,7 +5,6 @@ use halo2_proofs::{ plonk::{Assigned, Error}, }; -use crate::sinsemilla::chip::generator_table::DefaultGeneratorTable; use crate::sinsemilla::chip::hash_to_point::EccPointQ; use crate::sinsemilla::chip::SinsemillaChip; use crate::utilities::lookup_range_check::DefaultLookupRangeCheck; @@ -18,14 +17,13 @@ use crate::{ }, }; -impl - SinsemillaChip +impl + SinsemillaChip where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). #[allow(non_snake_case)] @@ -55,7 +53,7 @@ where } #[allow(non_snake_case)] - /// Assign the coordinates of the initial public point `Q` + /// Assign the coordinates of the initial public point `Q` to advice columns /// /// | offset | x_A | x_P | q_sinsemilla4 | /// -------------------------------------- diff --git a/halo2_gadgets/src/sinsemilla_opt/merkle.rs b/halo2_gadgets/src/sinsemilla_opt/merkle.rs index 2927585229..69d43a5c6d 100644 --- a/halo2_gadgets/src/sinsemilla_opt/merkle.rs +++ b/halo2_gadgets/src/sinsemilla_opt/merkle.rs @@ -1,3 +1,247 @@ //! Gadgets for implementing a Merkle tree with Sinsemilla. pub mod chip; + +#[cfg(test)] +pub mod tests { + + use crate::{ + ecc::tests::TestFixedBases, + sinsemilla::{ + chip::SinsemillaChip, + tests::{TestCommitDomain, TestHashDomain}, + HashDomains, + }, + utilities::{i2lebsp, lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions}, + }; + + use group::ff::{Field, PrimeField, PrimeFieldBits}; + use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner, Value}, + dev::MockProver, + pasta::pallas, + plonk::{Circuit, ConstraintSystem, Error}, + }; + + use crate::sinsemilla::merkle::chip::{MerkleChip, MerkleConfig}; + use crate::sinsemilla::merkle::MerklePath; + use crate::sinsemilla_opt::chip::SinsemillaChipOptimized; + use crate::utilities::lookup_range_check::LookupRangeCheck; + use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; + use rand::{rngs::OsRng, RngCore}; + use std::{convert::TryInto, iter}; + + const MERKLE_DEPTH: usize = 32; + + #[derive(Default)] + struct MyCircuit { + leaf: Value, + leaf_pos: Value, + merkle_path: Value<[pallas::Base; MERKLE_DEPTH]>, + } + + impl Circuit for MyCircuit { + type Config = ( + MerkleConfig< + TestHashDomain, + TestCommitDomain, + TestFixedBases, + LookupRangeCheckConfigOptimized, + >, + MerkleConfig< + TestHashDomain, + TestCommitDomain, + TestFixedBases, + LookupRangeCheckConfigOptimized, + >, + ); + 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(), + ]; + + // Shared fixed column for loading constants + let constants = meta.fixed_column(); + meta.enable_constant(constants); + + // NB: In the actual Action circuit, these fixed columns will be reused + // by other chips. For this test, we are creating new fixed columns. + let fixed_y_q_1 = meta.fixed_column(); + let fixed_y_q_2 = meta.fixed_column(); + + // Fixed columns for the Sinsemilla generator lookup table + let lookup = ( + meta.lookup_table_column(), + meta.lookup_table_column(), + meta.lookup_table_column(), + ); + let table_range_check_tag = meta.lookup_table_column(); + + let range_check = LookupRangeCheckConfigOptimized::configure_with_tag( + meta, + advices[9], + lookup.0, + table_range_check_tag, + ); + + let sinsemilla_config_1 = SinsemillaChip::configure( + meta, + advices[5..].try_into().unwrap(), + advices[7], + fixed_y_q_1, + lookup, + range_check, + ); + let config1 = MerkleChip::configure(meta, sinsemilla_config_1); + + let sinsemilla_config_2 = SinsemillaChip::configure( + meta, + advices[..5].try_into().unwrap(), + advices[2], + fixed_y_q_2, + lookup, + range_check, + ); + let config2 = MerkleChip::configure(meta, sinsemilla_config_2); + + (config1, config2) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + // Load generator table (shared across both configs) for SinsemillaChipOptimized + SinsemillaChipOptimized::::load( + config.0.sinsemilla_config.clone(), + &mut layouter, + )?; + + // Construct Merkle chips which will be placed side-by-side in the circuit. + let chip_1 = MerkleChip::construct(config.0.clone()); + let chip_2 = MerkleChip::construct(config.1.clone()); + + let leaf = chip_1.load_private( + layouter.namespace(|| ""), + config.0.cond_swap_config.a(), + self.leaf, + )?; + + let path = MerklePath { + chips: [chip_1, chip_2], + domain: TestHashDomain, + leaf_pos: self.leaf_pos, + path: self.merkle_path, + }; + + let computed_final_root = + path.calculate_root(layouter.namespace(|| "calculate root"), leaf)?; + + self.leaf + .zip(self.leaf_pos) + .zip(self.merkle_path) + .zip(computed_final_root.value()) + .assert_if_known(|(((leaf, leaf_pos), merkle_path), computed_final_root)| { + // The expected final root + let final_root = + merkle_path + .iter() + .enumerate() + .fold(*leaf, |node, (l, sibling)| { + let l = l as u8; + let (left, right) = if leaf_pos & (1 << l) == 0 { + (&node, sibling) + } else { + (sibling, &node) + }; + + use crate::sinsemilla::primitives as sinsemilla; + let merkle_crh = + sinsemilla::HashDomain::from_Q(TestHashDomain.Q().into()); + + merkle_crh + .hash( + iter::empty() + .chain(i2lebsp::<10>(l as u64).iter().copied()) + .chain( + left.to_le_bits() + .iter() + .by_vals() + .take(pallas::Base::NUM_BITS as usize), + ) + .chain( + right + .to_le_bits() + .iter() + .by_vals() + .take(pallas::Base::NUM_BITS as usize), + ), + ) + .unwrap_or(pallas::Base::zero()) + }); + + // Check the computed final root against the expected final root. + computed_final_root == &&final_root + }); + + Ok(()) + } + } + + #[test] + fn merkle_chip() { + let mut rng = OsRng; + + // Choose a random leaf and position + let leaf = pallas::Base::random(rng); + let pos = rng.next_u32(); + + // Choose a path of random inner nodes + let path: Vec<_> = (0..(MERKLE_DEPTH)) + .map(|_| pallas::Base::random(rng)) + .collect(); + + // The root is provided as a public input in the Orchard circuit. + + let circuit = MyCircuit { + leaf: Value::known(leaf), + leaf_pos: Value::known(pos), + merkle_path: Value::known(path.try_into().unwrap()), + }; + + let prover = MockProver::run(11, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), Ok(())) + } + + #[cfg(feature = "test-dev-graph")] + #[test] + fn print_merkle_chip() { + use plotters::prelude::*; + + let root = BitMapBackend::new("merkle-path-layout.png", (1024, 7680)).into_drawing_area(); + root.fill(&WHITE).unwrap(); + let root = root.titled("MerkleCRH Path", ("sans-serif", 60)).unwrap(); + + let circuit = MyCircuit::default(); + halo2_proofs::dev::CircuitLayout::default() + .show_labels(true) + .render(11, &circuit, &root) + .unwrap(); + } +} diff --git a/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs b/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs index 7b9d160e9c..1eaf2c0853 100644 --- a/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs @@ -6,12 +6,13 @@ use halo2_proofs::{ }; use pasta_curves::pallas; -use crate::sinsemilla::chip::generator_table::DefaultGeneratorTable; use crate::sinsemilla::chip::SinsemillaChip; -use crate::utilities::lookup_range_check::DefaultLookupRangeCheck; +use crate::sinsemilla::SinsemillaInstructions; +use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; use crate::{ sinsemilla::{merkle::chip::MerkleChip, primitives as sinsemilla}, sinsemilla_opt::SinsemillaInstructionsOptimized, + utilities_opt::lookup_range_check::DefaultLookupRangeCheckConfigOptimized, { ecc::FixedPoints, sinsemilla::{CommitDomains, HashDomains}, @@ -20,15 +21,12 @@ use crate::{ }, }; -impl - CondSwapInstructionsOptimized - for MerkleChip +impl CondSwapInstructionsOptimized + for MerkleChip where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { fn mux( &self, @@ -43,15 +41,13 @@ where } } -impl +impl SinsemillaInstructionsOptimized - for MerkleChip + for MerkleChip where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - LookupRangeCheckConfig: DefaultLookupRangeCheck, - GeneratorTableConfigType: DefaultGeneratorTable, { #[allow(non_snake_case)] #[allow(clippy::type_complexity)] @@ -66,8 +62,7 @@ where Hash, Commit, F, - LookupRangeCheckConfig, - GeneratorTableConfigType, + LookupRangeCheckConfigOptimized, >::construct(config); chip.hash_to_point_with_private_init(layouter, Q, message) } diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 09369c04f1..f553920036 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -71,6 +71,8 @@ pub struct LookupRangeCheckConfig { /// FIXME: add doc pub trait LookupRangeCheck { + /// FIXME: add doc + fn is_optimized() -> bool; /// FIXME: add doc fn config(&self) -> &LookupRangeCheckConfig; @@ -235,7 +237,6 @@ pub trait LookupRangeCheck { // Copy `element` to use in the k-bit lookup. let element = element.copy_advice(|| "element", &mut region, self.config().running_sum, 0)?; - self.short_range_check(&mut region, element, num_bits) }, ) @@ -273,6 +274,10 @@ pub trait LookupRangeCheck { } impl LookupRangeCheck for LookupRangeCheckConfig { + fn is_optimized() -> bool { + false + } + fn config(&self) -> &LookupRangeCheckConfig { self } diff --git a/halo2_gadgets/src/utilities_opt/cond_swap.rs b/halo2_gadgets/src/utilities_opt/cond_swap.rs index 4ba03e5eea..d14e5407ba 100644 --- a/halo2_gadgets/src/utilities_opt/cond_swap.rs +++ b/halo2_gadgets/src/utilities_opt/cond_swap.rs @@ -120,113 +120,18 @@ impl CondSwapChip { #[cfg(test)] mod tests { - use super::{CondSwapChip, CondSwapInstructions}; - use crate::utilities::cond_swap::CondSwapConfig; - use crate::utilities::lookup_range_check::LookupRangeCheck; - use crate::utilities::UtilitiesInstructions; + use crate::utilities::cond_swap::{CondSwapChip, CondSwapConfig}; use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; - 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; - - #[test] - fn cond_swap() { - #[derive(Default)] - struct MyCircuit { - a: Value, - b: Value, - swap: Value, - } - - impl Circuit for MyCircuit { - type Config = CondSwapConfig; - 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(), - ]; - - CondSwapChip::::configure(meta, advices) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let chip = CondSwapChip::::construct(config.clone()); - - // Load the pair and the swap flag into the circuit. - let a = chip.load_private(layouter.namespace(|| "a"), config.a, self.a)?; - // Return the swapped pair. - let swapped_pair = chip.swap( - layouter.namespace(|| "swap"), - (a.clone(), self.b), - self.swap, - )?; - - self.swap - .zip(a.value().zip(self.b.as_ref())) - .zip(swapped_pair.0.value().zip(swapped_pair.1.value())) - .assert_if_known(|((swap, (a, b)), (a_swapped, b_swapped))| { - if *swap { - // Check that `a` and `b` have been swapped - (a_swapped == b) && (b_swapped == a) - } else { - // Check that `a` and `b` have not been swapped - (a_swapped == a) && (b_swapped == b) - } - }); - - Ok(()) - } - } - - let rng = OsRng; - - // Test swap case - { - let circuit: MyCircuit = MyCircuit { - a: Value::known(Base::random(rng)), - b: Value::known(Base::random(rng)), - swap: Value::known(true), - }; - let prover = MockProver::::run(3, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - // Test non-swap case - { - let circuit: MyCircuit = MyCircuit { - a: Value::known(Base::random(rng)), - b: Value::known(Base::random(rng)), - swap: Value::known(false), - }; - let prover = MockProver::::run(3, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - } #[test] fn test_mux() { - use crate::ecc::{ - chip::{EccChip, EccConfig}, - tests::TestFixedBases, - NonIdentityPoint, Point, + use crate::{ + ecc::{ + chip::{EccChip, EccConfig}, + tests::TestFixedBases, + NonIdentityPoint, Point, + }, + utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, }; use group::{cofactor::CofactorCurveAffine, Curve, Group}; diff --git a/halo2_gadgets/src/utilities_opt/lookup_range_check.rs b/halo2_gadgets/src/utilities_opt/lookup_range_check.rs index 115d8ea811..6306e25bfb 100644 --- a/halo2_gadgets/src/utilities_opt/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities_opt/lookup_range_check.rs @@ -48,7 +48,7 @@ impl LookupRangeCheckConfigOptimized { /// # Side-effects /// /// Both the `running_sum` and `constants` columns will be equality-enabled. - fn configure_with_tag( + pub(crate) fn configure_with_tag( meta: &mut ConstraintSystem, running_sum: Column, table_idx: TableColumn, @@ -163,11 +163,18 @@ impl LookupRangeCheckConfigOptimized { config } + pub(crate) fn table_range_check_tag(&self) -> TableColumn { + self.table_range_check_tag + } } impl LookupRangeCheck for LookupRangeCheckConfigOptimized { + fn is_optimized() -> bool { + true + } + fn config(&self) -> &LookupRangeCheckConfig { &self.base } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 948d27daa4..f8c2abbb3d 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.60.0" +channel = "1.65.0" From 507a53ce73afd79365516f7479f4196cb7810d4e Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 29 Apr 2024 15:31:41 +0200 Subject: [PATCH 20/99] update code for hash --- halo2_gadgets/src/ecc.rs | 1 - halo2_gadgets/src/ecc/chip.rs | 38 +- halo2_gadgets/src/ecc/chip/mul.rs | 18 +- halo2_gadgets/src/ecc/chip/mul/overflow.rs | 8 +- .../src/ecc/chip/mul_fixed/base_field_elem.rs | 26 +- .../src/ecc/chip/mul_fixed/full_width.rs | 16 +- halo2_gadgets/src/ecc/chip/mul_fixed/short.rs | 14 +- halo2_gadgets/src/ecc_opt.rs | 13 - halo2_gadgets/src/ecc_opt/chip.rs | 4 +- .../src/ecc_opt/chip/mul_fixed/short.rs | 5 +- halo2_gadgets/src/sinsemilla/chip.rs | 189 +++++--- .../src/sinsemilla/chip/generator_table.rs | 7 +- .../src/sinsemilla/chip/hash_to_point.rs | 19 +- halo2_gadgets/src/sinsemilla/merkle/chip.rs | 216 ++++----- halo2_gadgets/src/sinsemilla_opt.rs | 12 +- halo2_gadgets/src/sinsemilla_opt/chip.rs | 198 ++++++-- .../src/sinsemilla_opt/chip/hash_to_point.rs | 32 +- halo2_gadgets/src/sinsemilla_opt/merkle.rs | 19 +- .../src/sinsemilla_opt/merkle/chip.rs | 437 ++++++++++++++++-- .../src/utilities/lookup_range_check.rs | 35 +- halo2_gadgets/src/utilities_opt/cond_swap.rs | 2 +- .../src/utilities_opt/lookup_range_check.rs | 4 - 22 files changed, 918 insertions(+), 395 deletions(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index a03eaa141a..1d1a4a48e3 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -596,7 +596,6 @@ pub(crate) mod tests { FixedPoints, }; use crate::{ - sinsemilla::primitives as sinsemilla, utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, }; diff --git a/halo2_gadgets/src/ecc/chip.rs b/halo2_gadgets/src/ecc/chip.rs index df8e1bb124..76d5a019a7 100644 --- a/halo2_gadgets/src/ecc/chip.rs +++ b/halo2_gadgets/src/ecc/chip.rs @@ -136,7 +136,7 @@ impl From for EccPoint { #[allow(non_snake_case)] pub struct EccConfig< FixedPoints: super::FixedPoints, - LookupRangeCheckConfig: DefaultLookupRangeCheck, + Lookup: DefaultLookupRangeCheck, > { /// Advice columns needed by instructions in the ECC chip. pub advices: [Column; 10], @@ -148,20 +148,20 @@ pub struct EccConfig< add: add::Config, /// Variable-base scalar multiplication - mul: mul::Config, + mul: mul::Config, /// Fixed-base full-width scalar multiplication mul_fixed_full: mul_fixed::full_width::Config, /// Fixed-base signed short scalar multiplication pub(crate) mul_fixed_short: mul_fixed::short::Config, /// Fixed-base mul using a base field element as a scalar - mul_fixed_base_field: mul_fixed::base_field_elem::Config, + mul_fixed_base_field: mul_fixed::base_field_elem::Config, /// Witness point pub(crate) witness_point: witness_point::Config, /// Lookup range check using 10-bit lookup table - pub lookup_config: LookupRangeCheckConfig, + pub lookup_config: Lookup, } /// A trait representing the kind of scalar used with a particular `FixedPoint`. @@ -229,17 +229,17 @@ pub trait FixedPoint: std::fmt::Debug + Eq + Clone { #[derive(Clone, Debug, Eq, PartialEq)] pub struct EccChip< FixedPoints: super::FixedPoints, - LookupRangeCheckConfig: DefaultLookupRangeCheck, + Lookup: DefaultLookupRangeCheck, > { - config: EccConfig, + config: EccConfig, } impl< FixedPoints: super::FixedPoints, - LookupRangeCheckConfig: DefaultLookupRangeCheck, - > Chip for EccChip + Lookup: DefaultLookupRangeCheck, + > Chip for EccChip { - type Config = EccConfig; + type Config = EccConfig; type Loaded = (); fn config(&self) -> &Self::Config { @@ -253,16 +253,16 @@ impl< impl< Fixed: super::FixedPoints, - LookupRangeCheckConfig: DefaultLookupRangeCheck, - > UtilitiesInstructions for EccChip + Lookup: DefaultLookupRangeCheck, + > UtilitiesInstructions for EccChip { type Var = AssignedCell; } impl< FixedPoints: super::FixedPoints, - LookupRangeCheckConfig: DefaultLookupRangeCheck, - > EccChip + Lookup: DefaultLookupRangeCheck, + > EccChip { /// Reconstructs this chip from the given config. pub fn construct(config: >::Config) -> Self { @@ -277,7 +277,7 @@ impl< meta: &mut ConstraintSystem, advices: [Column; 10], lagrange_coeffs: [Column; 8], - range_check: LookupRangeCheckConfig, + range_check: Lookup, ) -> >::Config { // Create witness point gate let witness_point = witness_point::Config::configure(meta, advices[0], advices[1]); @@ -315,7 +315,7 @@ impl< // Create gate that is only used in fixed-base mul using a base field element. let mul_fixed_base_field = - mul_fixed::base_field_elem::Config::::configure( + mul_fixed::base_field_elem::Config::::configure( meta, advices[6..9].try_into().unwrap(), range_check, @@ -421,8 +421,8 @@ pub enum ScalarVar { FullWidth, } -impl, LookupRangeCheckConfig: DefaultLookupRangeCheck> - EccInstructions for EccChip +impl, Lookup: DefaultLookupRangeCheck> + EccInstructions for EccChip where >::Base: FixedPoint, @@ -609,8 +609,8 @@ where } } -impl, LookupRangeCheckConfig: DefaultLookupRangeCheck> - BaseFitsInScalarInstructions for EccChip +impl, Lookup: DefaultLookupRangeCheck> + BaseFitsInScalarInstructions for EccChip where >::Base: FixedPoint, diff --git a/halo2_gadgets/src/ecc/chip/mul.rs b/halo2_gadgets/src/ecc/chip/mul.rs index b4b6d55518..61f36f88e9 100644 --- a/halo2_gadgets/src/ecc/chip/mul.rs +++ b/halo2_gadgets/src/ecc/chip/mul.rs @@ -46,7 +46,7 @@ const INCOMPLETE_LO_LEN: usize = INCOMPLETE_LEN - INCOMPLETE_HI_LEN; const COMPLETE_RANGE: Range = INCOMPLETE_LEN..(INCOMPLETE_LEN + NUM_COMPLETE_BITS); #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { +pub struct Config { // Selector used to check switching logic on LSB q_mul_lsb: Selector, // Configuration used in complete addition @@ -58,14 +58,14 @@ pub struct Config { // Configuration used for complete addition part of double-and-add algorithm complete_config: complete::Config, // Configuration used to check for overflow - overflow_config: overflow::Config, + overflow_config: overflow::Config, } -impl Config { +impl Config { pub(crate) fn configure( meta: &mut ConstraintSystem, add_config: add::Config, - lookup_config: LookupRangeCheckConfig, + lookup_config: Lookup, advices: [Column; 10], ) -> Self { let hi_config = incomplete::Config::configure( @@ -461,13 +461,13 @@ pub mod tests { Curve, }; use halo2_proofs::{ - circuit::{Chip, Layouter, Value}, + circuit::{Layouter, Value}, plonk::Error, }; use pasta_curves::pallas; use rand::rngs::OsRng; - use crate::utilities::lookup_range_check::{DefaultLookupRangeCheck, LookupRangeCheckConfig}; + use crate::utilities::lookup_range_check::{DefaultLookupRangeCheck}; use crate::{ ecc::{ chip::{EccChip, EccPoint}, @@ -477,10 +477,10 @@ pub mod tests { utilities::UtilitiesInstructions, }; - pub(crate) fn test_mul( - chip: EccChip, + pub(crate) fn test_mul( + chip: EccChip, mut layouter: impl Layouter, - p: &NonIdentityPoint>, + p: &NonIdentityPoint>, p_val: pallas::Affine, ) -> Result<(), Error> { let column = chip.config.advices[0]; diff --git a/halo2_gadgets/src/ecc/chip/mul/overflow.rs b/halo2_gadgets/src/ecc/chip/mul/overflow.rs index 8adaefa311..0912bd3a39 100644 --- a/halo2_gadgets/src/ecc/chip/mul/overflow.rs +++ b/halo2_gadgets/src/ecc/chip/mul/overflow.rs @@ -15,19 +15,19 @@ use pasta_curves::pallas; use std::iter; #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { +pub struct Config { // Selector to check z_0 = alpha + t_q (mod p) q_mul_overflow: Selector, // 10-bit lookup table - lookup_config: LookupRangeCheckConfig, + lookup_config: Lookup, // Advice columns advices: [Column; 3], } -impl Config { +impl Config { pub(super) fn configure( meta: &mut ConstraintSystem, - lookup_config: LookupRangeCheckConfig, + lookup_config: Lookup, advices: [Column; 3], ) -> Self { for advice in advices.iter() { diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs index 254ba6804c..1298140e43 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs @@ -18,21 +18,21 @@ use std::convert::TryInto; #[derive(Clone, Debug, Eq, PartialEq)] pub struct Config< Fixed: FixedPoints, - LookupRangeCheckConfig: DefaultLookupRangeCheck, + Lookup: DefaultLookupRangeCheck, > { q_mul_fixed_base_field: Selector, canon_advices: [Column; 3], - lookup_config: LookupRangeCheckConfig, + lookup_config: Lookup, super_config: super::Config, } -impl, LookupRangeCheckConfig: DefaultLookupRangeCheck> - Config +impl, Lookup: DefaultLookupRangeCheck> + Config { pub(crate) fn configure( meta: &mut ConstraintSystem, canon_advices: [Column; 3], - lookup_config: LookupRangeCheckConfig, + lookup_config: Lookup, super_config: super::Config, ) -> Self { for advice in canon_advices.iter() { @@ -401,8 +401,8 @@ pub mod tests { utilities::UtilitiesInstructions, }; - pub(crate) fn test_mul_fixed_base_field( - chip: EccChip, + pub(crate) fn test_mul_fixed_base_field( + chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { test_single_base( @@ -414,22 +414,22 @@ pub mod tests { } #[allow(clippy::op_ref)] - fn test_single_base( - chip: EccChip, + fn test_single_base( + chip: EccChip, mut layouter: impl Layouter, - base: FixedPointBaseField>, + base: FixedPointBaseField>, base_val: pallas::Affine, ) -> Result<(), Error> { let rng = OsRng; let column = chip.config().advices[0]; - fn constrain_equal_non_id( - chip: EccChip, + fn constrain_equal_non_id( + chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, scalar_val: pallas::Base, - result: Point>, + result: Point>, ) -> Result<(), Error> { // Move scalar from base field into scalar field (which always fits for Pallas). let scalar = pallas::Scalar::from_repr(scalar_val.to_repr()).unwrap(); diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs index a06b1b9394..fe2cc22094 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs @@ -194,8 +194,8 @@ pub mod tests { }; use crate::utilities::lookup_range_check::DefaultLookupRangeCheck; - pub(crate) fn test_mul_fixed( - chip: EccChip, + pub(crate) fn test_mul_fixed( + chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { let test_base = FullWidth::from_pallas_generator(); @@ -210,18 +210,18 @@ pub mod tests { } #[allow(clippy::op_ref)] - fn test_single_base( - chip: EccChip, + fn test_single_base( + chip: EccChip, mut layouter: impl Layouter, - base: FixedPoint>, + base: FixedPoint>, base_val: pallas::Affine, ) -> Result<(), Error> { - fn constrain_equal_non_id( - chip: EccChip, + fn constrain_equal_non_id( + chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, scalar_val: pallas::Scalar, - result: Point>, + result: Point>, ) -> Result<(), Error> { let expected = NonIdentityPoint::new( chip, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs index c746bd5f97..48a1cbf88a 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs @@ -264,16 +264,16 @@ pub mod tests { }; #[allow(clippy::op_ref)] - pub(crate) fn test_mul_fixed_short( - chip: EccChip, + pub(crate) fn test_mul_fixed_short( + chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { // test_short let base_val = Short.generator(); let test_short = FixedPointShort::from_inner(chip.clone(), Short); - fn load_magnitude_sign( - chip: EccChip, + fn load_magnitude_sign( + chip: EccChip, mut layouter: impl Layouter, magnitude: pallas::Base, sign: pallas::Base, @@ -290,12 +290,12 @@ pub mod tests { Ok((magnitude, sign)) } - fn constrain_equal_non_id( - chip: EccChip, + fn constrain_equal_non_id( + chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, scalar_val: pallas::Scalar, - result: Point>, + result: Point>, ) -> Result<(), Error> { let expected = NonIdentityPoint::new( chip, diff --git a/halo2_gadgets/src/ecc_opt.rs b/halo2_gadgets/src/ecc_opt.rs index 253662a7ca..b7a7dca5a4 100644 --- a/halo2_gadgets/src/ecc_opt.rs +++ b/halo2_gadgets/src/ecc_opt.rs @@ -99,19 +99,6 @@ pub(crate) mod tests { find_zs_and_us(*BASE, NUM_WINDOWS_SHORT).unwrap(); } - impl FullWidth { - pub(crate) fn from_pallas_generator() -> Self { - FullWidth(*BASE, &ZS_AND_US) - } - - pub(crate) fn from_parts( - base: pallas::Affine, - zs_and_us: &'static [(u64, [pallas::Base; H])], - ) -> Self { - FullWidth(base, zs_and_us) - } - } - impl FixedPoint for FullWidth { type FixedScalarKind = FullScalar; diff --git a/halo2_gadgets/src/ecc_opt/chip.rs b/halo2_gadgets/src/ecc_opt/chip.rs index ed391881b3..c2c70bc17f 100644 --- a/halo2_gadgets/src/ecc_opt/chip.rs +++ b/halo2_gadgets/src/ecc_opt/chip.rs @@ -19,8 +19,8 @@ use super::EccInstructionsOptimized; pub(crate) mod mul_fixed; pub(super) mod witness_point; -impl, LookupRangeCheckConfig: DefaultLookupRangeCheck> - EccInstructionsOptimized for EccChip +impl, Lookup: DefaultLookupRangeCheck> + EccInstructionsOptimized for EccChip where >::Base: FixedPoint, diff --git a/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs index 927aea4858..b0487b5d73 100644 --- a/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs +++ b/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs @@ -92,13 +92,12 @@ pub mod tests { use crate::{ ecc::{chip::EccChip, tests::TestFixedBases, Point}, utilities::{ - lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, UtilitiesInstructions, }, }; - pub(crate) fn test_mul_sign( - chip: EccChip, + pub(crate) fn test_mul_sign( + chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { // Generate a random non-identity point P diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs index 4793a99da2..fa64deedfe 100644 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ b/halo2_gadgets/src/sinsemilla/chip.rs @@ -30,12 +30,12 @@ pub(crate) mod hash_to_point; /// Configuration for the Sinsemilla hash chip #[derive(Eq, PartialEq, Clone, Debug)] -pub struct SinsemillaConfig +pub struct SinsemillaConfig where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - LookupRangeCheckConfig: DefaultLookupRangeCheck, + Lookup: DefaultLookupRangeCheck, { /// Binary selector used in lookup argument and in the body of the Sinsemilla hash. pub(crate) q_sinsemilla1: Selector, @@ -59,17 +59,17 @@ where /// generators of the Sinsemilla hash. pub(crate) generator_table: GeneratorTableConfig, /// An advice column configured to perform lookup range checks. - pub(crate) lookup_config: LookupRangeCheckConfig, + pub(crate) lookup_config: Lookup, pub(crate) _marker: PhantomData<(Hash, Commit, F)>, } -impl - SinsemillaConfig +impl + SinsemillaConfig where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - LookupRangeCheckConfig: DefaultLookupRangeCheck, + Lookup: DefaultLookupRangeCheck, { /// Returns an array of all advice columns in this config, in arbitrary order. pub(super) fn advices(&self) -> [Column; 5] { @@ -83,7 +83,7 @@ where } /// Returns the lookup range check config used in this config. - pub fn lookup_config(&self) -> LookupRangeCheckConfig { + pub fn lookup_config(&self) -> Lookup { self.lookup_config } @@ -99,25 +99,25 @@ where /// /// [Chip description](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html#plonk--halo-2-constraints). #[derive(Eq, PartialEq, Clone, Debug)] -pub struct SinsemillaChip +pub struct SinsemillaChip where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - LookupRangeCheckConfig: DefaultLookupRangeCheck, + Lookup: DefaultLookupRangeCheck, { - config: SinsemillaConfig, + config: SinsemillaConfig, } -impl Chip - for SinsemillaChip +impl Chip + for SinsemillaChip where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - LookupRangeCheckConfig: DefaultLookupRangeCheck, + Lookup: DefaultLookupRangeCheck, { - type Config = SinsemillaConfig; + type Config = SinsemillaConfig; type Loaded = (); fn config(&self) -> &Self::Config { @@ -129,13 +129,13 @@ where } } -impl - SinsemillaChip +impl + SinsemillaChip where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - LookupRangeCheckConfig: DefaultLookupRangeCheck, + Lookup: DefaultLookupRangeCheck, { /// Reconstructs this chip from the given config. pub fn construct(config: >::Config) -> Self { @@ -144,7 +144,7 @@ where /// Loads the lookup table required by this chip into the circuit. pub fn load( - config: SinsemillaConfig, + config: SinsemillaConfig, layouter: &mut impl Layouter, ) -> Result<>::Loaded, Error> { // Load the lookup table. @@ -152,59 +152,13 @@ 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)] - pub fn configure( + pub(crate) fn create_initial_y_q_gate( meta: &mut ConstraintSystem, - advices: [Column; 5], - witness_pieces: Column, - fixed_y_q: Column, - lookup: (TableColumn, TableColumn, TableColumn), - range_check: LookupRangeCheckConfig, - ) -> >::Config { - // FIXME: add comments - - // Enable equality on all advice columns - for advice in advices.iter() { - meta.enable_equality(*advice); - } - - let config = SinsemillaConfig:: { - q_sinsemilla1: meta.complex_selector(), - q_sinsemilla2: meta.fixed_column(), - q_sinsemilla4: meta.selector(), - fixed_y_q, - double_and_add: DoubleAndAdd { - x_a: advices[0], - x_p: advices[1], - lambda_1: advices[3], - lambda_2: advices[4], - }, - bits: advices[2], - witness_pieces, - generator_table: GeneratorTableConfig { - table_idx: lookup.0, - table_x: lookup.1, - table_y: lookup.2, - }, - lookup_config: range_check, - _marker: PhantomData, - }; - - // Set up lookup argument - GeneratorTableConfig::configure(meta, &config); - + config: &SinsemillaConfig, + ) { let two = pallas::Base::from(2); - // Closures for expressions that are derived multiple times - // x_r = lambda_1^2 - x_a - x_p - let x_r = |meta: &mut VirtualCells, rotation| { - config.double_and_add.x_r(meta, rotation) - }; - // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) let Y_A = |meta: &mut VirtualCells, rotation| { config.double_and_add.Y_A(meta, rotation) @@ -214,11 +168,8 @@ where // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial meta.create_gate("Initial y_Q", |meta| { let q_s4 = meta.query_selector(config.q_sinsemilla4); - let y_q = if LookupRangeCheckConfig::is_optimized() { - meta.query_advice(config.double_and_add.x_p, Rotation::prev()) - } else { - meta.query_fixed(config.fixed_y_q) - }; + let y_q = meta.query_fixed(config.fixed_y_q); + // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) let Y_A_cur = Y_A(meta, Rotation::cur()); @@ -227,6 +178,25 @@ where Constraints::with_selector(q_s4, Some(("init_y_q_check", init_y_q_check))) }); + } + + #[allow(non_snake_case)] + pub(crate) fn create_sinsemilla_gate( + meta: &mut ConstraintSystem, + config: &SinsemillaConfig, + ) { + let two = pallas::Base::from(2); + + // Closures for expressions that are derived multiple times + // x_r = lambda_1^2 - x_a - x_p + let x_r = |meta: &mut VirtualCells, rotation| { + config.double_and_add.x_r(meta, rotation) + }; + + // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) + let Y_A = |meta: &mut VirtualCells, rotation| { + config.double_and_add.Y_A(meta, rotation) + }; // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial meta.create_gate("Sinsemilla gate", |meta| { @@ -272,20 +242,89 @@ where Constraints::with_selector(q_s1, [("Secant line", secant_line), ("y check", y_check)]) }); + } + + pub(crate) fn create_config( + meta: &mut ConstraintSystem, + advices: [Column; 5], + witness_pieces: Column, + fixed_y_q: Column, + lookup: (TableColumn, TableColumn, TableColumn), + range_check: Lookup, + ) -> >::Config { + // Enable equality on all advice columns + for advice in advices.iter() { + meta.enable_equality(*advice); + } + + let config = SinsemillaConfig:: { + q_sinsemilla1: meta.complex_selector(), + q_sinsemilla2: meta.fixed_column(), + q_sinsemilla4: meta.selector(), + fixed_y_q, + double_and_add: DoubleAndAdd { + x_a: advices[0], + x_p: advices[1], + lambda_1: advices[3], + lambda_2: advices[4], + }, + bits: advices[2], + witness_pieces, + generator_table: GeneratorTableConfig { + table_idx: lookup.0, + table_x: lookup.1, + table_y: lookup.2, + }, + lookup_config: range_check, + _marker: PhantomData, + }; + + // Set up lookup argument + GeneratorTableConfig::configure(meta, &config); + + config + } + + /// # Side-effects + /// + /// All columns in `advices` and will be equality-enabled. + #[allow(clippy::too_many_arguments)] + #[allow(non_snake_case)] + pub fn configure( + meta: &mut ConstraintSystem, + advices: [Column; 5], + witness_pieces: Column, + fixed_y_q: Column, + lookup: (TableColumn, TableColumn, TableColumn), + range_check: Lookup, + ) -> >::Config { + // create SinsemillaConfig + let config = Self::create_config( + meta, + advices, + witness_pieces, + fixed_y_q, + lookup, + range_check, + ); + + Self::create_initial_y_q_gate(meta, &config); + + Self::create_sinsemilla_gate(meta, &config); config } } // Implement `SinsemillaInstructions` for `SinsemillaChip` -impl +impl SinsemillaInstructions - for SinsemillaChip + for SinsemillaChip where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - LookupRangeCheckConfig: DefaultLookupRangeCheck, + Lookup: DefaultLookupRangeCheck, { type CellValue = AssignedCell; diff --git a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs index ed7cc9e554..80551a6c91 100644 --- a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs +++ b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs @@ -6,7 +6,6 @@ use halo2_proofs::{ }; use super::{CommitDomains, FixedPoints, HashDomains}; -use crate::utilities::lookup_range_check::LookupRangeCheckConfig; use crate::{ sinsemilla::primitives::{self as sinsemilla, SINSEMILLA_S}, utilities::lookup_range_check::DefaultLookupRangeCheck, @@ -27,14 +26,14 @@ impl GeneratorTableConfig { /// Even though the lookup table can be used in other parts of the circuit, /// this specific configuration sets up Sinsemilla-specific constraints /// controlled by `q_sinsemilla`, and would likely not apply to other chips. - pub fn configure( + pub fn configure( meta: &mut ConstraintSystem, - config: &super::SinsemillaConfig, + config: &super::SinsemillaConfig, ) where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - LookupRangeCheckConfig: DefaultLookupRangeCheck, + Lookup: DefaultLookupRangeCheck, { let (table_idx, table_x, table_y) = ( config.generator_table.table_idx, diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 1bb1ce9ed6..0456fc0893 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -1,5 +1,5 @@ use super::super::{CommitDomains, HashDomains, SinsemillaInstructions}; -use super::{NonIdentityEccPoint, SinsemillaChip, SinsemillaConfig}; +use super::{NonIdentityEccPoint, SinsemillaChip}; use crate::{ ecc::FixedPoints, sinsemilla::primitives::{self as sinsemilla, lebs2ip_k, INV_TWO_POW_K, SINSEMILLA_S}, @@ -24,18 +24,18 @@ pub enum EccPointQ<'a> { PrivatePoint(&'a NonIdentityEccPoint), } -impl - SinsemillaChip +impl + SinsemillaChip where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - LookupRangeCheckConfig: DefaultLookupRangeCheck, + Lookup: DefaultLookupRangeCheck, { /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). #[allow(non_snake_case)] #[allow(clippy::type_complexity)] - pub(super) fn hash_message( + pub(crate) fn hash_message( &self, region: &mut Region<'_, pallas::Base>, Q: pallas::Affine, @@ -51,13 +51,7 @@ where ), Error, > { - // todo: add doc about LookupRangeCheckConfig::is_optimized() - //let (offset, x_a, y_a) = self.public_initialization(region, Q)?; - let (offset, x_a, y_a) = if LookupRangeCheckConfig::is_optimized() { - self.public_initialization(region, Q)? - } else { - self.public_initialization_vanilla(region, Q)? - }; + 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)?; @@ -65,6 +59,7 @@ where } #[allow(non_snake_case)] + #[allow(unused_variables)] // Check equivalence to result from primitives::sinsemilla::hash_to_point pub(crate) fn check_hash_result( &self, diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs index dc7fb3f6f8..c54133e291 100644 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla/merkle/chip.rs @@ -28,17 +28,17 @@ use group::ff::PrimeField; /// Configuration for the `MerkleChip` implementation. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct MerkleConfig -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, - LookupRangeCheckConfig: DefaultLookupRangeCheck, +pub struct MerkleConfig + where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, + Lookup: DefaultLookupRangeCheck, { - advices: [Column; 5], - q_decompose: Selector, + pub(crate) advices: [Column; 5], + pub(crate) q_decompose: Selector, pub(crate) cond_swap_config: CondSwapConfig, - pub(crate) sinsemilla_config: SinsemillaConfig, + pub(crate) sinsemilla_config: SinsemillaConfig, } /// Chip implementing `MerkleInstructions`. @@ -52,25 +52,25 @@ where /// This chip does **NOT** constrain `left⋆` and `right⋆` to be canonical encodings of /// `left` and `right`. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct MerkleChip -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, - LookupRangeCheckConfig: DefaultLookupRangeCheck, +pub struct MerkleChip + where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, + Lookup: DefaultLookupRangeCheck, { - config: MerkleConfig, + pub(crate) config: MerkleConfig, } -impl Chip - for MerkleChip -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, - LookupRangeCheckConfig: DefaultLookupRangeCheck, +impl Chip +for MerkleChip + where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, + Lookup: DefaultLookupRangeCheck, { - type Config = MerkleConfig; + type Config = MerkleConfig; type Loaded = (); fn config(&self) -> &Self::Config { @@ -82,18 +82,18 @@ where } } -impl MerkleChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, - LookupRangeCheckConfig: DefaultLookupRangeCheck, +impl MerkleChip + where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, + Lookup: DefaultLookupRangeCheck, { /// Configures the [`MerkleChip`]. pub fn configure( meta: &mut ConstraintSystem, - sinsemilla_config: SinsemillaConfig, - ) -> MerkleConfig { + sinsemilla_config: SinsemillaConfig, + ) -> MerkleConfig { // All five advice columns are equality-enabled by SinsemillaConfig. let advices = sinsemilla_config.advices(); let cond_swap_config = CondSwapChip::configure(meta, advices); @@ -196,19 +196,19 @@ where } /// Constructs a [`MerkleChip`] given a [`MerkleConfig`]. - pub fn construct(config: MerkleConfig) -> Self { + pub fn construct(config: MerkleConfig) -> Self { MerkleChip { config } } } -impl - MerkleInstructions - for MerkleChip -where - Hash: HashDomains + Eq, - F: FixedPoints, - Commit: CommitDomains + Eq, - LookupRangeCheckConfig: DefaultLookupRangeCheck, +impl +MerkleInstructions +for MerkleChip + where + Hash: HashDomains + Eq, + F: FixedPoints, + Commit: CommitDomains + Eq, + Lookup: DefaultLookupRangeCheck, { #[allow(non_snake_case)] fn hash_layer( @@ -421,24 +421,24 @@ where } } -impl UtilitiesInstructions - for MerkleChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, - LookupRangeCheckConfig: DefaultLookupRangeCheck, +impl UtilitiesInstructions +for MerkleChip + where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, + Lookup: DefaultLookupRangeCheck, { type Var = AssignedCell; } -impl CondSwapInstructions - for MerkleChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, - LookupRangeCheckConfig: DefaultLookupRangeCheck, +impl CondSwapInstructions +for MerkleChip + where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, + Lookup: DefaultLookupRangeCheck, { #[allow(clippy::type_complexity)] fn swap( @@ -453,71 +453,71 @@ where } } -impl - SinsemillaInstructions - for MerkleChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, - LookupRangeCheckConfig: DefaultLookupRangeCheck, +impl +SinsemillaInstructions +for MerkleChip + where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, + Lookup: DefaultLookupRangeCheck, { type CellValue = - as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::CellValue; + as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::CellValue; type Message = - as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::Message; + as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::Message; type MessagePiece = - as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::MessagePiece; + as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::MessagePiece; type RunningSum = - as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::RunningSum; + as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::RunningSum; - type X = as SinsemillaInstructions< + type X = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::X; type NonIdentityPoint = - as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::NonIdentityPoint; + as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::NonIdentityPoint; type FixedPoints = - as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::FixedPoints; + as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::FixedPoints; type HashDomains = - as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::HashDomains; + as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::HashDomains; type CommitDomains = - as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::CommitDomains; + as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::CommitDomains; fn witness_message_piece( &self, @@ -526,7 +526,7 @@ where num_words: usize, ) -> Result { let config = self.config().sinsemilla_config.clone(); - let chip = SinsemillaChip::::construct(config); + let chip = SinsemillaChip::::construct(config); chip.witness_message_piece(layouter, value, num_words) } @@ -539,11 +539,11 @@ where message: Self::Message, ) -> Result<(Self::NonIdentityPoint, Vec>), Error> { let config = self.config().sinsemilla_config.clone(); - let chip = SinsemillaChip::::construct(config); + let chip = SinsemillaChip::::construct(config); chip.hash_to_point(layouter, Q, message) } fn extract(point: &Self::NonIdentityPoint) -> Self::X { - SinsemillaChip::::extract(point) + SinsemillaChip::::extract(point) } -} +} \ No newline at end of file diff --git a/halo2_gadgets/src/sinsemilla_opt.rs b/halo2_gadgets/src/sinsemilla_opt.rs index cca2af19f8..397209e80c 100644 --- a/halo2_gadgets/src/sinsemilla_opt.rs +++ b/halo2_gadgets/src/sinsemilla_opt.rs @@ -5,7 +5,6 @@ use std::fmt::Debug; use pasta_curves::arithmetic::CurveAffine; -use pasta_curves::pallas; use halo2_proofs::{circuit::Layouter, plonk::Error}; @@ -18,10 +17,15 @@ pub mod chip; pub mod merkle; pub mod primitives; -/// FIXME: add a doc +/// `SinsemillaInstructionsOptimized` provides an optimized set of instructions +/// for implementing the Sinsemilla hash function and commitment scheme +/// on elliptic curves. This trait is an extension of the `SinsemillaInstructions` trait, +/// designed to enhance performance in specific cryptographic scenarios.ld + pub trait SinsemillaInstructionsOptimized: - SinsemillaInstructions +SinsemillaInstructions { + /// Hashes a message to an ECC curve point. /// This returns both the resulting point, as well as the message /// decomposition in the form of intermediate values in a cumulative @@ -159,7 +163,6 @@ pub(crate) mod tests { tests::{FullWidth, TestFixedBases}, NonIdentityPoint, }, - utilities::lookup_range_check::LookupRangeCheckConfig, }, }; @@ -310,7 +313,6 @@ pub(crate) mod tests { let ecc_chip = EccChip::construct(config.0); - // todo: check SinsemillaChipOptimized::load // The two `SinsemillaChip`s share the same lookup table. SinsemillaChipOptimized::::load( config.1.clone(), diff --git a/halo2_gadgets/src/sinsemilla_opt/chip.rs b/halo2_gadgets/src/sinsemilla_opt/chip.rs index 909ad21f7c..d08c76153d 100644 --- a/halo2_gadgets/src/sinsemilla_opt/chip.rs +++ b/halo2_gadgets/src/sinsemilla_opt/chip.rs @@ -1,7 +1,6 @@ //! Chip implementations for the Sinsemilla gadgets. use super::SinsemillaInstructionsOptimized; -use crate::utilities::lookup_range_check::DefaultLookupRangeCheck; use crate::{ ecc::{chip::NonIdentityEccPoint, FixedPoints}, sinsemilla::{ @@ -11,7 +10,6 @@ use crate::{ }, utilities_opt::lookup_range_check::DefaultLookupRangeCheckConfigOptimized, }; -use halo2_proofs::plonk::Expression; use halo2_proofs::{ circuit::{AssignedCell, Chip, Layouter, Value}, plonk::{ @@ -20,56 +18,29 @@ use halo2_proofs::{ poly::Rotation, }; use pasta_curves::pallas; -use pasta_curves::pallas::Base; pub(crate) mod generator_table; mod hash_to_point; -// Implement `SinsemillaInstructionsOptimized` for `SinsemillaChip` -impl - SinsemillaInstructionsOptimized - for SinsemillaChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, - LookupRangeCheckConfig: DefaultLookupRangeCheck, -{ - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - fn hash_to_point_with_private_init( - &self, - mut layouter: impl Layouter, - Q: &Self::NonIdentityPoint, - message: Self::Message, - ) -> Result<(Self::NonIdentityPoint, Vec), Error> { - layouter.assign_region( - || "hash_to_point", - |mut region| self.hash_message_with_private_init(&mut region, Q, &message), - ) - } -} - /// A chip that implements 10-bit Sinsemilla using a lookup table and 5 advice columns. /// /// [Chip description](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html#plonk--halo-2-constraints). #[derive(Eq, PartialEq, Clone, Debug)] pub struct SinsemillaChipOptimized -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, + where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, { inner: SinsemillaChip, } -// FIXME: is this needed? impl Chip for SinsemillaChipOptimized -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, + where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, { type Config = SinsemillaConfig; type Loaded = (); @@ -84,11 +55,21 @@ where } impl SinsemillaChipOptimized -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, + where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, { + /// Reconstructs this chip from the given config. + pub fn construct(config: >::Config) -> Self { + Self { + inner: + SinsemillaChip::::construct( + config, + ), + } + } + /// Loads the lookup table required by this chip into the circuit. pub fn load( config: SinsemillaConfig, @@ -97,9 +78,142 @@ where // Load the lookup table. generator_table::load_with_tag( &config.generator_table, - // FIXME: consider to remove Option arount tag config.lookup_config.table_range_check_tag(), layouter, ) } + + #[allow(non_snake_case)] + fn create_initial_y_q_gate( + meta: &mut ConstraintSystem, + config: &SinsemillaConfig, + ) { + let two = pallas::Base::from(2); + + // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) + let Y_A = |meta: &mut VirtualCells, rotation| { + config.double_and_add.Y_A(meta, rotation) + }; + + // Check that the initial x_A, x_P, lambda_1, lambda_2 are consistent with y_Q. + // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial + meta.create_gate("Initial y_Q", |meta| { + let q_s4 = meta.query_selector(config.q_sinsemilla4); + let y_q = meta.query_advice(config.double_and_add.x_p, Rotation::prev()); + + // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) + let Y_A_cur = Y_A(meta, Rotation::cur()); + + // 2 * y_q - Y_{A,0} = 0 + let init_y_q_check = y_q * two - Y_A_cur; + + Constraints::with_selector(q_s4, Some(("init_y_q_check", init_y_q_check))) + }); + } + + /// # Side-effects + /// + /// All columns in `advices` and will be equality-enabled. + #[allow(clippy::too_many_arguments)] + #[allow(non_snake_case)] + pub fn configure( + meta: &mut ConstraintSystem, + advices: [Column; 5], + witness_pieces: Column, + fixed_y_q: Column, + lookup: (TableColumn, TableColumn, TableColumn), + range_check: DefaultLookupRangeCheckConfigOptimized, + ) -> >::Config { + let config = SinsemillaChip::::create_config( + meta, + advices, + witness_pieces, + fixed_y_q, + lookup, + range_check, + ); + + Self::create_initial_y_q_gate(meta, &config); + + SinsemillaChip::::create_sinsemilla_gate( + meta, &config, + ); + + config + } +} + +// Implement `SinsemillaInstructions` for `SinsemillaChip` +impl SinsemillaInstructions +for SinsemillaChipOptimized + where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, +{ + type CellValue = AssignedCell; + + type Message = Message; + type MessagePiece = MessagePiece; + + type RunningSum = Vec; + + type X = AssignedCell; + type NonIdentityPoint = NonIdentityEccPoint; + type FixedPoints = F; + + type HashDomains = Hash; + type CommitDomains = Commit; + + fn witness_message_piece( + &self, + layouter: impl Layouter, + field_elem: Value, + num_words: usize, + ) -> Result { + self.inner + .witness_message_piece(layouter, field_elem, num_words) + } + + #[allow(non_snake_case)] + #[allow(clippy::type_complexity)] + fn hash_to_point( + &self, + mut layouter: impl Layouter, + Q: pallas::Affine, + message: Self::Message, + ) -> Result<(Self::NonIdentityPoint, Vec), Error> { + layouter.assign_region( + || "hash_to_point", + |mut region| self.inner.hash_message_zsa(&mut region, Q, &message), + ) + } + + fn extract(point: &Self::NonIdentityPoint) -> Self::X { + point.x() + } } + +// Implement `SinsemillaInstructions` for `SinsemillaChip` +impl +SinsemillaInstructionsOptimized +for SinsemillaChipOptimized + where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, +{ + #[allow(non_snake_case)] + #[allow(clippy::type_complexity)] + fn hash_to_point_with_private_init( + &self, + mut layouter: impl Layouter, + Q: &Self::NonIdentityPoint, + message: Self::Message, + ) -> Result<(Self::NonIdentityPoint, Vec), Error> { + layouter.assign_region( + || "hash_to_point", + |mut region| self.inner.hash_message_with_private_init(&mut region, Q, &message), + ) + } +} \ No newline at end of file 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 469a5991e1..5f513ba5df 100644 --- a/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs @@ -17,14 +17,39 @@ use crate::{ }, }; -impl - SinsemillaChip +impl + SinsemillaChip where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - LookupRangeCheckConfig: DefaultLookupRangeCheck, + Lookup: DefaultLookupRangeCheck, { + #[allow(non_snake_case)] + #[allow(clippy::type_complexity)] + pub(crate) fn hash_message_zsa( + &self, + region: &mut Region<'_, pallas::Base>, + Q: pallas::Affine, + message: &>::Message, + ) -> Result< + ( + NonIdentityEccPoint, + Vec>>, + ), + Error, + > { + // Coordinates of the initial point `Q` are assigned to advice columns + 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)?; + + self.check_hash_result(EccPointQ::PublicPoint(Q), message, x_a, y_a, zs_sum) + } /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). #[allow(non_snake_case)] #[allow(clippy::type_complexity)] @@ -46,7 +71,6 @@ where > { let (offset, x_a, y_a) = self.private_initialization(region, Q)?; - // FIXME: calling construct_base is possibly(!) non-optimal let (x_a, y_a, zs_sum) = self.hash_all_pieces(region, offset, message, x_a, y_a)?; self.check_hash_result(EccPointQ::PrivatePoint(Q), message, x_a, y_a, zs_sum) diff --git a/halo2_gadgets/src/sinsemilla_opt/merkle.rs b/halo2_gadgets/src/sinsemilla_opt/merkle.rs index 69d43a5c6d..95e4d103cd 100644 --- a/halo2_gadgets/src/sinsemilla_opt/merkle.rs +++ b/halo2_gadgets/src/sinsemilla_opt/merkle.rs @@ -8,11 +8,10 @@ pub mod tests { use crate::{ ecc::tests::TestFixedBases, sinsemilla::{ - chip::SinsemillaChip, tests::{TestCommitDomain, TestHashDomain}, HashDomains, }, - utilities::{i2lebsp, lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions}, + utilities::{i2lebsp, UtilitiesInstructions}, }; use group::ff::{Field, PrimeField, PrimeFieldBits}; @@ -23,13 +22,13 @@ pub mod tests { plonk::{Circuit, ConstraintSystem, Error}, }; - use crate::sinsemilla::merkle::chip::{MerkleChip, MerkleConfig}; + use crate::sinsemilla::merkle::chip::{MerkleConfig}; use crate::sinsemilla::merkle::MerklePath; use crate::sinsemilla_opt::chip::SinsemillaChipOptimized; - use crate::utilities::lookup_range_check::LookupRangeCheck; use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; use rand::{rngs::OsRng, RngCore}; use std::{convert::TryInto, iter}; + use crate::sinsemilla_opt::merkle::chip::MerkleChipOptimized; const MERKLE_DEPTH: usize = 32; @@ -99,7 +98,7 @@ pub mod tests { table_range_check_tag, ); - let sinsemilla_config_1 = SinsemillaChip::configure( + let sinsemilla_config_1 = SinsemillaChipOptimized::configure( meta, advices[5..].try_into().unwrap(), advices[7], @@ -107,9 +106,9 @@ pub mod tests { lookup, range_check, ); - let config1 = MerkleChip::configure(meta, sinsemilla_config_1); + let config1 = MerkleChipOptimized::configure(meta, sinsemilla_config_1); - let sinsemilla_config_2 = SinsemillaChip::configure( + let sinsemilla_config_2 = SinsemillaChipOptimized::configure( meta, advices[..5].try_into().unwrap(), advices[2], @@ -117,7 +116,7 @@ pub mod tests { lookup, range_check, ); - let config2 = MerkleChip::configure(meta, sinsemilla_config_2); + let config2 = MerkleChipOptimized::configure(meta, sinsemilla_config_2); (config1, config2) } @@ -134,8 +133,8 @@ pub mod tests { )?; // Construct Merkle chips which will be placed side-by-side in the circuit. - let chip_1 = MerkleChip::construct(config.0.clone()); - let chip_2 = MerkleChip::construct(config.1.clone()); + let chip_1 = MerkleChipOptimized::construct(config.0.clone()); + let chip_2 = MerkleChipOptimized::construct(config.1.clone()); let leaf = chip_1.load_private( layouter.namespace(|| ""), diff --git a/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs b/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs index 1eaf2c0853..18240919d4 100644 --- a/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs @@ -1,69 +1,428 @@ //! Chip implementing a Merkle hash using Sinsemilla as the hash function. +use ff::PrimeField; use halo2_proofs::{ - circuit::{Chip, Layouter}, - plonk::Error, + circuit::{AssignedCell, Chip, Layouter, Value}, + plonk::{ConstraintSystem, Error}, }; use pasta_curves::pallas; -use crate::sinsemilla::chip::SinsemillaChip; -use crate::sinsemilla::SinsemillaInstructions; -use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; use crate::{ - sinsemilla::{merkle::chip::MerkleChip, primitives as sinsemilla}, - sinsemilla_opt::SinsemillaInstructionsOptimized, + sinsemilla::{ + merkle::{ + chip::{MerkleChip, MerkleConfig}, + MerkleInstructions, + }, + primitives as sinsemilla, + }, + sinsemilla_opt::chip::SinsemillaChipOptimized, utilities_opt::lookup_range_check::DefaultLookupRangeCheckConfigOptimized, { ecc::FixedPoints, - sinsemilla::{CommitDomains, HashDomains}, - utilities::cond_swap::CondSwapChip, - utilities_opt::cond_swap::CondSwapInstructionsOptimized, + sinsemilla::{chip::SinsemillaConfig, CommitDomains, HashDomains, SinsemillaInstructions}, + utilities::{cond_swap::CondSwapInstructions, UtilitiesInstructions}, }, }; +use crate::sinsemilla::MessagePiece; +use crate::utilities::RangeConstrained; + +/// Chip implementing `MerkleInstructions`. +/// +/// This chip specifically implements `MerkleInstructions::hash_layer` as the `MerkleCRH` +/// function `hash = SinsemillaHash(Q, 𝑙⋆ || left⋆ || right⋆)`, where: +/// - `𝑙⋆ = I2LEBSP_10(l)` +/// - `left⋆ = I2LEBSP_255(left)` +/// - `right⋆ = I2LEBSP_255(right)` +/// +/// This chip does **NOT** constrain `left⋆` and `right⋆` to be canonical encodings of +/// `left` and `right`. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct MerkleChipOptimized + where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, +{ + base: MerkleChip, +} + +impl Chip for MerkleChipOptimized + where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, +{ + type Config = MerkleConfig; + type Loaded = (); + + fn config(&self) -> &Self::Config { + &self.base.config + } + + fn loaded(&self) -> &Self::Loaded { + &() + } +} -impl CondSwapInstructionsOptimized - for MerkleChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, +impl MerkleChipOptimized + where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, { - fn mux( + /// Configures the [`MerkleChip`]. + pub fn configure( + meta: &mut ConstraintSystem, + sinsemilla_config: SinsemillaConfig< + Hash, + Commit, + F, + DefaultLookupRangeCheckConfigOptimized, + >, + ) -> MerkleConfig { + MerkleChip::configure(meta, sinsemilla_config) + } + + /// Constructs a [`MerkleChip`] given a [`MerkleConfig`]. + pub fn construct( + config: MerkleConfig, + ) -> Self { + MerkleChipOptimized { + base: MerkleChip { config }, + } + } +} + +impl +MerkleInstructions +for MerkleChipOptimized + where + Hash: HashDomains + Eq, + F: FixedPoints, + Commit: CommitDomains + Eq, +{ + // Todo: simplify the body? + #[allow(non_snake_case)] + fn hash_layer( &self, - layouter: &mut impl Layouter, - choice: Self::Var, + mut layouter: impl Layouter, + Q: pallas::Affine, + // l = MERKLE_DEPTH - layer - 1 + l: usize, left: Self::Var, right: Self::Var, ) -> Result { - let config = self.config().cond_swap_config.clone(); - let chip = CondSwapChip::::construct(config); - chip.mux(layouter, choice, left, right) + // Todo: simplify the body? copied and pasted from the body of the hash_layer function in halo2_gadgets/src/sinsemilla/merkle/chip.rs + + let config = self.config().clone(); + + // We need to hash `l || left || right`, where `l` is a 10-bit value. + // We allow `left` and `right` to be non-canonical 255-bit encodings. + // + // a = a_0||a_1 = l || (bits 0..=239 of left) + // b = b_0||b_1||b_2 + // = (bits 240..=249 of left) || (bits 250..=254 of left) || (bits 0..=4 of right) + // c = bits 5..=254 of right + // + // We start by witnessing all of the individual pieces, and range-constraining the + // short pieces b_1 and b_2. + // + // https://p.z.cash/halo2-0.1:sinsemilla-merkle-crh-bit-lengths?partial + + // `a = a_0||a_1` = `l` || (bits 0..=239 of `left`) + let a = MessagePiece::from_subpieces( + self.clone(), + layouter.namespace(|| "Witness a = a_0 || a_1"), + [ + RangeConstrained::bitrange_of(Value::known(&pallas::Base::from(l as u64)), 0..10), + RangeConstrained::bitrange_of(left.value(), 0..240), + ], + )?; + + // b = b_0 || b_1 || b_2 + // = (bits 240..=249 of left) || (bits 250..=254 of left) || (bits 0..=4 of right) + let (b_1, b_2, b) = { + // b_0 = (bits 240..=249 of `left`) + let b_0 = RangeConstrained::bitrange_of(left.value(), 240..250); + + // b_1 = (bits 250..=254 of `left`) + // Constrain b_1 to 5 bits. + let b_1 = RangeConstrained::witness_short( + &config.sinsemilla_config.lookup_config(), + layouter.namespace(|| "b_1"), + left.value(), + 250..(pallas::Base::NUM_BITS as usize), + )?; + + // b_2 = (bits 0..=4 of `right`) + // Constrain b_2 to 5 bits. + let b_2 = RangeConstrained::witness_short( + &config.sinsemilla_config.lookup_config(), + layouter.namespace(|| "b_2"), + right.value(), + 0..5, + )?; + + let b = MessagePiece::from_subpieces( + self.clone(), + layouter.namespace(|| "Witness b = b_0 || b_1 || b_2"), + [b_0, b_1.value(), b_2.value()], + )?; + + (b_1, b_2, b) + }; + + // c = bits 5..=254 of `right` + let c = MessagePiece::from_subpieces( + self.clone(), + layouter.namespace(|| "Witness c"), + [RangeConstrained::bitrange_of( + right.value(), + 5..(pallas::Base::NUM_BITS as usize), + )], + )?; + + // hash = SinsemillaHash(Q, 𝑙⋆ || left⋆ || right⋆) + // + // `hash = ⊥` is handled internally to `SinsemillaChip::hash_to_point`: incomplete + // addition constraints allows ⊥ to occur, and then during synthesis it detects + // these edge cases and raises an error (aborting proof creation). + // + // Note that MerkleCRH as-defined maps ⊥ to 0. This is for completeness outside + // the circuit (so that the ⊥ does not propagate into the type system). The chip + // explicitly doesn't map ⊥ to 0; in fact it cannot, as doing so would require + // constraints that amount to using complete addition. The rationale for excluding + // this map is the same as why Sinsemilla uses incomplete addition: this situation + // yields a nontrivial discrete log relation, and by assumption it is hard to find + // these. + // + // https://p.z.cash/proto:merkle-crh-orchard + let (point, zs) = self.hash_to_point( + layouter.namespace(|| format!("hash at l = {}", l)), + Q, + vec![a.inner(), b.inner(), c.inner()].into(), + )?; + let hash = Self::extract(&point); + + // `SinsemillaChip::hash_to_point` returns the running sum for each `MessagePiece`. + // Grab the outputs we need for the decomposition constraints. + let z1_a = zs[0][1].clone(); + let z1_b = zs[1][1].clone(); + + // Check that the pieces have been decomposed properly. + // + // The pieces and subpieces are arranged in the following configuration: + // | A_0 | A_1 | A_2 | A_3 | A_4 | q_decompose | + // ------------------------------------------------------- + // | a | b | c | left | right | 1 | + // | z1_a | z1_b | b_1 | b_2 | l | 0 | + { + layouter.assign_region( + || "Check piece decomposition", + |mut region| { + // Set the fixed column `l` to the current l. + // Recall that l = MERKLE_DEPTH - layer - 1. + // The layer with 2^n nodes is called "layer n". + config.q_decompose.enable(&mut region, 0)?; + region.assign_advice_from_constant( + || format!("l {}", l), + config.advices[4], + 1, + pallas::Base::from(l as u64), + )?; + + // Offset 0 + // Copy and assign `a` at the correct position. + a.inner().cell_value().copy_advice( + || "copy a", + &mut region, + config.advices[0], + 0, + )?; + // Copy and assign `b` at the correct position. + b.inner().cell_value().copy_advice( + || "copy b", + &mut region, + config.advices[1], + 0, + )?; + // Copy and assign `c` at the correct position. + c.inner().cell_value().copy_advice( + || "copy c", + &mut region, + config.advices[2], + 0, + )?; + // Copy and assign the left node at the correct position. + left.copy_advice(|| "left", &mut region, config.advices[3], 0)?; + // Copy and assign the right node at the correct position. + right.copy_advice(|| "right", &mut region, config.advices[4], 0)?; + + // Offset 1 + // Copy and assign z_1 of SinsemillaHash(a) = a_1 + z1_a.copy_advice(|| "z1_a", &mut region, config.advices[0], 1)?; + // Copy and assign z_1 of SinsemillaHash(b) = b_1 + z1_b.copy_advice(|| "z1_b", &mut region, config.advices[1], 1)?; + // Copy `b_1`, which has been constrained to be a 5-bit value + b_1.inner() + .copy_advice(|| "b_1", &mut region, config.advices[2], 1)?; + // Copy `b_2`, which has been constrained to be a 5-bit value + b_2.inner() + .copy_advice(|| "b_2", &mut region, config.advices[3], 1)?; + + Ok(()) + }, + )?; + } + // Check layer hash output against Sinsemilla primitives hash + #[cfg(test)] + { + use crate::{sinsemilla::primitives::HashDomain, utilities::i2lebsp}; + + use group::ff::PrimeFieldBits; + + left.value() + .zip(right.value()) + .zip(hash.value()) + .assert_if_known(|((left, right), hash)| { + let l = i2lebsp::<10>(l as u64); + let left: Vec<_> = left + .to_le_bits() + .iter() + .by_vals() + .take(pallas::Base::NUM_BITS as usize) + .collect(); + let right: Vec<_> = right + .to_le_bits() + .iter() + .by_vals() + .take(pallas::Base::NUM_BITS as usize) + .collect(); + let merkle_crh = HashDomain::from_Q(Q.into()); + + let mut message = l.to_vec(); + message.extend_from_slice(&left); + message.extend_from_slice(&right); + + let expected = merkle_crh.hash(message.into_iter()).unwrap(); + + expected.to_repr() == hash.to_repr() + }); + } + + Ok(hash) + + + } +} + +impl UtilitiesInstructions for MerkleChipOptimized + where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, +{ + type Var = AssignedCell; +} + +impl CondSwapInstructions for MerkleChipOptimized + where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, +{ + #[allow(clippy::type_complexity)] + fn swap( + &self, + layouter: impl Layouter, + pair: (Self::Var, Value), + swap: Value, + ) -> Result<(Self::Var, Self::Var), Error> { + self.base.swap(layouter, pair, swap) } } -impl - SinsemillaInstructionsOptimized - for MerkleChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, +impl SinsemillaInstructions +for MerkleChipOptimized + where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, { + type CellValue = as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::CellValue; + + type Message = as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::Message; + type MessagePiece = as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::MessagePiece; + type RunningSum = as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::RunningSum; + + type X = as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::X; + type NonIdentityPoint = as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::NonIdentityPoint; + type FixedPoints = as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::FixedPoints; + + type HashDomains = as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::HashDomains; + type CommitDomains = as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::CommitDomains; + + fn witness_message_piece( + &self, + layouter: impl Layouter, + value: Value, + num_words: usize, + ) -> Result { + let config = self.config().sinsemilla_config.clone(); + let chip = SinsemillaChipOptimized::::construct(config); + chip.witness_message_piece(layouter, value, num_words) + } + #[allow(non_snake_case)] #[allow(clippy::type_complexity)] - fn hash_to_point_with_private_init( + fn hash_to_point( &self, layouter: impl Layouter, - Q: &Self::NonIdentityPoint, + Q: pallas::Affine, message: Self::Message, ) -> Result<(Self::NonIdentityPoint, Vec>), Error> { let config = self.config().sinsemilla_config.clone(); - let chip = SinsemillaChip::< - Hash, - Commit, - F, - LookupRangeCheckConfigOptimized, - >::construct(config); - chip.hash_to_point_with_private_init(layouter, Q, message) + let chip = SinsemillaChipOptimized::::construct(config); + chip.hash_to_point(layouter, Q, message) } -} + + fn extract(point: &Self::NonIdentityPoint) -> Self::X { + SinsemillaChipOptimized::::extract(point) + } +} \ No newline at end of file diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index f553920036..35dcd6ecf3 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -69,14 +69,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 - fn is_optimized() -> bool; - /// FIXME: add doc + /// Returns a reference to the `LookupRangeCheckConfig` instance. fn config(&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, @@ -86,9 +94,14 @@ 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 + /// Constrain `x` to be a NUM_BITS word. + /// + /// `element` must have been assigned to `self.running_sum` at offset 0. fn short_range_check( &self, region: &mut Region<'_, F>, @@ -274,9 +287,6 @@ pub trait LookupRangeCheck { } impl LookupRangeCheck for LookupRangeCheckConfig { - fn is_optimized() -> bool { - false - } fn config(&self) -> &LookupRangeCheckConfig { self @@ -293,7 +303,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, @@ -308,7 +317,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); @@ -424,10 +432,13 @@ impl LookupRangeCheck for LookupRangeCh } } -/// FIXME: add doc +/// The `DefaultLookupRangeCheck` trait extends the `LookupRangeCheck` with additional +/// standard traits necessary for effective use in cryptographic contexts. pub trait DefaultLookupRangeCheck: LookupRangeCheck + Eq + PartialEq + Clone + Copy + Debug { } impl DefaultLookupRangeCheck for LookupRangeCheckConfig {} + + diff --git a/halo2_gadgets/src/utilities_opt/cond_swap.rs b/halo2_gadgets/src/utilities_opt/cond_swap.rs index d14e5407ba..ffe9d45838 100644 --- a/halo2_gadgets/src/utilities_opt/cond_swap.rs +++ b/halo2_gadgets/src/utilities_opt/cond_swap.rs @@ -131,7 +131,7 @@ mod tests { tests::TestFixedBases, NonIdentityPoint, Point, }, - utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, + utilities::lookup_range_check::{LookupRangeCheck}, }; use group::{cofactor::CofactorCurveAffine, Curve, Group}; diff --git a/halo2_gadgets/src/utilities_opt/lookup_range_check.rs b/halo2_gadgets/src/utilities_opt/lookup_range_check.rs index 6306e25bfb..97ab50c97e 100644 --- a/halo2_gadgets/src/utilities_opt/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities_opt/lookup_range_check.rs @@ -171,10 +171,6 @@ impl LookupRangeCheckConfigOptimized { impl LookupRangeCheck for LookupRangeCheckConfigOptimized { - fn is_optimized() -> bool { - true - } - fn config(&self) -> &LookupRangeCheckConfig { &self.base } From 2e31e97debd7bdb03996a0eb3a9a3dd14a55e41a Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 29 Apr 2024 15:35:31 +0200 Subject: [PATCH 21/99] fmt --- halo2_gadgets/src/ecc.rs | 4 +- halo2_gadgets/src/ecc/chip.rs | 24 ++-- halo2_gadgets/src/ecc/chip/mul.rs | 2 +- .../src/ecc/chip/mul_fixed/base_field_elem.rs | 9 +- .../src/ecc_opt/chip/mul_fixed/short.rs | 4 +- halo2_gadgets/src/sinsemilla/chip.rs | 9 +- .../src/sinsemilla/chip/hash_to_point.rs | 3 +- halo2_gadgets/src/sinsemilla/merkle/chip.rs | 121 ++++++++---------- halo2_gadgets/src/sinsemilla_opt.rs | 15 +-- halo2_gadgets/src/sinsemilla_opt/chip.rs | 59 +++++---- .../src/sinsemilla_opt/chip/hash_to_point.rs | 3 +- halo2_gadgets/src/sinsemilla_opt/merkle.rs | 4 +- .../src/sinsemilla_opt/merkle/chip.rs | 70 +++++----- .../src/utilities/lookup_range_check.rs | 3 - halo2_gadgets/src/utilities_opt/cond_swap.rs | 2 +- 15 files changed, 148 insertions(+), 184 deletions(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 1d1a4a48e3..97859c3ddd 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -595,9 +595,7 @@ pub(crate) mod tests { }, FixedPoints, }; - use crate::{ - utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, - }; + use crate::utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}; #[derive(Debug, Eq, PartialEq, Clone)] pub(crate) struct TestFixedBases; diff --git a/halo2_gadgets/src/ecc/chip.rs b/halo2_gadgets/src/ecc/chip.rs index 76d5a019a7..c27a34ca6b 100644 --- a/halo2_gadgets/src/ecc/chip.rs +++ b/halo2_gadgets/src/ecc/chip.rs @@ -227,17 +227,13 @@ pub trait FixedPoint: std::fmt::Debug + Eq + Clone { /// An [`EccInstructions`] chip that uses 10 advice columns. #[derive(Clone, Debug, Eq, PartialEq)] -pub struct EccChip< - FixedPoints: super::FixedPoints, - Lookup: DefaultLookupRangeCheck, -> { +pub struct EccChip, Lookup: DefaultLookupRangeCheck> +{ config: EccConfig, } -impl< - FixedPoints: super::FixedPoints, - Lookup: DefaultLookupRangeCheck, - > Chip for EccChip +impl, Lookup: DefaultLookupRangeCheck> + Chip for EccChip { type Config = EccConfig; type Loaded = (); @@ -251,18 +247,14 @@ impl< } } -impl< - Fixed: super::FixedPoints, - Lookup: DefaultLookupRangeCheck, - > UtilitiesInstructions for EccChip +impl, Lookup: DefaultLookupRangeCheck> + UtilitiesInstructions for EccChip { type Var = AssignedCell; } -impl< - FixedPoints: super::FixedPoints, - Lookup: DefaultLookupRangeCheck, - > EccChip +impl, Lookup: DefaultLookupRangeCheck> + EccChip { /// Reconstructs this chip from the given config. pub fn construct(config: >::Config) -> Self { diff --git a/halo2_gadgets/src/ecc/chip/mul.rs b/halo2_gadgets/src/ecc/chip/mul.rs index 61f36f88e9..a67b77b0e8 100644 --- a/halo2_gadgets/src/ecc/chip/mul.rs +++ b/halo2_gadgets/src/ecc/chip/mul.rs @@ -467,7 +467,7 @@ pub mod tests { use pasta_curves::pallas; use rand::rngs::OsRng; - use crate::utilities::lookup_range_check::{DefaultLookupRangeCheck}; + use crate::utilities::lookup_range_check::DefaultLookupRangeCheck; use crate::{ ecc::{ chip::{EccChip, EccPoint}, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs index 1298140e43..5ea0b38eef 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs @@ -16,19 +16,14 @@ use pasta_curves::pallas; use std::convert::TryInto; #[derive(Clone, Debug, Eq, PartialEq)] -pub struct Config< - Fixed: FixedPoints, - Lookup: DefaultLookupRangeCheck, -> { +pub struct Config, Lookup: DefaultLookupRangeCheck> { q_mul_fixed_base_field: Selector, canon_advices: [Column; 3], lookup_config: Lookup, super_config: super::Config, } -impl, Lookup: DefaultLookupRangeCheck> - Config -{ +impl, Lookup: DefaultLookupRangeCheck> Config { pub(crate) fn configure( meta: &mut ConstraintSystem, canon_advices: [Column; 3], diff --git a/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs index b0487b5d73..830eec83b2 100644 --- a/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs +++ b/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs @@ -91,9 +91,7 @@ pub mod tests { use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; use crate::{ ecc::{chip::EccChip, tests::TestFixedBases, Point}, - utilities::{ - UtilitiesInstructions, - }, + utilities::UtilitiesInstructions, }; pub(crate) fn test_mul_sign( diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs index fa64deedfe..7d96f2c8f3 100644 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ b/halo2_gadgets/src/sinsemilla/chip.rs @@ -63,8 +63,7 @@ where pub(crate) _marker: PhantomData<(Hash, Commit, F)>, } -impl - SinsemillaConfig +impl SinsemillaConfig where Hash: HashDomains, F: FixedPoints, @@ -109,8 +108,7 @@ where config: SinsemillaConfig, } -impl Chip - for SinsemillaChip +impl Chip for SinsemillaChip where Hash: HashDomains, Fixed: FixedPoints, @@ -129,8 +127,7 @@ where } } -impl - SinsemillaChip +impl SinsemillaChip where Hash: HashDomains, F: FixedPoints, diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 0456fc0893..93b5e29d11 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -24,8 +24,7 @@ pub enum EccPointQ<'a> { PrivatePoint(&'a NonIdentityEccPoint), } -impl - SinsemillaChip +impl SinsemillaChip where Hash: HashDomains, Fixed: FixedPoints, diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs index c54133e291..d05d9fc8b3 100644 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla/merkle/chip.rs @@ -29,11 +29,11 @@ use group::ff::PrimeField; /// Configuration for the `MerkleChip` implementation. #[derive(Clone, Debug, PartialEq, Eq)] pub struct MerkleConfig - where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, +where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, + Lookup: DefaultLookupRangeCheck, { pub(crate) advices: [Column; 5], pub(crate) q_decompose: Selector, @@ -53,22 +53,21 @@ pub struct MerkleConfig /// `left` and `right`. #[derive(Clone, Debug, PartialEq, Eq)] pub struct MerkleChip - where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, +where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, + Lookup: DefaultLookupRangeCheck, { pub(crate) config: MerkleConfig, } -impl Chip -for MerkleChip - where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, +impl Chip for MerkleChip +where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, + Lookup: DefaultLookupRangeCheck, { type Config = MerkleConfig; type Loaded = (); @@ -83,11 +82,11 @@ for MerkleChip } impl MerkleChip - where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, + Lookup: DefaultLookupRangeCheck, { /// Configures the [`MerkleChip`]. pub fn configure( @@ -202,13 +201,13 @@ impl MerkleChip } impl -MerkleInstructions -for MerkleChip - where - Hash: HashDomains + Eq, - F: FixedPoints, - Commit: CommitDomains + Eq, - Lookup: DefaultLookupRangeCheck, + MerkleInstructions + for MerkleChip +where + Hash: HashDomains + Eq, + F: FixedPoints, + Commit: CommitDomains + Eq, + Lookup: DefaultLookupRangeCheck, { #[allow(non_snake_case)] fn hash_layer( @@ -422,23 +421,23 @@ for MerkleChip } impl UtilitiesInstructions -for MerkleChip - where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + for MerkleChip +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, + Lookup: DefaultLookupRangeCheck, { type Var = AssignedCell; } impl CondSwapInstructions -for MerkleChip - where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + for MerkleChip +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, + Lookup: DefaultLookupRangeCheck, { #[allow(clippy::type_complexity)] fn swap( @@ -454,35 +453,31 @@ for MerkleChip } impl -SinsemillaInstructions -for MerkleChip - where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + SinsemillaInstructions + for MerkleChip +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, + Lookup: DefaultLookupRangeCheck, { - type CellValue = - as SinsemillaInstructions< + type CellValue = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::CellValue; - type Message = - as SinsemillaInstructions< + type Message = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::Message; - type MessagePiece = - as SinsemillaInstructions< + type MessagePiece = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::MessagePiece; - type RunningSum = - as SinsemillaInstructions< + type RunningSum = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, @@ -493,27 +488,23 @@ for MerkleChip { sinsemilla::K }, { sinsemilla::C }, >>::X; - type NonIdentityPoint = - as SinsemillaInstructions< + type NonIdentityPoint = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::NonIdentityPoint; - type FixedPoints = - as SinsemillaInstructions< + type FixedPoints = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::FixedPoints; - type HashDomains = - as SinsemillaInstructions< + type HashDomains = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::HashDomains; - type CommitDomains = - as SinsemillaInstructions< + type CommitDomains = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, @@ -546,4 +537,4 @@ for MerkleChip fn extract(point: &Self::NonIdentityPoint) -> Self::X { SinsemillaChip::::extract(point) } -} \ No newline at end of file +} diff --git a/halo2_gadgets/src/sinsemilla_opt.rs b/halo2_gadgets/src/sinsemilla_opt.rs index 397209e80c..79e788be06 100644 --- a/halo2_gadgets/src/sinsemilla_opt.rs +++ b/halo2_gadgets/src/sinsemilla_opt.rs @@ -23,9 +23,8 @@ pub mod primitives; /// designed to enhance performance in specific cryptographic scenarios.ld pub trait SinsemillaInstructionsOptimized: -SinsemillaInstructions + SinsemillaInstructions { - /// Hashes a message to an ECC curve point. /// This returns both the resulting point, as well as the message /// decomposition in the form of intermediate values in a cumulative @@ -156,14 +155,12 @@ pub(crate) mod tests { use crate::{ ecc::ScalarFixed, - sinsemilla::primitives::{self as sinsemilla, K}, - { - ecc::{ - chip::{find_zs_and_us, EccChip, EccConfig, H, NUM_WINDOWS}, - tests::{FullWidth, TestFixedBases}, - NonIdentityPoint, - }, + ecc::{ + chip::{find_zs_and_us, EccChip, EccConfig, H, NUM_WINDOWS}, + tests::{FullWidth, TestFixedBases}, + NonIdentityPoint, }, + sinsemilla::primitives::{self as sinsemilla, K}, }; use group::{ff::Field, Curve}; diff --git a/halo2_gadgets/src/sinsemilla_opt/chip.rs b/halo2_gadgets/src/sinsemilla_opt/chip.rs index d08c76153d..a630f27e0c 100644 --- a/halo2_gadgets/src/sinsemilla_opt/chip.rs +++ b/halo2_gadgets/src/sinsemilla_opt/chip.rs @@ -28,19 +28,19 @@ mod hash_to_point; /// [Chip description](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html#plonk--halo-2-constraints). #[derive(Eq, PartialEq, Clone, Debug)] pub struct SinsemillaChipOptimized - where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, +where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, { inner: SinsemillaChip, } impl Chip for SinsemillaChipOptimized - where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, +where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, { type Config = SinsemillaConfig; type Loaded = (); @@ -55,18 +55,18 @@ impl Chip for SinsemillaChipOptimized SinsemillaChipOptimized - where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, { /// Reconstructs this chip from the given config. pub fn construct(config: >::Config) -> Self { Self { inner: - SinsemillaChip::::construct( - config, - ), + SinsemillaChip::::construct( + config, + ), } } @@ -145,11 +145,11 @@ impl SinsemillaChipOptimized // Implement `SinsemillaInstructions` for `SinsemillaChip` impl SinsemillaInstructions -for SinsemillaChipOptimized - where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, + for SinsemillaChipOptimized +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, { type CellValue = AssignedCell; @@ -196,12 +196,12 @@ for SinsemillaChipOptimized // Implement `SinsemillaInstructions` for `SinsemillaChip` impl -SinsemillaInstructionsOptimized -for SinsemillaChipOptimized - where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, + SinsemillaInstructionsOptimized + for SinsemillaChipOptimized +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, { #[allow(non_snake_case)] #[allow(clippy::type_complexity)] @@ -213,7 +213,10 @@ for SinsemillaChipOptimized ) -> Result<(Self::NonIdentityPoint, Vec), Error> { layouter.assign_region( || "hash_to_point", - |mut region| self.inner.hash_message_with_private_init(&mut region, Q, &message), + |mut region| { + self.inner + .hash_message_with_private_init(&mut region, Q, &message) + }, ) } -} \ No newline at end of file +} 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 5f513ba5df..956a7cd70f 100644 --- a/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs @@ -17,8 +17,7 @@ use crate::{ }, }; -impl - SinsemillaChip +impl SinsemillaChip where Hash: HashDomains, Fixed: FixedPoints, diff --git a/halo2_gadgets/src/sinsemilla_opt/merkle.rs b/halo2_gadgets/src/sinsemilla_opt/merkle.rs index 95e4d103cd..d1676765b0 100644 --- a/halo2_gadgets/src/sinsemilla_opt/merkle.rs +++ b/halo2_gadgets/src/sinsemilla_opt/merkle.rs @@ -22,13 +22,13 @@ pub mod tests { plonk::{Circuit, ConstraintSystem, Error}, }; - use crate::sinsemilla::merkle::chip::{MerkleConfig}; + use crate::sinsemilla::merkle::chip::MerkleConfig; use crate::sinsemilla::merkle::MerklePath; use crate::sinsemilla_opt::chip::SinsemillaChipOptimized; + use crate::sinsemilla_opt::merkle::chip::MerkleChipOptimized; use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; use rand::{rngs::OsRng, RngCore}; use std::{convert::TryInto, iter}; - use crate::sinsemilla_opt::merkle::chip::MerkleChipOptimized; const MERKLE_DEPTH: usize = 32; diff --git a/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs b/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs index 18240919d4..f0ab3d5ca1 100644 --- a/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs @@ -7,6 +7,8 @@ use halo2_proofs::{ }; use pasta_curves::pallas; +use crate::sinsemilla::MessagePiece; +use crate::utilities::RangeConstrained; use crate::{ sinsemilla::{ merkle::{ @@ -23,8 +25,6 @@ use crate::{ utilities::{cond_swap::CondSwapInstructions, UtilitiesInstructions}, }, }; -use crate::sinsemilla::MessagePiece; -use crate::utilities::RangeConstrained; /// Chip implementing `MerkleInstructions`. /// @@ -38,19 +38,19 @@ use crate::utilities::RangeConstrained; /// `left` and `right`. #[derive(Clone, Debug, PartialEq, Eq)] pub struct MerkleChipOptimized - where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, +where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, { base: MerkleChip, } impl Chip for MerkleChipOptimized - where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, +where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, { type Config = MerkleConfig; type Loaded = (); @@ -65,10 +65,10 @@ impl Chip for MerkleChipOptimized MerkleChipOptimized - where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, { /// Configures the [`MerkleChip`]. pub fn configure( @@ -94,12 +94,12 @@ impl MerkleChipOptimized } impl -MerkleInstructions -for MerkleChipOptimized - where - Hash: HashDomains + Eq, - F: FixedPoints, - Commit: CommitDomains + Eq, + MerkleInstructions + for MerkleChipOptimized +where + Hash: HashDomains + Eq, + F: FixedPoints, + Commit: CommitDomains + Eq, { // Todo: simplify the body? #[allow(non_snake_case)] @@ -311,25 +311,23 @@ for MerkleChipOptimized } Ok(hash) - - } } impl UtilitiesInstructions for MerkleChipOptimized - where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, { type Var = AssignedCell; } impl CondSwapInstructions for MerkleChipOptimized - where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, { #[allow(clippy::type_complexity)] fn swap( @@ -343,11 +341,11 @@ impl CondSwapInstructions for MerkleChipOptimized } impl SinsemillaInstructions -for MerkleChipOptimized - where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, + for MerkleChipOptimized +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, { type CellValue = as SinsemillaInstructions< pallas::Affine, @@ -425,4 +423,4 @@ for MerkleChipOptimized fn extract(point: &Self::NonIdentityPoint) -> Self::X { SinsemillaChipOptimized::::extract(point) } -} \ No newline at end of file +} diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 35dcd6ecf3..a4ab1ba5ab 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -287,7 +287,6 @@ pub trait LookupRangeCheck { } impl LookupRangeCheck for LookupRangeCheckConfig { - fn config(&self) -> &LookupRangeCheckConfig { self } @@ -440,5 +439,3 @@ pub trait DefaultLookupRangeCheck: } impl DefaultLookupRangeCheck for LookupRangeCheckConfig {} - - diff --git a/halo2_gadgets/src/utilities_opt/cond_swap.rs b/halo2_gadgets/src/utilities_opt/cond_swap.rs index ffe9d45838..eae0b148fd 100644 --- a/halo2_gadgets/src/utilities_opt/cond_swap.rs +++ b/halo2_gadgets/src/utilities_opt/cond_swap.rs @@ -131,7 +131,7 @@ mod tests { tests::TestFixedBases, NonIdentityPoint, Point, }, - utilities::lookup_range_check::{LookupRangeCheck}, + utilities::lookup_range_check::LookupRangeCheck, }; use group::{cofactor::CofactorCurveAffine, Curve, Group}; From b02478a6c6a99f6c33ebc4fbf0b519c1c7e51f7d Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 29 Apr 2024 19:11:40 +0200 Subject: [PATCH 22/99] fix run tests error --- halo2_gadgets/Cargo.toml | 3 +-- rust-toolchain.toml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/halo2_gadgets/Cargo.toml b/halo2_gadgets/Cargo.toml index 1aa754264e..2021d77e25 100644 --- a/halo2_gadgets/Cargo.toml +++ b/halo2_gadgets/Cargo.toml @@ -49,7 +49,6 @@ pprof = { version = "0.8", features = ["criterion", "flamegraph"] } # MSRV 1.56 bench = false [features] -default = ["test-dev-graph"] test-dev-graph = [ "halo2_proofs/dev-graph", "plotters", @@ -83,4 +82,4 @@ harness = false [[bench]] name = "sha256" harness = false -required-features = ["unstable-sha256-gadget"] +required-features = ["unstable-sha256-gadget"] \ No newline at end of file diff --git a/rust-toolchain.toml b/rust-toolchain.toml index f8c2abbb3d..948d27daa4 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.65.0" +channel = "1.60.0" From e6d1dbede6bd422306c499fdb43e0bfe02235701 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 29 Apr 2024 20:17:55 +0200 Subject: [PATCH 23/99] minor update --- halo2_gadgets/src/sinsemilla/merkle.rs | 2 +- halo2_gadgets/src/sinsemilla_opt/merkle.rs | 2 +- halo2_gadgets/src/utilities_opt/lookup_range_check.rs | 4 ---- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 1485c466f1..21561e7316 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -407,7 +407,7 @@ pub mod tests { let circuit = MyCircuit::default(); halo2_proofs::dev::CircuitLayout::default() - .show_labels(true) + .show_labels(false) .render(11, &circuit, &root) .unwrap(); } diff --git a/halo2_gadgets/src/sinsemilla_opt/merkle.rs b/halo2_gadgets/src/sinsemilla_opt/merkle.rs index d1676765b0..3983e42659 100644 --- a/halo2_gadgets/src/sinsemilla_opt/merkle.rs +++ b/halo2_gadgets/src/sinsemilla_opt/merkle.rs @@ -239,7 +239,7 @@ pub mod tests { let circuit = MyCircuit::default(); halo2_proofs::dev::CircuitLayout::default() - .show_labels(true) + .show_labels(false) .render(11, &circuit, &root) .unwrap(); } diff --git a/halo2_gadgets/src/utilities_opt/lookup_range_check.rs b/halo2_gadgets/src/utilities_opt/lookup_range_check.rs index 97ab50c97e..e2c1a808a9 100644 --- a/halo2_gadgets/src/utilities_opt/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities_opt/lookup_range_check.rs @@ -31,8 +31,6 @@ pub struct LookupRangeCheckConfigOptimized { base: LookupRangeCheckConfig, q_range_check_4: Selector, q_range_check_5: Selector, - // FIXME: Instead of making it pub, add a method in LookupRangeCheckConfig that returns table_range_check_tag - //pub(crate) table_range_check_tag: TableColumn, } @@ -63,7 +61,6 @@ impl LookupRangeCheckConfigOptimized { let q_range_check_4 = meta.complex_selector(); let q_range_check_5 = meta.complex_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 = LookupRangeCheckConfigOptimized { base: LookupRangeCheckConfig { @@ -83,7 +80,6 @@ impl LookupRangeCheckConfigOptimized { meta.lookup(|meta| { let q_lookup = meta.query_selector(config.base.q_lookup); let q_running = meta.query_selector(config.base.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.base.running_sum, Rotation::cur()); let one = Expression::Constant(F::ONE); From 23a295172b6c8cb0b642512109801b5116d79c6a Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 29 Apr 2024 20:22:09 +0200 Subject: [PATCH 24/99] test error --- halo2_gadgets/src/ecc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 38fab0a49a..e703337046 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -1,5 +1,5 @@ //! Elliptic curve operations. - +// test error use std::fmt::Debug; use halo2_proofs::{ From 301e7d82e1cc8dee43389d6602b13e8a7a57f601 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 29 Apr 2024 20:35:32 +0200 Subject: [PATCH 25/99] Revert "test error" This reverts commit 23a295172b6c8cb0b642512109801b5116d79c6a. --- halo2_gadgets/src/ecc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index e703337046..38fab0a49a 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -1,5 +1,5 @@ //! Elliptic curve operations. -// test error + use std::fmt::Debug; use halo2_proofs::{ From c3240066afff7e3690d9080c83ea84ce960ee78a Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Tue, 30 Apr 2024 13:18:33 +0200 Subject: [PATCH 26/99] re-naming structs and functions --- .../src/sinsemilla/chip/hash_to_point.rs | 16 ++++----- halo2_gadgets/src/sinsemilla_opt/chip.rs | 11 +++--- .../src/sinsemilla_opt/chip/hash_to_point.rs | 35 +++++++++++++------ .../src/sinsemilla_opt/merkle/chip.rs | 8 ++--- .../src/utilities/lookup_range_check.rs | 4 +-- 5 files changed, 42 insertions(+), 32 deletions(-) diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 93b5e29d11..2aefb97233 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -24,6 +24,10 @@ pub enum EccPointQ<'a> { PrivatePoint(&'a NonIdentityEccPoint), } +type HashOutput = NonIdentityEccPoint; +type CellMatrix = Vec>>; +type HashResult = Result<(HashOutput, CellMatrix), Error>; + impl SinsemillaChip where Hash: HashDomains, @@ -43,14 +47,8 @@ where { sinsemilla::K }, { sinsemilla::C }, >>::Message, - ) -> Result< - ( - NonIdentityEccPoint, - Vec>>, - ), - Error, - > { - let (offset, x_a, y_a) = self.public_initialization_vanilla(region, Q)?; + ) -> HashResult { + 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)?; @@ -137,7 +135,7 @@ where /// | offset | x_A | q_sinsemilla4 | fixed_y_q | /// -------------------------------------- /// | 0 | x_Q | 1 | y_Q | - pub(crate) fn public_initialization_vanilla( + pub(crate) fn public_initialization( &self, region: &mut Region<'_, pallas::Base>, Q: pallas::Affine, diff --git a/halo2_gadgets/src/sinsemilla_opt/chip.rs b/halo2_gadgets/src/sinsemilla_opt/chip.rs index a630f27e0c..1b544edf75 100644 --- a/halo2_gadgets/src/sinsemilla_opt/chip.rs +++ b/halo2_gadgets/src/sinsemilla_opt/chip.rs @@ -143,7 +143,7 @@ where } } -// Implement `SinsemillaInstructions` for `SinsemillaChip` +// Implement `SinsemillaInstructions` for `SinsemillaChipOptimized` impl SinsemillaInstructions for SinsemillaChipOptimized where @@ -185,7 +185,7 @@ where ) -> Result<(Self::NonIdentityPoint, Vec), Error> { layouter.assign_region( || "hash_to_point", - |mut region| self.inner.hash_message_zsa(&mut region, Q, &message), + |mut region| self.hash_message(&mut region, Q, &message), ) } @@ -194,7 +194,7 @@ where } } -// Implement `SinsemillaInstructions` for `SinsemillaChip` +// Implement `SinsemillaInstructionsOptimized` for `SinsemillaChipOptimized` impl SinsemillaInstructionsOptimized for SinsemillaChipOptimized @@ -213,10 +213,7 @@ where ) -> Result<(Self::NonIdentityPoint, Vec), Error> { layouter.assign_region( || "hash_to_point", - |mut region| { - self.inner - .hash_message_with_private_init(&mut region, Q, &message) - }, + |mut region| self.hash_message_with_private_init(&mut region, Q, &message), ) } } 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 956a7cd70f..8ef33ab4ef 100644 --- a/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs @@ -7,7 +7,7 @@ use halo2_proofs::{ use crate::sinsemilla::chip::hash_to_point::EccPointQ; use crate::sinsemilla::chip::SinsemillaChip; -use crate::utilities::lookup_range_check::DefaultLookupRangeCheck; +use crate::sinsemilla_opt::chip::SinsemillaChipOptimized; use crate::{ ecc::{chip::NonIdentityEccPoint, FixedPoints}, sinsemilla::{ @@ -17,16 +17,15 @@ use crate::{ }, }; -impl SinsemillaChip +impl SinsemillaChipOptimized where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, { #[allow(non_snake_case)] #[allow(clippy::type_complexity)] - pub(crate) fn hash_message_zsa( + pub(crate) fn hash_message( &self, region: &mut Region<'_, pallas::Base>, Q: pallas::Affine, @@ -45,9 +44,17 @@ where // Coordinates of the initial point `Q` are assigned to advice columns 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)?; - - self.check_hash_result(EccPointQ::PublicPoint(Q), message, x_a, y_a, zs_sum) + let (x_a, y_a, zs_sum) = + SinsemillaChip::hash_all_pieces(&self.inner, region, offset, message, x_a, y_a)?; + + SinsemillaChip::check_hash_result( + &self.inner, + EccPointQ::PublicPoint(Q), + message, + x_a, + y_a, + zs_sum, + ) } /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). #[allow(non_snake_case)] @@ -70,9 +77,17 @@ where > { let (offset, x_a, y_a) = self.private_initialization(region, Q)?; - let (x_a, y_a, zs_sum) = self.hash_all_pieces(region, offset, message, x_a, y_a)?; - - self.check_hash_result(EccPointQ::PrivatePoint(Q), message, x_a, y_a, zs_sum) + let (x_a, y_a, zs_sum) = + SinsemillaChip::hash_all_pieces(&self.inner, region, offset, message, x_a, y_a)?; + + SinsemillaChip::check_hash_result( + &self.inner, + EccPointQ::PrivatePoint(Q), + message, + x_a, + y_a, + zs_sum, + ) } #[allow(non_snake_case)] diff --git a/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs b/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs index f0ab3d5ca1..3445bef41f 100644 --- a/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs @@ -114,7 +114,7 @@ where ) -> Result { // Todo: simplify the body? copied and pasted from the body of the hash_layer function in halo2_gadgets/src/sinsemilla/merkle/chip.rs - let config = self.config().clone(); + let config = self.base.config().clone(); // We need to hash `l || left || right`, where `l` is a 10-bit value. // We allow `left` and `right` to be non-canonical 255-bit encodings. @@ -131,7 +131,7 @@ where // `a = a_0||a_1` = `l` || (bits 0..=239 of `left`) let a = MessagePiece::from_subpieces( - self.clone(), + self.base.clone(), layouter.namespace(|| "Witness a = a_0 || a_1"), [ RangeConstrained::bitrange_of(Value::known(&pallas::Base::from(l as u64)), 0..10), @@ -164,7 +164,7 @@ where )?; let b = MessagePiece::from_subpieces( - self.clone(), + self.base.clone(), layouter.namespace(|| "Witness b = b_0 || b_1 || b_2"), [b_0, b_1.value(), b_2.value()], )?; @@ -174,7 +174,7 @@ where // c = bits 5..=254 of `right` let c = MessagePiece::from_subpieces( - self.clone(), + self.base.clone(), layouter.namespace(|| "Witness c"), [RangeConstrained::bitrange_of( right.value(), diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index a4ab1ba5ab..ab28eb860b 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -335,8 +335,8 @@ impl LookupRangeCheck for LookupRangeCh // In the short range check, the word is directly witnessed. let short_lookup = { - let short_word = z_cur.clone(); - let q_short = one.clone() - q_running; + let short_word = z_cur; + let q_short = one - q_running; q_short * short_word }; From af29df443306d97a6f74984af56a8b2c2d720c1c Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Tue, 30 Apr 2024 13:46:59 +0200 Subject: [PATCH 27/99] fix complex type --- halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 2aefb97233..8818147f41 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -69,13 +69,7 @@ where x_a: X, y_a: AssignedCell, pallas::Base>, zs_sum: Vec>>, - ) -> Result< - ( - NonIdentityEccPoint, - Vec>>, - ), - Error, - > { + ) -> HashResult { #[cfg(test)] { use crate::sinsemilla::primitives::{K, S_PERSONALIZATION}; From 1ea04bb86fe3d493f4d83a0e3595d76562ac020d Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 6 May 2024 09:35:46 +0200 Subject: [PATCH 28/99] add round trip test to verify that the pinned verification key (representing the circuit) is as expected --- halo2_gadgets/src/ecc.rs | 24 + halo2_gadgets/src/sinsemilla.rs | 25 + halo2_gadgets/src/sinsemilla/merkle.rs | 40 +- halo2_gadgets/src/sinsemilla/merkle/chip.rs | 54 +- halo2_gadgets/src/sinsemilla/vk_merkle_chip | 3271 +++++ .../src/sinsemilla_opt/merkle/chip.rs | 227 +- .../src/utilities/lookup_range_check.rs | 333 + .../src/utilities/vk_lookup_range_check | 244 + .../src/utilities/vk_short_range_check | 244 + halo2_gadgets/src/vk_ecc_chip | 9915 +++++++++++++ halo2_gadgets/src/vk_sinsemilla_chip | 11821 ++++++++++++++++ 11 files changed, 25966 insertions(+), 232 deletions(-) create mode 100644 halo2_gadgets/src/sinsemilla/vk_merkle_chip create mode 100644 halo2_gadgets/src/utilities/vk_lookup_range_check create mode 100644 halo2_gadgets/src/utilities/vk_short_range_check create mode 100644 halo2_gadgets/src/vk_ecc_chip create mode 100644 halo2_gadgets/src/vk_sinsemilla_chip diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 97859c3ddd..b835aaf3eb 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -580,13 +580,16 @@ pub(crate) mod tests { use ff::PrimeField; use group::{prime::PrimeCurveAffine, Curve, Group}; + use halo2_proofs::poly::commitment::Params; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, dev::MockProver, + plonk, plonk::{Circuit, ConstraintSystem, Error}, }; use lazy_static::lazy_static; use pasta_curves::pallas; + use pasta_curves::vesta::Affine; use super::{ chip::{ @@ -595,6 +598,7 @@ pub(crate) mod tests { }, FixedPoints, }; + use crate::utilities::lookup_range_check::tests::test_proof_size; use crate::utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}; #[derive(Debug, Eq, PartialEq, Clone)] @@ -907,6 +911,26 @@ pub(crate) mod tests { assert_eq!(prover.verify(), Ok(())) } + #[test] + fn round_trip() { + let k = 11; + let circuit = MyCircuit { test_errors: false }; + + // Setup phase: generate parameters, vk for the circuit. + let params: Params = Params::new(k); + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + + // Test that the pinned verification key (representing the circuit) + // is as expected. + { + //panic!("{:#?}", vk.pinned()); + assert_eq!( + format!("{:#?}\n", vk.pinned()), + include_str!("vk_ecc_chip").replace("\r\n", "\n") + ); + } + test_proof_size(k, circuit, params, vk) + } #[cfg(feature = "test-dev-graph")] #[test] fn print_ecc_chip() { diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index a3e2dc892b..439dba9fae 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -462,6 +462,7 @@ pub(crate) mod tests { use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, dev::MockProver, + plonk, plonk::{Circuit, ConstraintSystem, Error}, }; use rand::rngs::OsRng; @@ -488,6 +489,9 @@ pub(crate) mod tests { use lazy_static::lazy_static; use pasta_curves::pallas; + use crate::utilities::lookup_range_check::tests::test_proof_size; + use halo2_proofs::poly::commitment::Params; + use pasta_curves::vesta::Affine; use std::convert::TryInto; pub(crate) const PERSONALIZATION: &str = "MerkleCRH"; @@ -761,6 +765,27 @@ pub(crate) mod tests { assert_eq!(prover.verify(), Ok(())) } + #[test] + fn round_trip() { + let k = 11; + let circuit = MyCircuit {}; + + // Setup phase: generate parameters, vk for the circuit. + let params: Params = Params::new(k); + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + + // Test that the pinned verification key (representing the circuit) + // is as expected. + { + //panic!("{:#?}", vk.pinned()); + assert_eq!( + format!("{:#?}\n", vk.pinned()), + include_str!("vk_sinsemilla_chip").replace("\r\n", "\n") + ); + } + test_proof_size(11, circuit, params, vk) + } + #[cfg(feature = "test-dev-graph")] #[test] fn print_sinsemilla_chip() { diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 21561e7316..58bcff9559 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -196,9 +196,12 @@ pub mod tests { circuit::{Layouter, SimpleFloorPlanner, Value}, dev::MockProver, pasta::pallas, + plonk, plonk::{Circuit, ConstraintSystem, Error}, }; + use halo2_proofs::poly::commitment::Params; + use pasta_curves::vesta::Affine; use rand::{rngs::OsRng, RngCore}; use std::{convert::TryInto, iter}; @@ -370,9 +373,7 @@ pub mod tests { Ok(()) } } - - #[test] - fn merkle_chip() { + fn generate_circuit() -> MyCircuit { let mut rng = OsRng; // Choose a random leaf and position @@ -385,17 +386,44 @@ pub mod tests { .collect(); // The root is provided as a public input in the Orchard circuit. - - let circuit = MyCircuit { + MyCircuit { leaf: Value::known(leaf), leaf_pos: Value::known(pos), merkle_path: Value::known(path.try_into().unwrap()), - }; + } + } + + #[test] + fn merkle_chip() { + let circuit = generate_circuit(); let prover = MockProver::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())) } + #[test] + fn round_trip() { + let k = 11; + let circuit = generate_circuit(); + + // Setup phase: generate parameters, vk for the circuit. + let params: Params = Params::new(k); + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + + // Test that the pinned verification key (representing the circuit) + // is as expected. Which indicates the layouters are the same. + { + //panic!("{:#?}", vk.pinned()); + assert_eq!( + format!("{:#?}\n", vk.pinned()), + include_str!("vk_merkle_chip").replace("\r\n", "\n") + ); + } + + // Test that the proof size is as expected. + crate::utilities::lookup_range_check::tests::test_proof_size(k, circuit, params, vk) + } + #[cfg(feature = "test-dev-graph")] #[test] fn print_merkle_chip() { diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs index d05d9fc8b3..4ce0662e91 100644 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla/merkle/chip.rs @@ -200,13 +200,59 @@ where } } -impl - MerkleInstructions +pub(crate) trait MerkleSinsemillaInstructions +where + Self: SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + MessagePiece = as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::MessagePiece, + RunningSum = as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::RunningSum, + X = as SinsemillaInstructions< + pallas::Affine, + { sinsemilla::K }, + { sinsemilla::C }, + >>::X, + >, + Hash: HashDomains, + Commit: CommitDomains, + F: FixedPoints, + Lookup: DefaultLookupRangeCheck, +{ +} + +impl MerkleSinsemillaInstructions for MerkleChip where - Hash: HashDomains + Eq, + Hash: HashDomains, F: FixedPoints, - Commit: CommitDomains + Eq, + Commit: CommitDomains, + Lookup: DefaultLookupRangeCheck, +{ +} + +impl + MerkleInstructions + for InstructionsChip +where + InstructionsChip: MerkleSinsemillaInstructions + + UtilitiesInstructions> + + CondSwapInstructions + + Chip> + + Eq + + Clone + + std::fmt::Debug, + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, Lookup: DefaultLookupRangeCheck, { #[allow(non_snake_case)] diff --git a/halo2_gadgets/src/sinsemilla/vk_merkle_chip b/halo2_gadgets/src/sinsemilla/vk_merkle_chip new file mode 100644 index 0000000000..229243b02c --- /dev/null +++ b/halo2_gadgets/src/sinsemilla/vk_merkle_chip @@ -0,0 +1,3271 @@ +PinnedVerificationKey { + base_modulus: "0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001", + scalar_modulus: "0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001", + domain: PinnedEvaluationDomain { + k: 11, + extended_k: 14, + omega: 0x181b50ad5f32119e31cbd395426d600b7a9b88bcaaa1c24eef28545aada17813, + }, + cs: PinnedConstraintSystem { + num_fixed_columns: 14, + num_advice_columns: 10, + num_instance_columns: 0, + num_selectors: 11, + gates: [ + Product( + Product( + Product( + Product( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Product( + Scaled( + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Scaled( + Fixed { + query_index: 5, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Product( + Sum( + Advice { + query_index: 6, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 3, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 6, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 6, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 3, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 4, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + ), + ), + ), + Product( + Fixed { + query_index: 10, + column_index: 10, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Sum( + Sum( + Advice { + query_index: 9, + column_index: 5, + rotation: Rotation( + 1, + ), + }, + Sum( + Sum( + Product( + Advice { + query_index: 6, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 6, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 3, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 4, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Advice { + query_index: 3, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Fixed { + query_index: 10, + column_index: 10, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Scaled( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Sum( + Advice { + query_index: 3, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 9, + column_index: 5, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Negated( + Sum( + Sum( + Scaled( + Product( + Sum( + Advice { + query_index: 6, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 3, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 6, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 6, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 3, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 4, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Product( + Fixed { + query_index: 2, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Sum( + Fixed { + query_index: 2, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + ), + ), + ), + Product( + Sum( + Advice { + query_index: 8, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + ), + Sum( + Advice { + query_index: 9, + column_index: 5, + rotation: Rotation( + 1, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 8, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 8, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 9, + column_index: 5, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Advice { + query_index: 10, + column_index: 6, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + ), + ), + Product( + Scaled( + Product( + Fixed { + query_index: 2, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Sum( + Fixed { + query_index: 2, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + ), + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Advice { + query_index: 8, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 5, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Product( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 3, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 6, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Product( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 3, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 4, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Advice { + query_index: 3, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 9, + column_index: 5, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + ), + ), + Negated( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Advice { + query_index: 9, + column_index: 5, + rotation: Rotation( + 1, + ), + }, + Scaled( + Sum( + Sum( + Advice { + query_index: 4, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 10, + column_index: 6, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + ), + ), + Scaled( + Advice { + query_index: 7, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + ), + 0x0001000000000000000000000000000000000000000000000000000000000000, + ), + ), + Negated( + Advice { + query_index: 6, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Advice { + query_index: 8, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + Scaled( + Advice { + query_index: 5, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000020, + ), + ), + Negated( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 10, + column_index: 6, + rotation: Rotation( + 1, + ), + }, + Negated( + Sum( + Advice { + query_index: 7, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + Scaled( + Advice { + query_index: 8, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000020, + ), + ), + ), + ), + ), + Product( + Product( + Product( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Scaled( + Fixed { + query_index: 7, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Product( + Sum( + Advice { + query_index: 14, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 15, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 11, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 14, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 14, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 11, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 12, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + ), + ), + ), + Product( + Fixed { + query_index: 11, + column_index: 11, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Advice { + query_index: 15, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 15, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Sum( + Sum( + Advice { + query_index: 18, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + Sum( + Sum( + Product( + Advice { + query_index: 14, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 14, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 11, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 12, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Advice { + query_index: 11, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Fixed { + query_index: 11, + column_index: 11, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Scaled( + Advice { + query_index: 15, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Sum( + Advice { + query_index: 11, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 18, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Negated( + Sum( + Sum( + Scaled( + Product( + Sum( + Advice { + query_index: 14, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 15, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 11, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 14, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 14, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 11, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 12, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Product( + Fixed { + query_index: 6, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Sum( + Fixed { + query_index: 6, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + ), + ), + ), + Product( + Sum( + Advice { + query_index: 17, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 19, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + ), + Sum( + Advice { + query_index: 18, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 17, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 17, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 18, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Advice { + query_index: 20, + column_index: 1, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + ), + ), + Product( + Scaled( + Product( + Fixed { + query_index: 6, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Sum( + Fixed { + query_index: 6, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + ), + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Advice { + query_index: 17, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + Product( + Product( + Product( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 13, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Product( + Advice { + query_index: 15, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 12, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Advice { + query_index: 15, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 11, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + Product( + Product( + Product( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 14, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Product( + Advice { + query_index: 15, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 11, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Advice { + query_index: 15, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 12, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + Product( + Product( + Product( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Advice { + query_index: 15, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Advice { + query_index: 15, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Advice { + query_index: 11, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 18, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + ), + ), + Negated( + Advice { + query_index: 19, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Advice { + query_index: 18, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + Scaled( + Sum( + Sum( + Advice { + query_index: 12, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 20, + column_index: 1, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + ), + ), + Scaled( + Advice { + query_index: 16, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + ), + 0x0001000000000000000000000000000000000000000000000000000000000000, + ), + ), + Negated( + Advice { + query_index: 14, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Advice { + query_index: 17, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + Scaled( + Advice { + query_index: 13, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000020, + ), + ), + Negated( + Advice { + query_index: 15, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 20, + column_index: 1, + rotation: Rotation( + 1, + ), + }, + Negated( + Sum( + Advice { + query_index: 16, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + Scaled( + Advice { + query_index: 17, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000020, + ), + ), + ), + ), + ), + ], + advice_queries: [ + ( + Column { + index: 9, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 9, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 9, + column_type: Advice, + }, + Rotation( + -1, + ), + ), + ( + Column { + index: 5, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 6, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 7, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 8, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 7, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 8, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 5, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 6, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 1, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 2, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 3, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 4, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 2, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 3, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 4, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 1, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ], + instance_queries: [], + fixed_queries: [ + ( + Column { + index: 0, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 3, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 6, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 4, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 5, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 1, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 7, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 2, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 8, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 9, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 10, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 11, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 12, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 13, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ], + permutation: Argument { + columns: [ + Column { + index: 0, + column_type: Fixed, + }, + Column { + index: 9, + column_type: Advice, + }, + Column { + index: 5, + column_type: Advice, + }, + Column { + index: 6, + column_type: Advice, + }, + Column { + index: 7, + column_type: Advice, + }, + Column { + index: 8, + column_type: Advice, + }, + Column { + index: 0, + column_type: Advice, + }, + Column { + index: 1, + column_type: Advice, + }, + Column { + index: 2, + column_type: Advice, + }, + Column { + index: 3, + column_type: Advice, + }, + Column { + index: 4, + column_type: Advice, + }, + ], + }, + lookups: [ + Argument { + input_expressions: [ + Product( + Fixed { + query_index: 8, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Fixed { + query_index: 9, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 9, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ], + table_expressions: [ + Fixed { + query_index: 1, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ], + }, + Argument { + input_expressions: [ + Product( + Fixed { + query_index: 10, + column_index: 10, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 5, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Product( + Sum( + Fixed { + query_index: 2, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Product( + Fixed { + query_index: 2, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Sum( + Fixed { + query_index: 2, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + ), + ), + ), + Advice { + query_index: 7, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + ), + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + ), + ), + ), + Sum( + Product( + Fixed { + query_index: 10, + column_index: 10, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + Scaled( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 10, + column_index: 10, + rotation: Rotation( + 0, + ), + }, + ), + ), + 0x0db5218be6881f0f1431d4ea7d4afc7b29a05bafbede62b55a91eb912044ea5f, + ), + ), + Sum( + Product( + Fixed { + query_index: 10, + column_index: 10, + rotation: Rotation( + 0, + ), + }, + Sum( + Scaled( + Product( + Sum( + Advice { + query_index: 6, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 3, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 6, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 6, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 3, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 4, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + Negated( + Product( + Advice { + query_index: 6, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 3, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 4, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + ), + Scaled( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 10, + column_index: 10, + rotation: Rotation( + 0, + ), + }, + ), + ), + 0x2f0f40c2f152a01c9caf66298493d5d0944a041c2e65ba0117c24f76bf8e6483, + ), + ), + ], + table_expressions: [ + Fixed { + query_index: 1, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Fixed { + query_index: 3, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Fixed { + query_index: 4, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ], + }, + Argument { + input_expressions: [ + Product( + Fixed { + query_index: 11, + column_index: 11, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 13, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Product( + Sum( + Fixed { + query_index: 6, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Product( + Fixed { + query_index: 6, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Sum( + Fixed { + query_index: 6, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + ), + ), + ), + Advice { + query_index: 16, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + ), + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + ), + ), + ), + Sum( + Product( + Fixed { + query_index: 11, + column_index: 11, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 12, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Scaled( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 11, + column_index: 11, + rotation: Rotation( + 0, + ), + }, + ), + ), + 0x0db5218be6881f0f1431d4ea7d4afc7b29a05bafbede62b55a91eb912044ea5f, + ), + ), + Sum( + Product( + Fixed { + query_index: 11, + column_index: 11, + rotation: Rotation( + 0, + ), + }, + Sum( + Scaled( + Product( + Sum( + Advice { + query_index: 14, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 15, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 11, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 14, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 14, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 11, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 12, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + Negated( + Product( + Advice { + query_index: 14, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 11, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 12, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + ), + Scaled( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 11, + column_index: 11, + rotation: Rotation( + 0, + ), + }, + ), + ), + 0x2f0f40c2f152a01c9caf66298493d5d0944a041c2e65ba0117c24f76bf8e6483, + ), + ), + ], + table_expressions: [ + Fixed { + query_index: 1, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Fixed { + query_index: 3, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Fixed { + query_index: 4, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ], + }, + ], + constants: [ + Column { + index: 0, + column_type: Fixed, + }, + ], + minimum_degree: None, + }, + fixed_commitments: [ + (0x26b223d8ba8ed483bbbdb8447f9166eb40bd77cc586970213757dceca5b3fe7f, 0x05dd2ed4a2456bd237250d2945d955fb415c841e2545fb0d4a8c937f5f933b61), + (0x129d241edb86e5c96fdd9d7beb75bd9a14e7d8592808036c9cf592cfed690b7a, 0x2b54f489a381e59f402ce34abc683b3cec3df0d01377115dc5a143fc9aa09340), + (0x17924baebd9681321232d8646f280221f34cd2d87cd125eeadaa974ab4d5dfd0, 0x311b6a25f7169fb1713e5539e10e52a1bdf6767a2fbbbc56d1f5d59a15024efa), + (0x05f5862cad2888855bc3c1843a9eff57b11b592d9eb0e13354256661387f5231, 0x32236b14df85bf5f532a930232cb23a5c56ef7d67aaeed8bcb8fc10ea132cbd6), + (0x3e727e8554679f98120355d39d958dbd8755d5a7f8b42ea87f258064c4b3eb57, 0x0c0d5c23f3ee62ac1b2d986dd3033bbcab260d590e1393de3a14a4b31ae091bb), + (0x3748680dd6a91c5dec668b30fb6bf9a450aeb884b81cbc344914f265760e7131, 0x18530eaa5c58b61bd3fc38220ea484c0922524a815a8f752be955c229f9c4164), + (0x03c48d550f56a16644251c9a5dc416e30b29a610010ac7709125782b1607b3e6, 0x3edfa55036455c23093e78530124d2b7778b608a68ab039008e2bd7d438416f0), + (0x24fd2ce32655dc5f11fe8e2f9ab780f71a933b9475da27aed0bc3f7f37e29ca1, 0x0cfbb4dc2d19dc3eeecbc1f987c45defa62c0a2a32b601f6eb6305b0b6e3cffa), + (0x29290c56da02655ce46b785d7af446f84badffca09b4cbd41e523bc5b7a2b40c, 0x0e8bcdd3843da6764954a9360d7dc02f98408c07b20a15e7e592b54086655ef5), + (0x2bbc94ef7b22aebef24f9a4b0cc1831882548b605171366017d45c3e6fd92075, 0x082b801a6e176239943bfb759fb02138f47a5c8cc4aa7fa0af559fde4e3abd97), + (0x2b63c25913a7c51ed52510e22881c2289379dadf144cfaf17cfbd9849ec2593a, 0x07fdeaac027477b02310fbac9575219384101c8c84e67b7be66ab0160f4bea22), + (0x109ac97c3d9d86563fd9847eee02f6affa4d788acd9697f2f828248fd6c7c595, 0x3ca254a78e74bfb5bd8144e2af8561b1f9f97d04b64965c0b97bd47cc00a1a1e), + (0x159abc8bbb102b81095fe82b2e576d2fd3789725ccad02192867eb6b262a6a8f, 0x1485a4c81a8415340d1571c05b0c99267af41def845f07f7254b87f5f1b056a0), + (0x065fa931d37c658c03dea4ad6a87dc06572639527c15c4631a116fd2f2d67062, 0x27765f16048554d160f8e9f1e8f5e285ee71871279b6a83a3060289572cb8844), + ], + permutation: VerifyingKey { + commitments: [ + (0x12c01814753e91eb23e4606d794078a518c227be4acaff3884f9a9bc9ab40000, 0x3ffeae87fb800669e7a3bda23781a4d16893f0b107382688b56e8f212c84a288), + (0x32383e328758decb242d42f75986c1cd5aef9f1a6d6e39c54a53a17630b8a16d, 0x00ae32219df5287e4c3c64ebf0ef83771fad95d67b2f7f3a444f5ede969d1c0c), + (0x06c29c2bad49d6ff8dd5669fd563dbe126692880bbeb495d15f810e5acfaa14a, 0x2be470a3fa70893026bb0506aadd32844fae950eefa502111b5806e916007d95), + (0x2b32307f41326e8d99a5146ba6aee133ed87d305cd0dd4419e537e2b2028e22a, 0x2334c482571d9f726a0715ae1824965009c5fabd6c3864e996e4ae2020e95c7e), + (0x2ebbf8cdb2a64ea5ce464f9439f328e564a02fde4e4f7a8855edcd9c9ef2b2e4, 0x0e73d4cdbe01bff75617a34ddb6fa10c460e3c5556bf4c86230ef54e10a955cf), + (0x0f6ecf422fad0e4ff83c6aa5812dc5c36c87d145d5c2e7f40ca6f0c332067826, 0x22b7cb6d58f8f249d6c656cdac28cdfe0c720f4ac1e4fb571a7c4dcd4f3c7bd0), + (0x0482e99357c02b25b0e8dd7327b34783dc4459119c0635b5de330d843e277da0, 0x0e30c1696995c9c31d1d179c86b99f2a6f66eaf290765344d2219bfb200f353d), + (0x37aba51a64c17ab63e7d76e11ca84ab0aaf7f208fccfd764d27b8b2531046d53, 0x0822915e6a8916334856d07619c7f8862d1c582d651127e9ad81343d9869c5af), + (0x2f1e036cc7cf77f6e64cdb1e6cb74dfeff998ec7dbd9ca90d3655db915150641, 0x27b2e33fdd6dd2344bd10c03522af2dbf38cd675c1ef4b23786bccdf8a8cc44a), + (0x38a60d928d64f1ef68c137da22be0d1d545c750dc4bb06018f78dbdafe0e32f4, 0x2cdc02d55e4164a17b06994225662703361a6ba56b64c5e5980aae6bd5f18bb1), + (0x03b739f9b5f0a3b6093d9d8c7f53068d7dbb5f9dc43ef1871a7bc36dbb0f01d6, 0x2bb4c2c0e642711d11136a9ecfb7bac1d05b400c3a150aeb84bbdb31d01e8c5e), + ], + }, +} diff --git a/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs b/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs index 3445bef41f..b11cf6b57e 100644 --- a/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs @@ -1,20 +1,14 @@ //! Chip implementing a Merkle hash using Sinsemilla as the hash function. -use ff::PrimeField; use halo2_proofs::{ circuit::{AssignedCell, Chip, Layouter, Value}, plonk::{ConstraintSystem, Error}, }; use pasta_curves::pallas; -use crate::sinsemilla::MessagePiece; -use crate::utilities::RangeConstrained; use crate::{ sinsemilla::{ - merkle::{ - chip::{MerkleChip, MerkleConfig}, - MerkleInstructions, - }, + merkle::chip::{MerkleChip, MerkleConfig, MerkleSinsemillaInstructions}, primitives as sinsemilla, }, sinsemilla_opt::chip::SinsemillaChipOptimized, @@ -93,225 +87,14 @@ where } } -impl - MerkleInstructions +impl + MerkleSinsemillaInstructions for MerkleChipOptimized where - Hash: HashDomains + Eq, + Hash: HashDomains, F: FixedPoints, - Commit: CommitDomains + Eq, + Commit: CommitDomains, { - // Todo: simplify the body? - #[allow(non_snake_case)] - fn hash_layer( - &self, - mut layouter: impl Layouter, - Q: pallas::Affine, - // l = MERKLE_DEPTH - layer - 1 - l: usize, - left: Self::Var, - right: Self::Var, - ) -> Result { - // Todo: simplify the body? copied and pasted from the body of the hash_layer function in halo2_gadgets/src/sinsemilla/merkle/chip.rs - - let config = self.base.config().clone(); - - // We need to hash `l || left || right`, where `l` is a 10-bit value. - // We allow `left` and `right` to be non-canonical 255-bit encodings. - // - // a = a_0||a_1 = l || (bits 0..=239 of left) - // b = b_0||b_1||b_2 - // = (bits 240..=249 of left) || (bits 250..=254 of left) || (bits 0..=4 of right) - // c = bits 5..=254 of right - // - // We start by witnessing all of the individual pieces, and range-constraining the - // short pieces b_1 and b_2. - // - // https://p.z.cash/halo2-0.1:sinsemilla-merkle-crh-bit-lengths?partial - - // `a = a_0||a_1` = `l` || (bits 0..=239 of `left`) - let a = MessagePiece::from_subpieces( - self.base.clone(), - layouter.namespace(|| "Witness a = a_0 || a_1"), - [ - RangeConstrained::bitrange_of(Value::known(&pallas::Base::from(l as u64)), 0..10), - RangeConstrained::bitrange_of(left.value(), 0..240), - ], - )?; - - // b = b_0 || b_1 || b_2 - // = (bits 240..=249 of left) || (bits 250..=254 of left) || (bits 0..=4 of right) - let (b_1, b_2, b) = { - // b_0 = (bits 240..=249 of `left`) - let b_0 = RangeConstrained::bitrange_of(left.value(), 240..250); - - // b_1 = (bits 250..=254 of `left`) - // Constrain b_1 to 5 bits. - let b_1 = RangeConstrained::witness_short( - &config.sinsemilla_config.lookup_config(), - layouter.namespace(|| "b_1"), - left.value(), - 250..(pallas::Base::NUM_BITS as usize), - )?; - - // b_2 = (bits 0..=4 of `right`) - // Constrain b_2 to 5 bits. - let b_2 = RangeConstrained::witness_short( - &config.sinsemilla_config.lookup_config(), - layouter.namespace(|| "b_2"), - right.value(), - 0..5, - )?; - - let b = MessagePiece::from_subpieces( - self.base.clone(), - layouter.namespace(|| "Witness b = b_0 || b_1 || b_2"), - [b_0, b_1.value(), b_2.value()], - )?; - - (b_1, b_2, b) - }; - - // c = bits 5..=254 of `right` - let c = MessagePiece::from_subpieces( - self.base.clone(), - layouter.namespace(|| "Witness c"), - [RangeConstrained::bitrange_of( - right.value(), - 5..(pallas::Base::NUM_BITS as usize), - )], - )?; - - // hash = SinsemillaHash(Q, 𝑙⋆ || left⋆ || right⋆) - // - // `hash = ⊥` is handled internally to `SinsemillaChip::hash_to_point`: incomplete - // addition constraints allows ⊥ to occur, and then during synthesis it detects - // these edge cases and raises an error (aborting proof creation). - // - // Note that MerkleCRH as-defined maps ⊥ to 0. This is for completeness outside - // the circuit (so that the ⊥ does not propagate into the type system). The chip - // explicitly doesn't map ⊥ to 0; in fact it cannot, as doing so would require - // constraints that amount to using complete addition. The rationale for excluding - // this map is the same as why Sinsemilla uses incomplete addition: this situation - // yields a nontrivial discrete log relation, and by assumption it is hard to find - // these. - // - // https://p.z.cash/proto:merkle-crh-orchard - let (point, zs) = self.hash_to_point( - layouter.namespace(|| format!("hash at l = {}", l)), - Q, - vec![a.inner(), b.inner(), c.inner()].into(), - )?; - let hash = Self::extract(&point); - - // `SinsemillaChip::hash_to_point` returns the running sum for each `MessagePiece`. - // Grab the outputs we need for the decomposition constraints. - let z1_a = zs[0][1].clone(); - let z1_b = zs[1][1].clone(); - - // Check that the pieces have been decomposed properly. - // - // The pieces and subpieces are arranged in the following configuration: - // | A_0 | A_1 | A_2 | A_3 | A_4 | q_decompose | - // ------------------------------------------------------- - // | a | b | c | left | right | 1 | - // | z1_a | z1_b | b_1 | b_2 | l | 0 | - { - layouter.assign_region( - || "Check piece decomposition", - |mut region| { - // Set the fixed column `l` to the current l. - // Recall that l = MERKLE_DEPTH - layer - 1. - // The layer with 2^n nodes is called "layer n". - config.q_decompose.enable(&mut region, 0)?; - region.assign_advice_from_constant( - || format!("l {}", l), - config.advices[4], - 1, - pallas::Base::from(l as u64), - )?; - - // Offset 0 - // Copy and assign `a` at the correct position. - a.inner().cell_value().copy_advice( - || "copy a", - &mut region, - config.advices[0], - 0, - )?; - // Copy and assign `b` at the correct position. - b.inner().cell_value().copy_advice( - || "copy b", - &mut region, - config.advices[1], - 0, - )?; - // Copy and assign `c` at the correct position. - c.inner().cell_value().copy_advice( - || "copy c", - &mut region, - config.advices[2], - 0, - )?; - // Copy and assign the left node at the correct position. - left.copy_advice(|| "left", &mut region, config.advices[3], 0)?; - // Copy and assign the right node at the correct position. - right.copy_advice(|| "right", &mut region, config.advices[4], 0)?; - - // Offset 1 - // Copy and assign z_1 of SinsemillaHash(a) = a_1 - z1_a.copy_advice(|| "z1_a", &mut region, config.advices[0], 1)?; - // Copy and assign z_1 of SinsemillaHash(b) = b_1 - z1_b.copy_advice(|| "z1_b", &mut region, config.advices[1], 1)?; - // Copy `b_1`, which has been constrained to be a 5-bit value - b_1.inner() - .copy_advice(|| "b_1", &mut region, config.advices[2], 1)?; - // Copy `b_2`, which has been constrained to be a 5-bit value - b_2.inner() - .copy_advice(|| "b_2", &mut region, config.advices[3], 1)?; - - Ok(()) - }, - )?; - } - // Check layer hash output against Sinsemilla primitives hash - #[cfg(test)] - { - use crate::{sinsemilla::primitives::HashDomain, utilities::i2lebsp}; - - use group::ff::PrimeFieldBits; - - left.value() - .zip(right.value()) - .zip(hash.value()) - .assert_if_known(|((left, right), hash)| { - let l = i2lebsp::<10>(l as u64); - let left: Vec<_> = left - .to_le_bits() - .iter() - .by_vals() - .take(pallas::Base::NUM_BITS as usize) - .collect(); - let right: Vec<_> = right - .to_le_bits() - .iter() - .by_vals() - .take(pallas::Base::NUM_BITS as usize) - .collect(); - let merkle_crh = HashDomain::from_Q(Q.into()); - - let mut message = l.to_vec(); - message.extend_from_slice(&left); - message.extend_from_slice(&right); - - let expected = merkle_crh.hash(message.into_iter()).unwrap(); - - expected.to_repr() == hash.to_repr() - }); - } - - Ok(hash) - } } impl UtilitiesInstructions for MerkleChipOptimized diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index ab28eb860b..370e3cadf7 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -439,3 +439,336 @@ pub trait DefaultLookupRangeCheck: } impl DefaultLookupRangeCheck for LookupRangeCheckConfig {} + +#[cfg(test)] +pub(crate) mod tests { + use super::{LookupRangeCheck, LookupRangeCheckConfig}; + + use super::super::lebs2ip; + use crate::sinsemilla::primitives::K; + + use ff::{Field, PrimeFieldBits}; + use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner, Value}, + dev::{FailureLocation, MockProver, VerifyFailure}, + plonk, + plonk::{Circuit, ConstraintSystem, Error}, + }; + use pasta_curves::{pallas, vesta}; + + use halo2_proofs::plonk::{SingleVerifier, VerifyingKey}; + use halo2_proofs::poly::commitment::Params; + use halo2_proofs::transcript::{Blake2bRead, Blake2bWrite, Challenge255}; + use pasta_curves::vesta::Affine; + use rand::rngs::OsRng; + use std::{convert::TryInto, marker::PhantomData}; + + pub(crate) fn test_proof_size( + k: u32, + circuit: C, + params: Params, + vk: VerifyingKey, + ) where + C: Circuit, + { + // Test that the proof size is as expected. + let circuit_cost = + halo2_proofs::dev::CircuitCost::::measure(k, &circuit); + let expected_proof_size = usize::from(circuit_cost.proof_size(1)); + + let pk = plonk::keygen_pk(¶ms, vk.clone(), &circuit).unwrap(); + let mut transcript = Blake2bWrite::<_, vesta::Affine, _>::init(vec![]); + plonk::create_proof(¶ms, &pk, &[circuit], &[&[]], OsRng, &mut transcript).unwrap(); + let proof = transcript.finalize(); + + let strategy = SingleVerifier::new(¶ms); + let mut transcript: Blake2bRead<&[u8], vesta::Affine, Challenge255> = + Blake2bRead::init(&proof[..]); + let verify = plonk::verify_proof(¶ms, &vk, strategy, &[&[]], &mut transcript); + // Round-trip assertion: check the proof is valid and matches expected values. + assert!(verify.is_ok()); + assert_eq!(proof.len(), expected_proof_size); + } + #[test] + fn lookup_range_check() { + #[derive(Clone, Copy)] + struct MyCircuit { + num_words: usize, + _marker: PhantomData, + } + + impl Circuit for MyCircuit { + type Config = LookupRangeCheckConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + *self + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let running_sum = meta.advice_column(); + let table_idx = meta.lookup_table_column(); + let constants = meta.fixed_column(); + meta.enable_constant(constants); + + LookupRangeCheckConfig::::configure(meta, running_sum, table_idx) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + // Load table_idx + config.load(&mut layouter)?; + + // Lookup constraining element to be no longer than num_words * K bits. + let elements_and_expected_final_zs = [ + (F::from((1 << (self.num_words * K)) - 1), F::ZERO, true), // a word that is within self.num_words * K bits long + (F::from(1 << (self.num_words * K)), F::ONE, false), // a word that is just over self.num_words * K bits long + ]; + + fn expected_zs( + element: F, + num_words: usize, + ) -> Vec { + let chunks = { + element + .to_le_bits() + .iter() + .by_vals() + .take(num_words * K) + .collect::>() + .chunks_exact(K) + .map(|chunk| F::from(lebs2ip::(chunk.try_into().unwrap()))) + .collect::>() + }; + let expected_zs = { + let inv_two_pow_k = F::from(1 << K).invert().unwrap(); + chunks.iter().fold(vec![element], |mut zs, a_i| { + // z_{i + 1} = (z_i - a_i) / 2^{K} + let z = (zs[zs.len() - 1] - a_i) * inv_two_pow_k; + zs.push(z); + zs + }) + }; + expected_zs + } + + for (element, expected_final_z, strict) in elements_and_expected_final_zs.iter() { + let expected_zs = expected_zs::(*element, self.num_words); + + let zs = config.witness_check( + layouter.namespace(|| format!("Lookup {:?}", self.num_words)), + Value::known(*element), + self.num_words, + *strict, + )?; + + assert_eq!(*expected_zs.last().unwrap(), *expected_final_z); + + for (expected_z, z) in expected_zs.into_iter().zip(zs.iter()) { + z.value().assert_if_known(|z| &&expected_z == z); + } + } + Ok(()) + } + } + + { + let circuit: MyCircuit = MyCircuit { + num_words: 6, + _marker: PhantomData, + }; + + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), Ok(())); + + // Setup phase: generate parameters, vk for the circuit. + let params: Params = Params::new(11); + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + + // Test that the pinned verification key (representing the circuit) + // is as expected. + { + //panic!("{:#?}", vk.pinned()); + assert_eq!( + format!("{:#?}\n", vk.pinned()), + include_str!("vk_lookup_range_check").replace("\r\n", "\n") + ); + } + + // Test that the proof size is as expected. + test_proof_size(11, circuit, params, vk) + } + } + + #[test] + fn short_range_check() { + struct MyCircuit { + element: Value, + num_bits: usize, + } + + impl Circuit for MyCircuit { + type Config = LookupRangeCheckConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + MyCircuit { + element: Value::unknown(), + num_bits: self.num_bits, + } + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let running_sum = meta.advice_column(); + let table_idx = meta.lookup_table_column(); + let constants = meta.fixed_column(); + meta.enable_constant(constants); + + LookupRangeCheckConfig::::configure(meta, running_sum, table_idx) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + // Load table_idx + config.load(&mut layouter)?; + + // Lookup constraining element to be no longer than num_bits. + config.witness_short_check( + layouter.namespace(|| format!("Lookup {:?} bits", self.num_bits)), + self.element, + self.num_bits, + )?; + + Ok(()) + } + } + + // Edge case: zero bits + { + let circuit: MyCircuit = MyCircuit { + element: Value::known(pallas::Base::ZERO), + num_bits: 0, + }; + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), Ok(())); + + // Setup phase: generate parameters, vk for the circuit. + let params: Params = Params::new(11); + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + + // Test that the pinned verification key (representing the circuit) + // is as expected. Which indicates the layouters are the same. + { + //panic!("{:#?}", vk.pinned()); + assert_eq!( + format!("{:#?}\n", vk.pinned()), + include_str!("vk_short_range_check").replace("\r\n", "\n") + ); + } + + // Test that the proof size is as expected. + test_proof_size(11, circuit, params, vk) + } + + // Edge case: K bits + { + let circuit: MyCircuit = MyCircuit { + element: Value::known(pallas::Base::from((1 << K) - 1)), + num_bits: K, + }; + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), Ok(())); + } + + // Element within `num_bits` + { + let circuit: MyCircuit = MyCircuit { + element: Value::known(pallas::Base::from((1 << 6) - 1)), + num_bits: 6, + }; + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), Ok(())); + } + + // Element larger than `num_bits` but within K bits + { + let circuit: MyCircuit = MyCircuit { + element: Value::known(pallas::Base::from(1 << 6)), + num_bits: 6, + }; + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!( + prover.verify(), + Err(vec![VerifyFailure::Lookup { + lookup_index: 0, + location: FailureLocation::InRegion { + region: (1, "Range check 6 bits").into(), + offset: 1, + }, + }]) + ); + } + + // Element larger than K bits + { + let circuit: MyCircuit = MyCircuit { + element: Value::known(pallas::Base::from(1 << K)), + num_bits: 6, + }; + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!( + prover.verify(), + Err(vec![ + VerifyFailure::Lookup { + lookup_index: 0, + location: FailureLocation::InRegion { + region: (1, "Range check 6 bits").into(), + offset: 0, + }, + }, + VerifyFailure::Lookup { + lookup_index: 0, + location: FailureLocation::InRegion { + region: (1, "Range check 6 bits").into(), + offset: 1, + }, + }, + ]) + ); + } + + // Element which is not within `num_bits`, but which has a shifted value within + // num_bits + { + let num_bits = 6; + let shifted = pallas::Base::from((1 << num_bits) - 1); + // Recall that shifted = element * 2^{K-s} + // => element = shifted * 2^{s-K} + let element = shifted + * pallas::Base::from(1 << (K as u64 - num_bits)) + .invert() + .unwrap(); + let circuit: MyCircuit = MyCircuit { + element: Value::known(element), + num_bits: num_bits as usize, + }; + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!( + prover.verify(), + Err(vec![VerifyFailure::Lookup { + lookup_index: 0, + location: FailureLocation::InRegion { + region: (1, "Range check 6 bits").into(), + offset: 0, + }, + }]) + ); + } + } +} diff --git a/halo2_gadgets/src/utilities/vk_lookup_range_check b/halo2_gadgets/src/utilities/vk_lookup_range_check new file mode 100644 index 0000000000..48948bcbc7 --- /dev/null +++ b/halo2_gadgets/src/utilities/vk_lookup_range_check @@ -0,0 +1,244 @@ +PinnedVerificationKey { + base_modulus: "0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001", + scalar_modulus: "0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001", + domain: PinnedEvaluationDomain { + k: 11, + extended_k: 14, + omega: 0x181b50ad5f32119e31cbd395426d600b7a9b88bcaaa1c24eef28545aada17813, + }, + cs: PinnedConstraintSystem { + num_fixed_columns: 5, + num_advice_columns: 1, + num_instance_columns: 0, + num_selectors: 3, + gates: [ + Product( + Fixed { + query_index: 4, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Scaled( + Advice { + query_index: 2, + column_index: 0, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + Advice { + query_index: 1, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ], + advice_queries: [ + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + -1, + ), + ), + ], + instance_queries: [], + fixed_queries: [ + ( + Column { + index: 1, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 0, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 2, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 3, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 4, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ], + permutation: Argument { + columns: [ + Column { + index: 1, + column_type: Fixed, + }, + Column { + index: 0, + column_type: Advice, + }, + ], + }, + lookups: [ + Argument { + input_expressions: [ + Product( + Fixed { + query_index: 2, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Fixed { + query_index: 3, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 1, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 3, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ], + table_expressions: [ + Fixed { + query_index: 1, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ], + }, + ], + constants: [ + Column { + index: 1, + column_type: Fixed, + }, + ], + minimum_degree: None, + }, + fixed_commitments: [ + (0x05f5862cad2888855bc3c1843a9eff57b11b592d9eb0e13354256661387f5231, 0x32236b14df85bf5f532a930232cb23a5c56ef7d67aaeed8bcb8fc10ea132cbd6), + (0x2bbc94ef7b22aebef24f9a4b0cc1831882548b605171366017d45c3e6fd92075, 0x082b801a6e176239943bfb759fb02138f47a5c8cc4aa7fa0af559fde4e3abd97), + (0x1e8ad0c6992851e2d92d368088d79e3326cd63e2a12bb086407dc3dbe0691fb0, 0x0895d1133a5889cf2a52bf5a7ac48502ac399a0088625be4db7aaec534ee8576), + (0x1e8ad0c6992851e2d92d368088d79e3326cd63e2a12bb086407dc3dbe0691fb0, 0x0895d1133a5889cf2a52bf5a7ac48502ac399a0088625be4db7aaec534ee8576), + (0x2bbc94ef7b22aebef24f9a4b0cc1831882548b605171366017d45c3e6fd92075, 0x082b801a6e176239943bfb759fb02138f47a5c8cc4aa7fa0af559fde4e3abd97), + ], + permutation: VerifyingKey { + commitments: [ + (0x2477ff33a8671d640d752567c99805c0dda68328ddfff306b085f13be1fd9079, 0x3f7c0fa2ae0b1b7683c39103509711d525eb2dfb73ed21458b77b9d0de222923), + (0x1c85783d2128c72103589576bf9d4ed2a509202944a52b48db13848f9431439f, 0x0c363acac4903e6907846abb10920dcf7a2b8c7462ac37f64d0da5cf7f9a643e), + ], + }, +} diff --git a/halo2_gadgets/src/utilities/vk_short_range_check b/halo2_gadgets/src/utilities/vk_short_range_check new file mode 100644 index 0000000000..6de944cf6c --- /dev/null +++ b/halo2_gadgets/src/utilities/vk_short_range_check @@ -0,0 +1,244 @@ +PinnedVerificationKey { + base_modulus: "0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001", + scalar_modulus: "0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001", + domain: PinnedEvaluationDomain { + k: 11, + extended_k: 14, + omega: 0x181b50ad5f32119e31cbd395426d600b7a9b88bcaaa1c24eef28545aada17813, + }, + cs: PinnedConstraintSystem { + num_fixed_columns: 5, + num_advice_columns: 1, + num_instance_columns: 0, + num_selectors: 3, + gates: [ + Product( + Fixed { + query_index: 4, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Scaled( + Advice { + query_index: 2, + column_index: 0, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + Advice { + query_index: 1, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ], + advice_queries: [ + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + -1, + ), + ), + ], + instance_queries: [], + fixed_queries: [ + ( + Column { + index: 1, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 0, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 2, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 3, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 4, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ], + permutation: Argument { + columns: [ + Column { + index: 1, + column_type: Fixed, + }, + Column { + index: 0, + column_type: Advice, + }, + ], + }, + lookups: [ + Argument { + input_expressions: [ + Product( + Fixed { + query_index: 2, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Fixed { + query_index: 3, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 1, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 3, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ], + table_expressions: [ + Fixed { + query_index: 1, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ], + }, + ], + constants: [ + Column { + index: 1, + column_type: Fixed, + }, + ], + minimum_degree: None, + }, + fixed_commitments: [ + (0x05f5862cad2888855bc3c1843a9eff57b11b592d9eb0e13354256661387f5231, 0x32236b14df85bf5f532a930232cb23a5c56ef7d67aaeed8bcb8fc10ea132cbd6), + (0x27c2b8ac34f64d4d18eada2b41dc9d8c30409eb866c7e4d539204fadcb696826, 0x0881a9c2e2e4a577b5a951254bd508dedafa5f1c7be905aaf4fbac60971bc9f7), + (0x0980acedb0fd2c02718002125bf80f969175d1f90d1320f9f3d5e2ac584e0212, 0x235c651fefd49e387ef9a6293a428810994974d218c4757ca3f9c0971ae25767), + (0x2bbc94ef7b22aebef24f9a4b0cc1831882548b605171366017d45c3e6fd92075, 0x082b801a6e176239943bfb759fb02138f47a5c8cc4aa7fa0af559fde4e3abd97), + (0x28d1c924953bc53f232465943d25fd085f85727ae4e2d26249207da1e59559e2, 0x184d19e00f109c4dacf8026c6e0fc4181178b32a236828047c46d9d61eab90fa), + ], + permutation: VerifyingKey { + commitments: [ + (0x3b7b93d7540327328791a14933d8f3345abd943eb35b67a8a4bd2eb72e2a707a, 0x26fff57a6fa3c01dd0d739fc56479303b4302d6baa6f1da06f4013419c40e10c), + (0x3fdf7a15a0d2378accc11f704f4ba4a487b542ace83c7f5a8551b569a3b9a380, 0x34253920878d15d6fe1b5198c31bdd670d32e81621e9fcd569d582e596ed0af5), + ], + }, +} diff --git a/halo2_gadgets/src/vk_ecc_chip b/halo2_gadgets/src/vk_ecc_chip new file mode 100644 index 0000000000..5eb13f31e1 --- /dev/null +++ b/halo2_gadgets/src/vk_ecc_chip @@ -0,0 +1,9915 @@ +PinnedVerificationKey { + base_modulus: "0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001", + scalar_modulus: "0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001", + domain: PinnedEvaluationDomain { + k: 11, + extended_k: 14, + omega: 0x181b50ad5f32119e31cbd395426d600b7a9b88bcaaa1c24eef28545aada17813, + }, + cs: PinnedConstraintSystem { + num_fixed_columns: 19, + num_advice_columns: 10, + num_instance_columns: 0, + num_selectors: 20, + gates: [ + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Product( + Scaled( + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Sum( + Product( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Product( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Sum( + Product( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Product( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Product( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Product( + Product( + Sum( + Sum( + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Product( + Sum( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Sum( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Product( + Sum( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Product( + Sum( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Sum( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Sum( + Product( + Sum( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Product( + Sum( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Negated( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + Sum( + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Negated( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + Negated( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Product( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Product( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + Negated( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Product( + Sum( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Product( + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Product( + Sum( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Product( + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 13, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 15, + column_index: 5, + rotation: Rotation( + 1, + ), + }, + ), + Sum( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Advice { + query_index: 16, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 16, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 17, + column_index: 1, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + Product( + Sum( + Scaled( + Sum( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Sum( + Product( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 15, + column_index: 5, + rotation: Rotation( + 1, + ), + }, + ), + Sum( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Advice { + query_index: 16, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + Product( + Sum( + Scaled( + Sum( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Sum( + Product( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + Negated( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + ), + Sum( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Advice { + query_index: 16, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 16, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 17, + column_index: 1, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 20, + column_index: 6, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 20, + column_index: 6, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + Product( + Sum( + Scaled( + Sum( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 20, + column_index: 6, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Sum( + Product( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + ), + Sum( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Advice { + query_index: 16, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 20, + column_index: 6, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 20, + column_index: 6, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + Product( + Sum( + Scaled( + Sum( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 20, + column_index: 6, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Sum( + Product( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + Negated( + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + ), + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Product( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 21, + column_index: 1, + rotation: Rotation( + -1, + ), + }, + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + ), + ), + ), + ), + ), + Sum( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 21, + column_index: 1, + rotation: Rotation( + -1, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Product( + Advice { + query_index: 23, + column_index: 7, + rotation: Rotation( + -1, + ), + }, + Product( + Constant( + 0x0000000000000000000000000000000010000000000000000000000000000000, + ), + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000040, + ), + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Advice { + query_index: 20, + column_index: 6, + rotation: Rotation( + -1, + ), + }, + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Constant( + 0x00000000000000000000000000000000224698fc0994a8dd8c46eb2100000001, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Advice { + query_index: 23, + column_index: 7, + rotation: Rotation( + -1, + ), + }, + Sum( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Constant( + 0x0000000000000000000000000000000010000000000000000000000000000000, + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Advice { + query_index: 23, + column_index: 7, + rotation: Rotation( + -1, + ), + }, + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Advice { + query_index: 23, + column_index: 7, + rotation: Rotation( + -1, + ), + }, + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Product( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 22, + column_index: 6, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Scaled( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Scaled( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Product( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Scaled( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Scaled( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + ), + ), + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 16, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Product( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Scaled( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Scaled( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + ), + ), + Sum( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 17, + column_index: 1, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + Product( + Fixed { + query_index: 16, + column_index: 16, + rotation: Rotation( + 0, + ), + }, + Product( + Product( + Product( + Product( + Product( + Product( + Product( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000006, + ), + Negated( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000007, + ), + Negated( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + ), + ), + ), + Product( + Fixed { + query_index: 16, + column_index: 16, + rotation: Rotation( + 0, + ), + }, + Sum( + Sum( + Sum( + Sum( + Sum( + Sum( + Sum( + Sum( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000000, + ), + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Fixed { + query_index: 3, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Fixed { + query_index: 4, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Fixed { + query_index: 5, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Fixed { + query_index: 6, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Fixed { + query_index: 7, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Fixed { + query_index: 8, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Fixed { + query_index: 9, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Fixed { + query_index: 10, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Fixed { + query_index: 16, + column_index: 16, + rotation: Rotation( + 0, + ), + }, + Sum( + Sum( + Product( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Fixed { + query_index: 2, + column_index: 10, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Fixed { + query_index: 16, + column_index: 16, + rotation: Rotation( + 0, + ), + }, + Sum( + Sum( + Product( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Product( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + ), + ), + ), + Product( + Fixed { + query_index: 17, + column_index: 17, + rotation: Rotation( + 0, + ), + }, + Sum( + Sum( + Sum( + Sum( + Sum( + Sum( + Sum( + Sum( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000000, + ), + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Fixed { + query_index: 3, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Fixed { + query_index: 4, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Fixed { + query_index: 5, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Fixed { + query_index: 6, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Fixed { + query_index: 7, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Fixed { + query_index: 8, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Fixed { + query_index: 9, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Fixed { + query_index: 10, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Fixed { + query_index: 17, + column_index: 17, + rotation: Rotation( + 0, + ), + }, + Sum( + Sum( + Product( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Fixed { + query_index: 2, + column_index: 10, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Fixed { + query_index: 17, + column_index: 17, + rotation: Rotation( + 0, + ), + }, + Sum( + Sum( + Product( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Product( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + ), + ), + ), + Product( + Fixed { + query_index: 17, + column_index: 17, + rotation: Rotation( + 0, + ), + }, + Product( + Product( + Product( + Product( + Product( + Product( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000006, + ), + Negated( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000007, + ), + Negated( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Product( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Product( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + ), + Product( + Product( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Sum( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + Negated( + Product( + Advice { + query_index: 24, + column_index: 8, + rotation: Rotation( + -1, + ), + }, + Constant( + 0x0000000000000000000000000000000001000000000000000000000000000000, + ), + ), + ), + ), + ), + ), + Product( + Product( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Product( + Sum( + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + Negated( + Scaled( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + Negated( + Scaled( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + ), + ), + ), + ), + Product( + Product( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 22, + column_index: 6, + rotation: Rotation( + 1, + ), + }, + ), + ), + Product( + Product( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Product( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Product( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 24, + column_index: 8, + rotation: Rotation( + -1, + ), + }, + Negated( + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Scaled( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + ), + ), + ), + ), + Product( + Product( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Sum( + Advice { + query_index: 20, + column_index: 6, + rotation: Rotation( + -1, + ), + }, + Negated( + Scaled( + Advice { + query_index: 24, + column_index: 8, + rotation: Rotation( + -1, + ), + }, + 0x1000000000000000000000000000000000000000000000000000000000000000, + ), + ), + ), + Constant( + 0x0000000000000000000000000000000400000000000000000000000000000000, + ), + ), + Negated( + Constant( + 0x00000000000000000000000000000000224698fc094cf91b992d30ed00000001, + ), + ), + ), + ), + ), + ), + ], + advice_queries: [ + ( + Column { + index: 9, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 9, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 9, + column_type: Advice, + }, + Rotation( + -1, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 1, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 2, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 3, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 2, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 3, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 4, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 5, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 6, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 7, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 8, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 4, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 5, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 1, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 7, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 8, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 6, + column_type: Advice, + }, + Rotation( + -1, + ), + ), + ( + Column { + index: 1, + column_type: Advice, + }, + Rotation( + -1, + ), + ), + ( + Column { + index: 6, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 7, + column_type: Advice, + }, + Rotation( + -1, + ), + ), + ( + Column { + index: 8, + column_type: Advice, + }, + Rotation( + -1, + ), + ), + ], + instance_queries: [], + fixed_queries: [ + ( + Column { + index: 9, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 0, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 10, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 1, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 2, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 3, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 4, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 5, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 6, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 7, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 8, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 11, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 12, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 13, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 14, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 15, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 16, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 17, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 18, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ], + permutation: Argument { + columns: [ + Column { + index: 9, + column_type: Fixed, + }, + Column { + index: 9, + column_type: Advice, + }, + Column { + index: 0, + column_type: Advice, + }, + Column { + index: 1, + column_type: Advice, + }, + Column { + index: 2, + column_type: Advice, + }, + Column { + index: 3, + column_type: Advice, + }, + Column { + index: 4, + column_type: Advice, + }, + Column { + index: 6, + column_type: Advice, + }, + Column { + index: 8, + column_type: Advice, + }, + Column { + index: 7, + column_type: Advice, + }, + Column { + index: 5, + column_type: Advice, + }, + ], + }, + lookups: [ + Argument { + input_expressions: [ + Product( + Fixed { + query_index: 11, + column_index: 11, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 12, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ], + table_expressions: [ + Fixed { + query_index: 1, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ], + }, + ], + constants: [ + Column { + index: 9, + column_type: Fixed, + }, + ], + minimum_degree: None, + }, + fixed_commitments: [ + (0x05f5862cad2888855bc3c1843a9eff57b11b592d9eb0e13354256661387f5231, 0x32236b14df85bf5f532a930232cb23a5c56ef7d67aaeed8bcb8fc10ea132cbd6), + (0x15e9797cbf96b3ab5f2a21595a5ede5becc665dbf113ae1bd93c5fdd577b3fdd, 0x2276c102a90057ccaac390724cd3e8032eaa0d5c7630b979e2f86354d46044fe), + (0x0a3757ecd8df677c56dd731a5988940130dc69375d09185120348b4c24f23f9a, 0x209e7e273d9d9254893a220d7329114fa83eda5d483437612cf638275b4d97f2), + (0x337f1898449ead1933c764ae23b48d20f646e528b079ac5cd0743d9ac8e8f063, 0x144e28d47be3a5d90eab8ec65a10b965fd83c7b34f8e4b387154f126efbbf7a7), + (0x1ba31dfd22b785ba6080c0a1378f14d104f571d6ab2ac6e650865b27296773db, 0x3c49108055aa494775123cb379dbee7ae628e193cba15827df962722a9a47367), + (0x0fdf7430975fbf9361ee6a0eef8e811b838cf64cb042d5988c669010329a8e8c, 0x1292f817500e4ef166ccf48483d061b41372ac7e44ed52b04fbf03da5b04fc79), + (0x145d45d803dfd99569e689c02583b2a63f004e25ba23bf9acc17148b42267480, 0x230efff0cad7a66c33eb7462b4b60237619e1287a6c23a122057ef0359d324a6), + (0x0ce14fcd6eef4247d75df3d38a918bd8d8c66362629ca8ca697254bf703f1dc9, 0x3cc92942c824cad0a3f16828a29dd42785485b878e459a289db7c377973f2aee), + (0x0bd58593a2e2657cd0a228b678a4a7ec04492e20768108383cfdae26613da0b9, 0x090c75a86508be75f6f57e33946c5f9170f40d08e058eb33c8370311fed2868c), + (0x2bbc94ef7b22aebef24f9a4b0cc1831882548b605171366017d45c3e6fd92075, 0x082b801a6e176239943bfb759fb02138f47a5c8cc4aa7fa0af559fde4e3abd97), + (0x1676bb18498c153055ba927b909ef96c5edf8108be253d7a86663f57cd815cd1, 0x0ca79754ab892586fe9df1ae7a23e527bbae042eb89e96747f3befe88c493446), + (0x2e0cad5df5c23f42086784fd79c09b1dff1718dd1700e5157a1592dec21306a8, 0x01cd2a585d4dacd1c4ebb7eccc804a7284792641900d383e9f6f496482c01144), + (0x2e0cad5df5c23f42086784fd79c09b1dff1718dd1700e5157a1592dec21306a8, 0x01cd2a585d4dacd1c4ebb7eccc804a7284792641900d383e9f6f496482c01144), + (0x11ee40a7ae1d9b3bc41a88dd50a69661de280c85222c5567ea3fc06c606558a5, 0x0c6ad5f6fb00347486477aededc92f686f6d079737fd2ca147b7db5ea7381061), + (0x33be67428155b1361122a6eddf7e24a7cbeddcce8166dead5d9d5ec6714b25f2, 0x3ec742ac0f64c3ffc4d47bbdeaba0603c55ef74d40065b84b7d738c95f473c79), + (0x11c136f6ea303c5630240788e7a4db6c3aa321aaeaebecbd473af5ace4d05248, 0x0afe33d04a38bae95c2ec4c4372b2d766369c4c5b10f82dcbd4375a41f838d79), + (0x320eb135936ed226a108ccc06bea1ce3ea57dfc2d708fc2ea868ee90330fe22b, 0x15f1174d43608cb597ad1708d2c15e6fcb399219662c75a476b34d51d7ef8f09), + (0x2157882bf836df0d37c2fe7b4c03c099712bf0f1f70475cf79a47a269cd05d6e, 0x2b21b30255ccaa0152b483916b033c38c54edaf1ae8987df41d4812affd004fa), + (0x0bb1ce75e6be204e3d006a0dd70adbc82e9babae94be0a0fcd0eba958bf78d95, 0x25af91a42e58455509f322ab700f45210e369a79cfc3635db30fa5298d46475b), + ], + permutation: VerifyingKey { + commitments: [ + (0x2dfdfeda0fc01492b0884d17870ef7c30a6a59502ead966bb6c072b216ef7b33, 0x206d9ce95f9c1bfb675cd14130a877aa70650b7d1bb5cbf82f3fbfa517c2a19a), + (0x001deacc3520d2f07b82695befedaee3c62c595d80d0f406f473ab3e8c362213, 0x316bcc3ef777e42b96c36bbb95b41654dc91b4fbf264e3796267716917e0b63f), + (0x142095bd2f3ceed4e0ee7eaae4952488aa314d89f4755b81bc4f4df5e849947a, 0x0e6b8ab5b49069d21ea86f1d320c2959f144a3b1f284231312ea776f337b00b6), + (0x20bdfa7afff8a496620db915f9323e348b0ea52ccb0e5ef2a26cc5edfb4a3490, 0x033516b53f25239682efb9f0b6865a1841a2f80e88c08c9431f08906bf2ece95), + (0x3b3d22054a70b22ab2f4daabb0671df492f8ae365372d34f9ed9cbf053f77560, 0x386d905cc46f526544a620c7251d661cf09ec673efafce3bd36f59295e8c8e10), + (0x23bdd78c87775077ce68d63f15349c6851d18cef963e714fad7c182172539964, 0x36df72f765faa06fdc6e79e9b71557043f1b3c32677cbe852bfb89b9ff2adf73), + (0x1f058e8d0ce9494143e267f9190d4a8a0f4fc18cee14b9cbb00fd4324d028d2f, 0x053c9574cfa8f32a4795152eb742f40752011ad9704a6b7a05fdf2d660948eca), + (0x0c116eea00a8888c4a5917f514f323b993c732ad08d9655cbcfb3ea57645c1d3, 0x1811bf498434bba922e2eb1b1dfc3025bedd7fe7aecb3837a561c1e78ee56b05), + (0x1317f5890e3c536bc205f7ecc9e286414f7abcd160903ba663f33cd37821a1ac, 0x39d386ba96759c162f980de92743c908b4808e252d04309fc5c10fb48c8f5f17), + (0x05aa4e237c2775c8105b736664b7b873a3a0a35cda546e29439fdcd87c844afc, 0x36129c33ee883439d98e23d4fb625a22df4b8b62d41702d82b59eb264c649832), + (0x2e48423c28c290a75feb9d431f59ec36e48d9e88c3ff46a9e1dfb04ed894d88d, 0x00d3bb38bca1ec15ac2e79c8e9c093fb496cca52c58f2947b51537ce718d9060), + ], + }, +} diff --git a/halo2_gadgets/src/vk_sinsemilla_chip b/halo2_gadgets/src/vk_sinsemilla_chip new file mode 100644 index 0000000000..1e5ee09d57 --- /dev/null +++ b/halo2_gadgets/src/vk_sinsemilla_chip @@ -0,0 +1,11821 @@ +PinnedVerificationKey { + base_modulus: "0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001", + scalar_modulus: "0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001", + domain: PinnedEvaluationDomain { + k: 11, + extended_k: 14, + omega: 0x181b50ad5f32119e31cbd395426d600b7a9b88bcaaa1c24eef28545aada17813, + }, + cs: PinnedConstraintSystem { + num_fixed_columns: 25, + num_advice_columns: 10, + num_instance_columns: 0, + num_selectors: 24, + gates: [ + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Product( + Scaled( + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Sum( + Product( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Product( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Sum( + Product( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Product( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Product( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Product( + Product( + Sum( + Sum( + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Product( + Sum( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Sum( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Product( + Sum( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Product( + Sum( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Sum( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Sum( + Product( + Sum( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Product( + Sum( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Negated( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + Sum( + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Negated( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + Negated( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Product( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Product( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + Negated( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Product( + Sum( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Product( + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Product( + Sum( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Product( + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 19, + column_index: 19, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 15, + column_index: 5, + rotation: Rotation( + 1, + ), + }, + ), + Sum( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Advice { + query_index: 16, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 16, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 17, + column_index: 1, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + Product( + Sum( + Scaled( + Sum( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Sum( + Product( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 15, + column_index: 5, + rotation: Rotation( + 1, + ), + }, + ), + Sum( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Advice { + query_index: 16, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + Product( + Sum( + Scaled( + Sum( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Sum( + Product( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + Negated( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 20, + column_index: 20, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + ), + Sum( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Advice { + query_index: 16, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 16, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 17, + column_index: 1, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 20, + column_index: 6, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 20, + column_index: 6, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + Product( + Sum( + Scaled( + Sum( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 20, + column_index: 6, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Sum( + Product( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + ), + Sum( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Advice { + query_index: 16, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 20, + column_index: 6, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 20, + column_index: 6, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + Product( + Sum( + Scaled( + Sum( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 20, + column_index: 6, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Sum( + Product( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Product( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Negated( + Scaled( + Product( + Sum( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + ), + ), + Negated( + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + ), + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Product( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 21, + column_index: 1, + rotation: Rotation( + -1, + ), + }, + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Advice { + query_index: 2, + column_index: 9, + rotation: Rotation( + -1, + ), + }, + ), + ), + ), + ), + ), + Sum( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 21, + column_index: 1, + rotation: Rotation( + -1, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Product( + Advice { + query_index: 23, + column_index: 7, + rotation: Rotation( + -1, + ), + }, + Product( + Constant( + 0x0000000000000000000000000000000010000000000000000000000000000000, + ), + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000040, + ), + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Sum( + Advice { + query_index: 20, + column_index: 6, + rotation: Rotation( + -1, + ), + }, + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Constant( + 0x00000000000000000000000000000000224698fc0994a8dd8c46eb2100000001, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Advice { + query_index: 23, + column_index: 7, + rotation: Rotation( + -1, + ), + }, + Sum( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Constant( + 0x0000000000000000000000000000000010000000000000000000000000000000, + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Advice { + query_index: 23, + column_index: 7, + rotation: Rotation( + -1, + ), + }, + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Advice { + query_index: 23, + column_index: 7, + rotation: Rotation( + -1, + ), + }, + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Product( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 22, + column_index: 6, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Scaled( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Scaled( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Product( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Scaled( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Scaled( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + ), + ), + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 16, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Product( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 21, + column_index: 21, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Product( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Scaled( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + Negated( + Scaled( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + ), + ), + ), + ), + Sum( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 17, + column_index: 1, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + Product( + Fixed { + query_index: 22, + column_index: 22, + rotation: Rotation( + 0, + ), + }, + Product( + Product( + Product( + Product( + Product( + Product( + Product( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000006, + ), + Negated( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000007, + ), + Negated( + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + ), + ), + ), + Product( + Fixed { + query_index: 22, + column_index: 22, + rotation: Rotation( + 0, + ), + }, + Sum( + Sum( + Sum( + Sum( + Sum( + Sum( + Sum( + Sum( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000000, + ), + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Fixed { + query_index: 3, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Fixed { + query_index: 4, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Fixed { + query_index: 5, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Fixed { + query_index: 6, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Fixed { + query_index: 7, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Fixed { + query_index: 8, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Fixed { + query_index: 9, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Sum( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + Fixed { + query_index: 10, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Fixed { + query_index: 22, + column_index: 22, + rotation: Rotation( + 0, + ), + }, + Sum( + Sum( + Product( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Fixed { + query_index: 2, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Fixed { + query_index: 22, + column_index: 22, + rotation: Rotation( + 0, + ), + }, + Sum( + Sum( + Product( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Product( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + ), + ), + ), + Product( + Fixed { + query_index: 23, + column_index: 23, + rotation: Rotation( + 0, + ), + }, + Sum( + Sum( + Sum( + Sum( + Sum( + Sum( + Sum( + Sum( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000000, + ), + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Fixed { + query_index: 3, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Fixed { + query_index: 4, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Fixed { + query_index: 5, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Fixed { + query_index: 6, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Fixed { + query_index: 7, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Fixed { + query_index: 8, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Fixed { + query_index: 9, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Product( + Product( + Product( + Product( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Fixed { + query_index: 10, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Fixed { + query_index: 23, + column_index: 23, + rotation: Rotation( + 0, + ), + }, + Sum( + Sum( + Product( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Fixed { + query_index: 2, + column_index: 12, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Fixed { + query_index: 23, + column_index: 23, + rotation: Rotation( + 0, + ), + }, + Sum( + Sum( + Product( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Product( + Product( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + ), + ), + ), + Product( + Fixed { + query_index: 23, + column_index: 23, + rotation: Rotation( + 0, + ), + }, + Product( + Product( + Product( + Product( + Product( + Product( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000005, + ), + Negated( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000006, + ), + Negated( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000007, + ), + Negated( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Sum( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + Negated( + Product( + Advice { + query_index: 24, + column_index: 8, + rotation: Rotation( + -1, + ), + }, + Constant( + 0x0000000000000000000000000000000001000000000000000000000000000000, + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Product( + Sum( + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + Negated( + Scaled( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Sum( + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + Negated( + Scaled( + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000008, + ), + ), + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 22, + column_index: 6, + rotation: Rotation( + 1, + ), + }, + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Product( + Product( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 24, + column_index: 8, + rotation: Rotation( + -1, + ), + }, + Negated( + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Scaled( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Sum( + Advice { + query_index: 20, + column_index: 6, + rotation: Rotation( + -1, + ), + }, + Negated( + Scaled( + Advice { + query_index: 24, + column_index: 8, + rotation: Rotation( + -1, + ), + }, + 0x1000000000000000000000000000000000000000000000000000000000000000, + ), + ), + ), + Constant( + 0x0000000000000000000000000000000400000000000000000000000000000000, + ), + ), + Negated( + Constant( + 0x00000000000000000000000000000000224698fc094cf91b992d30ed00000001, + ), + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Scaled( + Fixed { + query_index: 3, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Product( + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + ), + ), + ), + Product( + Fixed { + query_index: 17, + column_index: 17, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Sum( + Sum( + Advice { + query_index: 16, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + Sum( + Sum( + Product( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Fixed { + query_index: 17, + column_index: 17, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Scaled( + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 16, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Negated( + Sum( + Sum( + Scaled( + Product( + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Product( + Fixed { + query_index: 11, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Sum( + Fixed { + query_index: 11, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + ), + ), + ), + Product( + Sum( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 14, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + ), + Sum( + Advice { + query_index: 16, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 16, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Advice { + query_index: 17, + column_index: 1, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + ), + ), + Product( + Scaled( + Product( + Fixed { + query_index: 11, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Sum( + Fixed { + query_index: 11, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + ), + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Advice { + query_index: 8, + column_index: 3, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 24, + column_index: 24, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Scaled( + Fixed { + query_index: 4, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Product( + Sum( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + ), + ), + ), + Product( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Sum( + Sum( + Advice { + query_index: 15, + column_index: 5, + rotation: Rotation( + 1, + ), + }, + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + Product( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Scaled( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Sum( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 15, + column_index: 5, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + Negated( + Sum( + Sum( + Scaled( + Product( + Sum( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + ), + ), + ), + Product( + Sum( + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + ), + Sum( + Advice { + query_index: 15, + column_index: 5, + rotation: Rotation( + 1, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 15, + column_index: 5, + rotation: Rotation( + 1, + ), + }, + ), + ), + Negated( + Advice { + query_index: 22, + column_index: 6, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + ), + ), + Product( + Scaled( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + ), + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Advice { + query_index: 19, + column_index: 8, + rotation: Rotation( + 1, + ), + }, + ), + ), + ), + ), + ), + ], + advice_queries: [ + ( + Column { + index: 9, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 9, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 9, + column_type: Advice, + }, + Rotation( + -1, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 1, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 2, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 3, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 2, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 3, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 4, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 5, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 6, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 7, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 8, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 4, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 5, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 1, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 7, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 8, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 6, + column_type: Advice, + }, + Rotation( + -1, + ), + ), + ( + Column { + index: 1, + column_type: Advice, + }, + Rotation( + -1, + ), + ), + ( + Column { + index: 6, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 7, + column_type: Advice, + }, + Rotation( + -1, + ), + ), + ( + Column { + index: 8, + column_type: Advice, + }, + Rotation( + -1, + ), + ), + ], + instance_queries: [], + fixed_queries: [ + ( + Column { + index: 0, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 1, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 12, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 2, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 3, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 4, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 5, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 6, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 7, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 8, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 9, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 13, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 10, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 11, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 14, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 15, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 16, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 17, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 18, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 19, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 20, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 21, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 22, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 23, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 24, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ], + permutation: Argument { + columns: [ + Column { + index: 0, + column_type: Fixed, + }, + Column { + index: 9, + column_type: Advice, + }, + Column { + index: 0, + column_type: Advice, + }, + Column { + index: 1, + column_type: Advice, + }, + Column { + index: 2, + column_type: Advice, + }, + Column { + index: 3, + column_type: Advice, + }, + Column { + index: 4, + column_type: Advice, + }, + Column { + index: 6, + column_type: Advice, + }, + Column { + index: 8, + column_type: Advice, + }, + Column { + index: 7, + column_type: Advice, + }, + Column { + index: 5, + column_type: Advice, + }, + ], + }, + lookups: [ + Argument { + input_expressions: [ + Product( + Fixed { + query_index: 15, + column_index: 15, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Fixed { + query_index: 16, + column_index: 16, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 1, + column_index: 9, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 16, + column_index: 16, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ], + table_expressions: [ + Fixed { + query_index: 1, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ], + }, + Argument { + input_expressions: [ + Product( + Fixed { + query_index: 17, + column_index: 17, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 5, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Product( + Sum( + Fixed { + query_index: 11, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Negated( + Product( + Fixed { + query_index: 11, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Sum( + Fixed { + query_index: 11, + column_index: 13, + rotation: Rotation( + 0, + ), + }, + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + ), + ), + ), + Advice { + query_index: 7, + column_index: 2, + rotation: Rotation( + 1, + ), + }, + ), + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + ), + ), + ), + Sum( + Product( + Fixed { + query_index: 17, + column_index: 17, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + Scaled( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 17, + column_index: 17, + rotation: Rotation( + 0, + ), + }, + ), + ), + 0x0db5218be6881f0f1431d4ea7d4afc7b29a05bafbede62b55a91eb912044ea5f, + ), + ), + Sum( + Product( + Fixed { + query_index: 17, + column_index: 17, + rotation: Rotation( + 0, + ), + }, + Sum( + Scaled( + Product( + Sum( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + Negated( + Product( + Advice { + query_index: 6, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 3, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 4, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + ), + Scaled( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 17, + column_index: 17, + rotation: Rotation( + 0, + ), + }, + ), + ), + 0x2f0f40c2f152a01c9caf66298493d5d0944a041c2e65ba0117c24f76bf8e6483, + ), + ), + ], + table_expressions: [ + Fixed { + query_index: 1, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Fixed { + query_index: 12, + column_index: 10, + rotation: Rotation( + 0, + ), + }, + Fixed { + query_index: 13, + column_index: 11, + rotation: Rotation( + 0, + ), + }, + ], + }, + Argument { + input_expressions: [ + Product( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 12, + column_index: 7, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Product( + Sum( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Negated( + Product( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Sum( + Fixed { + query_index: 14, + column_index: 14, + rotation: Rotation( + 0, + ), + }, + Negated( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + ), + ), + ), + ), + ), + Advice { + query_index: 18, + column_index: 7, + rotation: Rotation( + 1, + ), + }, + ), + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + ), + ), + ), + Sum( + Product( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + Scaled( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + 0x0db5218be6881f0f1431d4ea7d4afc7b29a05bafbede62b55a91eb912044ea5f, + ), + ), + Sum( + Product( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + Sum( + Scaled( + Product( + Sum( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 0, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + Sum( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Negated( + Sum( + Sum( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), + Negated( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + 0x2000000000000000000000000000000011234c7e04a67c8dcc96987680000001, + ), + Negated( + Product( + Advice { + query_index: 13, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 10, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Negated( + Advice { + query_index: 11, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), + ), + ), + Scaled( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + 0x2f0f40c2f152a01c9caf66298493d5d0944a041c2e65ba0117c24f76bf8e6483, + ), + ), + ], + table_expressions: [ + Fixed { + query_index: 1, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Fixed { + query_index: 12, + column_index: 10, + rotation: Rotation( + 0, + ), + }, + Fixed { + query_index: 13, + column_index: 11, + rotation: Rotation( + 0, + ), + }, + ], + }, + ], + constants: [ + Column { + index: 0, + column_type: Fixed, + }, + ], + minimum_degree: None, + }, + fixed_commitments: [ + (0x372e1011c41715c062e0bdb944973af06c5e779e64d2eb64b713ba7a923bd921, 0x0df587dbf80715f2e1a3429e4970dc1ee2b4478ac56fc6308bd1423a96630eff), + (0x05f5862cad2888855bc3c1843a9eff57b11b592d9eb0e13354256661387f5231, 0x32236b14df85bf5f532a930232cb23a5c56ef7d67aaeed8bcb8fc10ea132cbd6), + (0x278ceb78d7e41109f04648e31a17d363250264779a54822b6af849e08394f8c6, 0x38657e78f288108b1eabf5752c294db179397f61b34e3bcce8b9ea64f0414ccf), + (0x02f77b8037894d3be78b9913b56f87a4a11de5b23a2715653c95284f5f4a533a, 0x21f3437bc1226236ea0b87217af56ccca66daa8641dfa562c1bac1c9c97e9ba3), + (0x226cbe263518a231a03864a40070593012418e4adaad26a9657068c92bd99834, 0x30aa25907ea9e3751193ca7a4d1e25c1f085f07e24fa55790d8dde572cbb4b39), + (0x31bb1ac8ad43e9c13b44aec205cedd51ba49044f42b9778a281c8f78499c5844, 0x0d10aa271191e573188ce755174183966f97996f460a32129f409c6e33452859), + (0x3cafd5ce5d34b1e0318cc5b0e655cc0411dd86d2c917c4c776923920ce4b8783, 0x1cec31e481cd980c231475d95ce7595a241d33128f0d0f556fa3e3ce64309182), + (0x17749546b03083d43554511e69f5f2049e78c7893f4c6012a44e51f0e8ed314a, 0x39347f6d9fc4dd61e475a277ce7dfb0e4d1d31e1c0a10d8bbe6b4029cb778964), + (0x31d60c414c7acf6d5941cf201088d51eb81e528ffefa458f2fccea9d81ad274b, 0x3aa09ba345b10e2ff005c50f5d1fb5b86a7145c2f744cadac9567fde1e4e1b17), + (0x1de5f02daa9e1bd92e54a37fd41969e14c89c09b718a791f616c0de7c51eea94, 0x096456cd7e00ab2d318dd5d38ef0b918faff5225d8dc34e1fe3c2db4ef5698bb), + (0x3e727e8554679f98120355d39d958dbd8755d5a7f8b42ea87f258064c4b3eb57, 0x0c0d5c23f3ee62ac1b2d986dd3033bbcab260d590e1393de3a14a4b31ae091bb), + (0x3748680dd6a91c5dec668b30fb6bf9a450aeb884b81cbc344914f265760e7131, 0x18530eaa5c58b61bd3fc38220ea484c0922524a815a8f752be955c229f9c4164), + (0x2fa9bff8025b9eb1fd60c0bec845d6d09c49a03d7020280feae9751acb88bdb6, 0x0958e83ae406bdc3c0704afa316f3717568c74cc4475127443a6c9058444234c), + (0x2f39f6d3b0dd8e900034e38670e853e761825dff78c4060e2ca4832ecb1de86a, 0x13c40f0fe6243ac40fb8abbcf7e62f027362a8e0b65b38f7657dc4db3e471fdc), + (0x0fc9e35a206e0ecd68eb1aa156be11067d48cb853f8b7be8366e693077c05adc, 0x0f2d1e728e41ca4cdf33998fcf2b9ff442523b2d854ea7b800cc79ef381ef053), + (0x2bbc94ef7b22aebef24f9a4b0cc1831882548b605171366017d45c3e6fd92075, 0x082b801a6e176239943bfb759fb02138f47a5c8cc4aa7fa0af559fde4e3abd97), + (0x2bbc94ef7b22aebef24f9a4b0cc1831882548b605171366017d45c3e6fd92075, 0x082b801a6e176239943bfb759fb02138f47a5c8cc4aa7fa0af559fde4e3abd97), + (0x0132c6f79957c48e8e89c8bb06a02b1ab2fa2872c6bbf2a98d24ae2cf286ab65, 0x101570d65833ffd44e4a481f7f2c0b42854b2785beebe0f3e3e7cf0432b0f2a8), + (0x1bb21f71d0d3cf31cc7604e6c80f219a95ad8a2fdda1ba4749038a850cb295e5, 0x21fbf3282559a16f747df709bb6e53ae247bf4aefdef22d1456ceee0069a5a30), + (0x298e4558e567ccac97873d2423022d66ccaf4330fe3a168a283fe38c36ded7cf, 0x2a19cc559c589cd3dce09b37b01d147351e5629d81aa067a92564bbab3264606), + (0x25fdb5e53d333b73513af137b20e1ff8556ba3528f8421dc94fff7993c2825fc, 0x1dd77006ac8a5883fc101e9869119f58702ecd6ba2248d6fe887dec9a9cb7abe), + (0x2bbc94ef7b22aebef24f9a4b0cc1831882548b605171366017d45c3e6fd92075, 0x082b801a6e176239943bfb759fb02138f47a5c8cc4aa7fa0af559fde4e3abd97), + (0x2bbc94ef7b22aebef24f9a4b0cc1831882548b605171366017d45c3e6fd92075, 0x082b801a6e176239943bfb759fb02138f47a5c8cc4aa7fa0af559fde4e3abd97), + (0x1807fc6a973fabd4cfdb43133ab368dc3ec8b3e3c49a33022ceb7a11312994a9, 0x090fa9b27aad0b2466a0fe73bc6e27b071522f808223697e06a97b0067a295d9), + (0x09899c24004863d99205b3e8d12091fb9efc7f869213aabfa755ce8226296ac8, 0x3b9fd993ade2b56baa51cb480372188b2b4a6c029721abd78f882376a2e1066f), + ], + permutation: VerifyingKey { + commitments: [ + (0x19b1e656ecc4bcddac6e6223161f9a676f6dc320323dd923d07b107bd956980f, 0x12b19731c6cf97867694f17f8241ae4f87699babe1f2e0aff0da5843c495687c), + (0x34015e25137a9a8ea4feb8af77f10d27fc6a04e952823f7e2343a749419df2ce, 0x2c6589a5343037dd14d33821800626bba96354283fb05011f27dcda6a6b860fb), + (0x3b99cb11670a52fb09cdb23f99dec85dd61bfee1120cb6cb7f976a027e7fe29d, 0x147c5a63bed5b0a16b5f28c68ccc46bb175a71f093c1a14e71c944ca20d2d5a8), + (0x0447bb1bd9cd21264decdcf1d3d8c51152dde3e2973c289636c5143fee588597, 0x2693688ea58e92c734de32906f8646d3e7eb92df37eab9e95f8e1fa0fb47740c), + (0x139a2e45b57a51ef2b2f091026e534e710f4095a248e029411c83545ffbe980a, 0x3a9f5a5f1778dc3ab162ba7e408f8787deccc79eed79f39ba8e95d30d59bf072), + (0x3bb81950a72eed5a0d778f649dcfdebbc7fd777c40ebbc8423a5359b1657ec69, 0x0827061e9cb496f1de9b65eb40414b801f1cab7ea1451db61b26d8828db12934), + (0x053904bdde8cfead3b517bb4f6ded3e699f8b94ca6156a9dd2f92a2a05a7ec5a, 0x16753ff97c0d82ff586bb7a07bf7f27a92df90b3617fa5e75d4f55c3b0ef8711), + (0x3804548f6816452747a5b542fa5656353fc989db40d69e9e27d6f973b5deebb0, 0x389a44d5037866dd83993af75831a5f90a18ad5244255aa5bd2c922cc5853055), + (0x1364aec73f61f3bbef067b079769ef911ef829c7bc96aad03eb7f67f5267f7a2, 0x2286218435feaff751a5b11ffcad519cce178967d265737fce47b4ce2bbf3855), + (0x0c789966ab89d6e03049ae4d06a58aad553df983f7feaf75568ef95e477d8a48, 0x16786ba48d94e3c7968ea059eb9ce4db1684a7804d886a586bb691dca1646754), + (0x16633696ce5a30d1d301ceaab86aad90ea6ea22adf090e31859b4fb571e9b746, 0x035966e0a73b53474ee433e2f835e1a8b02c29a49f109bdd590a37d2b946dd03), + ], + }, +} From 684c13e3b24d3315276b31f7adcd594c432b180d Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 6 May 2024 12:30:55 +0200 Subject: [PATCH 29/99] update serialized_proof_test_case --- Cargo.lock | 6 +- .../src/circuit_proof_test_case_ecc.bin | Bin 0 -> 3872 bytes .../circuit_proof_test_case_sinsemilla.bin | Bin 0 -> 4576 bytes halo2_gadgets/src/ecc.rs | 37 ++++++- halo2_gadgets/src/sinsemilla.rs | 36 ++++++- .../circuit_proof_test_case_merkle.bin | Bin 0 -> 4160 bytes halo2_gadgets/src/sinsemilla/merkle.rs | 38 ++++++- halo2_gadgets/src/utilities.rs | 1 + .../src/utilities/lookup_range_check.rs | 64 ++++++------ halo2_gadgets/src/utilities/test_circuit.rs | 95 ++++++++++++++++++ 10 files changed, 239 insertions(+), 38 deletions(-) create mode 100644 halo2_gadgets/src/circuit_proof_test_case_ecc.bin create mode 100644 halo2_gadgets/src/circuit_proof_test_case_sinsemilla.bin create mode 100644 halo2_gadgets/src/sinsemilla/circuit_proof_test_case_merkle.bin create mode 100644 halo2_gadgets/src/utilities/test_circuit.rs diff --git a/Cargo.lock b/Cargo.lock index 2f8bc71dfb..c7ceac9436 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -2280,4 +2280,4 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" dependencies = [ "simd-adler32", -] +] \ No newline at end of file diff --git a/halo2_gadgets/src/circuit_proof_test_case_ecc.bin b/halo2_gadgets/src/circuit_proof_test_case_ecc.bin new file mode 100644 index 0000000000000000000000000000000000000000..1565f2935cce5a184ba1b5fff88f3c95b78b319d GIT binary patch literal 3872 zcmajf^&=dP!@%)#hI6{R>on6bZ8+VN6Z^<99AlW7c1)j+VRAYqrn|eDIC0u^jPpGI z!T0^^>-V?q_e8w4C}4ICqTXr}J5QJp_da;Q#I^XElH-0UN|>ruwQzKx(`ZJP8<}@odUSts!Z zt`{UP6O#CamZaWlRM>mFheBT^+ZAw{1I5S^;}Rt{ZaVYB)IF}3f+|X9;wcti^qlCl z7jg<=nx#jxV8(-zQVk8~-1xuYGUd+1uK{2`*U8Xx<{2vZHu9Fr_UEI!-YzTlc?w%A(46cLB74M&_(OvFd*43Fe4mN6XU)Z%1j(IJ#qg zpD9}Cs)DONgSZ^D#VUsXGT(;^i8ES!@*)iM)1`dTlD)7CIKrQ)l*ZPclXH15wVNW z%;&%W6xZxx>vVLam0u~m=nwNVax?uihswcjYdPtY?<5!QWVP4X!>5Ir$iJ;`ARP3# z>I7>GQC|kLx+|vLkQf5ihL6@=yT+OV>|Z>aXQ5&rtxm zhaM)Q_4&E0F8fk*)+tYP}Hyq`bV2s zA5HSCDxpLVQTzBX%jd4Xy$?qZL!xD{veWqF9NysV$2jyC-Ii`XMPqnrrD|1qe5;KZ z8b8+GtxxIl61toDv-R1BEkLALC1UJ{Yg{4xl2O-_) z6b!5S?u~_IN7azd--iR+S_$||)H;2P~;YpK1Ao45* zxOuLeDf<%2$aT2a!(arg?#bx50>Lj^@A;?oS%iCF+biKUt?VvvRz5OBhP|v8&tU?f z&RhX!jMT!-AL;8|{DC|dWQ`fxl@11qWejMykjXFzWOmr+xc46|OZ+@hBOSEYWfmjD zh-#OWro}6^N@nYv60O#&k3rQ%D7n;{{+4-dM>hO$m1@L>BXvdmVvgcF^|?zN9RcAV zCtQrDf%j^s$@G2yp?a}YT22|qYJeU4kiZ&?uNczd_M!xCNs_Y3DKdktHS6q}2%qoa zl=Ku;A_;Lv)i(t+DU6hRIMPH3e<@*Js7v<9WrRsa(Z?vRr4P78GU(>CF$QuN(BI^C z8G`LoN%3V(K^OOCH#MX;P<;$^!h1neWurNHk7Lr=2p=in zY3@xAz0PMg496A-6))SA5@7lAZL+AOY)ttSG^+sU*c>Hxy;AKP2ef?!0W~t9w`Wz~ zc!+wbmlgB{*m3_Vu(?j- zRpAO!em9)aOv=^mO`%5Z9`%WMA#sLJFCVCv-bj1oKt61Zlx4pEYlja;s(m_QX}X~Z z>1?|=j=djZdd$Nu813VXzf`2<%B;&v)cD{Gn8XZF2bh1mw7eLBrTse}m*(JMyeYa- z99WZ5AQqZaI5?)rHX>GHFuSi9R61bE(3Wvx!SG-@)m>@u9Bu!dmfnoB7h+MpYothH&C|;j4WqRMnO^0Uu>QYQWWm{bc6R{AmjMe+ zJ;kDaNUZ;ArR|lr7P?f9Ju^aN8QP2Q1`I_$rY)*bAZTeL?m*%n6hApVcnwc-=4ER% z0_*52{5{+X4=XbuH(L92t=y2pJ!X8Fn%4CMMI2&JP;DbnP$~8io4e&owjVN$C{~T@_gvVO+C)vAH7nWpGe5z1XnE zzaQQcjI2A$rZcl1O#M<^mXu8<23I`0rmGC}n93DTSFx4bS+W3wBW~|1?Qk=>*$ljx zB*Ckx);{WI6Zz=12ZzSVDTBfE>55x1e(9M?EvKwtO6KvS_)mny8@vX;ffD>DlKFa@ z`y(HhaHUqS%PBcnt%)xKMaQu>th|~caEdnu8jy+_{5& z{o;a!nQ_BE&zF0Ia>+yFbklGKEFR?l_k&4ileR@H&e%xvaDN0 zSzL}1Ni+%VE$1Wr3xsBdJ%;eOeV< zS;_UkJcUPaqRV?{VWSO|GCc_~7J@ku1}Z_IFk-wV38J{Qrc-8?H>P`CSZb~=Yhd7v?`IN{K3m4@YRT))!;B#x6gW zo6wQEeR5gdLt{KG2=6)-t;5X~Zr}~lPsk>xZ7W*q6KKYX9xBg+-YG@aue%?4u<{Zn zrC$~AOr|uA>?m}jRVLCNFi#7*`0iJIdV;mOqPcMcn(lnxlxB^2t^sidBt-)h7&UHT z*|WC<#(cCFJ~CdH?yP1Ghgf|Jg_I9Qa6{+qa^Cv2&i+-`SCWR+Gz>+?D4zR&Ri}Q6 zIDvZ(KiE1Wu_VXKb|Jp-+oxWP@4#P`^F8eP``cD+*8B);uBEq%{F0l>!YUUJC;xuF z$tBdv;zID&OKkV;$+KE>@G_c;>6=dygU%8Ck%v1gRd|SgPfx)WO^@9J7fZ6v+c6lC zFN-|x#F)1~?a6=NPx;!^?AYdm7~Go)4J<-#Xg3??y1L z2_#DCku6Yy zkF6+dlMVkmG8GjmA7pb>nD>Wzc~z(1bTNQoL$hLdWvM{rlDGvB?0()9adyTFCXsS; zS-G3Qs?m!JTCrxe+1eu5AmiBJ$n8nwACV>S9;fN)<27JBV#XmV%3Y=Z51CR~O%El` z)9l$doR6gBkqkL;&PGqCLTw8n!yt~RzXLgS;L?`v6w%ZwY9NJ%aK;BVT7r?<&e1Hy7zYXJg-If#%p z3KtQbP>gI{EL9traegG!Q%;w6p#mbD{~Ay+|Nkq%>?9vZtjg==N3LSnlBaN%A9JKq-8q>Z@{(e_7=G6jT~vSO(i%lt45nuR<;6hy zS_ICSWb0BSJtR%z&TJ#R#NP_1nFRul={QqD${ewa)81?Vr{+;oY*khD+%(cgJ7qs|tJM1Ebo zlS`GBnoE|)W!J>t233fb_G5Xh>8~ac0ZL|&S+{a9|CVj#1=s7d8(Cd=WNG^^J4;v9 z^k)8uryXq;3(Vq6BK%;=f&jpf(AS9fB2YzZ!pElbr(Xxxo4PPr0RAFe#`!bU=G3X4 zrin0tf+i3>U@?~~D#TfxPb2Xw>W8WlQKCYA@GI(K$EhT;+mui)!5o-U;~HH@L%s9w z<~UYSHQj(i55#5^OEpJgz_|TJtpZ+@d?{nq-d>Z)M6UmR{iZ!?h@mHKejZyLk?;#% zeNd-E==MCtGcwxj$l20sbaGyd(;D3SiI1jd8dupr0o+;hm7=~0XGhot- zHwd=r6-eaByj-cQ4l#+Jd0RX4dabTD}qxyI|=v zYj01+bff=smrSUcGnl3Xsk4?hQcWB7a&3ycZrIt+jCx*6-Yj^%+x90+xfvwzXurB1 zp4R3~(71!wAXpPsa>?etil*eJ9{htN3VccHKg_+8rN@dt^tB{QVl|>9F|7e_u=7MzBoRsH8b0WyPCd z;u7vY^<7_L#1Zl4aFSMaPqeMzJwali-uqh{Hb5?h0pz|F4uq-OHTv!)YDvTH{3EBv zUW{7!#GcSbSi%yJDvy56zlYHqBwOUhn#Yw}2J?6sob&nwbabKoN3TjP4oC*HH)R;~ znZ|6;60Pwi^)I7Ivmx0P5j>>=9fT!mFzr@eyFo=S8?nLWOSHA)_1mG{28kz5V>gL} z9w8iH&pTuk|I5B;P)7>4LnCTbOH63HRC#IPk z>>MS%YahFJpo^AY4cI(XL}>+#PHsd7ISu@1*FD0oU9^9HRJU33S0jy;G!iI64e^hx zfKxmI?wU_y?1t-(#*6WiK52TjO{_gRTGHDSi(bi?Xs}LTKsQ(3+2VH&6D0%=OfW6AjQ{z^kr1|j23;owuolx!wr0H zn$KC;3B{UJ2-1nl)4wwA3gtKee@@wMWS%>?W3*8@qL-10WJ4Cz5}H>!DNbJ52?u-C zecyiq>_6hPmnFR_UsCz}PZ!qT?X!GB8CieEqJ&-))nVNt$lC?3J8R~5dvQbUh+7Fl zmNP9hkR3^YeuaN77BNT(B^veR^>L|18Qt;WtY!38j`Uu}D-gEV26`d( z_!?IDu)a*63}b8WEe!XqcT1KiGI_FN^|Ez=Tht;FIR8?jv zsC)e~^7uy9*#T$oZSRIXHw?hvR!~9Cds2^IgtaHgr6LRl%fu4?o^h;J^n(RwUZRTd zVLCCCYDo~8Nk%%Rk12|NX66>U&CD@(mWh#IS$R2jdg`7%e&o<64Nc#)n<3*1@_Mib zWSlMB<1wmh07F&k+*~kh4d0FtJ2Y*2ZdP&VrtPJ&nnV#GY|ViC>P=q>B5NoP6T?{v z;6kLkz5oqQe&}iMjK?zL_n>}TuE9i*zdJDrmI%X%f_%9p>#F2}{Ij+nGA3*#$Tk5VHf|he-MCaJ#(MX*BbTo|H zm*jTDH-*(O^fDtmmFGqF}3h zi1TI|VA$P_cGVjh-5_Whcg9;ED@8Wb&!?r>|^I4RfzKt#xx32m_5+1rUp`g0?K}c?$_P|W( zm@sqnIaLYj1$eOkz`twAo?yV#oqp5&qUd^9nM9g(!zkccRBk?d$>&d7t@&w}M(p31 z*-Mh73eCgBwaePMg-?xW@IKvW-*U(5Sd*`TTe)X3$Nc#>GxH2XFJvXd{48edAal#` zFQvTiSPV+=cgRCrac3$c=YT_uhk zX7R3+=dSZB&z{rZ(&et!2hHhJhNrv<>QNH(P4|A(ixMI+rGR4EHKOeUe>~ktlWg(? z!qA_Nh-JXJWCF)iE&OV?_tV&VG#+q+qWE(IrQh!8eA-jb{tw^Ve$HjQcNAG}SmAuy zgX6IHKqQCmQ0|IfNiW}?Z%)oiINfxX4ReSNH0CTQX7Nxcxbei_2#=mu!ZVDzgKx#+ zhf!SJTr6hG7sSuT4-Q*;LB3q=EdWnej1jCRYmKXU3f4aRmDs}MB;Q}!EKf%j(lb;5 z5HB+aUDj?@4RQQ19rC;Z5#K>iIx0D$xDOXl;u8f|d3ld!fJRsMWq2Dsqw}#1i|F*G zsL@C8hx#7l>o7%?k;J)BdS!gm$uWZi+8$mOVW5t>gR79szNp}vJ+d`o(wU3~q%l*J z?j7<~XTPhgL=SPh%GHv+pYzLYE8RN&qSZ`~2NA@}mJ=qvG2UHAN<~ikBmQP5>B=8F zssAlW;7$gkr*BlTIA^SSz%mNmgd=tN>dA8C(>w5D2sB@*7=C8KNDB-At1OsI6=DQd;hiZ5Vp|cNrDh%uk{_+Rxf+-B6^yev>K zeu|%nuc@>qA#iRn+)HQ)#UE`fpqY9*wB5Ai(G^a6Baa((KSO9tk;@|D!SlS_00fL0=wV zi+1r}ZC#!9cG}8p7qK8!OY&+|E4KY2M3ZGYP9551)Yl945kf`g55VI|fw$N%Ab0b8 z8zjbzxeiwO+HsGC#PYBaUxq*GV+eI4$G42}R#(ga-anRVUK-1KS% z(Hq>A=ZG`=zYcD1U_kabj%F!($ukrw8~B$fBE=L>O@$F&G5(5-U5{6cLPk50)pp

|d3_{PK*bWd z;qCX3_|1d@M{I(Ub+E!OPKjtVCI;Oez&WARj%Snh)Jcp7%?$|$q2jW3eTXid?j6jf z8cEpJ4)k0Hgj2AnVp4G9u_?4!QosHc*eH+lEiF?DKTJ$DM^HLM=Ut8Ud69%ojR|~| znwuFbOp0sY5%8n|UG$OGT?hW8_=Wsjd^z!6X?#5psEV$f!y!6c$b|1<${P{NntOku zra)25KBd;dMu^SEf-54zQgjYt(V~TyF!zOSd=hF34HAYUF2jRz2XXi8mxK(*j3r`lGyf!&88_ zSK$DkDF^cw@eY_Q*fAxmC;_VfFXp(kKlAjHcDdy3?$0&~dN8mg*<6o_c3yd3{J(0$ za(=c~Md?pf5w;zg6oA4+Hid5kg&`LQqh)`vBks=zC-gCSM>7C@V zgb0X#$e|@J}(cIm{v}e9mi=Y2-b3MUXd5X&vv_V1J^5iOs!|h^y$A43^GQ`WtD8 zdwu{)rGg`&WspK~?5>$^mqYAYrWi)Ucwd{)O7Tz*ftVfX@N_Q6>B)ezO1aOJFkxk5!?egb#aseDw zbDqJ$*q-hmgX)uqwX7>jw;QJ982u4S%8StDi;$t@jIeDkfD1$rPyX$id=*O=P*u76 zR@5~&GsLcnSDb0WcyeD%LbY}xX=mX+H&)V?Do-m)V*pCWUVc@yDk!zT)hMx`; zG8-R&rv4XpUu+34<@x5cmCh;~OJp1-Oh#sFgvQOW~9&Wk3HuNbBgH?`mjFQ zVwk;`ta82klwfn6FymoJGXx;FM6PeOdXYa)%fn`wLyu!t*`e3rMamXav{O`*3 z+wXC2>)a;!*FJDkew96QoxRI*tE19&y{X(Uw6T_LYay{CG;?+vRO) zT#pTgR(;9fB^h8!Co$Em4E_6Y)m5B>>-n*)7Ri2(XzlfN{^djDDR+QLceC&;3*%K? zh}SyG)g9N-V*Czf`i$q{`i7QXr0dL8w!Co`>>X_kj;3b8UMLCT!VJFM!L7~ekETX1zvXit1!AdB&>UAV9*FT>^uz1$xn z&KCBQEhbaswZ}xqzLp7=q)c>;{aZce9FE437W*5>XH!RuC%D3?Dc!poNZ zqYY2%4qZjALYCidQ!bOeo9l1I5<9ONjTB!8(*erW#*6x>i){VaHdG`(iS0Aal39ZL zN9?Xw-gJY<_%Cx2j^Rq6Q2e`hIYY}+9RM-?VARrOd`?@N#}=bc^^;I1ao4( z12we#*$_$y{Z9@0B_Sdyx&t9y=_WBu%I-YRb+ZAd$;n%zGs&+XEW+3GO zXqltNfEVRL*Nv)QTn7?qEw8atZfe3b_(y-R@LSL*wDR@A!Kn7I)Bfi|k_4A6xB1r_ zSc4c3n(*&ia&3#>vnu|%@mttTQGgLw=ZOVCNse5>C?BN^6Sl$Pu^=IxXOVlk`#I#3 z>WRkCXJJ;~m|irzwHU`BtS1pE{}I))x%YuceJwLDSk50aP-0)~$bKM?Qsr*9w%=8N ze=9CSHl5ca6n(L^gA7+Qxsk!%9I1At!L;agc?%5z0;b;-D|fzu|8<{USzvy>iR8Q5ygka&-295yPOz+Z(aN1&aRHregmC9L;-> literal 0 HcmV?d00001 diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index b835aaf3eb..66ec826e41 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -598,8 +598,8 @@ pub(crate) mod tests { }, FixedPoints, }; - use crate::utilities::lookup_range_check::tests::test_proof_size; use crate::utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}; + use crate::utilities::test_circuit::{Proof, read_test_case, test_proof_size, write_test_case}; #[derive(Debug, Eq, PartialEq, Clone)] pub(crate) struct TestFixedBases; @@ -931,6 +931,41 @@ pub(crate) mod tests { } test_proof_size(k, circuit, params, vk) } + + #[test] + fn serialized_proof_test_case() { + use std::fs; + + let circuit = MyCircuit { test_errors: false }; + // Setup phase: generate parameters, vk for the circuit. + let params:Params = Params::new(11); + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + + if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { + let create_proof = || -> std::io::Result<()> { + let proof = Proof::create( + &vk, + ¶ms, + circuit, + ).unwrap(); + assert!(proof.verify(&vk, ¶ms).is_ok()); + + let file = std::fs::File::create("src/circuit_proof_test_case_ecc.bin")?; + write_test_case(file, &proof) + }; + create_proof().expect("should be able to write new proof"); + } + + // Parse the hardcoded proof test case. + let proof= { + let test_case_bytes = fs::read("src/circuit_proof_test_case_ecc.bin").unwrap(); + read_test_case(&test_case_bytes[..]).expect("proof must be valid") + }; + + // todo: check size + assert_eq!(proof.as_ref().len(), 3872); + assert!(proof.verify(&vk, ¶ms).is_ok()); + } #[cfg(feature = "test-dev-graph")] #[test] fn print_ecc_chip() { diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 439dba9fae..ace786e1fd 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -489,10 +489,10 @@ pub(crate) mod tests { use lazy_static::lazy_static; use pasta_curves::pallas; - use crate::utilities::lookup_range_check::tests::test_proof_size; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; use std::convert::TryInto; + use crate::utilities::test_circuit::{Proof, read_test_case, test_proof_size, write_test_case}; pub(crate) const PERSONALIZATION: &str = "MerkleCRH"; @@ -786,6 +786,40 @@ pub(crate) mod tests { test_proof_size(11, circuit, params, vk) } + #[test] + fn serialized_proof_test_case() { + use std::fs; + + let circuit = MyCircuit {}; + // Setup phase: generate parameters, vk for the circuit. + let params:Params = Params::new(11); + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + + if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { + let create_proof = || -> std::io::Result<()> { + let proof = Proof::create( + &vk, + ¶ms, + circuit, + ).unwrap(); + assert!(proof.verify(&vk, ¶ms).is_ok()); + + let file = std::fs::File::create("src/circuit_proof_test_case_sinsemilla.bin")?; + write_test_case(file, &proof) + }; + create_proof().expect("should be able to write new proof"); + } + + // Parse the hardcoded proof test case. + let proof= { + let test_case_bytes = fs::read("src/circuit_proof_test_case_sinsemilla.bin").unwrap(); + read_test_case(&test_case_bytes[..]).expect("proof must be valid") + }; + + assert_eq!(proof.as_ref().len(), 4576); + assert!(proof.verify(&vk, ¶ms).is_ok()); + } + #[cfg(feature = "test-dev-graph")] #[test] fn print_sinsemilla_chip() { diff --git a/halo2_gadgets/src/sinsemilla/circuit_proof_test_case_merkle.bin b/halo2_gadgets/src/sinsemilla/circuit_proof_test_case_merkle.bin new file mode 100644 index 0000000000000000000000000000000000000000..df788aebfabd74cf7f76ccb1d5b2a90bec188121 GIT binary patch literal 4160 zcmV-G5Wny4=>7~%D@Lc7iCnR=YbMU7yNI4&6~;@f8m`)O5%{gcATZeKTivT6q2y>p zFNs7p(YX|qdRv-Te;tudO3kpeIK}j9{Y^~}uBbzqj5foa`jN*^x7i=dJgl1Y=YK3H zGPQ!(-*y6kt%_A0Clp4RR9WaZbGfWm)Ox85osc@St)!LA{9FZi za5frlWc>}61UM@VBy61Z2x<0BGceF@ONv_HmXizt_OvB_Ffbrn6m(H_{a-RcSiX+u(f~h>&qW z!#y}%BSoh4C-Rgj7-X=&iGM~nC>q=WfsR5>XI04893Hf=u~0SHeVW?)%sQo1637R5 z1ztJ}!k#y!c>vhTzbU&NgR`1M-JS}UfsechME6?*ET@T=VdhMUgcD_&Nm%6V%03GD zT6Mfs3J+i*qD9Ts zkfW8xO5zO%z8yIDqFgkZEqf;)Uc%QqSy(e2wOaeGz5!`Ki+3JHBG`?wI~XdXBcuyE zPId-&wp|3h#iR4YUt}!Igv&mD>hR>k`>J4sub3`$F(Eb8!%*=6p*oPPDgY86J4Bfy zNQv`i{K-bytck!=U=tx5w0UwexuyJImYs9=bsa;#G0kre6%6Vg^&Ke=7Pa~Mf@DZ2zk3+6_ezr<=7>MB+=)jG4$TXm}&K~PP|wY zXmTJQ>pG~PEm;i`MZ)G#s7?<&^^^%kGEF`|;RkS6z_A-wX#6(vW+Di&1qp2HG&Q~< z%jYsWPBFb(+;rV?PCY!61(nOrHrRJc{cJzmq@3$NbVqxRCL~Z=cp3Y0RAUP$*1i~L z$6jcKEhriVL!pZH6u;XC$I{AZ-di1uy@nzGomzkwnTsN-M%uaw3#sE7pxQgfz`=q$ z-RHdqc7`m_%aIgyuV>F)F$Dt~h342K{7U+8Dt(ENZrt9%ElL!~l-V@+K1r@^gkLil z->*DO1SNcyb*iO~uS^*@uh1`s}5aIA(tNS~{C>tgMT##D;>MR?8)yfHg@eOKXFeRq$v2VMQ~|)qPyC z&$F>lq6Oebza=#<;vFRQEg16esR)q3*6&jd*!+pAK$UTP*B5F@$q^PD9TwSH#bkEH9Co{IsMj{db00000000000000000000000000000000000 z0001+toi0)73lruYG|V&+zej(`1X7iE26b zl?)g3k4Lj6yCgm0+_ z=s1>pc}O>IiR&2bqli{vKj zfP?Kk4O(w+FTbAN`>tNylnv+4zz9sxurR5T=7I?n$ZY(kmd7#NbO2MpqJlQaEntV+SCrI#0j2Z}D6G*+&)Tzw(Zp(2(#o z`8C_|Th+{kx1ghe4E6Q81dNFTJJl|_r9<-}bS@DgL$WJ7mWYFw3x(>;@}Vuqg+0S+ z#1<5m>>#tQ*n1QCoRvJ1dP#NL~T5Md)cCwgH`_7Qw@B0E)iG zHo~kdaGBAE72G1T&1wk1W03BN>CaCi$fgJJYF_Y9ZnNAS)|Ew}Fi>PFWQH1)?O(qw zA-pz-dV{h-%$qD~+Ix)fykj7t)b;c2n;k4~9}Q45Ol}^GXR2BhvC~Dv$2MxO2NZOv zW1Z4pWtu<#5 z`+iP+iC1l=p3R$=mxz_t8pl-e zAb)O^8*Zq_FYyRSU+!VT9e47U)uiS+iDay`W6`3JPqlt{F>1v3?JsX%#9vHw6S_Hsfi?K+BUwY9^v z0W=Z%azi?do>PUo&jp9rbWKxtFGdDTgu0OQMUumH`_C1~SyvxfrZxMLGvXtnis^m7 zKQ+IIEvnCcrpzo1+zd4Ce;vWi=z(f?1|cXa%pYQ#x1^HZg+nM{{?i*juqx{E6a_1ah_@6b*|8Rn2@SAo7EaUerp5;x(@d`G zBYL_C`wKAo!g4rI*cvWs3HzAIpZC!d9yDC|$L?=Om7&%lA^)5a{j39_KhEs0w!tOe zdjj)J;^ZbKyLf}*0HUmdWdr2qWHt)SOB|PQMUJpPX>h7@BIye+O zLij>OV{kk)gxXbckJgkl``NuJ6iL_i*fHM|+vrikX%SA)bbQ6%e^Jgkh$yaHQ;P!S zZfzI_+e*{C$tk0#lE0}^&N;1rdwYXIiOYDXsr5MP!D|0DePh8o=o2%{8RQ%$9a6ZK zMvF+zaKevj1_cS4^lXH?F&F8MQRIyYrHVN)UcXLJmZY7Zo@1-1SksSLH~U{Ncs8cL zJ7z5ZYyE`iGFWKZa+V^D?gh*1mnAd^H4w}FSaae#FZ9OS{6Y)!^W)gP{OcXYZMlM4%o2H1@Sed zlW?xf`Dxp#e)}^h4@ikhiL_LeSfOd`Um4SFkcpKI+vQyWwNunqB~cad9SaNNZ9}O$vJPb9H>3O4LCXobEfW6ucAOrJ64{t%hq$H4@(NA=bKFsy#~eHud6& zZ;8iB0PeG_=sq4INnWGsr$Wov&@b%Rx(;=Z5N=Mhk2>~DfU+*IzEBS|mWjw7{Vk=k zL~9%{A9E(`S)Xm)`V#^Db+Z%l;MYC$bo8Yv{hRwk_fb5GVQ8e;aKP}-CAB|dzzDN|JSNV zayp*xqt#6Wbso+fYQS#1)Y8Fs9kOz>H@g&WOwge|^|1gm`BlvAL*Z$&PCO-jnw67q2$@l;O literal 0 HcmV?d00001 diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 58bcff9559..6e857cfd3c 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -204,6 +204,7 @@ pub mod tests { use pasta_curves::vesta::Affine; use rand::{rngs::OsRng, RngCore}; use std::{convert::TryInto, iter}; + use crate::utilities::test_circuit::{Proof, read_test_case, test_proof_size, write_test_case}; const MERKLE_DEPTH: usize = 32; @@ -421,7 +422,42 @@ pub mod tests { } // Test that the proof size is as expected. - crate::utilities::lookup_range_check::tests::test_proof_size(k, circuit, params, vk) + test_proof_size(k, circuit, params, vk) + } + + #[test] + fn serialized_proof_test_case() { + use std::fs; + + let circuit = generate_circuit(); + // Setup phase: generate parameters, vk for the circuit. + let params:Params = Params::new(11); + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + + if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { + let create_proof = || -> std::io::Result<()> { + let proof = Proof::create( + &vk, + ¶ms, + circuit, + ).unwrap(); + assert!(proof.verify(&vk, ¶ms).is_ok()); + + + let file = std::fs::File::create("src/sinsemilla/circuit_proof_test_case_merkle.bin")?; + write_test_case(file, &proof) + }; + create_proof().expect("should be able to write new proof"); + } + + // Parse the hardcoded proof test case. + let proof= { + let test_case_bytes = fs::read("src/sinsemilla/circuit_proof_test_case_merkle.bin").unwrap(); + read_test_case(&test_case_bytes[..]).expect("proof must be valid") + }; + + assert_eq!(proof.as_ref().len(), 4160); + assert!(proof.verify(&vk, ¶ms).is_ok()); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/utilities.rs b/halo2_gadgets/src/utilities.rs index 739f4411de..515b02caaa 100644 --- a/halo2_gadgets/src/utilities.rs +++ b/halo2_gadgets/src/utilities.rs @@ -12,6 +12,7 @@ use std::ops::Range; pub mod cond_swap; pub mod decompose_running_sum; pub mod lookup_range_check; +pub mod test_circuit; /// A type that has a value at either keygen or proving time. pub trait FieldValue { diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 370e3cadf7..b2e1b956c5 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -454,41 +454,14 @@ pub(crate) mod tests { plonk, plonk::{Circuit, ConstraintSystem, Error}, }; - use pasta_curves::{pallas, vesta}; + use pasta_curves::{pallas}; - use halo2_proofs::plonk::{SingleVerifier, VerifyingKey}; use halo2_proofs::poly::commitment::Params; - use halo2_proofs::transcript::{Blake2bRead, Blake2bWrite, Challenge255}; use pasta_curves::vesta::Affine; - use rand::rngs::OsRng; - use std::{convert::TryInto, marker::PhantomData}; - - pub(crate) fn test_proof_size( - k: u32, - circuit: C, - params: Params, - vk: VerifyingKey, - ) where - C: Circuit, - { - // Test that the proof size is as expected. - let circuit_cost = - halo2_proofs::dev::CircuitCost::::measure(k, &circuit); - let expected_proof_size = usize::from(circuit_cost.proof_size(1)); - - let pk = plonk::keygen_pk(¶ms, vk.clone(), &circuit).unwrap(); - let mut transcript = Blake2bWrite::<_, vesta::Affine, _>::init(vec![]); - plonk::create_proof(¶ms, &pk, &[circuit], &[&[]], OsRng, &mut transcript).unwrap(); - let proof = transcript.finalize(); - - let strategy = SingleVerifier::new(¶ms); - let mut transcript: Blake2bRead<&[u8], vesta::Affine, Challenge255> = - Blake2bRead::init(&proof[..]); - let verify = plonk::verify_proof(¶ms, &vk, strategy, &[&[]], &mut transcript); - // Round-trip assertion: check the proof is valid and matches expected values. - assert!(verify.is_ok()); - assert_eq!(proof.len(), expected_proof_size); - } + use std::{convert::TryInto, fs, marker::PhantomData}; + use crate::utilities::test_circuit::{Proof, read_test_case, test_proof_size, write_test_case}; + + #[test] fn lookup_range_check() { #[derive(Clone, Copy)] @@ -598,6 +571,33 @@ pub(crate) mod tests { ); } + // serialized_proof_test_case + { + if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { + let create_proof = || -> std::io::Result<()> { + let proof = Proof::create( + &vk, + ¶ms, + circuit, + ).unwrap(); + assert!(proof.verify(&vk, ¶ms).is_ok()); + + let file = std::fs::File::create("src/utilities/circuit_proof_test_case_lookup_range_check.bin")?; + write_test_case(file, &proof) + }; + create_proof().expect("should be able to write new proof"); + } + // Parse the hardcoded proof test case. + let proof= { + let test_case_bytes = fs::read("src/utilities/circuit_proof_test_case_lookup_range_check.bin").unwrap(); + read_test_case(&test_case_bytes[..]).expect("proof must be valid") + }; + + // todo: check size + assert_eq!(proof.as_ref().len(), 4160); + assert!(proof.verify(&vk, ¶ms).is_ok()); + } + // Test that the proof size is as expected. test_proof_size(11, circuit, params, vk) } diff --git a/halo2_gadgets/src/utilities/test_circuit.rs b/halo2_gadgets/src/utilities/test_circuit.rs new file mode 100644 index 0000000000..9e3108bb18 --- /dev/null +++ b/halo2_gadgets/src/utilities/test_circuit.rs @@ -0,0 +1,95 @@ +use std::io::{Read, Write}; +use pasta_curves::{pallas, vesta}; +use pasta_curves::vesta::Affine; +use rand::rngs::OsRng; +use halo2_proofs::plonk; +use halo2_proofs::plonk::{Circuit, SingleVerifier, VerifyingKey}; +use halo2_proofs::poly::commitment::Params; +use halo2_proofs::transcript::{Blake2bRead, Blake2bWrite}; + +/// A proof structure +#[derive(Clone, Debug)] +pub struct Proof(Vec); +impl AsRef<[u8]> for Proof { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl Proof { + /// Creates a proof for the given circuits and instances. + pub fn create( + vk: &VerifyingKey, + params: &Params, + circuit: C, + ) + -> Result + where + C: Circuit, + { + let pk = plonk::keygen_pk(¶ms, vk.clone(), &circuit).unwrap(); + + let mut transcript = Blake2bWrite::<_, vesta::Affine, _>::init(vec![]); + plonk::create_proof( + ¶ms, + &pk, + &[circuit], + &[&[]], + OsRng, + &mut transcript, + )?; + let proof = transcript.finalize(); + + Ok(Proof(proof)) + } + + /// Verifies this proof with the instances. + pub fn verify( + &self, + vk: &VerifyingKey, + params: &Params, + ) -> Result<(), plonk::Error> { + + let strategy = SingleVerifier::new(¶ms); + let mut transcript = Blake2bRead::init(&self.0[..]); + plonk::verify_proof(¶ms, &vk, strategy, &[&[]], &mut transcript) + } + pub fn new(bytes: Vec) -> Self { + Proof(bytes) + } +} + +pub(crate) fn test_proof_size( + k: u32, + circuit: C, + params: Params, + vk: VerifyingKey, +) where + C: Circuit, +{ + // Test that the proof size is as expected. + let circuit_cost = + halo2_proofs::dev::CircuitCost::::measure(k, &circuit); + let expected_proof_size = usize::from(circuit_cost.proof_size(1)); + + + let proof = Proof::create(&vk,¶ms,circuit).unwrap(); + + assert!(proof.verify(&vk, ¶ms).is_ok()); + assert_eq!(proof.as_ref().len(), expected_proof_size); +} +pub fn write_test_case( + mut w: W, + proof: &Proof, +) -> std::io::Result<()> { + w.write_all(proof.as_ref())?; + Ok(()) +} + +pub fn read_test_case(mut r: R) -> std::io::Result { + let mut proof_bytes = vec![]; + r.read_to_end(&mut proof_bytes)?; + let proof = Proof::new(proof_bytes); + + Ok(proof) +} From a25a6adc27014e49831fe28f10022a296d66f5fb Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 6 May 2024 13:52:22 +0200 Subject: [PATCH 30/99] update --- halo2_gadgets/src/ecc.rs | 13 ++--- halo2_gadgets/src/sinsemilla.rs | 12 ++--- halo2_gadgets/src/sinsemilla/merkle.rs | 19 +++----- ...uit_proof_test_case_lookup_range_check.bin | Bin 0 -> 1888 bytes .../src/utilities/lookup_range_check.rs | 24 +++++---- halo2_gadgets/src/utilities/test_circuit.rs | 46 ++++++++---------- 6 files changed, 47 insertions(+), 67 deletions(-) create mode 100644 halo2_gadgets/src/utilities/circuit_proof_test_case_lookup_range_check.bin diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 66ec826e41..4325cc3e39 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -599,7 +599,7 @@ pub(crate) mod tests { FixedPoints, }; use crate::utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}; - use crate::utilities::test_circuit::{Proof, read_test_case, test_proof_size, write_test_case}; + use crate::utilities::test_circuit::{read_test_case, test_proof_size, write_test_case, Proof}; #[derive(Debug, Eq, PartialEq, Clone)] pub(crate) struct TestFixedBases; @@ -938,16 +938,12 @@ pub(crate) mod tests { let circuit = MyCircuit { test_errors: false }; // Setup phase: generate parameters, vk for the circuit. - let params:Params = Params::new(11); + let params: Params = Params::new(11); let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { let create_proof = || -> std::io::Result<()> { - let proof = Proof::create( - &vk, - ¶ms, - circuit, - ).unwrap(); + let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); assert!(proof.verify(&vk, ¶ms).is_ok()); let file = std::fs::File::create("src/circuit_proof_test_case_ecc.bin")?; @@ -957,12 +953,11 @@ pub(crate) mod tests { } // Parse the hardcoded proof test case. - let proof= { + let proof = { let test_case_bytes = fs::read("src/circuit_proof_test_case_ecc.bin").unwrap(); read_test_case(&test_case_bytes[..]).expect("proof must be valid") }; - // todo: check size assert_eq!(proof.as_ref().len(), 3872); assert!(proof.verify(&vk, ¶ms).is_ok()); } diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index ace786e1fd..0d585e42c2 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -489,10 +489,10 @@ pub(crate) mod tests { use lazy_static::lazy_static; use pasta_curves::pallas; + use crate::utilities::test_circuit::{read_test_case, test_proof_size, write_test_case, Proof}; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; use std::convert::TryInto; - use crate::utilities::test_circuit::{Proof, read_test_case, test_proof_size, write_test_case}; pub(crate) const PERSONALIZATION: &str = "MerkleCRH"; @@ -792,16 +792,12 @@ pub(crate) mod tests { let circuit = MyCircuit {}; // Setup phase: generate parameters, vk for the circuit. - let params:Params = Params::new(11); + let params: Params = Params::new(11); let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { let create_proof = || -> std::io::Result<()> { - let proof = Proof::create( - &vk, - ¶ms, - circuit, - ).unwrap(); + let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); assert!(proof.verify(&vk, ¶ms).is_ok()); let file = std::fs::File::create("src/circuit_proof_test_case_sinsemilla.bin")?; @@ -811,7 +807,7 @@ pub(crate) mod tests { } // Parse the hardcoded proof test case. - let proof= { + let proof = { let test_case_bytes = fs::read("src/circuit_proof_test_case_sinsemilla.bin").unwrap(); read_test_case(&test_case_bytes[..]).expect("proof must be valid") }; diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 6e857cfd3c..4d6a0f2517 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -200,11 +200,11 @@ pub mod tests { plonk::{Circuit, ConstraintSystem, Error}, }; + use crate::utilities::test_circuit::{read_test_case, test_proof_size, write_test_case, Proof}; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; use rand::{rngs::OsRng, RngCore}; use std::{convert::TryInto, iter}; - use crate::utilities::test_circuit::{Proof, read_test_case, test_proof_size, write_test_case}; const MERKLE_DEPTH: usize = 32; @@ -431,28 +431,25 @@ pub mod tests { let circuit = generate_circuit(); // Setup phase: generate parameters, vk for the circuit. - let params:Params = Params::new(11); + let params: Params = Params::new(11); let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { let create_proof = || -> std::io::Result<()> { - let proof = Proof::create( - &vk, - ¶ms, - circuit, - ).unwrap(); + let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); assert!(proof.verify(&vk, ¶ms).is_ok()); - - let file = std::fs::File::create("src/sinsemilla/circuit_proof_test_case_merkle.bin")?; + let file = + std::fs::File::create("src/sinsemilla/circuit_proof_test_case_merkle.bin")?; write_test_case(file, &proof) }; create_proof().expect("should be able to write new proof"); } // Parse the hardcoded proof test case. - let proof= { - let test_case_bytes = fs::read("src/sinsemilla/circuit_proof_test_case_merkle.bin").unwrap(); + let proof = { + let test_case_bytes = + fs::read("src/sinsemilla/circuit_proof_test_case_merkle.bin").unwrap(); read_test_case(&test_case_bytes[..]).expect("proof must be valid") }; diff --git a/halo2_gadgets/src/utilities/circuit_proof_test_case_lookup_range_check.bin b/halo2_gadgets/src/utilities/circuit_proof_test_case_lookup_range_check.bin new file mode 100644 index 0000000000000000000000000000000000000000..f3e6a81189e600346b32d64655193c7a8b72c077 GIT binary patch literal 1888 zcmajY=OY^k1AuX}u?aOATPRvY%$&3(sBtA%HEOgqYuBi8A!0PI*u=Qjp0PrtO6}-t z#-?aFwbDlI+M_7g&@L7M7>MSJkbu4MX;N0(G z4C*WJ_V!)`W-6{HY5m5QZ%6$XHSAdFD%g{EKXjiZzk=j$^Htr0Okbm1z~jHMEs?O; z3uXdizV)Fgef3SDoLqh)ny%}{goA2*p!GqcJjbtX$LnxdB=>9GFP(aG>2^uYj!P4W z&eOSl)dBCQDB6Obpk!Ae4mjhx-OR}DMIIS+NW8hz_9RGs!b4%%*?^VY_;axHrP=jX zORsaZ+S!>rAEQs32<$nH4gI3$Etp+(=jQTgnC(eAmEWyk3SInT#_KTr-(imMS>dre z-_9V+oQ}cpo@rTbEV+vm2KX5k^@&x`-cQ;y@@1<0hQHR*6Fi`_;UCo(5u#?iATdg< zjB3QLnJANo;8$bDEPp|L4RWdEM-}RBTry28aA;T6E3j6o7uS~V3v}h^uT)|9O*Y4w zh#xd=hvr;+A0>eu?nu3^=i9SWu11H_*eR?lkF4*{FvHgYQx z_YQzHsJjA$R>d?B%TZAYF|Z_ zrbEp|=H1}MN>r!ZG@c+u@V?|lU*FmJrJYE>5r>uf+&+OrMiBugq&Wemrl{^;`+K}! z=k^BDy^{+o8_~++@0k!8s<3oh!Vf#ALK|Mptw{t_OK?4_OPYvmg(z#z zb{+p{rcG>GOhB5%!vytO){?nE?NGgbSI+f!fyx-{EN3FYxZi0=E;{lY5JN5d>le`_ zFRe(Il^4}$qY`8me(6a4l}hbBWd<5xl?Zhd$S~SRhF_5f)9appyvAQ5zG|_4Ayg=f z2Lr8FuKr3(hZG?hZT(YVc8gy;+7)WmL`#_Z8gxA1vZ1uSCewJo#Yq})y~RC)G?{yH zWt`o*MCgConHp4%nI?=4wc&0{k}TB#5d8(GIP(J%*Ju#0^}G2L%e%&N%BwkvhRx)V zM0D=H+L8`pVSz!sG=%23*2Zj3J0SNz%XZ)vR zuIELg0bCCzof341(+Y*za>}|@_{HVx(mwg2V&#h^btFeH;ogr+2)eY-Li7IRRh$O zy!RKQMVcraHr84jz&B_LQwGILX^d6RT*V|p+!>r5Nrhs9cphpS< z`lGi@bhjDEO}Fp|%QHO@shln6ff{c)vp3mLks?;f@+t~?lT{w%Kw6MQ=?^=ZJkPrO zV;;4wb_M#52i-ux%7Gg{i zn4Y~+J;WNa&1f|nBf*w&S=03;1ouZEcyxE5FZt6}|3DNx7=H)n-q8r!si#sHntf7{ zAypWd5mcY8?cIX#w&5!sBcD`r)|Q((`j1#Pn1XYQ$h-6j)#BpnkcX@voX`2kTW!kt zay88}`673{r5Yn9+Aw0LRR^VE8dI|wjNbY~Gu|Uo1);(M2cYc%e?2$Cv`Lyl)7ho| z37=f0wAvtzN+RME7c2D&c~zr_p*_dF(gsmaYck+s8Z7h1->Ab$vwS@GYWRGXL{jX( zd1BDbks}QqCG9WW3sTBkiH#IvCHj+A^{sT~ox+*=YHn8(ie7Y|?HI$ZqKV)Jc(|j` oQy2?#m@J6xLrjmKUTR(WX%ECLzZp+Qm324~kUyg~@qcjs2ZeNn=l}o! literal 0 HcmV?d00001 diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index b2e1b956c5..782a7d234b 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -454,13 +454,12 @@ pub(crate) mod tests { plonk, plonk::{Circuit, ConstraintSystem, Error}, }; - use pasta_curves::{pallas}; + use pasta_curves::pallas; + use crate::utilities::test_circuit::{read_test_case, test_proof_size, write_test_case, Proof}; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; use std::{convert::TryInto, fs, marker::PhantomData}; - use crate::utilities::test_circuit::{Proof, read_test_case, test_proof_size, write_test_case}; - #[test] fn lookup_range_check() { @@ -575,26 +574,25 @@ pub(crate) mod tests { { if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { let create_proof = || -> std::io::Result<()> { - let proof = Proof::create( - &vk, - ¶ms, - circuit, - ).unwrap(); + let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); assert!(proof.verify(&vk, ¶ms).is_ok()); - let file = std::fs::File::create("src/utilities/circuit_proof_test_case_lookup_range_check.bin")?; + let file = std::fs::File::create( + "src/utilities/circuit_proof_test_case_lookup_range_check.bin", + )?; write_test_case(file, &proof) }; create_proof().expect("should be able to write new proof"); } // Parse the hardcoded proof test case. - let proof= { - let test_case_bytes = fs::read("src/utilities/circuit_proof_test_case_lookup_range_check.bin").unwrap(); + let proof = { + let test_case_bytes = + fs::read("src/utilities/circuit_proof_test_case_lookup_range_check.bin") + .unwrap(); read_test_case(&test_case_bytes[..]).expect("proof must be valid") }; - // todo: check size - assert_eq!(proof.as_ref().len(), 4160); + assert_eq!(proof.as_ref().len(), 1888); assert!(proof.verify(&vk, ¶ms).is_ok()); } diff --git a/halo2_gadgets/src/utilities/test_circuit.rs b/halo2_gadgets/src/utilities/test_circuit.rs index 9e3108bb18..5066e3f1f5 100644 --- a/halo2_gadgets/src/utilities/test_circuit.rs +++ b/halo2_gadgets/src/utilities/test_circuit.rs @@ -1,11 +1,13 @@ -use std::io::{Read, Write}; -use pasta_curves::{pallas, vesta}; -use pasta_curves::vesta::Affine; -use rand::rngs::OsRng; +//! functions used for circuit test + use halo2_proofs::plonk; use halo2_proofs::plonk::{Circuit, SingleVerifier, VerifyingKey}; use halo2_proofs::poly::commitment::Params; use halo2_proofs::transcript::{Blake2bRead, Blake2bWrite}; +use pasta_curves::vesta::Affine; +use pasta_curves::{pallas, vesta}; +use rand::rngs::OsRng; +use std::io::{Read, Write}; /// A proof structure #[derive(Clone, Debug)] @@ -22,22 +24,14 @@ impl Proof { vk: &VerifyingKey, params: &Params, circuit: C, - ) - -> Result - where - C: Circuit, + ) -> Result + where + C: Circuit, { - let pk = plonk::keygen_pk(¶ms, vk.clone(), &circuit).unwrap(); + let pk = plonk::keygen_pk(params, vk.clone(), &circuit).unwrap(); let mut transcript = Blake2bWrite::<_, vesta::Affine, _>::init(vec![]); - plonk::create_proof( - ¶ms, - &pk, - &[circuit], - &[&[]], - OsRng, - &mut transcript, - )?; + plonk::create_proof(params, &pk, &[circuit], &[&[]], OsRng, &mut transcript)?; let proof = transcript.finalize(); Ok(Proof(proof)) @@ -49,16 +43,17 @@ impl Proof { vk: &VerifyingKey, params: &Params, ) -> Result<(), plonk::Error> { - - let strategy = SingleVerifier::new(¶ms); + let strategy = SingleVerifier::new(params); let mut transcript = Blake2bRead::init(&self.0[..]); - plonk::verify_proof(¶ms, &vk, strategy, &[&[]], &mut transcript) + plonk::verify_proof(params, vk, strategy, &[&[]], &mut transcript) } + /// Constructs a new Proof value. pub fn new(bytes: Vec) -> Self { Proof(bytes) } } +#[allow(dead_code)] pub(crate) fn test_proof_size( k: u32, circuit: C, @@ -72,20 +67,19 @@ pub(crate) fn test_proof_size( halo2_proofs::dev::CircuitCost::::measure(k, &circuit); let expected_proof_size = usize::from(circuit_cost.proof_size(1)); - - let proof = Proof::create(&vk,¶ms,circuit).unwrap(); + let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); assert!(proof.verify(&vk, ¶ms).is_ok()); assert_eq!(proof.as_ref().len(), expected_proof_size); } -pub fn write_test_case( - mut w: W, - proof: &Proof, -) -> std::io::Result<()> { + +/// write proof to a file +pub fn write_test_case(mut w: W, proof: &Proof) -> std::io::Result<()> { w.write_all(proof.as_ref())?; Ok(()) } +/// read proof from a file pub fn read_test_case(mut r: R) -> std::io::Result { let mut proof_bytes = vec![]; r.read_to_end(&mut proof_bytes)?; From 42f1b0ae535137f651262e9a894803d80ac86b1f Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 6 May 2024 22:59:19 +0200 Subject: [PATCH 31/99] update short lookup test --- halo2_gadgets/src/ecc.rs | 2 +- halo2_gadgets/src/sinsemilla.rs | 2 +- halo2_gadgets/src/sinsemilla/merkle.rs | 2 +- ...cuit_proof_test_case_short_range_check.bin | Bin 0 -> 5664 bytes .../src/utilities/lookup_range_check.rs | 141 +++++++++- halo2_gadgets/src/utilities/test_circuit.rs | 33 ++- ...ort_range_check => vk_short_range_check_0} | 0 .../src/utilities/vk_short_range_check_1 | 244 ++++++++++++++++++ .../src/utilities/vk_short_range_check_2 | 244 ++++++++++++++++++ 9 files changed, 653 insertions(+), 15 deletions(-) create mode 100644 halo2_gadgets/src/utilities/circuit_proof_test_case_short_range_check.bin rename halo2_gadgets/src/utilities/{vk_short_range_check => vk_short_range_check_0} (100%) create mode 100644 halo2_gadgets/src/utilities/vk_short_range_check_1 create mode 100644 halo2_gadgets/src/utilities/vk_short_range_check_2 diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 4325cc3e39..8cb9ce4d57 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -929,7 +929,7 @@ pub(crate) mod tests { include_str!("vk_ecc_chip").replace("\r\n", "\n") ); } - test_proof_size(k, circuit, params, vk) + test_proof_size(k, circuit, ¶ms, &vk) } #[test] diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 0d585e42c2..b9e2b6418e 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -783,7 +783,7 @@ pub(crate) mod tests { include_str!("vk_sinsemilla_chip").replace("\r\n", "\n") ); } - test_proof_size(11, circuit, params, vk) + test_proof_size(11, circuit, ¶ms, &vk) } #[test] diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 4d6a0f2517..345877ec24 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -422,7 +422,7 @@ pub mod tests { } // Test that the proof size is as expected. - test_proof_size(k, circuit, params, vk) + test_proof_size(k, circuit, ¶ms, &vk) } #[test] diff --git a/halo2_gadgets/src/utilities/circuit_proof_test_case_short_range_check.bin b/halo2_gadgets/src/utilities/circuit_proof_test_case_short_range_check.bin new file mode 100644 index 0000000000000000000000000000000000000000..61d4e7caaba6043cb67921e1daa37134ef44273d GIT binary patch literal 5664 zcmajgg*zOM1AuWcb-FuFclVu+VcN!+9!^b7$8=419LJpQHr?IbX4-T&zu$lGegB5{ zc|LB9veqe0LWv=DPRAT0->+$X{WBIHoV^h1AV&l!e8%CRs^kr$6(oJ z{LxOjJh#fR=k>-7q*yEWBFd-6-7(fkVd4>8q=j?n0VO>$yyShJVbb`A)e^(Qr40W) zLX7vi!9h|g9>TU2RzqBszC5mk;*pl~9D<>I^y6>JZps%tzl?;gb~#Sp2no{aiF13x z`VVqIHj;ZY#y@WV=1)7{Z9SU~@EMrQ4zd_9^|k3c$s9xFwjwNxDSdq_?yXA^l4o({U?OL(`PkoSS-5W-?;f;T2L1MvSwc<}(K9K2cm|pLKK%q?T zwIUB*e~DjU91JUGTZw*3bliwEm!WhBcdmqgt)XgVgd?;qpc5ID#C+OAz0d9)+@q(4 ze3U9qx0*lOOOQ;CR1J}5k;?$#V(+oxT_qLV_Xr>Jiy$01bC=X|89e4a1~{C&*Gw3_ zZbYg^If)BDvXtS06y919Jyj5WCE&nujn9Pkd=~)w*S%a&Vo3?>ga%?B`*U+>Cr?X} z0Npa2o*fk}d<;yo^d@w!7}$SqoO7jV0qIM!1j7qsaD!@R)?N5+mk0|YITV}DXCF*n zSabG4ySTq)w7e#Zg)0;zT#dP~Iq%n9gx}G3$CyUiiTrEWG-Cl#IkB0Y5bpIv8s%6y z#Lv*FF^XJXiE9cD1+{Z)bEDbLNxW>+U?coTmUvD6cmE3SA*C$q|tx^pA?H1A22 z?`jf{gNfWp_KOUhbc>QqDOdMestPTc^aW5&*)heCCs_SIKh1Aqnu6`l3hr1wKHcCN zm~jZKg}zqTwz7urMjf?}8CnpMH&bel=KINP1jTa?21_lh37Wx}<-Dn>P-GCXQY23} zF-(dHI(1k`@1VBU^(XNJ2=dtoVG(0IQa=VbKt^&nzfJy7PTr@r|@bsT=N7KNUHe z2>)7L@8fC-Xc@`9O5UJTFB4hKJ8hp@8^%gR(uh3OEb$1bWu=*7Wf1MPj6S$zueftEFEl5Bb9AEB`qjN5HExIuxKt}fYT)pU+qp7U(c z(i!`-w|-TWxF&ewc!+lKMMkA~JbDr;{wa;6*gU4YWVT!D)M0wfHU82L2I0vp^rVOR z=#5){FWSFgDLe3xnb9*)B{5xHm~>W05TukzkcL_@4a>8g*#vMs+Pr@K`f8*tmNn4* zX=|}m)c;Kx>!bV`e#`x?Fx~hDI)$F?X$T6M2Cc zdG^1G0{k+B)~SVBEyp98kLewgSrvM7m%u5E0!+ehNlPt%#S%^L)%F;Pvyl#l^33TU z9_rXr48Eh|Wd z(88~A=eFjN#vg05K^;8e##0YN=~Rj=)+%)jAgKrr60|?=^bVx>n9VyAYJvW@qgIHX z$Gl?cQmO17=ZV2FTt2AD!L|yPS?XB##PAz6{(5#pnwnS)z;TDlgD{uO9l&8Nj@1S+gV$@B=x{Xg<5qnDoA+zv=wIQ7pL9qzG|FR~uht!V7+q4WP_I22%k+ zHn`d_-*OdJJ;g=@9WoHy<);PQbzX*RwXcH5vB;&;aaHRWaE)_WY!#t;8mT38v@ujSNjI(rx;+GlDQGO>Z`)U% zY!7pB5N{zhyVD8OCa`@F%~BN zOqY{@kLZ(b@75R8_DIxA{9VT=tocuwseEiPC_6Dpo?w?$HV#F7QlcLgM9-3X;-(N# z@3D)F`@@_uMGs?S(`vg!xHadJWEeM%EG0ShpANrIZhVzBh)bsBghLP$P9Avez{b@Fd)B2Na@ zk8})tLr++QTzB{!Tv}?{LEj25s~5>2m|A!W(PQJ#l7`%;b!J9xRqlJ%?ldC*q4K;d zgZPaP27a87ow8;-@}tUNdeAepzAV`MRBv|k$TV^BDrB=bE+A_G7hMS5*}KiM!i08@ zHFxGKs!IaXfD@1Ixn7Gzd*(O9#m(aN8c9|9M&B8T|26kl_pkk&kDG^r8gIySd>yu zi6hrzX11`b3QZBjH+*C|djrA_6!sEt5nu8KRv6KKxACJTqIZf6HdHjC!s(Q{TI&rU zsy7tQy=)@D;Xdl@>Bw(Ebb5H{O1P|;`Bb$MxDw7DI%~-YiEmeo$2NRo!}>RpXt$q8 zDb=5NCn+P?gfhQMU}Gx4>h~lavCRL*4*6(0R+p6bbFt>OOQEeX6&VJx)ZucKTjIWL zno^>m1#KPi4^DfA?xijx3H7dJVClo6{r3kIBnThD$H0^J+9a&x{U-#NH}5IsOpdHgD?qfIIOk{8#(Uh6ea^@MsbgAu zY=s>qU!fPD-(pp*nfQ${0&6J$EHDJ~qxP(O zmB{QfoA)XV!_+Z>L#ebFpHwORSx!I8%c_Kun$=>#I=G{qk+&v}QQ4@H*Wi4@v+xOr zq*{y_@?GzIkM#!I)w{aF=Z|;p>f=1QoxUM8o1NluffT1fEMz-I1rSWyX6---j3wHa z;yP@)rF^WhrcJ;{Zf;!2t_e@H@Fl5E9%ktHTJz~n4qFVo8U0QB$RZ)xDf*$^z#=)3 zlatLVzA_==_#_o{t)j@}4aVonF5RBWdV9U_g850v#sScJ<&v*u<7HJ&N3MaGS1?lk z1?6vOUWezNSZOU{L&p)NR1m^|E{KyKk0K{o62YbR)#1){;+VCsp7MvT8+-O_xLoqY zvyiu`d11kKo_fS7V=)FIWcMjg9=$|HupY*jI_9>Fkl;;@4)Rk%!>u zs%uV2=B>m1#tE8R739Skx7|+s0)iEU1*n%!qb^B=m$79PH%7LRMexcM2T zrV|{Rj55=Ddz8v3X5E&tMM&yN@E+?XNeW%SxIl7KKX=~qy`~+8HqtgD`S6I9?bOES zm7jG6Ody&!qJlroKT6)WA#03Yg@F+pVi~Jh13xs77FGbVP7btfHu)<%+*=nU%r|U% z$&PTrAKB1wbhxCj029?e)gk`W z^{Vi2Y-HpZ3;)C70KAY1?;!AxF|vE%Ohc?aa~kwzq-DEvIt{~@pBiZszkGn==|3vF zl0h@q6tSQIo|}bO=b)ITJ*Q&%ed9f{TB$>@`vDlRGGCUD*GlxOLdS=#^fMcHNH4Si zuM0K5@s+X!2iAA?N;JB0w-0=%RN?NKFXRqZa3I^JQ#!V57^*`R&?`u8$+Jzr7AFsr z98E{djw>E37*2!#+Q9hbSSr9=s+gxr#}T8+=u%Gak6fNC&7H#MLcu*^f@mH)eL&#U z4#w9UyvsX9GtahO4$qy$m-!cfCM_9i23&+u5xeAgnl*e^EJ=;rQD*;bklKR(`R@pd z9Y_F}oaJ#;mtyOGd}O>hGio2dGD=SZZb?ljbEgAhif*D9@z5u4cJJ;l1Cqo1w7t@P z*t1Nh-)GuqCyZh1*?1$}7J}9W{yifs<5x@IwgsE*bGO5hnalcM1QL7S$!ETAqjr zZ34klz}nICtCo=W&2imWUi)-UCI9y9jnEU4DisSWu)-->v%YL&VS(D{u!;h=PjFt1 z!mHapg+x@Y7(rXM$I;v&^Y;H2ojWNcS~RLlK1TF{+Gjm+xG(po1BwO^qF@+`pP8!5 z5i6#AiT}vgj*N`$_1*=`4co8ZF{L8R3PkU#aQ>IC zy*qS2pSftuL>-SNQ%z|)x>;)TXL&4A^=P(svTDm&-LZOe==5pLQtC8rWnVM;6iL@5 zw&qtSyosq1f#^V@!!2s-#A!F-k*)bf=e#p+HmbWlem}8c69wkZMdcwnK1u=XdL{Zq zO?|ur!OqE2jlyRPZNmyU7>uB6=f=|$lnG1`^*#w$VeILNh8`Tv-%I-XM6mx?6HE`WLxT0@$g%-irPyaeT0VxR)XGdgDxPPcNb4znF43mM zEa?Bbl8c?Q;ZxXMMW&<2Wrstqf(8-CW(mv6`f|{@j`yVPFb0;1lva0a>(?%BNc*Gr;I;O|Cokdq$y)!|)<+p&=A*J;1IAneaWnWg~ar= zh5P7|z)?BeM5BwBkVcv`muYT}`KQ^LF;kJy=)j@^PupI2;tv&UI;I_ppQlBq6{}^q z%W=TPM5YhIeVg$VQSVdG-v!LHx^w(04@A0mh4xS4BD#G9FH8w-q2Rlk4S&mPq<7K* z*Hp=8)^zrgpI(A={MpSYkk~j^pI}7i#*Y1w= z?n@#uvI)vM0{W6WrjL@D-zY)GH%KqqXLh~y4^_N|b=mrHlfLuvj${drZ8~Yxh&*Tl z?DG1LG0)Q6xLCl@^+w5K+pGl4n9TrNmV&gv-2*(hz_VI$57EtWS<2Kdd-PrJZaQmj zhk*1*P(@{FXNVldGM{nhocSGm4{tML@chwi$l$!~l(&#;R52W%4@oO|BlY z=4(e(vopsjkAOK2=d8VoV;gn$@;(;7aAUq|LWoIyTFh+8ZQOBj}h=_mRnC)Ap zIV=If=R)_K6cS!hkIfR%jvdXU@IWy{_A&~@g>&3re(aCYqYEqRqfR^NZx7dRSfa|B zi-N0>cP?(Lm^qWpNM7Q+{NBq9`KvGpD9ALQcikGuw-CG;|0e7atFR*+>eNi-UX}F- zI`|~_yv`|++_Nb~g8M2-ppaxck^}(j6=T zeQT_geHGu#syZSFo|3}VI}9_QV@48EYp_n?j8ZO(hju~JFVnE)S3U`hq8_$)@uye_)ANRuV@FmJxf<7p#RK|aK&>G$69lWU5m { element: Value, num_bits: usize, @@ -647,7 +648,23 @@ pub(crate) mod tests { } } + + if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { + } + else { + // Parse the hardcoded proof test case. + let proofs= { + let test_case_bytes = fs::read("src/utilities/circuit_proof_test_case_short_range_check.bin").unwrap(); + read_all_proofs(&test_case_bytes[..]).expect("proof must be valid") + }; + } + + // Setup phase: generate parameters + let params: Params = Params::new(11); + let mut proofs = Vec::new(); + // Edge case: zero bits + // case 0 { let circuit: MyCircuit = MyCircuit { element: Value::known(pallas::Base::ZERO), @@ -656,8 +673,7 @@ pub(crate) mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - // Setup phase: generate parameters, vk for the circuit. - let params: Params = Params::new(11); + // generate vk let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); // Test that the pinned verification key (representing the circuit) @@ -666,15 +682,37 @@ pub(crate) mod tests { //panic!("{:#?}", vk.pinned()); assert_eq!( format!("{:#?}\n", vk.pinned()), - include_str!("vk_short_range_check").replace("\r\n", "\n") + include_str!("vk_short_range_check_0").replace("\r\n", "\n") ); } - // Test that the proof size is as expected. - test_proof_size(11, circuit, params, vk) + test_proof_size(11, circuit.clone(), ¶ms, &vk); + + // serialized_proof_test_case + { + if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { + let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); + assert!(proof.verify(&vk, ¶ms).is_ok()); + proofs.push(proof.clone()); + } + else { + match proofs.get(0) { + Some(proof) => { + println!("proof={:?}", proof); + + assert_eq!(proof.as_ref().len(), 1888); + assert!(proof.verify(&vk, ¶ms).is_ok()); + } + None => println!("Index out of bounds"), + } + } + } + + } // Edge case: K bits + // case 1 { let circuit: MyCircuit = MyCircuit { element: Value::known(pallas::Base::from((1 << K) - 1)), @@ -682,9 +720,46 @@ pub(crate) mod tests { }; let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); + + // generate vk + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + + // Test that the pinned verification key (representing the circuit) + // is as expected. Which indicates the layouters are the same. + { + //panic!("{:#?}", vk.pinned()); + assert_eq!( + format!("{:#?}\n", vk.pinned()), + include_str!("vk_short_range_check_1").replace("\r\n", "\n") + ); + } + // Test that the proof size is as expected. + test_proof_size(11, circuit.clone(), ¶ms, &vk); + + // serialized_proof_test_case + { + if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { + let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); + assert!(proof.verify(&vk, ¶ms).is_ok()); + proofs.push(proof.clone()); + } + else { + match proofs.get(1) { + Some(proof) => { + println!("proof={:?}", proof); + + assert_eq!(proof.as_ref().len(), 1888); + assert!(proof.verify(&vk, ¶ms).is_ok()); + } + None => println!("Index out of bounds"), + } + } + } + } // Element within `num_bits` + // case 2 { let circuit: MyCircuit = MyCircuit { element: Value::known(pallas::Base::from((1 << 6) - 1)), @@ -692,6 +767,52 @@ pub(crate) mod tests { }; let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); + + // generate vk + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + + // Test that the pinned verification key (representing the circuit) + // is as expected. Which indicates the layouters are the same. + { + //panic!("{:#?}", vk.pinned()); + assert_eq!( + format!("{:#?}\n", vk.pinned()), + include_str!("vk_short_range_check_2").replace("\r\n", "\n") + ); + } + // Test that the proof size is as expected. + test_proof_size(11, circuit.clone(), ¶ms, &vk); + + // serialized_proof_test_case + { + if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { + let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); + assert!(proof.verify(&vk, ¶ms).is_ok()); + proofs.push(proof.clone()); + } + else { + match proofs.get(2) { + Some(proof) => { + println!("proof={:?}", proof); + + assert_eq!(proof.as_ref().len(), 1888); + assert!(proof.verify(&vk, ¶ms).is_ok()); + } + None => println!("Index out of bounds"), + } + } + } + } + + if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { + let create_proof = || -> std::io::Result<()> { + + let file = std::fs::File::create( + "src/utilities/circuit_proof_test_case_short_range_check.bin" + )?; + write_all_test_case(file, &proofs) + }; + create_proof().expect("should be able to write new proof"); } // Element larger than `num_bits` but within K bits @@ -711,6 +832,8 @@ pub(crate) mod tests { }, }]) ); + + } // Element larger than K bits @@ -739,6 +862,8 @@ pub(crate) mod tests { }, ]) ); + + } // Element which is not within `num_bits`, but which has a shifted value within @@ -767,6 +892,8 @@ pub(crate) mod tests { }, }]) ); + + } } } diff --git a/halo2_gadgets/src/utilities/test_circuit.rs b/halo2_gadgets/src/utilities/test_circuit.rs index 5066e3f1f5..f7618e3970 100644 --- a/halo2_gadgets/src/utilities/test_circuit.rs +++ b/halo2_gadgets/src/utilities/test_circuit.rs @@ -1,5 +1,6 @@ //! functions used for circuit test +use std::io; use halo2_proofs::plonk; use halo2_proofs::plonk::{Circuit, SingleVerifier, VerifyingKey}; use halo2_proofs::poly::commitment::Params; @@ -53,12 +54,12 @@ impl Proof { } } -#[allow(dead_code)] +/// test the proof size. pub(crate) fn test_proof_size( k: u32, circuit: C, - params: Params, - vk: VerifyingKey, + params: &Params, + vk: &VerifyingKey, ) where C: Circuit, { @@ -67,9 +68,9 @@ pub(crate) fn test_proof_size( halo2_proofs::dev::CircuitCost::::measure(k, &circuit); let expected_proof_size = usize::from(circuit_cost.proof_size(1)); - let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); + let proof = Proof::create(vk, params, circuit).unwrap(); - assert!(proof.verify(&vk, ¶ms).is_ok()); + assert!(proof.verify(vk, params).is_ok()); assert_eq!(proof.as_ref().len(), expected_proof_size); } @@ -87,3 +88,25 @@ pub fn read_test_case(mut r: R) -> std::io::Result { Ok(proof) } + +/// write multiple proofs to a file +pub(crate) fn write_all_test_case( + mut w: W, + proofs: &Vec, +) -> std::io::Result<()> { + for proof in proofs { + w.write_all(proof.as_ref())?; + } + Ok(()) +} + +/// read multiple proofs from a file +pub fn read_all_proofs(mut r: R) -> io::Result> { + let mut proofs = Vec::new(); + let mut buffer = vec![0u8; 1888]; + + while let Ok(()) = r.read_exact(&mut buffer) { + proofs.push(Proof::new(buffer.clone())); + } + Ok(proofs) +} \ No newline at end of file diff --git a/halo2_gadgets/src/utilities/vk_short_range_check b/halo2_gadgets/src/utilities/vk_short_range_check_0 similarity index 100% rename from halo2_gadgets/src/utilities/vk_short_range_check rename to halo2_gadgets/src/utilities/vk_short_range_check_0 diff --git a/halo2_gadgets/src/utilities/vk_short_range_check_1 b/halo2_gadgets/src/utilities/vk_short_range_check_1 new file mode 100644 index 0000000000..d17acb3106 --- /dev/null +++ b/halo2_gadgets/src/utilities/vk_short_range_check_1 @@ -0,0 +1,244 @@ +PinnedVerificationKey { + base_modulus: "0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001", + scalar_modulus: "0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001", + domain: PinnedEvaluationDomain { + k: 11, + extended_k: 14, + omega: 0x181b50ad5f32119e31cbd395426d600b7a9b88bcaaa1c24eef28545aada17813, + }, + cs: PinnedConstraintSystem { + num_fixed_columns: 5, + num_advice_columns: 1, + num_instance_columns: 0, + num_selectors: 3, + gates: [ + Product( + Fixed { + query_index: 4, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Scaled( + Advice { + query_index: 2, + column_index: 0, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + Advice { + query_index: 1, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ], + advice_queries: [ + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + -1, + ), + ), + ], + instance_queries: [], + fixed_queries: [ + ( + Column { + index: 1, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 0, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 2, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 3, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 4, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ], + permutation: Argument { + columns: [ + Column { + index: 1, + column_type: Fixed, + }, + Column { + index: 0, + column_type: Advice, + }, + ], + }, + lookups: [ + Argument { + input_expressions: [ + Product( + Fixed { + query_index: 2, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Fixed { + query_index: 3, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 1, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 3, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ], + table_expressions: [ + Fixed { + query_index: 1, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ], + }, + ], + constants: [ + Column { + index: 1, + column_type: Fixed, + }, + ], + minimum_degree: None, + }, + fixed_commitments: [ + (0x05f5862cad2888855bc3c1843a9eff57b11b592d9eb0e13354256661387f5231, 0x32236b14df85bf5f532a930232cb23a5c56ef7d67aaeed8bcb8fc10ea132cbd6), + (0x369f0b3422178fecf6e9a4fc7224622da26e8b5c74fb9aca5864c9f72e30bd5c, 0x2d7892875c06c460c9c9f66449103e7b6ef2871fb0a4e39b9af90e938c8e291b), + (0x0980acedb0fd2c02718002125bf80f969175d1f90d1320f9f3d5e2ac584e0212, 0x235c651fefd49e387ef9a6293a428810994974d218c4757ca3f9c0971ae25767), + (0x2bbc94ef7b22aebef24f9a4b0cc1831882548b605171366017d45c3e6fd92075, 0x082b801a6e176239943bfb759fb02138f47a5c8cc4aa7fa0af559fde4e3abd97), + (0x28d1c924953bc53f232465943d25fd085f85727ae4e2d26249207da1e59559e2, 0x184d19e00f109c4dacf8026c6e0fc4181178b32a236828047c46d9d61eab90fa), + ], + permutation: VerifyingKey { + commitments: [ + (0x3b7b93d7540327328791a14933d8f3345abd943eb35b67a8a4bd2eb72e2a707a, 0x26fff57a6fa3c01dd0d739fc56479303b4302d6baa6f1da06f4013419c40e10c), + (0x3fdf7a15a0d2378accc11f704f4ba4a487b542ace83c7f5a8551b569a3b9a380, 0x34253920878d15d6fe1b5198c31bdd670d32e81621e9fcd569d582e596ed0af5), + ], + }, +} diff --git a/halo2_gadgets/src/utilities/vk_short_range_check_2 b/halo2_gadgets/src/utilities/vk_short_range_check_2 new file mode 100644 index 0000000000..8187051b09 --- /dev/null +++ b/halo2_gadgets/src/utilities/vk_short_range_check_2 @@ -0,0 +1,244 @@ +PinnedVerificationKey { + base_modulus: "0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001", + scalar_modulus: "0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001", + domain: PinnedEvaluationDomain { + k: 11, + extended_k: 14, + omega: 0x181b50ad5f32119e31cbd395426d600b7a9b88bcaaa1c24eef28545aada17813, + }, + cs: PinnedConstraintSystem { + num_fixed_columns: 5, + num_advice_columns: 1, + num_instance_columns: 0, + num_selectors: 3, + gates: [ + Product( + Fixed { + query_index: 4, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Scaled( + Advice { + query_index: 2, + column_index: 0, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + Advice { + query_index: 1, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ], + advice_queries: [ + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + -1, + ), + ), + ], + instance_queries: [], + fixed_queries: [ + ( + Column { + index: 1, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 0, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 2, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 3, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 4, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ], + permutation: Argument { + columns: [ + Column { + index: 1, + column_type: Fixed, + }, + Column { + index: 0, + column_type: Advice, + }, + ], + }, + lookups: [ + Argument { + input_expressions: [ + Product( + Fixed { + query_index: 2, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Fixed { + query_index: 3, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 1, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 3, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ], + table_expressions: [ + Fixed { + query_index: 1, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ], + }, + ], + constants: [ + Column { + index: 1, + column_type: Fixed, + }, + ], + minimum_degree: None, + }, + fixed_commitments: [ + (0x05f5862cad2888855bc3c1843a9eff57b11b592d9eb0e13354256661387f5231, 0x32236b14df85bf5f532a930232cb23a5c56ef7d67aaeed8bcb8fc10ea132cbd6), + (0x2ca6650c6fcad471c1c9d29e9115516064a1fe096af3b13821cf1fe7fee088eb, 0x18e61f68d5978b837a3e2295fe7ae7ca672268a519394f41aabd085aadc1221d), + (0x0980acedb0fd2c02718002125bf80f969175d1f90d1320f9f3d5e2ac584e0212, 0x235c651fefd49e387ef9a6293a428810994974d218c4757ca3f9c0971ae25767), + (0x2bbc94ef7b22aebef24f9a4b0cc1831882548b605171366017d45c3e6fd92075, 0x082b801a6e176239943bfb759fb02138f47a5c8cc4aa7fa0af559fde4e3abd97), + (0x28d1c924953bc53f232465943d25fd085f85727ae4e2d26249207da1e59559e2, 0x184d19e00f109c4dacf8026c6e0fc4181178b32a236828047c46d9d61eab90fa), + ], + permutation: VerifyingKey { + commitments: [ + (0x3b7b93d7540327328791a14933d8f3345abd943eb35b67a8a4bd2eb72e2a707a, 0x26fff57a6fa3c01dd0d739fc56479303b4302d6baa6f1da06f4013419c40e10c), + (0x3fdf7a15a0d2378accc11f704f4ba4a487b542ace83c7f5a8551b569a3b9a380, 0x34253920878d15d6fe1b5198c31bdd670d32e81621e9fcd569d582e596ed0af5), + ], + }, +} From 2b89fae2e78ff1f47e4533e898fdfd903526f8e4 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 6 May 2024 23:03:39 +0200 Subject: [PATCH 32/99] cargo fmt --- .../src/utilities/lookup_range_check.rs | 36 +++++++------------ halo2_gadgets/src/utilities/test_circuit.rs | 9 ++--- 2 files changed, 16 insertions(+), 29 deletions(-) diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 29a3073d47..fb8d191389 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -456,7 +456,10 @@ pub(crate) mod tests { }; use pasta_curves::pallas; - use crate::utilities::test_circuit::{read_test_case, test_proof_size, write_test_case, Proof, read_all_proofs, write_all_test_case}; + use crate::utilities::test_circuit::{ + read_all_proofs, read_test_case, test_proof_size, write_all_test_case, write_test_case, + Proof, + }; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; use std::{convert::TryInto, fs, marker::PhantomData}; @@ -648,13 +651,13 @@ pub(crate) mod tests { } } - if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { - } - else { + } else { // Parse the hardcoded proof test case. - let proofs= { - let test_case_bytes = fs::read("src/utilities/circuit_proof_test_case_short_range_check.bin").unwrap(); + let proofs = { + let test_case_bytes = + fs::read("src/utilities/circuit_proof_test_case_short_range_check.bin") + .unwrap(); read_all_proofs(&test_case_bytes[..]).expect("proof must be valid") }; } @@ -694,8 +697,7 @@ pub(crate) mod tests { let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); assert!(proof.verify(&vk, ¶ms).is_ok()); proofs.push(proof.clone()); - } - else { + } else { match proofs.get(0) { Some(proof) => { println!("proof={:?}", proof); @@ -707,8 +709,6 @@ pub(crate) mod tests { } } } - - } // Edge case: K bits @@ -742,8 +742,7 @@ pub(crate) mod tests { let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); assert!(proof.verify(&vk, ¶ms).is_ok()); proofs.push(proof.clone()); - } - else { + } else { match proofs.get(1) { Some(proof) => { println!("proof={:?}", proof); @@ -755,7 +754,6 @@ pub(crate) mod tests { } } } - } // Element within `num_bits` @@ -789,8 +787,7 @@ pub(crate) mod tests { let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); assert!(proof.verify(&vk, ¶ms).is_ok()); proofs.push(proof.clone()); - } - else { + } else { match proofs.get(2) { Some(proof) => { println!("proof={:?}", proof); @@ -806,9 +803,8 @@ pub(crate) mod tests { if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { let create_proof = || -> std::io::Result<()> { - let file = std::fs::File::create( - "src/utilities/circuit_proof_test_case_short_range_check.bin" + "src/utilities/circuit_proof_test_case_short_range_check.bin", )?; write_all_test_case(file, &proofs) }; @@ -832,8 +828,6 @@ pub(crate) mod tests { }, }]) ); - - } // Element larger than K bits @@ -862,8 +856,6 @@ pub(crate) mod tests { }, ]) ); - - } // Element which is not within `num_bits`, but which has a shifted value within @@ -892,8 +884,6 @@ pub(crate) mod tests { }, }]) ); - - } } } diff --git a/halo2_gadgets/src/utilities/test_circuit.rs b/halo2_gadgets/src/utilities/test_circuit.rs index f7618e3970..c8c64079f9 100644 --- a/halo2_gadgets/src/utilities/test_circuit.rs +++ b/halo2_gadgets/src/utilities/test_circuit.rs @@ -1,6 +1,5 @@ //! functions used for circuit test -use std::io; use halo2_proofs::plonk; use halo2_proofs::plonk::{Circuit, SingleVerifier, VerifyingKey}; use halo2_proofs::poly::commitment::Params; @@ -8,6 +7,7 @@ use halo2_proofs::transcript::{Blake2bRead, Blake2bWrite}; use pasta_curves::vesta::Affine; use pasta_curves::{pallas, vesta}; use rand::rngs::OsRng; +use std::io; use std::io::{Read, Write}; /// A proof structure @@ -90,10 +90,7 @@ pub fn read_test_case(mut r: R) -> std::io::Result { } /// write multiple proofs to a file -pub(crate) fn write_all_test_case( - mut w: W, - proofs: &Vec, -) -> std::io::Result<()> { +pub(crate) fn write_all_test_case(mut w: W, proofs: &Vec) -> std::io::Result<()> { for proof in proofs { w.write_all(proof.as_ref())?; } @@ -109,4 +106,4 @@ pub fn read_all_proofs(mut r: R) -> io::Result> { proofs.push(Proof::new(buffer.clone())); } Ok(proofs) -} \ No newline at end of file +} From 8552c97859d1b67dac76e85b089d115e5dad2f8f Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 6 May 2024 23:22:05 +0200 Subject: [PATCH 33/99] fix Clippy error --- .../src/utilities/lookup_range_check.rs | 76 ++++++------------- halo2_gadgets/src/utilities/test_circuit.rs | 2 + 2 files changed, 25 insertions(+), 53 deletions(-) diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index fb8d191389..525d953dcd 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -651,20 +651,14 @@ pub(crate) mod tests { } } - if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { - } else { - // Parse the hardcoded proof test case. - let proofs = { - let test_case_bytes = - fs::read("src/utilities/circuit_proof_test_case_short_range_check.bin") - .unwrap(); - read_all_proofs(&test_case_bytes[..]).expect("proof must be valid") - }; - } + let proofs = { + let test_case_bytes = + fs::read("src/utilities/circuit_proof_test_case_short_range_check.bin").unwrap(); + read_all_proofs(&test_case_bytes[..]).expect("proof must be valid") + }; // Setup phase: generate parameters let params: Params = Params::new(11); - let mut proofs = Vec::new(); // Edge case: zero bits // case 0 @@ -689,24 +683,16 @@ pub(crate) mod tests { ); } // Test that the proof size is as expected. - test_proof_size(11, circuit.clone(), ¶ms, &vk); + test_proof_size(11, circuit, ¶ms, &vk); // serialized_proof_test_case { - if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { - let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); - assert!(proof.verify(&vk, ¶ms).is_ok()); - proofs.push(proof.clone()); - } else { - match proofs.get(0) { - Some(proof) => { - println!("proof={:?}", proof); - - assert_eq!(proof.as_ref().len(), 1888); - assert!(proof.verify(&vk, ¶ms).is_ok()); - } - None => println!("Index out of bounds"), + match proofs.get(0) { + Some(proof) => { + assert_eq!(proof.as_ref().len(), 1888); + assert!(proof.verify(&vk, ¶ms).is_ok()); } + None => println!("Index out of bounds"), } } } @@ -734,24 +720,16 @@ pub(crate) mod tests { ); } // Test that the proof size is as expected. - test_proof_size(11, circuit.clone(), ¶ms, &vk); + test_proof_size(11, circuit, ¶ms, &vk); // serialized_proof_test_case { - if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { - let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); - assert!(proof.verify(&vk, ¶ms).is_ok()); - proofs.push(proof.clone()); - } else { - match proofs.get(1) { - Some(proof) => { - println!("proof={:?}", proof); - - assert_eq!(proof.as_ref().len(), 1888); - assert!(proof.verify(&vk, ¶ms).is_ok()); - } - None => println!("Index out of bounds"), + match proofs.get(1) { + Some(proof) => { + assert_eq!(proof.as_ref().len(), 1888); + assert!(proof.verify(&vk, ¶ms).is_ok()); } + None => println!("Index out of bounds"), } } } @@ -779,24 +757,16 @@ pub(crate) mod tests { ); } // Test that the proof size is as expected. - test_proof_size(11, circuit.clone(), ¶ms, &vk); + test_proof_size(11, circuit, ¶ms, &vk); // serialized_proof_test_case { - if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { - let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); - assert!(proof.verify(&vk, ¶ms).is_ok()); - proofs.push(proof.clone()); - } else { - match proofs.get(2) { - Some(proof) => { - println!("proof={:?}", proof); - - assert_eq!(proof.as_ref().len(), 1888); - assert!(proof.verify(&vk, ¶ms).is_ok()); - } - None => println!("Index out of bounds"), + match proofs.get(2) { + Some(proof) => { + assert_eq!(proof.as_ref().len(), 1888); + assert!(proof.verify(&vk, ¶ms).is_ok()); } + None => println!("Index out of bounds"), } } } diff --git a/halo2_gadgets/src/utilities/test_circuit.rs b/halo2_gadgets/src/utilities/test_circuit.rs index c8c64079f9..51ea0e0a27 100644 --- a/halo2_gadgets/src/utilities/test_circuit.rs +++ b/halo2_gadgets/src/utilities/test_circuit.rs @@ -55,6 +55,7 @@ impl Proof { } /// test the proof size. +#[allow(dead_code)] pub(crate) fn test_proof_size( k: u32, circuit: C, @@ -90,6 +91,7 @@ pub fn read_test_case(mut r: R) -> std::io::Result { } /// write multiple proofs to a file +#[allow(dead_code)] pub(crate) fn write_all_test_case(mut w: W, proofs: &Vec) -> std::io::Result<()> { for proof in proofs { w.write_all(proof.as_ref())?; From f35cbe940d60466c22eff253505168c7344b6900 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Tue, 7 May 2024 15:01:20 +0200 Subject: [PATCH 34/99] clean up code --- halo2_gadgets/src/ecc_opt.rs | 123 +----------------- halo2_gadgets/src/sinsemilla.rs | 47 +++---- halo2_gadgets/src/sinsemilla_opt.rs | 16 +-- .../src/utilities/lookup_range_check.rs | 2 +- halo2_gadgets/src/utilities/test_circuit.rs | 7 +- 5 files changed, 33 insertions(+), 162 deletions(-) diff --git a/halo2_gadgets/src/ecc_opt.rs b/halo2_gadgets/src/ecc_opt.rs index b7a7dca5a4..4275d47f8a 100644 --- a/halo2_gadgets/src/ecc_opt.rs +++ b/halo2_gadgets/src/ecc_opt.rs @@ -61,7 +61,6 @@ impl + Clone + Debug + Eq> } #[cfg(test)] pub(crate) mod tests { - use ff::PrimeField; use group::{prime::PrimeCurveAffine, Curve, Group}; use halo2_proofs::{ @@ -69,132 +68,12 @@ pub(crate) mod tests { dev::MockProver, plonk::{Circuit, ConstraintSystem, Error}, }; - use lazy_static::lazy_static; use pasta_curves::pallas; - use crate::ecc::{ - chip::{ - find_zs_and_us, BaseFieldElem, EccChip, EccConfig, FixedPoint, FullScalar, ShortScalar, - H, NUM_WINDOWS, NUM_WINDOWS_SHORT, - }, - FixedPoints, - }; + use crate::ecc::chip::{EccChip, EccConfig}; use crate::utilities::lookup_range_check::LookupRangeCheck; use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; - #[derive(Debug, Eq, PartialEq, Clone)] - pub(crate) struct TestFixedBases; - #[derive(Debug, Eq, PartialEq, Clone)] - pub(crate) struct FullWidth(pallas::Affine, &'static [(u64, [pallas::Base; H])]); - #[derive(Debug, Eq, PartialEq, Clone)] - pub(crate) struct BaseField; - #[derive(Debug, Eq, PartialEq, Clone)] - pub(crate) struct Short; - - lazy_static! { - static ref BASE: pallas::Affine = pallas::Point::generator().to_affine(); - static ref ZS_AND_US: Vec<(u64, [pallas::Base; H])> = - find_zs_and_us(*BASE, NUM_WINDOWS).unwrap(); - static ref ZS_AND_US_SHORT: Vec<(u64, [pallas::Base; H])> = - find_zs_and_us(*BASE, NUM_WINDOWS_SHORT).unwrap(); - } - - impl FixedPoint for FullWidth { - type FixedScalarKind = FullScalar; - - fn generator(&self) -> pallas::Affine { - self.0 - } - - fn u(&self) -> Vec<[[u8; 32]; H]> { - self.1 - .iter() - .map(|(_, us)| { - [ - us[0].to_repr(), - us[1].to_repr(), - us[2].to_repr(), - us[3].to_repr(), - us[4].to_repr(), - us[5].to_repr(), - us[6].to_repr(), - us[7].to_repr(), - ] - }) - .collect() - } - - fn z(&self) -> Vec { - self.1.iter().map(|(z, _)| *z).collect() - } - } - - impl FixedPoint for BaseField { - type FixedScalarKind = BaseFieldElem; - - fn generator(&self) -> pallas::Affine { - *BASE - } - - fn u(&self) -> Vec<[[u8; 32]; H]> { - ZS_AND_US - .iter() - .map(|(_, us)| { - [ - us[0].to_repr(), - us[1].to_repr(), - us[2].to_repr(), - us[3].to_repr(), - us[4].to_repr(), - us[5].to_repr(), - us[6].to_repr(), - us[7].to_repr(), - ] - }) - .collect() - } - - fn z(&self) -> Vec { - ZS_AND_US.iter().map(|(z, _)| *z).collect() - } - } - - impl FixedPoint for Short { - type FixedScalarKind = ShortScalar; - - fn generator(&self) -> pallas::Affine { - *BASE - } - - fn u(&self) -> Vec<[[u8; 32]; H]> { - ZS_AND_US_SHORT - .iter() - .map(|(_, us)| { - [ - us[0].to_repr(), - us[1].to_repr(), - us[2].to_repr(), - us[3].to_repr(), - us[4].to_repr(), - us[5].to_repr(), - us[6].to_repr(), - us[7].to_repr(), - ] - }) - .collect() - } - - fn z(&self) -> Vec { - ZS_AND_US_SHORT.iter().map(|(z, _)| *z).collect() - } - } - - impl FixedPoints for TestFixedBases { - type FullScalar = FullWidth; - type ShortScalar = Short; - type Base = BaseField; - } - struct MyCircuit { test_errors: bool, } diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index b9e2b6418e..d5b0dab5e2 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -276,12 +276,12 @@ pub struct HashDomain< > where SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, EccChip: EccInstructions< - C, - NonIdentityPoint = >::NonIdentityPoint, - FixedPoints = >::FixedPoints, - > + Clone - + Debug - + Eq, + C, + NonIdentityPoint = >::NonIdentityPoint, + FixedPoints = >::FixedPoints, + > + Clone + + Debug + + Eq, { pub(crate) sinsemilla_chip: SinsemillaChip, pub(crate) ecc_chip: EccChip, @@ -289,10 +289,10 @@ pub struct HashDomain< } impl - HashDomain -where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, - EccChip: EccInstructions< +HashDomain + where + SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, + EccChip: EccInstructions< C, NonIdentityPoint = >::NonIdentityPoint, FixedPoints = >::FixedPoints, @@ -376,22 +376,22 @@ pub struct CommitDomain< > where SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, EccChip: EccInstructions< - C, - NonIdentityPoint = >::NonIdentityPoint, - FixedPoints = >::FixedPoints, - > + Clone - + Debug - + Eq, + C, + NonIdentityPoint = >::NonIdentityPoint, + FixedPoints = >::FixedPoints, + > + Clone + + Debug + + Eq, { pub(crate) M: HashDomain, pub(crate) R: ecc::FixedPoint, } impl - CommitDomain -where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, - EccChip: EccInstructions< +CommitDomain + where + SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, + EccChip: EccInstructions< C, NonIdentityPoint = >::NonIdentityPoint, FixedPoints = >::FixedPoints, @@ -403,7 +403,6 @@ where pub fn new( sinsemilla_chip: SinsemillaChip, ecc_chip: EccChip, - // TODO: Instead of using SinsemilllaChip::CommitDomains, just use something that implements a CommitDomains trait domain: &SinsemillaChip::CommitDomains, ) -> Self { CommitDomain { @@ -429,12 +428,6 @@ where Error, > { assert_eq!(self.M.sinsemilla_chip, message.chip); - - // FIXME: consider returning ZSA version of the following lines. - // It's not a breaking change because `blinding_factor` simply wraps `R.mul` - // and `hash` simply wraps `M.hash_to_point` - are those wrapper really needed? - //let blind = self.blinding_factor(layouter.namespace(|| "[r] R"), r)?; - //let (p, zs) = self.hash(layouter.namespace(|| "M"), message)?; let (blind, _) = self.R.mul(layouter.namespace(|| "[r] R"), r)?; let (p, zs) = self.M.hash_to_point(layouter.namespace(|| "M"), message)?; let commitment = p.add(layouter.namespace(|| "M + [r] R"), &blind)?; diff --git a/halo2_gadgets/src/sinsemilla_opt.rs b/halo2_gadgets/src/sinsemilla_opt.rs index 79e788be06..30d1d2c83c 100644 --- a/halo2_gadgets/src/sinsemilla_opt.rs +++ b/halo2_gadgets/src/sinsemilla_opt.rs @@ -41,10 +41,10 @@ pub trait SinsemillaInstructionsOptimized - HashDomain -where - SinsemillaChip: SinsemillaInstructionsOptimized + Clone + Debug + Eq, - EccChip: EccInstructions< +HashDomain + where + SinsemillaChip: SinsemillaInstructionsOptimized + Clone + Debug + Eq, + EccChip: EccInstructions< C, NonIdentityPoint = >::NonIdentityPoint, FixedPoints = >::FixedPoints, @@ -70,10 +70,10 @@ where } impl - CommitDomain -where - SinsemillaChip: SinsemillaInstructionsOptimized + Clone + Debug + Eq, - EccChip: EccInstructions< +CommitDomain + where + SinsemillaChip: SinsemillaInstructionsOptimized + Clone + Debug + Eq, + EccChip: EccInstructions< C, NonIdentityPoint = >::NonIdentityPoint, FixedPoints = >::FixedPoints, diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 525d953dcd..73e14bec06 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -654,7 +654,7 @@ pub(crate) mod tests { let proofs = { let test_case_bytes = fs::read("src/utilities/circuit_proof_test_case_short_range_check.bin").unwrap(); - read_all_proofs(&test_case_bytes[..]).expect("proof must be valid") + read_all_proofs(&test_case_bytes[..], 1888).expect("proof must be valid") }; // Setup phase: generate parameters diff --git a/halo2_gadgets/src/utilities/test_circuit.rs b/halo2_gadgets/src/utilities/test_circuit.rs index 51ea0e0a27..c42bcf0c63 100644 --- a/halo2_gadgets/src/utilities/test_circuit.rs +++ b/halo2_gadgets/src/utilities/test_circuit.rs @@ -54,7 +54,7 @@ impl Proof { } } -/// test the proof size. +/// Test that the proof size is as expected. #[allow(dead_code)] pub(crate) fn test_proof_size( k: u32, @@ -64,7 +64,6 @@ pub(crate) fn test_proof_size( ) where C: Circuit, { - // Test that the proof size is as expected. let circuit_cost = halo2_proofs::dev::CircuitCost::::measure(k, &circuit); let expected_proof_size = usize::from(circuit_cost.proof_size(1)); @@ -100,9 +99,9 @@ pub(crate) fn write_all_test_case(mut w: W, proofs: &Vec) -> st } /// read multiple proofs from a file -pub fn read_all_proofs(mut r: R) -> io::Result> { +pub fn read_all_proofs(mut r: R, proof_size: usize) -> io::Result> { let mut proofs = Vec::new(); - let mut buffer = vec![0u8; 1888]; + let mut buffer = vec![0u8; proof_size]; while let Ok(()) = r.read_exact(&mut buffer) { proofs.push(Proof::new(buffer.clone())); From f65d5a330bac57efb47cafec4bfb1a4392edf463 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Fri, 10 May 2024 14:56:33 +0200 Subject: [PATCH 35/99] add initial files --- halo2_gadgets/src/ecc_opt.rs | 289 --------- halo2_gadgets/src/ecc_opt/chip.rs | 61 -- halo2_gadgets/src/ecc_opt/chip/mul_fixed.rs | 1 - .../src/ecc_opt/chip/mul_fixed/short.rs | 597 ------------------ .../src/ecc_opt/chip/witness_point.rs | 50 -- halo2_gadgets/src/lib.rs | 3 - halo2_gadgets/src/sinsemilla.rs | 1 + halo2_gadgets/src/sinsemilla/merkle/chip.rs | 2 + halo2_gadgets/src/sinsemilla/primitives.rs | 2 - halo2_gadgets/src/sinsemilla_opt.rs | 464 -------------- halo2_gadgets/src/sinsemilla_opt/chip.rs | 219 ------- .../sinsemilla_opt/chip/generator_table.rs | 111 ---- .../src/sinsemilla_opt/chip/hash_to_point.rs | 181 ------ halo2_gadgets/src/sinsemilla_opt/merkle.rs | 246 -------- .../src/sinsemilla_opt/merkle/chip.rs | 209 ------ .../src/sinsemilla_opt/primitives.rs | 74 --- halo2_gadgets/src/utilities_opt.rs | 4 - halo2_gadgets/src/utilities_opt/cond_swap.rs | 352 ----------- .../src/utilities_opt/lookup_range_check.rs | 566 ----------------- 19 files changed, 3 insertions(+), 3429 deletions(-) delete mode 100644 halo2_gadgets/src/ecc_opt.rs delete mode 100644 halo2_gadgets/src/ecc_opt/chip.rs delete mode 100644 halo2_gadgets/src/ecc_opt/chip/mul_fixed.rs delete mode 100644 halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs delete mode 100644 halo2_gadgets/src/ecc_opt/chip/witness_point.rs delete mode 100644 halo2_gadgets/src/sinsemilla_opt.rs delete mode 100644 halo2_gadgets/src/sinsemilla_opt/chip.rs delete mode 100644 halo2_gadgets/src/sinsemilla_opt/chip/generator_table.rs delete mode 100644 halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs delete mode 100644 halo2_gadgets/src/sinsemilla_opt/merkle.rs delete mode 100644 halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs delete mode 100644 halo2_gadgets/src/sinsemilla_opt/primitives.rs delete mode 100644 halo2_gadgets/src/utilities_opt.rs delete mode 100644 halo2_gadgets/src/utilities_opt/cond_swap.rs delete mode 100644 halo2_gadgets/src/utilities_opt/lookup_range_check.rs diff --git a/halo2_gadgets/src/ecc_opt.rs b/halo2_gadgets/src/ecc_opt.rs deleted file mode 100644 index 4275d47f8a..0000000000 --- a/halo2_gadgets/src/ecc_opt.rs +++ /dev/null @@ -1,289 +0,0 @@ -//! Elliptic curve operations. - -use std::fmt::Debug; - -use halo2_proofs::{ - arithmetic::CurveAffine, - circuit::{AssignedCell, Layouter}, - plonk::Error, -}; - -use crate::ecc::{EccInstructions, Point}; - -pub(crate) mod chip; - -/// The set of circuit instructions required to use the ECC gadgets. -pub trait EccInstructionsOptimized: EccInstructions { - /// Witnesses the given constant point as a private input to the circuit. - /// This allows the point to be the identity, mapped to (0, 0) in - /// affine coordinates. - fn witness_point_from_constant( - &self, - layouter: &mut impl Layouter, - value: C, - ) -> Result; - - /// Performs variable-base sign-scalar multiplication, returning `[sign] point` - /// `sign` must be in {-1, 1}. - fn mul_sign( - &self, - layouter: &mut impl Layouter, - sign: &AssignedCell, - point: &Self::Point, - ) -> Result; -} - -impl + Clone + Debug + Eq> Point { - /// Constructs a new point with the given fixed value. - pub fn new_from_constant( - chip: EccChip, - mut layouter: impl Layouter, - value: C, - ) -> Result { - let point = chip.witness_point_from_constant(&mut layouter, value); - point.map(|inner| Point { chip, inner }) - } - - /// Returns `[sign] self`. - /// `sign` must be in {-1, 1}. - pub fn mul_sign( - &self, - mut layouter: impl Layouter, - sign: &AssignedCell, - ) -> Result, Error> { - self.chip - .mul_sign(&mut layouter, sign, &self.inner) - .map(|point| Point { - chip: self.chip.clone(), - inner: point, - }) - } -} -#[cfg(test)] -pub(crate) mod tests { - use group::{prime::PrimeCurveAffine, Curve, Group}; - - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::MockProver, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use pasta_curves::pallas; - - use crate::ecc::chip::{EccChip, EccConfig}; - use crate::utilities::lookup_range_check::LookupRangeCheck; - use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; - - struct MyCircuit { - test_errors: bool, - } - - #[allow(non_snake_case)] - impl Circuit for MyCircuit { - type Config = EccConfig< - crate::ecc::tests::TestFixedBases, - LookupRangeCheckConfigOptimized, - >; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - MyCircuit { test_errors: false } - } - - 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(), - ]; - let lookup_table = 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(), - ]; - // Shared fixed column for loading constants - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - let range_check = LookupRangeCheckConfigOptimized::configure_with_tag( - meta, - advices[9], - lookup_table, - table_range_check_tag, - ); - EccChip::< - crate::ecc::tests::TestFixedBases, - LookupRangeCheckConfigOptimized, - >::configure(meta, advices, lagrange_coeffs, range_check) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let chip = EccChip::construct(config.clone()); - - // Load 10-bit lookup table. In the Action circuit, this will be - // provided by the Sinsemilla chip. - config.lookup_config.load(&mut layouter)?; - - // Generate a random non-identity point P - let p_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); // P - let p = crate::ecc::NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "P"), - Value::known(p_val), - )?; - let p_neg = -p_val; - let p_neg = crate::ecc::NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "-P"), - Value::known(p_neg), - )?; - - // Generate a random non-identity point Q - let q_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); // Q - let q = crate::ecc::NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "Q"), - Value::known(q_val), - )?; - - // Make sure P and Q are not the same point. - assert_ne!(p_val, q_val); - - // Test that we can witness the identity as a point, but not as a non-identity point. - { - let _ = super::Point::new( - chip.clone(), - layouter.namespace(|| "identity"), - Value::known(pallas::Affine::identity()), - )?; - - crate::ecc::NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "identity"), - Value::known(pallas::Affine::identity()), - ) - .expect_err("Trying to witness the identity should return an error"); - } - - // Test witness non-identity point - { - crate::ecc::chip::witness_point::tests::test_witness_non_id( - chip.clone(), - layouter.namespace(|| "witness non-identity point"), - ) - } - - // Test complete addition - { - crate::ecc::chip::add::tests::test_add( - chip.clone(), - layouter.namespace(|| "complete addition"), - p_val, - &p, - q_val, - &q, - &p_neg, - )?; - } - - // Test incomplete addition - { - crate::ecc::chip::add_incomplete::tests::test_add_incomplete( - chip.clone(), - layouter.namespace(|| "incomplete addition"), - p_val, - &p, - q_val, - &q, - &p_neg, - self.test_errors, - )?; - } - - // Test variable-base scalar multiplication - { - crate::ecc::chip::mul::tests::test_mul( - chip.clone(), - layouter.namespace(|| "variable-base scalar mul"), - &p, - p_val, - )?; - } - - // Test variable-base sign-scalar multiplication - { - super::chip::mul_fixed::short::tests::test_mul_sign( - chip.clone(), - layouter.namespace(|| "variable-base sign-scalar mul"), - )?; - } - - // Test full-width fixed-base scalar multiplication - { - crate::ecc::chip::mul_fixed::full_width::tests::test_mul_fixed( - chip.clone(), - layouter.namespace(|| "full-width fixed-base scalar mul"), - )?; - } - - // Test signed short fixed-base scalar multiplication - { - crate::ecc::chip::mul_fixed::short::tests::test_mul_fixed_short( - chip.clone(), - layouter.namespace(|| "signed short fixed-base scalar mul"), - )?; - } - - // Test fixed-base scalar multiplication with a base field element - { - crate::ecc::chip::mul_fixed::base_field_elem::tests::test_mul_fixed_base_field( - chip, - layouter.namespace(|| "fixed-base scalar mul with base field element"), - )?; - } - - Ok(()) - } - } - - #[test] - fn ecc_chip() { - let k = 13; - let circuit = MyCircuit { test_errors: true }; - let prover = MockProver::run(k, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())) - } - - #[cfg(feature = "test-dev-graph")] - #[test] - fn print_ecc_chip() { - use plotters::prelude::*; - - let root = BitMapBackend::new("ecc-chip-layout.png", (1024, 7680)).into_drawing_area(); - root.fill(&WHITE).unwrap(); - let root = root.titled("Ecc Chip Layout", ("sans-serif", 60)).unwrap(); - - let circuit = MyCircuit { test_errors: false }; - halo2_proofs::dev::CircuitLayout::default() - .render(13, &circuit, &root) - .unwrap(); - } -} diff --git a/halo2_gadgets/src/ecc_opt/chip.rs b/halo2_gadgets/src/ecc_opt/chip.rs deleted file mode 100644 index c2c70bc17f..0000000000 --- a/halo2_gadgets/src/ecc_opt/chip.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! Chip implementations for the ECC gadgets. - -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Layouter}, - plonk::Error, -}; -use pasta_curves::pallas; - -use crate::{ - ecc::{ - chip::{BaseFieldElem, EccChip, FixedPoint, FullScalar, ShortScalar}, - FixedPoints, - }, - utilities::lookup_range_check::DefaultLookupRangeCheck, -}; - -use super::EccInstructionsOptimized; - -pub(crate) mod mul_fixed; -pub(super) mod witness_point; - -impl, Lookup: DefaultLookupRangeCheck> - EccInstructionsOptimized for EccChip -where - >::Base: - FixedPoint, - >::FullScalar: - FixedPoint, - >::ShortScalar: - FixedPoint, -{ - fn witness_point_from_constant( - &self, - layouter: &mut impl Layouter, - value: pallas::Affine, - ) -> Result { - let config = self.config().witness_point; - layouter.assign_region( - || "witness point (constant)", - |mut region| config.constant_point(value, 0, &mut region), - ) - } - - /// Performs variable-base sign-scalar multiplication, returning `[sign] point` - /// `sign` must be in {-1, 1}. - fn mul_sign( - &self, - layouter: &mut impl Layouter, - sign: &AssignedCell, - point: &Self::Point, - ) -> Result { - // Multiply point by sign, using the same gate as mul_fixed::short. - // This also constrains sign to be in {-1, 1}. - let config_short = self.config().mul_fixed_short.clone(); - config_short.assign_scalar_sign( - layouter.namespace(|| "variable-base sign-scalar mul"), - sign, - point, - ) - } -} diff --git a/halo2_gadgets/src/ecc_opt/chip/mul_fixed.rs b/halo2_gadgets/src/ecc_opt/chip/mul_fixed.rs deleted file mode 100644 index d1dea74e22..0000000000 --- a/halo2_gadgets/src/ecc_opt/chip/mul_fixed.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod short; diff --git a/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs deleted file mode 100644 index 830eec83b2..0000000000 --- a/halo2_gadgets/src/ecc_opt/chip/mul_fixed/short.rs +++ /dev/null @@ -1,597 +0,0 @@ -use crate::ecc::chip::EccPoint; - -use super::super::FixedPoints; - -use halo2_proofs::{ - circuit::{AssignedCell, Layouter}, - plonk::Error, -}; -use pasta_curves::pallas; - -use crate::ecc::chip::mul_fixed::short::Config; - -impl> Config { - /// Multiply the point by sign, using the q_mul_fixed_short gate. - /// Constraints `sign` in {-1, 1} - pub fn assign_scalar_sign( - &self, - mut layouter: impl Layouter, - sign: &AssignedCell, - point: &EccPoint, - ) -> Result { - let signed_point = layouter.assign_region( - || "Signed point", - |mut region| { - let offset = 0; - - // Enable mul_fixed_short selector to check the sign logic. - self.q_mul_fixed_short.enable(&mut region, offset)?; - - // Set "last window" to 0 (this field is irrelevant here). - region.assign_advice_from_constant( - || "u=0", - self.super_config.u, - offset, - pallas::Base::zero(), - )?; - - // Copy sign to `window` column - sign.copy_advice(|| "sign", &mut region, self.super_config.window, offset)?; - - // Assign the input y-coordinate. - point.y.copy_advice( - || "unsigned y", - &mut region, - self.super_config.add_config.y_qr, - offset, - )?; - - // Conditionally negate y-coordinate according to the value of sign - let signed_y_val = sign.value().and_then(|sign| { - if sign == &-pallas::Base::one() { - -point.y.value() - } else { - point.y.value().cloned() - } - }); - - // Assign the output signed y-coordinate. - let signed_y = region.assign_advice( - || "signed y", - self.super_config.add_config.y_p, - offset, - || signed_y_val, - )?; - - Ok(EccPoint { - x: point.x.clone(), - y: signed_y, - }) - }, - )?; - - Ok(signed_point) - } -} - -#[cfg(test)] -pub mod tests { - use ff::PrimeField; - use group::{Curve, Group}; - use halo2_proofs::{ - arithmetic::CurveAffine, - circuit::{AssignedCell, Chip, Layouter, Value}, - plonk::{Any, Error}, - }; - use pasta_curves::pallas; - - use crate::ecc::tests::Short; - use crate::ecc::ScalarFixedShort; - use crate::utilities::lookup_range_check::DefaultLookupRangeCheck; - use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; - use crate::{ - ecc::{chip::EccChip, tests::TestFixedBases, Point}, - utilities::UtilitiesInstructions, - }; - - pub(crate) fn test_mul_sign( - chip: EccChip, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // Generate a random non-identity point P - let p_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); - let p = Point::new( - chip.clone(), - layouter.namespace(|| "P"), - Value::known(p_val), - )?; - - // Create -P - let p_neg_val = -p_val; - let p_neg = Point::new( - chip.clone(), - layouter.namespace(|| "-P"), - Value::known(p_neg_val), - )?; - - // Create the identity point - let identity = Point::new( - chip.clone(), - layouter.namespace(|| "identity"), - Value::known(pallas::Point::identity().to_affine()), - )?; - - // Create -1 and 1 scalars - let pos_sign = chip.load_private( - layouter.namespace(|| "positive sign"), - chip.config().advices[0], - Value::known(pallas::Base::one()), - )?; - let neg_sign = chip.load_private( - layouter.namespace(|| "negative sign"), - chip.config().advices[1], - Value::known(-pallas::Base::one()), - )?; - - // [1] P == P - { - let result = p.mul_sign(layouter.namespace(|| "[1] P"), &pos_sign)?; - result.constrain_equal(layouter.namespace(|| "constrain [1] P"), &p)?; - } - - // [-1] P == -P - { - let result = p.mul_sign(layouter.namespace(|| "[1] P"), &neg_sign)?; - result.constrain_equal(layouter.namespace(|| "constrain [1] P"), &p_neg)?; - } - - // [1] 0 == 0 - { - let result = identity.mul_sign(layouter.namespace(|| "[1] O"), &pos_sign)?; - result.constrain_equal(layouter.namespace(|| "constrain [1] 0"), &identity)?; - } - - // [-1] 0 == 0 - { - let result = identity.mul_sign(layouter.namespace(|| "[-1] O"), &neg_sign)?; - result.constrain_equal(layouter.namespace(|| "constrain [1] 0"), &identity)?; - } - - Ok(()) - } - - #[test] - fn invalid_magnitude_sign() { - use crate::{ - ecc::chip::{EccConfig, FixedPoint}, - utilities::UtilitiesInstructions, - }; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - dev::{FailureLocation, MockProver, VerifyFailure}, - plonk::{Circuit, ConstraintSystem, Error}, - }; - - #[derive(Default)] - struct MyCircuit { - magnitude: Value, - sign: Value, - // For test checking - magnitude_error: Value, - } - - impl UtilitiesInstructions for MyCircuit { - type Var = AssignedCell; - } - - impl Circuit for MyCircuit { - type Config = EccConfig< - TestFixedBases, - LookupRangeCheckConfigOptimized, - >; - 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(), - ]; - let lookup_table = 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(), - ]; - - // Shared fixed column for loading constants - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - let range_check = LookupRangeCheckConfigOptimized::configure_with_tag( - meta, - advices[9], - lookup_table, - table_range_check_tag, - ); - EccChip::< - TestFixedBases, - LookupRangeCheckConfigOptimized< - pallas::Base, - { crate::sinsemilla::primitives::K }, - >, - >::configure(meta, advices, lagrange_coeffs, range_check) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let column = config.advices[0]; - - let short_config = config.mul_fixed_short.clone(); - let magnitude_sign = { - let magnitude = self.load_private( - layouter.namespace(|| "load magnitude"), - column, - self.magnitude, - )?; - let sign = - self.load_private(layouter.namespace(|| "load sign"), column, self.sign)?; - ScalarFixedShort::new( - EccChip::construct(config), - layouter.namespace(|| "signed short scalar"), - (magnitude, sign), - )? - }; - - short_config.assign(layouter, &magnitude_sign.inner, &Short)?; - - Ok(()) - } - } - - // Copied from halo2_proofs::dev::util - fn format_value(v: pallas::Base) -> String { - use ff::Field; - if v.is_zero_vartime() { - "0".into() - } else if v == pallas::Base::one() { - "1".into() - } else if v == -pallas::Base::one() { - "-1".into() - } else { - // Format value as hex. - let s = format!("{:?}", v); - // Remove leading zeroes. - let s = s.strip_prefix("0x").unwrap(); - let s = s.trim_start_matches('0'); - format!("0x{}", s) - } - } - - // Magnitude larger than 64 bits should fail - { - let circuits = [ - // 2^64 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 64)), - sign: Value::known(pallas::Base::one()), - magnitude_error: Value::known(pallas::Base::from(1 << 1)), - }, - // -2^64 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 64)), - sign: Value::known(-pallas::Base::one()), - magnitude_error: Value::known(pallas::Base::from(1 << 1)), - }, - // 2^66 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 66)), - sign: Value::known(pallas::Base::one()), - magnitude_error: Value::known(pallas::Base::from(1 << 3)), - }, - // -2^66 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 66)), - sign: Value::known(-pallas::Base::one()), - magnitude_error: Value::known(pallas::Base::from(1 << 3)), - }, - // 2^254 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 127).square()), - sign: Value::known(pallas::Base::one()), - magnitude_error: Value::known( - pallas::Base::from_u128(1 << 95).square() * pallas::Base::from(2), - ), - }, - // -2^254 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 127).square()), - sign: Value::known(-pallas::Base::one()), - magnitude_error: Value::known( - pallas::Base::from_u128(1 << 95).square() * pallas::Base::from(2), - ), - }, - ]; - - for circuit in circuits.iter() { - let prover = MockProver::::run(11, circuit, vec![]).unwrap(); - circuit.magnitude_error.assert_if_known(|magnitude_error| { - assert_eq!( - prover.verify(), - Err(vec![ - VerifyFailure::ConstraintNotSatisfied { - constraint: ( - (17, "Short fixed-base mul gate").into(), - 0, - "last_window_check", - ) - .into(), - location: FailureLocation::InRegion { - region: (3, "Short fixed-base mul (most significant word)") - .into(), - offset: 1, - }, - cell_values: vec![( - ((Any::Advice, 5).into(), 0).into(), - format_value(*magnitude_error), - )], - }, - VerifyFailure::Permutation { - column: (Any::Fixed, 10).into(), - location: FailureLocation::OutsideRegion { row: 0 }, - }, - VerifyFailure::Permutation { - column: (Any::Advice, 4).into(), - location: FailureLocation::InRegion { - region: (2, "Short fixed-base mul (incomplete addition)") - .into(), - offset: 22, - }, - }, - ]) - ); - true - }); - } - } - - // Sign that is not +/- 1 should fail - { - let magnitude_u64 = rand::random::(); - let circuit = MyCircuit { - magnitude: Value::known(pallas::Base::from(magnitude_u64)), - sign: Value::known(pallas::Base::zero()), - magnitude_error: Value::unknown(), - }; - - let negation_check_y = { - *(Short.generator() * pallas::Scalar::from(magnitude_u64)) - .to_affine() - .coordinates() - .unwrap() - .y() - }; - - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![ - VerifyFailure::ConstraintNotSatisfied { - constraint: ((17, "Short fixed-base mul gate").into(), 1, "sign_check") - .into(), - location: FailureLocation::InRegion { - region: (3, "Short fixed-base mul (most significant word)").into(), - offset: 1, - }, - cell_values: vec![(((Any::Advice, 4).into(), 0).into(), "0".to_string())], - }, - VerifyFailure::ConstraintNotSatisfied { - constraint: ( - (17, "Short fixed-base mul gate").into(), - 3, - "negation_check" - ) - .into(), - location: FailureLocation::InRegion { - region: (3, "Short fixed-base mul (most significant word)").into(), - offset: 1, - }, - cell_values: vec![ - ( - ((Any::Advice, 1).into(), 0).into(), - format_value(negation_check_y), - ), - ( - ((Any::Advice, 3).into(), 0).into(), - format_value(negation_check_y), - ), - (((Any::Advice, 4).into(), 0).into(), "0".to_string()), - ], - } - ]) - ); - } - } - - #[test] - fn invalid_sign_in_mul_sign() { - use crate::{ecc::chip::EccConfig, utilities::UtilitiesInstructions}; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - dev::{FailureLocation, MockProver, VerifyFailure}, - plonk::{Circuit, ConstraintSystem, Error}, - }; - - #[derive(Default)] - struct MyCircuit { - base: Value, - sign: Value, - } - - impl UtilitiesInstructions for MyCircuit { - type Var = AssignedCell; - } - - impl Circuit for MyCircuit { - type Config = EccConfig< - TestFixedBases, - LookupRangeCheckConfigOptimized, - >; - 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(), - ]; - let lookup_table = 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(), - ]; - - // Shared fixed column for loading constants - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - let range_check = LookupRangeCheckConfigOptimized::configure_with_tag( - meta, - advices[9], - lookup_table, - table_range_check_tag, - ); - EccChip::< - TestFixedBases, - LookupRangeCheckConfigOptimized< - pallas::Base, - { crate::sinsemilla::primitives::K }, - >, - >::configure(meta, advices, lagrange_coeffs, range_check) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let chip = EccChip::construct(config.clone()); - - let column = config.advices[0]; - - //let short_config = config.mul_fixed_short.clone(); - let base = Point::new(chip, layouter.namespace(|| "load base"), self.base)?; - - let sign = - self.load_private(layouter.namespace(|| "load sign"), column, self.sign)?; - - base.mul_sign(layouter.namespace(|| "[sign] base"), &sign)?; - - Ok(()) - } - } - - // Copied from halo2_proofs::dev::util - fn format_value(v: pallas::Base) -> String { - use ff::Field; - if v.is_zero_vartime() { - "0".into() - } else if v == pallas::Base::one() { - "1".into() - } else if v == -pallas::Base::one() { - "-1".into() - } else { - // Format value as hex. - let s = format!("{:?}", v); - // Remove leading zeroes. - let s = s.strip_prefix("0x").unwrap(); - let s = s.trim_start_matches('0'); - format!("0x{}", s) - } - } - - // Sign that is not +/- 1 should fail - // Generate a random non-identity point - let point = pallas::Point::random(rand::rngs::OsRng); - let circuit = MyCircuit { - base: Value::known(point.to_affine()), - sign: Value::known(pallas::Base::zero()), - }; - - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![ - VerifyFailure::ConstraintNotSatisfied { - constraint: ((17, "Short fixed-base mul gate").into(), 1, "sign_check").into(), - location: FailureLocation::InRegion { - region: (2, "Signed point").into(), - offset: 0, - }, - cell_values: vec![(((Any::Advice, 4).into(), 0).into(), "0".to_string())], - }, - VerifyFailure::ConstraintNotSatisfied { - constraint: ( - (17, "Short fixed-base mul gate").into(), - 3, - "negation_check" - ) - .into(), - location: FailureLocation::InRegion { - region: (2, "Signed point").into(), - offset: 0, - }, - cell_values: vec![ - ( - ((Any::Advice, 1).into(), 0).into(), - format_value(*point.to_affine().coordinates().unwrap().y()), - ), - ( - ((Any::Advice, 3).into(), 0).into(), - format_value(*point.to_affine().coordinates().unwrap().y()), - ), - (((Any::Advice, 4).into(), 0).into(), "0".to_string()), - ], - } - ]) - ); - } -} diff --git a/halo2_gadgets/src/ecc_opt/chip/witness_point.rs b/halo2_gadgets/src/ecc_opt/chip/witness_point.rs deleted file mode 100644 index 9e1bfeae6d..0000000000 --- a/halo2_gadgets/src/ecc_opt/chip/witness_point.rs +++ /dev/null @@ -1,50 +0,0 @@ -use crate::ecc::chip::EccPoint; - -use group::prime::PrimeCurveAffine; - -use halo2_proofs::{ - circuit::Region, - plonk::{Assigned, Error}, -}; -use pasta_curves::{arithmetic::CurveAffine, pallas}; - -use crate::ecc::chip::witness_point::{Config, Coordinates}; - -impl Config { - fn assign_xy_from_constant( - &self, - value: (Assigned, Assigned), - offset: usize, - region: &mut Region<'_, pallas::Base>, - ) -> Result { - // Assign `x` value - let x_var = region.assign_advice_from_constant(|| "x", self.x, offset, value.0)?; - - // Assign `y` value - let y_var = region.assign_advice_from_constant(|| "y", self.y, offset, value.1)?; - - Ok((x_var, y_var)) - } - - /// Assigns a constant point that can be the identity. - pub(crate) fn constant_point( - &self, - value: pallas::Affine, - offset: usize, - region: &mut Region<'_, pallas::Base>, - ) -> Result { - // Enable `q_point` selector - self.q_point.enable(region, offset)?; - - let value = if value == pallas::Affine::identity() { - // Map the identity to (0, 0). - (Assigned::Zero, Assigned::Zero) - } else { - let value = value.coordinates().unwrap(); - (value.x().into(), value.y().into()) - }; - - self.assign_xy_from_constant(value, offset, region) - .map(|(x, y)| EccPoint::from_coordinates_unchecked(x, y)) - } -} diff --git a/halo2_gadgets/src/lib.rs b/halo2_gadgets/src/lib.rs index 33ffcfa6b8..2ac2623a99 100644 --- a/halo2_gadgets/src/lib.rs +++ b/halo2_gadgets/src/lib.rs @@ -22,12 +22,9 @@ #![deny(unsafe_code)] pub mod ecc; -pub mod ecc_opt; pub mod poseidon; #[cfg(feature = "unstable-sha256-gadget")] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-sha256-gadget")))] pub mod sha256; pub mod sinsemilla; -pub mod sinsemilla_opt; pub mod utilities; -pub mod utilities_opt; diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index d5b0dab5e2..e10e504013 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -403,6 +403,7 @@ CommitDomain pub fn new( sinsemilla_chip: SinsemillaChip, ecc_chip: EccChip, + // TODO: Instead of using SinsemilllaChip::CommitDomains, just use something that implements a CommitDomains trait domain: &SinsemillaChip::CommitDomains, ) -> Self { CommitDomain { diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs index 4ce0662e91..5c26cff058 100644 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla/merkle/chip.rs @@ -200,6 +200,8 @@ where } } +/// The MerkleSinsemillaInstructions trait extends the capabilities of SinsemillaInstructions, +/// for specific cryptographic operations involving generic lookup. pub(crate) trait MerkleSinsemillaInstructions where Self: SinsemillaInstructions< diff --git a/halo2_gadgets/src/sinsemilla/primitives.rs b/halo2_gadgets/src/sinsemilla/primitives.rs index 2ebde8faf4..c47ac1b379 100644 --- a/halo2_gadgets/src/sinsemilla/primitives.rs +++ b/halo2_gadgets/src/sinsemilla/primitives.rs @@ -184,8 +184,6 @@ impl HashDomain { #[derive(Debug)] #[allow(non_snake_case)] pub struct CommitDomain { - // FIXME: THis comment came from ZSA version - /// A domain in which $\mathsf{SinsemillaHashToPoint}$ and $\mathsf{SinsemillaHash}$ can be used pub(crate) M: HashDomain, pub(crate) R: pallas::Point, } diff --git a/halo2_gadgets/src/sinsemilla_opt.rs b/halo2_gadgets/src/sinsemilla_opt.rs deleted file mode 100644 index 30d1d2c83c..0000000000 --- a/halo2_gadgets/src/sinsemilla_opt.rs +++ /dev/null @@ -1,464 +0,0 @@ -//! The [Sinsemilla] hash function. -//! -//! [Sinsemilla]: https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash - -use std::fmt::Debug; - -use pasta_curves::arithmetic::CurveAffine; - -use halo2_proofs::{circuit::Layouter, plonk::Error}; - -use crate::{ - ecc::{self, EccInstructions}, - sinsemilla::{CommitDomain, HashDomain, Message, SinsemillaInstructions}, -}; - -pub mod chip; -pub mod merkle; -pub mod primitives; - -/// `SinsemillaInstructionsOptimized` provides an optimized set of instructions -/// for implementing the Sinsemilla hash function and commitment scheme -/// on elliptic curves. This trait is an extension of the `SinsemillaInstructions` trait, -/// designed to enhance performance in specific cryptographic scenarios.ld - -pub trait SinsemillaInstructionsOptimized: - SinsemillaInstructions -{ - /// Hashes a message to an ECC curve point. - /// This returns both the resulting point, as well as the message - /// decomposition in the form of intermediate values in a cumulative - /// sum. - /// The initial point `Q` is a private point. - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - fn hash_to_point_with_private_init( - &self, - layouter: impl Layouter, - Q: &Self::NonIdentityPoint, - message: Self::Message, - ) -> Result<(Self::NonIdentityPoint, Vec), Error>; -} - -impl -HashDomain - where - SinsemillaChip: SinsemillaInstructionsOptimized + Clone + Debug + Eq, - EccChip: EccInstructions< - C, - NonIdentityPoint = >::NonIdentityPoint, - FixedPoints = >::FixedPoints, - > + Clone - + Debug - + Eq, -{ - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - /// Evaluate the Sinsemilla hash of `message` from the private initial point `Q`. - pub fn hash_to_point_with_private_init( - &self, - layouter: impl Layouter, - Q: &>::NonIdentityPoint, - message: Message, - ) -> Result<(ecc::NonIdentityPoint, Vec), Error> { - assert_eq!(self.sinsemilla_chip, message.chip); - self.sinsemilla_chip - .hash_to_point_with_private_init(layouter, Q, message.inner) - .map(|(point, zs)| (ecc::NonIdentityPoint::from_inner(self.ecc_chip.clone(), point), zs)) - } - -} - -impl -CommitDomain - where - SinsemillaChip: SinsemillaInstructionsOptimized + Clone + Debug + Eq, - EccChip: EccInstructions< - C, - NonIdentityPoint = >::NonIdentityPoint, - FixedPoints = >::FixedPoints, - > + Clone - + Debug - + Eq, -{ - #[allow(clippy::type_complexity)] - /// Evaluates the Sinsemilla hash of `message` from the public initial point `Q` stored - /// into `CommitDomain`. - pub fn hash( - &self, - layouter: impl Layouter, - message: Message, - ) -> Result< - ( - ecc::NonIdentityPoint, - Vec, - ), - Error, - > { - assert_eq!(self.M.sinsemilla_chip, message.chip); - self.M.hash_to_point(layouter, message) - } - - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - /// Evaluates the Sinsemilla hash of `message` from the private initial point `Q`. - pub fn hash_with_private_init( - &self, - layouter: impl Layouter, - Q: &>::NonIdentityPoint, - message: Message, - ) -> Result< - ( - ecc::NonIdentityPoint, - Vec, - ), - Error, - > { - assert_eq!(self.M.sinsemilla_chip, message.chip); - self.M.hash_to_point_with_private_init(layouter, Q, message) - } - - #[allow(clippy::type_complexity)] - /// Returns the public initial point `Q` stored into `CommitDomain`. - pub fn q_init(&self) -> C { - self.M.Q - } - - #[allow(clippy::type_complexity)] - /// Evaluates the blinding factor equal to $\[r\] R$ where `r` is stored in the `CommitDomain`. - pub fn blinding_factor( - &self, - mut layouter: impl Layouter, - r: ecc::ScalarFixed, - ) -> Result< - ecc::Point, - Error, - > { - let (blind, _) = self.R.mul(layouter.namespace(|| "[r] R"), r)?; - Ok(blind) - } -} - -#[cfg(test)] -pub(crate) mod tests { - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::MockProver, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use rand::rngs::OsRng; - - use crate::sinsemilla::{ - chip::{SinsemillaChip, SinsemillaConfig}, - CommitDomain, CommitDomains, HashDomain, HashDomains, Message, MessagePiece, - }; - - use crate::{ - ecc::ScalarFixed, - ecc::{ - chip::{find_zs_and_us, EccChip, EccConfig, H, NUM_WINDOWS}, - tests::{FullWidth, TestFixedBases}, - NonIdentityPoint, - }, - sinsemilla::primitives::{self as sinsemilla, K}, - }; - - use group::{ff::Field, Curve}; - use lazy_static::lazy_static; - use pasta_curves::pallas; - - use crate::sinsemilla_opt::chip::SinsemillaChipOptimized; - use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; - use std::convert::TryInto; - - pub(crate) const PERSONALIZATION: &str = "MerkleCRH"; - - lazy_static! { - static ref COMMIT_DOMAIN: sinsemilla::CommitDomain = - sinsemilla::CommitDomain::new(PERSONALIZATION); - static ref Q: pallas::Affine = COMMIT_DOMAIN.Q().to_affine(); - static ref R: pallas::Affine = COMMIT_DOMAIN.R().to_affine(); - static ref R_ZS_AND_US: Vec<(u64, [pallas::Base; H])> = - find_zs_and_us(*R, NUM_WINDOWS).unwrap(); - } - - #[derive(Debug, Clone, Eq, PartialEq)] - pub(crate) struct TestHashDomain; - impl HashDomains for TestHashDomain { - fn Q(&self) -> pallas::Affine { - *Q - } - } - - // This test does not make use of the CommitDomain. - #[derive(Debug, Clone, Eq, PartialEq)] - pub(crate) struct TestCommitDomain; - impl CommitDomains for TestCommitDomain { - fn r(&self) -> FullWidth { - FullWidth::from_parts(*R, &R_ZS_AND_US) - } - - fn hash_domain(&self) -> TestHashDomain { - TestHashDomain - } - } - - struct MyCircuit {} - - impl Circuit for MyCircuit { - #[allow(clippy::type_complexity)] - type Config = ( - EccConfig< - TestFixedBases, - LookupRangeCheckConfigOptimized, - >, - SinsemillaConfig< - TestHashDomain, - TestCommitDomain, - TestFixedBases, - LookupRangeCheckConfigOptimized, - >, - SinsemillaConfig< - TestHashDomain, - TestCommitDomain, - TestFixedBases, - LookupRangeCheckConfigOptimized, - >, - ); - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - MyCircuit {} - } - - #[allow(non_snake_case)] - 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(), - ]; - - // Shared fixed column for loading constants - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - 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(), - ]; - - // Fixed columns for the Sinsemilla generator lookup table - let lookup = ( - table_idx, - meta.lookup_table_column(), - meta.lookup_table_column(), - ); - - let range_check = LookupRangeCheckConfigOptimized::configure_with_tag( - meta, - advices[9], - table_idx, - table_range_check_tag, - ); - - let ecc_config = EccChip::< - TestFixedBases, - LookupRangeCheckConfigOptimized, - >::configure(meta, advices, lagrange_coeffs, range_check); - - let config1 = SinsemillaChip::configure( - meta, - advices[..5].try_into().unwrap(), - advices[2], - lagrange_coeffs[0], - lookup, - range_check, - ); - let config2 = SinsemillaChip::configure( - meta, - advices[5..].try_into().unwrap(), - advices[7], - lagrange_coeffs[1], - lookup, - range_check, - ); - (ecc_config, config1, config2) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let rng = OsRng; - - let ecc_chip = EccChip::construct(config.0); - - // The two `SinsemillaChip`s share the same lookup table. - SinsemillaChipOptimized::::load( - config.1.clone(), - &mut layouter, - )?; - - // This MerkleCRH example is purely for illustrative purposes. - // It is not an implementation of the Orchard protocol spec. - { - let chip1 = SinsemillaChip::construct(config.1); - - let merkle_crh = HashDomain::new(chip1.clone(), ecc_chip.clone(), &TestHashDomain); - - // Layer 31, l = MERKLE_DEPTH - 1 - layer = 0 - let l_bitstring = vec![Value::known(false); K]; - let l = MessagePiece::from_bitstring( - chip1.clone(), - layouter.namespace(|| "l"), - &l_bitstring, - )?; - - // Left leaf - let left_bitstring: Vec> = (0..250) - .map(|_| Value::known(rand::random::())) - .collect(); - let left = MessagePiece::from_bitstring( - chip1.clone(), - layouter.namespace(|| "left"), - &left_bitstring, - )?; - - // Right leaf - let right_bitstring: Vec> = (0..250) - .map(|_| Value::known(rand::random::())) - .collect(); - let right = MessagePiece::from_bitstring( - chip1.clone(), - layouter.namespace(|| "right"), - &right_bitstring, - )?; - - let l_bitstring: Value> = l_bitstring.into_iter().collect(); - let left_bitstring: Value> = left_bitstring.into_iter().collect(); - let right_bitstring: Value> = right_bitstring.into_iter().collect(); - - // Witness expected parent - let expected_parent = { - let expected_parent = l_bitstring.zip(left_bitstring.zip(right_bitstring)).map( - |(l, (left, right))| { - let merkle_crh = sinsemilla::HashDomain::from_Q((*Q).into()); - let point = merkle_crh - .hash_to_point( - l.into_iter() - .chain(left.into_iter()) - .chain(right.into_iter()), - ) - .unwrap(); - point.to_affine() - }, - ); - - NonIdentityPoint::new( - ecc_chip.clone(), - layouter.namespace(|| "Witness expected parent"), - expected_parent, - )? - }; - - // Parent - let (parent, _) = { - let message = Message::from_pieces(chip1, vec![l, left, right]); - merkle_crh.hash_to_point(layouter.namespace(|| "parent"), message)? - }; - - parent.constrain_equal( - layouter.namespace(|| "parent == expected parent"), - &expected_parent, - )?; - } - - { - let chip2 = SinsemillaChip::construct(config.2); - - let test_commit = - CommitDomain::new(chip2.clone(), ecc_chip.clone(), &TestCommitDomain); - let r_val = pallas::Scalar::random(rng); - let message: Vec> = (0..500) - .map(|_| Value::known(rand::random::())) - .collect(); - - let (result, _) = { - let r = ScalarFixed::new( - ecc_chip.clone(), - layouter.namespace(|| "r"), - Value::known(r_val), - )?; - let message = Message::from_bitstring( - chip2, - layouter.namespace(|| "witness message"), - message.clone(), - )?; - test_commit.commit(layouter.namespace(|| "commit"), message, r)? - }; - - // Witness expected result. - let expected_result = { - let message: Value> = message.into_iter().collect(); - let expected_result = message.map(|message| { - let domain = sinsemilla::CommitDomain::new(PERSONALIZATION); - let point = domain.commit(message.into_iter(), &r_val).unwrap(); - point.to_affine() - }); - - NonIdentityPoint::new( - ecc_chip, - layouter.namespace(|| "Witness expected result"), - expected_result, - )? - }; - - result.constrain_equal( - layouter.namespace(|| "result == expected result"), - &expected_result, - ) - } - } - } - - #[test] - fn sinsemilla_chip() { - let k = 11; - let circuit = MyCircuit {}; - let prover = MockProver::run(k, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())) - } - - #[cfg(feature = "test-dev-graph")] - #[test] - fn print_sinsemilla_chip() { - use plotters::prelude::*; - - let root = - BitMapBackend::new("sinsemilla-hash-layout.png", (1024, 7680)).into_drawing_area(); - root.fill(&WHITE).unwrap(); - let root = root.titled("SinsemillaHash", ("sans-serif", 60)).unwrap(); - - let circuit = MyCircuit {}; - halo2_proofs::dev::CircuitLayout::default() - .render(11, &circuit, &root) - .unwrap(); - } -} diff --git a/halo2_gadgets/src/sinsemilla_opt/chip.rs b/halo2_gadgets/src/sinsemilla_opt/chip.rs deleted file mode 100644 index 1b544edf75..0000000000 --- a/halo2_gadgets/src/sinsemilla_opt/chip.rs +++ /dev/null @@ -1,219 +0,0 @@ -//! Chip implementations for the Sinsemilla gadgets. - -use super::SinsemillaInstructionsOptimized; -use crate::{ - ecc::{chip::NonIdentityEccPoint, FixedPoints}, - sinsemilla::{ - chip::{SinsemillaChip, SinsemillaConfig}, - message::{Message, MessagePiece}, - primitives as sinsemilla, CommitDomains, HashDomains, SinsemillaInstructions, - }, - utilities_opt::lookup_range_check::DefaultLookupRangeCheckConfigOptimized, -}; -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Layouter, Value}, - plonk::{ - Advice, Column, ConstraintSystem, Constraints, Error, Fixed, TableColumn, VirtualCells, - }, - poly::Rotation, -}; -use pasta_curves::pallas; - -pub(crate) mod generator_table; - -mod hash_to_point; - -/// A chip that implements 10-bit Sinsemilla using a lookup table and 5 advice columns. -/// -/// [Chip description](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html#plonk--halo-2-constraints). -#[derive(Eq, PartialEq, Clone, Debug)] -pub struct SinsemillaChipOptimized -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, -{ - inner: SinsemillaChip, -} - -impl Chip for SinsemillaChipOptimized -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, -{ - type Config = SinsemillaConfig; - type Loaded = (); - - fn config(&self) -> &Self::Config { - self.inner.config() - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -impl SinsemillaChipOptimized -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - /// Reconstructs this chip from the given config. - pub fn construct(config: >::Config) -> Self { - Self { - inner: - SinsemillaChip::::construct( - config, - ), - } - } - - /// Loads the lookup table required by this chip into the circuit. - pub fn load( - config: SinsemillaConfig, - layouter: &mut impl Layouter, - ) -> Result<>::Loaded, Error> { - // Load the lookup table. - generator_table::load_with_tag( - &config.generator_table, - config.lookup_config.table_range_check_tag(), - layouter, - ) - } - - #[allow(non_snake_case)] - fn create_initial_y_q_gate( - meta: &mut ConstraintSystem, - config: &SinsemillaConfig, - ) { - let two = pallas::Base::from(2); - - // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) - let Y_A = |meta: &mut VirtualCells, rotation| { - config.double_and_add.Y_A(meta, rotation) - }; - - // Check that the initial x_A, x_P, lambda_1, lambda_2 are consistent with y_Q. - // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial - meta.create_gate("Initial y_Q", |meta| { - let q_s4 = meta.query_selector(config.q_sinsemilla4); - let y_q = meta.query_advice(config.double_and_add.x_p, Rotation::prev()); - - // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) - let Y_A_cur = Y_A(meta, Rotation::cur()); - - // 2 * y_q - Y_{A,0} = 0 - let init_y_q_check = y_q * two - Y_A_cur; - - Constraints::with_selector(q_s4, Some(("init_y_q_check", init_y_q_check))) - }); - } - - /// # Side-effects - /// - /// All columns in `advices` and will be equality-enabled. - #[allow(clippy::too_many_arguments)] - #[allow(non_snake_case)] - pub fn configure( - meta: &mut ConstraintSystem, - advices: [Column; 5], - witness_pieces: Column, - fixed_y_q: Column, - lookup: (TableColumn, TableColumn, TableColumn), - range_check: DefaultLookupRangeCheckConfigOptimized, - ) -> >::Config { - let config = SinsemillaChip::::create_config( - meta, - advices, - witness_pieces, - fixed_y_q, - lookup, - range_check, - ); - - Self::create_initial_y_q_gate(meta, &config); - - SinsemillaChip::::create_sinsemilla_gate( - meta, &config, - ); - - config - } -} - -// Implement `SinsemillaInstructions` for `SinsemillaChipOptimized` -impl SinsemillaInstructions - for SinsemillaChipOptimized -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - type CellValue = AssignedCell; - - type Message = Message; - type MessagePiece = MessagePiece; - - type RunningSum = Vec; - - type X = AssignedCell; - type NonIdentityPoint = NonIdentityEccPoint; - type FixedPoints = F; - - type HashDomains = Hash; - type CommitDomains = Commit; - - fn witness_message_piece( - &self, - layouter: impl Layouter, - field_elem: Value, - num_words: usize, - ) -> Result { - self.inner - .witness_message_piece(layouter, field_elem, num_words) - } - - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - fn hash_to_point( - &self, - mut layouter: impl Layouter, - Q: pallas::Affine, - message: Self::Message, - ) -> Result<(Self::NonIdentityPoint, Vec), Error> { - layouter.assign_region( - || "hash_to_point", - |mut region| self.hash_message(&mut region, Q, &message), - ) - } - - fn extract(point: &Self::NonIdentityPoint) -> Self::X { - point.x() - } -} - -// Implement `SinsemillaInstructionsOptimized` for `SinsemillaChipOptimized` -impl - SinsemillaInstructionsOptimized - for SinsemillaChipOptimized -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - fn hash_to_point_with_private_init( - &self, - mut layouter: impl Layouter, - Q: &Self::NonIdentityPoint, - message: Self::Message, - ) -> Result<(Self::NonIdentityPoint, Vec), Error> { - layouter.assign_region( - || "hash_to_point", - |mut region| self.hash_message_with_private_init(&mut region, Q, &message), - ) - } -} diff --git a/halo2_gadgets/src/sinsemilla_opt/chip/generator_table.rs b/halo2_gadgets/src/sinsemilla_opt/chip/generator_table.rs deleted file mode 100644 index fc87e48c07..0000000000 --- a/halo2_gadgets/src/sinsemilla_opt/chip/generator_table.rs +++ /dev/null @@ -1,111 +0,0 @@ -use halo2_proofs::{ - circuit::{Layouter, Value}, - plonk::{Error, TableColumn}, -}; - -use pasta_curves::pallas; - -use crate::sinsemilla::{ - chip::generator_table::GeneratorTableConfig, - primitives::{K, SINSEMILLA_S}, -}; - -/// 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( - config: &GeneratorTableConfig, - 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", - config.table_idx, - index, - || Value::known(pallas::Base::from(index as u64)), - )?; - table.assign_cell(|| "table_x", config.table_x, index, || Value::known(*x))?; - table.assign_cell(|| "table_y", config.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", - config.table_idx, - new_index, - || Value::known(pallas::Base::from(index as u64)), - )?; - table.assign_cell( - || "table_x", - config.table_x, - new_index, - || Value::known(*x), - )?; - table.assign_cell( - || "table_y", - config.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", - config.table_idx, - new_index, - || Value::known(pallas::Base::from(index as u64)), - )?; - table.assign_cell( - || "table_x", - config.table_x, - new_index, - || Value::known(*x), - )?; - table.assign_cell( - || "table_y", - config.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(()) - }, - ) -} diff --git a/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs deleted file mode 100644 index 8ef33ab4ef..0000000000 --- a/halo2_gadgets/src/sinsemilla_opt/chip/hash_to_point.rs +++ /dev/null @@ -1,181 +0,0 @@ -use pasta_curves::{arithmetic::CurveAffine, pallas}; - -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Region}, - plonk::{Assigned, Error}, -}; - -use crate::sinsemilla::chip::hash_to_point::EccPointQ; -use crate::sinsemilla::chip::SinsemillaChip; -use crate::sinsemilla_opt::chip::SinsemillaChipOptimized; -use crate::{ - ecc::{chip::NonIdentityEccPoint, FixedPoints}, - sinsemilla::{ - chip::hash_to_point::{X, Y}, - primitives::{self as sinsemilla}, - CommitDomains, HashDomains, SinsemillaInstructions, - }, -}; - -impl SinsemillaChipOptimized -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, -{ - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - pub(crate) fn hash_message( - &self, - region: &mut Region<'_, pallas::Base>, - Q: pallas::Affine, - message: &>::Message, - ) -> Result< - ( - NonIdentityEccPoint, - Vec>>, - ), - Error, - > { - // Coordinates of the initial point `Q` are assigned to advice columns - let (offset, x_a, y_a) = self.public_initialization(region, Q)?; - - let (x_a, y_a, zs_sum) = - SinsemillaChip::hash_all_pieces(&self.inner, region, offset, message, x_a, y_a)?; - - SinsemillaChip::check_hash_result( - &self.inner, - EccPointQ::PublicPoint(Q), - message, - x_a, - y_a, - zs_sum, - ) - } - /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - pub(crate) fn hash_message_with_private_init( - &self, - region: &mut Region<'_, pallas::Base>, - Q: &NonIdentityEccPoint, - message: &>::Message, - ) -> Result< - ( - NonIdentityEccPoint, - Vec>>, - ), - Error, - > { - let (offset, x_a, y_a) = self.private_initialization(region, Q)?; - - let (x_a, y_a, zs_sum) = - SinsemillaChip::hash_all_pieces(&self.inner, region, offset, message, x_a, y_a)?; - - SinsemillaChip::check_hash_result( - &self.inner, - EccPointQ::PrivatePoint(Q), - message, - x_a, - y_a, - zs_sum, - ) - } - - #[allow(non_snake_case)] - /// Assign the coordinates of the initial public point `Q` to advice columns - /// - /// | offset | x_A | x_P | q_sinsemilla4 | - /// -------------------------------------- - /// | 0 | | y_Q | | - /// | 1 | x_Q | | 1 | - pub(crate) 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.q_sinsemilla4.enable(region, offset + 1)?; - let y_a: AssignedCell, pallas::Base> = region - .assign_advice_from_constant( - || "fixed y_q", - config.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( - || "fixed x_q", - config.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 private point `Q` - /// - /// | offset | x_A | x_P | q_sinsemilla4 | - /// -------------------------------------- - /// | 0 | | y_Q | | - /// | 1 | x_Q | | 1 | - fn private_initialization( - &self, - region: &mut Region<'_, pallas::Base>, - Q: &NonIdentityEccPoint, - ) -> Result<(usize, X, Y), Error> { - let config = self.config().clone(); - let mut offset = 0; - - // Assign `x_Q` and `y_Q` in the region and constrain the initial x_a, lambda_1, lambda_2, - // x_p, y_Q using the q_sinsemilla4 selector. - let y_a: Y = { - // Enable `q_sinsemilla4` on the second row. - config.q_sinsemilla4.enable(region, offset + 1)?; - let q_y: AssignedCell, pallas::Base> = Q.y().into(); - let y_a: AssignedCell, pallas::Base> = - q_y.copy_advice(|| "fixed y_q", region, config.double_and_add.x_p, offset)?; - - y_a.value_field().into() - }; - offset += 1; - - let x_a: X = { - let q_x: AssignedCell, pallas::Base> = Q.x().into(); - let x_a = q_x.copy_advice(|| "fixed x_q", region, config.double_and_add.x_a, offset)?; - - x_a.into() - }; - - Ok((offset, x_a, y_a)) - } -} diff --git a/halo2_gadgets/src/sinsemilla_opt/merkle.rs b/halo2_gadgets/src/sinsemilla_opt/merkle.rs deleted file mode 100644 index 3983e42659..0000000000 --- a/halo2_gadgets/src/sinsemilla_opt/merkle.rs +++ /dev/null @@ -1,246 +0,0 @@ -//! Gadgets for implementing a Merkle tree with Sinsemilla. - -pub mod chip; - -#[cfg(test)] -pub mod tests { - - use crate::{ - ecc::tests::TestFixedBases, - sinsemilla::{ - tests::{TestCommitDomain, TestHashDomain}, - HashDomains, - }, - utilities::{i2lebsp, UtilitiesInstructions}, - }; - - use group::ff::{Field, PrimeField, PrimeFieldBits}; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::MockProver, - pasta::pallas, - plonk::{Circuit, ConstraintSystem, Error}, - }; - - use crate::sinsemilla::merkle::chip::MerkleConfig; - use crate::sinsemilla::merkle::MerklePath; - use crate::sinsemilla_opt::chip::SinsemillaChipOptimized; - use crate::sinsemilla_opt::merkle::chip::MerkleChipOptimized; - use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; - use rand::{rngs::OsRng, RngCore}; - use std::{convert::TryInto, iter}; - - const MERKLE_DEPTH: usize = 32; - - #[derive(Default)] - struct MyCircuit { - leaf: Value, - leaf_pos: Value, - merkle_path: Value<[pallas::Base; MERKLE_DEPTH]>, - } - - impl Circuit for MyCircuit { - type Config = ( - MerkleConfig< - TestHashDomain, - TestCommitDomain, - TestFixedBases, - LookupRangeCheckConfigOptimized, - >, - MerkleConfig< - TestHashDomain, - TestCommitDomain, - TestFixedBases, - LookupRangeCheckConfigOptimized, - >, - ); - 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(), - ]; - - // Shared fixed column for loading constants - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - // NB: In the actual Action circuit, these fixed columns will be reused - // by other chips. For this test, we are creating new fixed columns. - let fixed_y_q_1 = meta.fixed_column(); - let fixed_y_q_2 = meta.fixed_column(); - - // Fixed columns for the Sinsemilla generator lookup table - let lookup = ( - meta.lookup_table_column(), - meta.lookup_table_column(), - meta.lookup_table_column(), - ); - let table_range_check_tag = meta.lookup_table_column(); - - let range_check = LookupRangeCheckConfigOptimized::configure_with_tag( - meta, - advices[9], - lookup.0, - table_range_check_tag, - ); - - let sinsemilla_config_1 = SinsemillaChipOptimized::configure( - meta, - advices[5..].try_into().unwrap(), - advices[7], - fixed_y_q_1, - lookup, - range_check, - ); - let config1 = MerkleChipOptimized::configure(meta, sinsemilla_config_1); - - let sinsemilla_config_2 = SinsemillaChipOptimized::configure( - meta, - advices[..5].try_into().unwrap(), - advices[2], - fixed_y_q_2, - lookup, - range_check, - ); - let config2 = MerkleChipOptimized::configure(meta, sinsemilla_config_2); - - (config1, config2) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // Load generator table (shared across both configs) for SinsemillaChipOptimized - SinsemillaChipOptimized::::load( - config.0.sinsemilla_config.clone(), - &mut layouter, - )?; - - // Construct Merkle chips which will be placed side-by-side in the circuit. - let chip_1 = MerkleChipOptimized::construct(config.0.clone()); - let chip_2 = MerkleChipOptimized::construct(config.1.clone()); - - let leaf = chip_1.load_private( - layouter.namespace(|| ""), - config.0.cond_swap_config.a(), - self.leaf, - )?; - - let path = MerklePath { - chips: [chip_1, chip_2], - domain: TestHashDomain, - leaf_pos: self.leaf_pos, - path: self.merkle_path, - }; - - let computed_final_root = - path.calculate_root(layouter.namespace(|| "calculate root"), leaf)?; - - self.leaf - .zip(self.leaf_pos) - .zip(self.merkle_path) - .zip(computed_final_root.value()) - .assert_if_known(|(((leaf, leaf_pos), merkle_path), computed_final_root)| { - // The expected final root - let final_root = - merkle_path - .iter() - .enumerate() - .fold(*leaf, |node, (l, sibling)| { - let l = l as u8; - let (left, right) = if leaf_pos & (1 << l) == 0 { - (&node, sibling) - } else { - (sibling, &node) - }; - - use crate::sinsemilla::primitives as sinsemilla; - let merkle_crh = - sinsemilla::HashDomain::from_Q(TestHashDomain.Q().into()); - - merkle_crh - .hash( - iter::empty() - .chain(i2lebsp::<10>(l as u64).iter().copied()) - .chain( - left.to_le_bits() - .iter() - .by_vals() - .take(pallas::Base::NUM_BITS as usize), - ) - .chain( - right - .to_le_bits() - .iter() - .by_vals() - .take(pallas::Base::NUM_BITS as usize), - ), - ) - .unwrap_or(pallas::Base::zero()) - }); - - // Check the computed final root against the expected final root. - computed_final_root == &&final_root - }); - - Ok(()) - } - } - - #[test] - fn merkle_chip() { - let mut rng = OsRng; - - // Choose a random leaf and position - let leaf = pallas::Base::random(rng); - let pos = rng.next_u32(); - - // Choose a path of random inner nodes - let path: Vec<_> = (0..(MERKLE_DEPTH)) - .map(|_| pallas::Base::random(rng)) - .collect(); - - // The root is provided as a public input in the Orchard circuit. - - let circuit = MyCircuit { - leaf: Value::known(leaf), - leaf_pos: Value::known(pos), - merkle_path: Value::known(path.try_into().unwrap()), - }; - - let prover = MockProver::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())) - } - - #[cfg(feature = "test-dev-graph")] - #[test] - fn print_merkle_chip() { - use plotters::prelude::*; - - let root = BitMapBackend::new("merkle-path-layout.png", (1024, 7680)).into_drawing_area(); - root.fill(&WHITE).unwrap(); - let root = root.titled("MerkleCRH Path", ("sans-serif", 60)).unwrap(); - - let circuit = MyCircuit::default(); - halo2_proofs::dev::CircuitLayout::default() - .show_labels(false) - .render(11, &circuit, &root) - .unwrap(); - } -} diff --git a/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs b/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs deleted file mode 100644 index b11cf6b57e..0000000000 --- a/halo2_gadgets/src/sinsemilla_opt/merkle/chip.rs +++ /dev/null @@ -1,209 +0,0 @@ -//! Chip implementing a Merkle hash using Sinsemilla as the hash function. - -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Layouter, Value}, - plonk::{ConstraintSystem, Error}, -}; -use pasta_curves::pallas; - -use crate::{ - sinsemilla::{ - merkle::chip::{MerkleChip, MerkleConfig, MerkleSinsemillaInstructions}, - primitives as sinsemilla, - }, - sinsemilla_opt::chip::SinsemillaChipOptimized, - utilities_opt::lookup_range_check::DefaultLookupRangeCheckConfigOptimized, - { - ecc::FixedPoints, - sinsemilla::{chip::SinsemillaConfig, CommitDomains, HashDomains, SinsemillaInstructions}, - utilities::{cond_swap::CondSwapInstructions, UtilitiesInstructions}, - }, -}; - -/// Chip implementing `MerkleInstructions`. -/// -/// This chip specifically implements `MerkleInstructions::hash_layer` as the `MerkleCRH` -/// function `hash = SinsemillaHash(Q, 𝑙⋆ || left⋆ || right⋆)`, where: -/// - `𝑙⋆ = I2LEBSP_10(l)` -/// - `left⋆ = I2LEBSP_255(left)` -/// - `right⋆ = I2LEBSP_255(right)` -/// -/// This chip does **NOT** constrain `left⋆` and `right⋆` to be canonical encodings of -/// `left` and `right`. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MerkleChipOptimized -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, -{ - base: MerkleChip, -} - -impl Chip for MerkleChipOptimized -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, -{ - type Config = MerkleConfig; - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.base.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -impl MerkleChipOptimized -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - /// Configures the [`MerkleChip`]. - pub fn configure( - meta: &mut ConstraintSystem, - sinsemilla_config: SinsemillaConfig< - Hash, - Commit, - F, - DefaultLookupRangeCheckConfigOptimized, - >, - ) -> MerkleConfig { - MerkleChip::configure(meta, sinsemilla_config) - } - - /// Constructs a [`MerkleChip`] given a [`MerkleConfig`]. - pub fn construct( - config: MerkleConfig, - ) -> Self { - MerkleChipOptimized { - base: MerkleChip { config }, - } - } -} - -impl - MerkleSinsemillaInstructions - for MerkleChipOptimized -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ -} - -impl UtilitiesInstructions for MerkleChipOptimized -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - type Var = AssignedCell; -} - -impl CondSwapInstructions for MerkleChipOptimized -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - #[allow(clippy::type_complexity)] - fn swap( - &self, - layouter: impl Layouter, - pair: (Self::Var, Value), - swap: Value, - ) -> Result<(Self::Var, Self::Var), Error> { - self.base.swap(layouter, pair, swap) - } -} - -impl SinsemillaInstructions - for MerkleChipOptimized -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - type CellValue = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::CellValue; - - type Message = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::Message; - type MessagePiece = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::MessagePiece; - type RunningSum = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::RunningSum; - - type X = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::X; - type NonIdentityPoint = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::NonIdentityPoint; - type FixedPoints = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::FixedPoints; - - type HashDomains = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::HashDomains; - type CommitDomains = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::CommitDomains; - - fn witness_message_piece( - &self, - layouter: impl Layouter, - value: Value, - num_words: usize, - ) -> Result { - let config = self.config().sinsemilla_config.clone(); - let chip = SinsemillaChipOptimized::::construct(config); - chip.witness_message_piece(layouter, value, num_words) - } - - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - fn hash_to_point( - &self, - layouter: impl Layouter, - Q: pallas::Affine, - message: Self::Message, - ) -> Result<(Self::NonIdentityPoint, Vec>), Error> { - let config = self.config().sinsemilla_config.clone(); - let chip = SinsemillaChipOptimized::::construct(config); - chip.hash_to_point(layouter, Q, message) - } - - fn extract(point: &Self::NonIdentityPoint) -> Self::X { - SinsemillaChipOptimized::::extract(point) - } -} diff --git a/halo2_gadgets/src/sinsemilla_opt/primitives.rs b/halo2_gadgets/src/sinsemilla_opt/primitives.rs deleted file mode 100644 index dd2930d6d2..0000000000 --- a/halo2_gadgets/src/sinsemilla_opt/primitives.rs +++ /dev/null @@ -1,74 +0,0 @@ -//! Implementation of Sinsemilla outside the circuit. - -use group::Wnaf; -use halo2_proofs::arithmetic::CurveExt; -use pasta_curves::pallas; -use subtle::CtOption; - -use crate::sinsemilla::primitives::{CommitDomain, HashDomain}; - -impl CommitDomain { - /// Constructs a new `CommitDomain` from different values for `hash_domain` and `blind_domain` - pub fn new_with_personalization(hash_domain: &str, blind_domain: &str) -> Self { - let m_prefix = format!("{}-M", hash_domain); - let r_prefix = format!("{}-r", blind_domain); - let hasher_r = pallas::Point::hash_to_curve(&r_prefix); - CommitDomain { - M: HashDomain::new(&m_prefix), - R: hasher_r(&[]), - } - } - - /// $\mathsf{SinsemillaHashToPoint}$ from [§ 5.4.1.9][concretesinsemillahash]. - /// - /// [concretesinsemillahash]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillahash - pub fn hash_to_point(&self, msg: impl Iterator) -> CtOption { - self.M.hash_to_point(msg) - } - - /// Returns `SinsemillaCommit_r(personalization, msg) = hash_point + [r]R` - /// where `SinsemillaHash(personalization, msg) = hash_point` - /// and `R` is derived from the `personalization`. - #[allow(non_snake_case)] - pub fn commit_from_hash_point( - &self, - hash_point: CtOption, - r: &pallas::Scalar, - ) -> CtOption { - // We use complete addition for the blinding factor. - hash_point.map(|p| p + Wnaf::new().scalar(r).base(self.R)) - } -} - -#[cfg(test)] -mod tests { - use pasta_curves::pallas; - - #[test] - fn commit_in_several_steps() { - use rand::{rngs::OsRng, Rng}; - - use ff::Field; - - use crate::sinsemilla::primitives::CommitDomain; - - let domain = CommitDomain::new("z.cash:ZSA-NoteCommit"); - - let mut os_rng = OsRng::default(); - let msg: Vec = (0..36).map(|_| os_rng.gen::()).collect(); - - let rcm = pallas::Scalar::random(&mut os_rng); - - // Evaluate the commitment with commit function - let commit1 = domain.commit(msg.clone().into_iter(), &rcm); - - // Evaluate the commitment with the following steps - // 1. hash msg - // 2. evaluate the commitment from the hash point - let hash_point = domain.M.hash_to_point(msg.into_iter()); - let commit2 = domain.commit_from_hash_point(hash_point, &rcm); - - // Test equality - assert_eq!(commit1.unwrap(), commit2.unwrap()); - } -} diff --git a/halo2_gadgets/src/utilities_opt.rs b/halo2_gadgets/src/utilities_opt.rs deleted file mode 100644 index ddd75ce739..0000000000 --- a/halo2_gadgets/src/utilities_opt.rs +++ /dev/null @@ -1,4 +0,0 @@ -//! Utility gadgets. - -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 deleted file mode 100644 index eae0b148fd..0000000000 --- a/halo2_gadgets/src/utilities_opt/cond_swap.rs +++ /dev/null @@ -1,352 +0,0 @@ -//! Gadget and chip for a conditional swap utility. - -use group::ff::{Field, PrimeField}; -use pasta_curves::pallas; - -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Layouter}, - plonk::{self, Error}, -}; - -use crate::ecc::chip::{EccPoint, NonIdentityEccPoint}; - -use crate::utilities::cond_swap::{CondSwapChip, CondSwapInstructions}; - -/// Instructions for a conditional swap gadget. -pub trait CondSwapInstructionsOptimized: CondSwapInstructions { - /// Given an input `(choice, left, right)` where `choice` is a boolean flag, - /// returns `left` if `choice` is not set and `right` if `choice` is set. - fn mux( - &self, - layouter: &mut impl Layouter, - choice: Self::Var, - left: Self::Var, - right: Self::Var, - ) -> Result; -} - -impl CondSwapInstructionsOptimized for CondSwapChip { - fn mux( - &self, - layouter: &mut impl Layouter, - choice: Self::Var, - left: Self::Var, - right: Self::Var, - ) -> Result { - let config = self.config(); - - layouter.assign_region( - || "mux", - |mut region| { - // Enable `q_swap` selector - config.q_swap.enable(&mut region, 0)?; - - // Copy in `a` value - let left = left.copy_advice(|| "copy left", &mut region, config.a, 0)?; - - // Copy in `b` value - let right = right.copy_advice(|| "copy right", &mut region, config.b, 0)?; - - // Copy `choice` value - let choice = choice.copy_advice(|| "copy choice", &mut region, config.swap, 0)?; - - let a_swapped = left - .value() - .zip(right.value()) - .zip(choice.value()) - .map(|((left, right), choice)| { - if *choice == F::from(0_u64) { - left - } else { - right - } - }) - .cloned(); - let b_swapped = left - .value() - .zip(right.value()) - .zip(choice.value()) - .map(|((left, right), choice)| { - if *choice == F::from(0_u64) { - right - } else { - left - } - }) - .cloned(); - - region.assign_advice(|| "out b_swap", self.config.b_swapped, 0, || b_swapped)?; - region.assign_advice(|| "out a_swap", self.config.a_swapped, 0, || a_swapped) - }, - ) - } -} - -impl CondSwapChip { - /// Given an input `(choice, left, right)` where `choice` is a boolean flag and `left` and `right` are `EccPoint`, - /// returns `left` if `choice` is not set and `right` if `choice` is set. - pub fn mux_on_points( - &self, - mut layouter: impl Layouter, - choice: &AssignedCell, - left: &EccPoint, - right: &EccPoint, - ) -> Result { - let x_cell = self.mux(&mut layouter, choice.clone(), left.x(), right.x())?; - let y_cell = self.mux(&mut layouter, choice.clone(), left.y(), right.y())?; - Ok(EccPoint::from_coordinates_unchecked( - x_cell.into(), - y_cell.into(), - )) - } - - /// Given an input `(choice, left, right)` where `choice` is a boolean flag and `left` and `right` are - /// `NonIdentityEccPoint`, returns `left` if `choice` is not set and `right` if `choice` is set. - pub fn mux_on_non_identity_points( - &self, - mut layouter: impl Layouter, - choice: &AssignedCell, - left: &NonIdentityEccPoint, - right: &NonIdentityEccPoint, - ) -> Result { - let x_cell = self.mux(&mut layouter, choice.clone(), left.x(), right.x())?; - let y_cell = self.mux(&mut layouter, choice.clone(), left.y(), right.y())?; - Ok(NonIdentityEccPoint::from_coordinates_unchecked( - x_cell.into(), - y_cell.into(), - )) - } -} - -#[cfg(test)] -mod tests { - use crate::utilities::cond_swap::{CondSwapChip, CondSwapConfig}; - use crate::utilities_opt::lookup_range_check::LookupRangeCheckConfigOptimized; - - #[test] - fn test_mux() { - use crate::{ - ecc::{ - chip::{EccChip, EccConfig}, - tests::TestFixedBases, - NonIdentityPoint, Point, - }, - utilities::lookup_range_check::LookupRangeCheck, - }; - - 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< - TestFixedBases, - LookupRangeCheckConfigOptimized, - >, - } - - #[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 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::< - TestFixedBases, - LookupRangeCheckConfigOptimized< - pallas::Base, - { crate::sinsemilla::primitives::K }, - >, - >::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(())); - } - } -} diff --git a/halo2_gadgets/src/utilities_opt/lookup_range_check.rs b/halo2_gadgets/src/utilities_opt/lookup_range_check.rs deleted file mode 100644 index e2c1a808a9..0000000000 --- a/halo2_gadgets/src/utilities_opt/lookup_range_check.rs +++ /dev/null @@ -1,566 +0,0 @@ -//! Make use of a K-bit lookup table to decompose a field element into K-bit -//! words. - -use std::marker::PhantomData; - -use halo2_proofs::{ - circuit::{AssignedCell, Region}, - plonk::{ - Advice, Column, ConstraintSystem, Constraints, Error, Expression, Selector, TableColumn, - }, - poly::Rotation, -}; - -#[cfg(test)] -use halo2_proofs::circuit::{Layouter, Value}; - -use ff::PrimeFieldBits; - -use pasta_curves::pallas; - -use crate::{ - sinsemilla::primitives as sinsemilla, - utilities::lookup_range_check::{ - DefaultLookupRangeCheck, LookupRangeCheck, LookupRangeCheckConfig, - }, -}; - -/// Configuration that provides methods for a lookup range check. -#[derive(Eq, PartialEq, Debug, Clone, Copy)] -pub struct LookupRangeCheckConfigOptimized { - base: LookupRangeCheckConfig, - q_range_check_4: Selector, - q_range_check_5: Selector, - table_range_check_tag: TableColumn, -} - -impl LookupRangeCheckConfigOptimized { - /// 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. - pub(crate) fn configure_with_tag( - meta: &mut ConstraintSystem, - running_sum: Column, - table_idx: TableColumn, - table_range_check_tag: TableColumn, - ) -> Self { - meta.enable_equality(running_sum); - - let q_lookup = meta.complex_selector(); - let q_running = meta.complex_selector(); - let q_bitshift = meta.selector(); - - let q_range_check_4 = meta.complex_selector(); - let q_range_check_5 = meta.complex_selector(); - - // if the order of the creation makes a difference - let config = LookupRangeCheckConfigOptimized { - base: LookupRangeCheckConfig { - q_lookup, - q_running, - q_bitshift, - running_sum, - table_idx, - _marker: PhantomData, - }, - q_range_check_4, - q_range_check_5, - table_range_check_tag, - }; - - // https://p.z.cash/halo2-0.1:decompose-combined-lookup - meta.lookup(|meta| { - let q_lookup = meta.query_selector(config.base.q_lookup); - let q_running = meta.query_selector(config.base.q_running); - // if the order of the creation makes a difference - let z_cur = meta.query_advice(config.base.running_sum, Rotation::cur()); - let one = Expression::Constant(F::ONE); - - // In the case of a running sum decomposition, we recover the word from - // the difference of the running sums: - // z_i = 2^{K}⋅z_{i + 1} + a_i - // => a_i = z_i - 2^{K}⋅z_{i + 1} - let running_sum_lookup = { - let running_sum_word = { - let z_next = meta.query_advice(config.base.running_sum, Rotation::next()); - z_cur.clone() - z_next * F::from(1 << K) - }; - - q_running.clone() * running_sum_word - }; - - // In the short range check, the word is directly witnessed. - let short_lookup = { - let short_word = z_cur.clone(); - let q_short = one.clone() - q_running; - - q_short * short_word - }; - - let q_range_check_4 = meta.query_selector(config.q_range_check_4); - let q_range_check_5 = meta.query_selector(config.q_range_check_5); - - // q_range_check is equal to - // - 1 if q_range_check_4 = 1 or q_range_check_5 = 1 - // - 0 otherwise - let q_range_check = one.clone() - - (one.clone() - q_range_check_4.clone()) * (one.clone() - q_range_check_5.clone()); - - // num_bits is equal to - // - 5 if q_range_check_5 = 1 - // - 4 if q_range_check_4 = 1 and q_range_check_5 = 0 - // - 0 otherwise - let num_bits = q_range_check_5.clone() * Expression::Constant(F::from(5_u64)) - + (one.clone() - q_range_check_5) - * q_range_check_4 - * Expression::Constant(F::from(4_u64)); - - // Combine the running sum, short lookups and optimized range checks: - vec![ - ( - q_lookup.clone() - * ((one - q_range_check.clone()) * (running_sum_lookup + short_lookup) - + q_range_check.clone() * z_cur), - config.base.table_idx, - ), - ( - q_lookup * q_range_check * num_bits, - config.table_range_check_tag, - ), - ] - }); - - // For short lookups, check that the word has been shifted by the correct number of bits. - // https://p.z.cash/halo2-0.1:decompose-short-lookup - meta.create_gate("Short lookup bitshift", |meta| { - let q_bitshift = meta.query_selector(config.base.q_bitshift); - let word = meta.query_advice(config.base.running_sum, Rotation::prev()); - let shifted_word = meta.query_advice(config.base.running_sum, Rotation::cur()); - let inv_two_pow_s = meta.query_advice(config.base.running_sum, Rotation::next()); - - let two_pow_k = F::from(1 << K); - - // shifted_word = word * 2^{K-s} - // = word * 2^K * inv_two_pow_s - Constraints::with_selector( - q_bitshift, - Some(word * two_pow_k * inv_two_pow_s - shifted_word), - ) - }); - - config - } - - pub(crate) fn table_range_check_tag(&self) -> TableColumn { - self.table_range_check_tag - } -} - -impl LookupRangeCheck - for LookupRangeCheckConfigOptimized -{ - fn config(&self) -> &LookupRangeCheckConfig { - &self.base - } - - fn configure( - meta: &mut ConstraintSystem, - running_sum: Column, - table_idx: TableColumn, - ) -> Self { - let table_range_check_tag = meta.lookup_table_column(); - Self::configure_with_tag(meta, running_sum, table_idx, table_range_check_tag) - } - - #[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> { - layouter.assign_table( - || "table_idx", - |mut table| { - let mut assign_cells = - |offset: usize, table_size, value: u64| -> Result { - for index in 0..table_size { - let new_index = index + offset; - table.assign_cell( - || "table_idx", - self.base.table_idx, - new_index, - || Value::known(F::from(index as u64)), - )?; - table.assign_cell( - || "table_range_check_tag", - self.table_range_check_tag, - new_index, - || Value::known(F::from(value)), - )?; - } - Ok(offset + table_size) - }; - - // We generate the row values lazily (we only need them during keygen). - let mut offset = 0; - - //annotation: &'v (dyn Fn() -> String + 'v), - //column: TableColumn, - //offset: usize, - //to: &'v mut (dyn FnMut() -> Value> + 'v), - - offset = assign_cells(offset, 1 << K, 0)?; - offset = assign_cells(offset, 1 << 4, 4)?; - assign_cells(offset, 1 << 5, 5)?; - - Ok(()) - }, - ) - } - - /// Constrain `x` to be a NUM_BITS word. - /// - /// `element` must have been assigned to `self.running_sum` at offset 0. - fn short_range_check( - &self, - region: &mut Region<'_, F>, - element: AssignedCell, - num_bits: usize, - ) -> Result<(), Error> { - match num_bits { - 4 => { - self.base.q_lookup.enable(region, 0)?; - self.q_range_check_4.enable(region, 0)?; - Ok(()) - } - - 5 => { - self.base.q_lookup.enable(region, 0)?; - self.q_range_check_5.enable(region, 0)?; - Ok(()) - } - - _ => self.base.short_range_check(region, element, num_bits), - } - } -} - -#[cfg(test)] -mod tests { - use super::{LookupRangeCheck, LookupRangeCheckConfigOptimized}; - - use crate::sinsemilla::primitives::K; - use crate::utilities::lebs2ip; - - use ff::{Field, PrimeFieldBits}; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::{FailureLocation, MockProver, VerifyFailure}, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use pasta_curves::pallas; - - use std::{convert::TryInto, marker::PhantomData}; - - #[test] - fn lookup_range_check() { - #[derive(Clone, Copy)] - struct MyCircuit { - num_words: usize, - _marker: PhantomData, - } - - impl Circuit for MyCircuit { - type Config = LookupRangeCheckConfigOptimized; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - *self - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let running_sum = meta.advice_column(); - let table_idx = meta.lookup_table_column(); - let table_range_check_tag = meta.lookup_table_column(); - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - LookupRangeCheckConfigOptimized::::configure_with_tag( - meta, - running_sum, - table_idx, - table_range_check_tag, - ) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // Load table_idx - config.load(&mut layouter)?; - - // Lookup constraining element to be no longer than num_words * K bits. - let elements_and_expected_final_zs = [ - (F::from((1 << (self.num_words * K)) - 1), F::ZERO, true), // a word that is within self.num_words * K bits long - (F::from(1 << (self.num_words * K)), F::ONE, false), // a word that is just over self.num_words * K bits long - ]; - - fn expected_zs( - element: F, - num_words: usize, - ) -> Vec { - let chunks = { - element - .to_le_bits() - .iter() - .by_vals() - .take(num_words * K) - .collect::>() - .chunks_exact(K) - .map(|chunk| F::from(lebs2ip::(chunk.try_into().unwrap()))) - .collect::>() - }; - let expected_zs = { - let inv_two_pow_k = F::from(1 << K).invert().unwrap(); - chunks.iter().fold(vec![element], |mut zs, a_i| { - // z_{i + 1} = (z_i - a_i) / 2^{K} - let z = (zs[zs.len() - 1] - a_i) * inv_two_pow_k; - zs.push(z); - zs - }) - }; - expected_zs - } - - for (element, expected_final_z, strict) in elements_and_expected_final_zs.iter() { - let expected_zs = expected_zs::(*element, self.num_words); - - let zs = config.witness_check( - layouter.namespace(|| format!("Lookup {:?}", self.num_words)), - Value::known(*element), - self.num_words, - *strict, - )?; - - assert_eq!(*expected_zs.last().unwrap(), *expected_final_z); - - for (expected_z, z) in expected_zs.into_iter().zip(zs.iter()) { - z.value().assert_if_known(|z| &&expected_z == z); - } - } - Ok(()) - } - } - - { - let circuit: MyCircuit = MyCircuit { - num_words: 6, - _marker: PhantomData, - }; - - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - } - - #[test] - fn short_range_check() { - struct MyCircuit { - element: Value, - num_bits: usize, - } - - impl Circuit for MyCircuit { - type Config = LookupRangeCheckConfigOptimized; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - MyCircuit { - element: Value::unknown(), - num_bits: self.num_bits, - } - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let running_sum = meta.advice_column(); - let table_idx = meta.lookup_table_column(); - let table_range_check_tag = meta.lookup_table_column(); - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - LookupRangeCheckConfigOptimized::::configure_with_tag( - meta, - running_sum, - table_idx, - table_range_check_tag, - ) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // Load table_idx - config.load(&mut layouter)?; - - // Lookup constraining element to be no longer than num_bits. - config.witness_short_check( - layouter.namespace(|| format!("Lookup {:?} bits", self.num_bits)), - self.element, - self.num_bits, - )?; - - Ok(()) - } - } - - // Edge case: zero bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::ZERO), - num_bits: 0, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - // Edge case: K bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from((1 << K) - 1)), - num_bits: K, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - // Element within `num_bits` - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from((1 << 6) - 1)), - num_bits: 6, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - // Element larger than `num_bits` but within K bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from(1 << 6)), - num_bits: 6, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![VerifyFailure::Lookup { - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 1, - }, - }]) - ); - } - - // Element larger than K bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from(1 << K)), - num_bits: 6, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![ - VerifyFailure::Lookup { - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 0, - }, - }, - VerifyFailure::Lookup { - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 1, - }, - }, - ]) - ); - } - - // Element which is not within `num_bits`, but which has a shifted value within - // num_bits - { - let num_bits = 6; - let shifted = pallas::Base::from((1 << num_bits) - 1); - // Recall that shifted = element * 2^{K-s} - // => element = shifted * 2^{s-K} - let element = shifted - * pallas::Base::from(1 << (K as u64 - num_bits)) - .invert() - .unwrap(); - let circuit: MyCircuit = MyCircuit { - element: Value::known(element), - num_bits: num_bits as usize, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![VerifyFailure::Lookup { - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 0, - }, - }]) - ); - } - - // Element within 4 bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from((1 << 4) - 1)), - num_bits: 4, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - // Element larger than 5 bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from(1 << 5)), - num_bits: 5, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![VerifyFailure::Lookup { - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 5 bits").into(), - offset: 0, - }, - }]) - ); - } - } -} - -pub(crate) type DefaultLookupRangeCheckConfigOptimized = - LookupRangeCheckConfigOptimized; - -impl DefaultLookupRangeCheck for DefaultLookupRangeCheckConfigOptimized {} From 7e50d0b72c75991a04820373db5730c0556371ab Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Fri, 10 May 2024 15:30:36 +0200 Subject: [PATCH 36/99] minor update --- halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 8818147f41..5d7b6081d9 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -19,6 +19,7 @@ use std::ops::Deref; /// Define an enum that can hold either type #[derive(Debug, Clone)] +#[allow(dead_code)] pub enum EccPointQ<'a> { PublicPoint(pallas::Affine), PrivatePoint(&'a NonIdentityEccPoint), From 58f8b3f5c387a440fb05fb6d529c27208ee54092 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 13 May 2024 13:34:49 +0200 Subject: [PATCH 37/99] remove pub(crate) in ecc --- halo2_gadgets/src/ecc.rs | 6 +++--- halo2_gadgets/src/ecc/chip.rs | 20 +++++++++---------- halo2_gadgets/src/ecc/chip/mul.rs | 5 +++-- halo2_gadgets/src/ecc/chip/mul_fixed.rs | 6 +++--- halo2_gadgets/src/ecc/chip/mul_fixed/short.rs | 6 ++---- halo2_gadgets/src/ecc/chip/witness_point.rs | 4 ++-- 6 files changed, 23 insertions(+), 24 deletions(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 8cb9ce4d57..2e16b3d1a6 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -231,7 +231,7 @@ impl> ScalarFixed { #[derive(Debug)] pub struct ScalarFixedShort> { chip: EccChip, - pub(crate) inner: EccChip::ScalarFixedShort, + inner: EccChip::ScalarFixedShort, } impl> ScalarFixedShort { @@ -375,8 +375,8 @@ impl + Clone + Debug + Eq> /// A point on a specific elliptic curve. #[derive(Copy, Clone, Debug)] pub struct Point + Clone + Debug + Eq> { - pub(crate) chip: EccChip, - pub(crate) inner: EccChip::Point, + chip: EccChip, + inner: EccChip::Point, } impl + Clone + Debug + Eq> Point { diff --git a/halo2_gadgets/src/ecc/chip.rs b/halo2_gadgets/src/ecc/chip.rs index c27a34ca6b..7133bdfd78 100644 --- a/halo2_gadgets/src/ecc/chip.rs +++ b/halo2_gadgets/src/ecc/chip.rs @@ -14,12 +14,12 @@ use pasta_curves::{arithmetic::CurveAffine, pallas}; use std::convert::TryInto; -pub(crate) mod add; -pub(crate) mod add_incomplete; +pub(super) mod add; +pub(super) mod add_incomplete; pub mod constants; -pub(crate) mod mul; -pub(crate) mod mul_fixed; -pub(crate) mod witness_point; +pub(super) mod mul; +pub(super) mod mul_fixed; +pub(super) mod witness_point; pub use constants::*; @@ -34,11 +34,11 @@ pub struct EccPoint { /// x-coordinate /// /// Stored as an `Assigned` to enable batching inversions. - pub(crate) x: AssignedCell, pallas::Base>, + x: AssignedCell, pallas::Base>, /// y-coordinate /// /// Stored as an `Assigned` to enable batching inversions. - pub(crate) y: AssignedCell, pallas::Base>, + y: AssignedCell, pallas::Base>, } impl EccPoint { @@ -153,12 +153,12 @@ pub struct EccConfig< /// Fixed-base full-width scalar multiplication mul_fixed_full: mul_fixed::full_width::Config, /// Fixed-base signed short scalar multiplication - pub(crate) mul_fixed_short: mul_fixed::short::Config, + mul_fixed_short: mul_fixed::short::Config, /// Fixed-base mul using a base field element as a scalar mul_fixed_base_field: mul_fixed::base_field_elem::Config, /// Witness point - pub(crate) witness_point: witness_point::Config, + witness_point: witness_point::Config, /// Lookup range check using 10-bit lookup table pub lookup_config: Lookup, @@ -345,7 +345,7 @@ pub struct EccScalarFixed { type MagnitudeCell = AssignedCell; // TODO: Make V an enum Sign { Positive, Negative } type SignCell = AssignedCell; -pub(crate) type MagnitudeSign = (MagnitudeCell, SignCell); +type MagnitudeSign = (MagnitudeCell, SignCell); /// A signed short scalar used for fixed-base scalar multiplication. /// A short scalar must have magnitude in the range [0..2^64), with diff --git a/halo2_gadgets/src/ecc/chip/mul.rs b/halo2_gadgets/src/ecc/chip/mul.rs index a67b77b0e8..02d2e2d805 100644 --- a/halo2_gadgets/src/ecc/chip/mul.rs +++ b/halo2_gadgets/src/ecc/chip/mul.rs @@ -62,7 +62,7 @@ pub struct Config { } impl Config { - pub(crate) fn configure( + pub(super) fn configure( meta: &mut ConstraintSystem, add_config: add::Config, lookup_config: Lookup, @@ -460,6 +460,7 @@ pub mod tests { ff::{Field, PrimeField}, Curve, }; + use halo2_proofs::circuit::Chip; use halo2_proofs::{ circuit::{Layouter, Value}, plonk::Error, @@ -483,7 +484,7 @@ pub mod tests { p: &NonIdentityPoint>, p_val: pallas::Affine, ) -> Result<(), Error> { - let column = chip.config.advices[0]; + let column = chip.config().advices[0]; fn constrain_equal_non_id< EccChip: EccInstructions + Clone + Eq + std::fmt::Debug, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed.rs b/halo2_gadgets/src/ecc/chip/mul_fixed.rs index 686cb6203e..d0781056b8 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed.rs @@ -41,11 +41,11 @@ pub struct Config> { fixed_z: Column, // Decomposition of an `n-1`-bit scalar into `k`-bit windows: // a = a_0 + 2^k(a_1) + 2^{2k}(a_2) + ... + 2^{(n-1)k}(a_{n-1}) - pub(crate) window: Column, + window: Column, // y-coordinate of accumulator (only used in the final row). - pub(crate) u: Column, + u: Column, // Configuration for `add` - pub(crate) add_config: add::Config, + add_config: add::Config, // Configuration for `add_incomplete` add_incomplete_config: add_incomplete::Config, _marker: PhantomData, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs index 48a1cbf88a..acbba7cc3a 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs @@ -13,8 +13,8 @@ use pasta_curves::pallas; #[derive(Clone, Debug, Eq, PartialEq)] pub struct Config> { // Selector used for fixed-base scalar mul with short signed exponent. - pub(crate) q_mul_fixed_short: Selector, - pub(crate) super_config: super::Config, + q_mul_fixed_short: Selector, + super_config: super::Config, } impl> Config { @@ -401,8 +401,6 @@ pub mod tests { Ok(()) } - // todo: fixit - #[test] fn invalid_magnitude_sign() { use crate::{ diff --git a/halo2_gadgets/src/ecc/chip/witness_point.rs b/halo2_gadgets/src/ecc/chip/witness_point.rs index 580a07ca1d..7cba8d6f87 100644 --- a/halo2_gadgets/src/ecc/chip/witness_point.rs +++ b/halo2_gadgets/src/ecc/chip/witness_point.rs @@ -12,14 +12,14 @@ use halo2_proofs::{ }; use pasta_curves::{arithmetic::CurveAffine, pallas}; -pub(crate) type Coordinates = ( +type Coordinates = ( AssignedCell, pallas::Base>, AssignedCell, pallas::Base>, ); #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct Config { - pub(crate) q_point: Selector, + q_point: Selector, q_point_non_id: Selector, // x-coordinate pub x: Column, From 738eabeb27a79af4a75b7b5fe0f538be982473f3 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 13 May 2024 13:45:39 +0200 Subject: [PATCH 38/99] add a line after cargo.toml --- halo2_gadgets/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/halo2_gadgets/Cargo.toml b/halo2_gadgets/Cargo.toml index 2021d77e25..09ab4efc84 100644 --- a/halo2_gadgets/Cargo.toml +++ b/halo2_gadgets/Cargo.toml @@ -82,4 +82,4 @@ harness = false [[bench]] name = "sha256" harness = false -required-features = ["unstable-sha256-gadget"] \ No newline at end of file +required-features = ["unstable-sha256-gadget"] From 0fb6dd4c1d05845d93feecf1d905ca620bfc24ff Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 13 May 2024 13:46:51 +0200 Subject: [PATCH 39/99] add a line after cargo.toml --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index c7ceac9436..8c33191917 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2280,4 +2280,4 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" dependencies = [ "simd-adler32", -] \ No newline at end of file +] From e2c9c30a5a50ac8473f08da3dc2859124b859529 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 13 May 2024 13:50:11 +0200 Subject: [PATCH 40/99] slide lines in base_field_elem --- halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs index 5ea0b38eef..c9861e24e9 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs @@ -463,10 +463,10 @@ pub mod tests { { let h = pallas::Base::from(H as u64); let scalar_fixed = "1333333333333333333333333333333333333333333333333333333333333333333333333333333333334" - .chars() - .fold(pallas::Base::zero(), |acc, c| { - acc * &h + &pallas::Base::from(c.to_digit(8).unwrap() as u64) - }); + .chars() + .fold(pallas::Base::zero(), |acc, c| { + acc * &h + &pallas::Base::from(c.to_digit(8).unwrap() as u64) + }); let result = { let scalar_fixed = chip.load_private( layouter.namespace(|| "mul with double"), From 5322c81bf61dc9e57bb48af2dd3bace81c6430b3 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 13 May 2024 13:51:11 +0200 Subject: [PATCH 41/99] slide lines in base_field_elem --- halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs index c9861e24e9..24f7114b4a 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs @@ -463,10 +463,10 @@ pub mod tests { { let h = pallas::Base::from(H as u64); let scalar_fixed = "1333333333333333333333333333333333333333333333333333333333333333333333333333333333334" - .chars() - .fold(pallas::Base::zero(), |acc, c| { - acc * &h + &pallas::Base::from(c.to_digit(8).unwrap() as u64) - }); + .chars() + .fold(pallas::Base::zero(), |acc, c| { + acc * &h + &pallas::Base::from(c.to_digit(8).unwrap() as u64) + }); let result = { let scalar_fixed = chip.load_private( layouter.namespace(|| "mul with double"), From 46773e3963d766030f88cd77056b2c6654f8fad3 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 13 May 2024 14:01:58 +0200 Subject: [PATCH 42/99] adjuct function orders for configure in sinsemilla/chip --- halo2_gadgets/src/sinsemilla.rs | 58 +++++---- halo2_gadgets/src/sinsemilla/chip.rs | 168 +++++++++++++-------------- 2 files changed, 112 insertions(+), 114 deletions(-) diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index e10e504013..8c5a4eaf37 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -15,7 +15,7 @@ use std::fmt::Debug; pub mod chip; pub mod merkle; -pub(crate) mod message; +mod message; pub mod primitives; /// The set of circuit instructions required to use the [`Sinsemilla`](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html) gadget. @@ -102,8 +102,8 @@ pub struct Message + Clone + Debug + Eq, { - pub(crate) chip: SinsemillaChip, - pub(crate) inner: SinsemillaChip::Message, + chip: SinsemillaChip, + inner: SinsemillaChip::Message, } impl @@ -112,7 +112,7 @@ where SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, { #![allow(dead_code)] - pub(crate) fn from_bitstring( + fn from_bitstring( chip: SinsemillaChip, mut layouter: impl Layouter, bitstring: Vec>, @@ -186,7 +186,7 @@ where SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, { #![allow(dead_code)] - pub(crate) fn from_bitstring( + fn from_bitstring( chip: SinsemillaChip, layouter: impl Layouter, bitstring: &[Value], @@ -276,23 +276,22 @@ pub struct HashDomain< > where SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, EccChip: EccInstructions< - C, - NonIdentityPoint = >::NonIdentityPoint, - FixedPoints = >::FixedPoints, - > + Clone - + Debug - + Eq, + C, + NonIdentityPoint = >::NonIdentityPoint, + FixedPoints = >::FixedPoints, + > + Clone + + Debug + + Eq, { - pub(crate) sinsemilla_chip: SinsemillaChip, - pub(crate) ecc_chip: EccChip, - pub(crate) Q: C, + sinsemilla_chip: SinsemillaChip, + ecc_chip: EccChip, + Q: C, } impl -HashDomain - where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, - EccChip: EccInstructions< + HashDomain where + SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, + EccChip: EccInstructions< C, NonIdentityPoint = >::NonIdentityPoint, FixedPoints = >::FixedPoints, @@ -376,22 +375,21 @@ pub struct CommitDomain< > where SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, EccChip: EccInstructions< - C, - NonIdentityPoint = >::NonIdentityPoint, - FixedPoints = >::FixedPoints, - > + Clone - + Debug - + Eq, + C, + NonIdentityPoint = >::NonIdentityPoint, + FixedPoints = >::FixedPoints, + > + Clone + + Debug + + Eq, { - pub(crate) M: HashDomain, - pub(crate) R: ecc::FixedPoint, + M: HashDomain, + R: ecc::FixedPoint, } impl -CommitDomain - where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, - EccChip: EccInstructions< + CommitDomain where + SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, + EccChip: EccInstructions< C, NonIdentityPoint = >::NonIdentityPoint, FixedPoints = >::FixedPoints, diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs index 7d96f2c8f3..419cea1609 100644 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ b/halo2_gadgets/src/sinsemilla/chip.rs @@ -23,10 +23,10 @@ use halo2_proofs::{ }; use pasta_curves::pallas; -pub(crate) mod generator_table; +mod generator_table; use generator_table::GeneratorTableConfig; -pub(crate) mod hash_to_point; +mod hash_to_point; /// Configuration for the Sinsemilla hash chip #[derive(Eq, PartialEq, Clone, Debug)] @@ -38,29 +38,29 @@ where Lookup: DefaultLookupRangeCheck, { /// Binary selector used in lookup argument and in the body of the Sinsemilla hash. - pub(crate) q_sinsemilla1: Selector, + q_sinsemilla1: Selector, /// Non-binary selector used in lookup argument and in the body of the Sinsemilla hash. - pub(crate) q_sinsemilla2: Column, + q_sinsemilla2: Column, /// q_sinsemilla2 is used to define a synthetic selector, /// q_sinsemilla3 = (q_sinsemilla2) ⋅ (q_sinsemilla2 - 1) /// Simple selector used to constrain hash initialization to be consistent with /// the y-coordinate of the domain $Q$. - pub(crate) q_sinsemilla4: Selector, + q_sinsemilla4: Selector, /// Fixed column used to load the y-coordinate of the domain $Q$. - pub(crate) fixed_y_q: Column, + fixed_y_q: Column, /// Logic specific to merged double-and-add. - pub(crate) double_and_add: DoubleAndAdd, + double_and_add: DoubleAndAdd, /// Advice column used to load the message. - pub(crate) bits: Column, + bits: Column, /// Advice column used to witness message pieces. This may or may not be the same /// column as `bits`. - pub(crate) witness_pieces: Column, + witness_pieces: Column, /// The lookup table where $(\mathsf{idx}, x_p, y_p)$ are loaded for the $2^K$ /// generators of the Sinsemilla hash. - pub(crate) generator_table: GeneratorTableConfig, + pub(super) generator_table: GeneratorTableConfig, /// An advice column configured to perform lookup range checks. - pub(crate) lookup_config: Lookup, - pub(crate) _marker: PhantomData<(Hash, Commit, F)>, + lookup_config: Lookup, + _marker: PhantomData<(Hash, Commit, F)>, } impl SinsemillaConfig @@ -149,8 +149,79 @@ 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)] + pub fn configure( + meta: &mut ConstraintSystem, + advices: [Column; 5], + witness_pieces: Column, + fixed_y_q: Column, + lookup: (TableColumn, TableColumn, TableColumn), + range_check: Lookup, + ) -> >::Config { + // create SinsemillaConfig + let config = Self::create_config( + meta, + advices, + witness_pieces, + fixed_y_q, + lookup, + range_check, + ); + + Self::create_initial_y_q_gate(meta, &config); + + Self::create_sinsemilla_gate(meta, &config); + + config + } + + pub(crate) fn create_config( + meta: &mut ConstraintSystem, + advices: [Column; 5], + witness_pieces: Column, + fixed_y_q: Column, + lookup: (TableColumn, TableColumn, TableColumn), + range_check: Lookup, + ) -> >::Config { + // Enable equality on all advice columns + for advice in advices.iter() { + meta.enable_equality(*advice); + } + + let config = SinsemillaConfig:: { + q_sinsemilla1: meta.complex_selector(), + q_sinsemilla2: meta.fixed_column(), + q_sinsemilla4: meta.selector(), + fixed_y_q, + double_and_add: DoubleAndAdd { + x_a: advices[0], + x_p: advices[1], + lambda_1: advices[3], + lambda_2: advices[4], + }, + bits: advices[2], + witness_pieces, + generator_table: GeneratorTableConfig { + table_idx: lookup.0, + table_x: lookup.1, + table_y: lookup.2, + }, + lookup_config: range_check, + _marker: PhantomData, + }; + + // Set up lookup argument + GeneratorTableConfig::configure(meta, &config); + + config + } + #[allow(non_snake_case)] - pub(crate) fn create_initial_y_q_gate( + fn create_initial_y_q_gate( meta: &mut ConstraintSystem, config: &SinsemillaConfig, ) { @@ -240,77 +311,6 @@ where Constraints::with_selector(q_s1, [("Secant line", secant_line), ("y check", y_check)]) }); } - - pub(crate) fn create_config( - meta: &mut ConstraintSystem, - advices: [Column; 5], - witness_pieces: Column, - fixed_y_q: Column, - lookup: (TableColumn, TableColumn, TableColumn), - range_check: Lookup, - ) -> >::Config { - // Enable equality on all advice columns - for advice in advices.iter() { - meta.enable_equality(*advice); - } - - let config = SinsemillaConfig:: { - q_sinsemilla1: meta.complex_selector(), - q_sinsemilla2: meta.fixed_column(), - q_sinsemilla4: meta.selector(), - fixed_y_q, - double_and_add: DoubleAndAdd { - x_a: advices[0], - x_p: advices[1], - lambda_1: advices[3], - lambda_2: advices[4], - }, - bits: advices[2], - witness_pieces, - generator_table: GeneratorTableConfig { - table_idx: lookup.0, - table_x: lookup.1, - table_y: lookup.2, - }, - lookup_config: range_check, - _marker: PhantomData, - }; - - // Set up lookup argument - GeneratorTableConfig::configure(meta, &config); - - config - } - - /// # Side-effects - /// - /// All columns in `advices` and will be equality-enabled. - #[allow(clippy::too_many_arguments)] - #[allow(non_snake_case)] - pub fn configure( - meta: &mut ConstraintSystem, - advices: [Column; 5], - witness_pieces: Column, - fixed_y_q: Column, - lookup: (TableColumn, TableColumn, TableColumn), - range_check: Lookup, - ) -> >::Config { - // create SinsemillaConfig - let config = Self::create_config( - meta, - advices, - witness_pieces, - fixed_y_q, - lookup, - range_check, - ); - - Self::create_initial_y_q_gate(meta, &config); - - Self::create_sinsemilla_gate(meta, &config); - - config - } } // Implement `SinsemillaInstructions` for `SinsemillaChip` From 3621e0e36768e56cf6ec3fb8f8fc1209b4a70995 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 13 May 2024 14:13:16 +0200 Subject: [PATCH 43/99] adjuct function orders for hash_message --- halo2_gadgets/src/sinsemilla/chip.rs | 2 +- .../src/sinsemilla/chip/generator_table.rs | 2 +- .../src/sinsemilla/chip/hash_to_point.rs | 136 +++++++++--------- 3 files changed, 70 insertions(+), 70 deletions(-) diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs index 419cea1609..95e40ec0f3 100644 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ b/halo2_gadgets/src/sinsemilla/chip.rs @@ -215,7 +215,7 @@ where }; // Set up lookup argument - GeneratorTableConfig::configure(meta, &config); + GeneratorTableConfig::configure(meta, config.clone()); config } diff --git a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs index 80551a6c91..41e2f42c99 100644 --- a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs +++ b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs @@ -28,7 +28,7 @@ impl GeneratorTableConfig { /// controlled by `q_sinsemilla`, and would likely not apply to other chips. pub fn configure( meta: &mut ConstraintSystem, - config: &super::SinsemillaConfig, + config: super::SinsemillaConfig, ) where Hash: HashDomains, F: FixedPoints, diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 5d7b6081d9..0c1bf9fa04 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -39,7 +39,7 @@ where /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). #[allow(non_snake_case)] #[allow(clippy::type_complexity)] - pub(crate) fn hash_message( + pub(super) fn hash_message( &self, region: &mut Region<'_, pallas::Base>, Q: pallas::Affine, @@ -56,73 +56,6 @@ where self.check_hash_result(EccPointQ::PublicPoint(Q), message, x_a, y_a, zs_sum) } - #[allow(non_snake_case)] - #[allow(unused_variables)] - // Check equivalence to result from primitives::sinsemilla::hash_to_point - pub(crate) fn check_hash_result( - &self, - Q: EccPointQ, - message: &>::Message, - x_a: X, - y_a: AssignedCell, pallas::Base>, - zs_sum: Vec>>, - ) -> HashResult { - #[cfg(test)] - { - use crate::sinsemilla::primitives::{K, S_PERSONALIZATION}; - - use group::{prime::PrimeCurveAffine, Curve}; - use pasta_curves::arithmetic::CurveExt; - - let field_elems: Value> = message - .iter() - .map(|piece| piece.field_elem().map(|elem| (elem, piece.num_words()))) - .collect(); - - let value_Q = match Q { - EccPointQ::PublicPoint(p) => Value::known(p), - EccPointQ::PrivatePoint(p) => p.point(), - }; - - field_elems - .zip(x_a.value().zip(y_a.value())) - .zip(value_Q) - .assert_if_known(|((field_elems, (x_a, y_a)), value_Q)| { - // Get message as a bitstring. - let bitstring: Vec = field_elems - .iter() - .flat_map(|(elem, num_words)| { - elem.to_le_bits().into_iter().take(K * num_words) - }) - .collect(); - - let hasher_S = pallas::Point::hash_to_curve(S_PERSONALIZATION); - let S = |chunk: &[bool]| hasher_S(&lebs2ip_k(chunk).to_le_bytes()); - - // We can use complete addition here because it differs from - // incomplete addition with negligible probability. - let expected_point = bitstring - .chunks(K) - .fold(value_Q.to_curve(), |acc, chunk| (acc + S(chunk)) + acc); - let actual_point = - pallas::Affine::from_xy(x_a.evaluate(), y_a.evaluate()).unwrap(); - expected_point.to_affine() == actual_point - }); - } - - 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, - )) - } - #[allow(non_snake_case)] /// Assign the coordinates of the initial public point `Q`, /// y_Q to a fixed column @@ -244,6 +177,73 @@ where Ok((x_a, y_a, zs_sum)) } + #[allow(non_snake_case)] + #[allow(unused_variables)] + // Check equivalence to result from primitives::sinsemilla::hash_to_point + pub(crate) fn check_hash_result( + &self, + Q: EccPointQ, + message: &>::Message, + x_a: X, + y_a: AssignedCell, pallas::Base>, + zs_sum: Vec>>, + ) -> HashResult { + #[cfg(test)] + { + use crate::sinsemilla::primitives::{K, S_PERSONALIZATION}; + + use group::{prime::PrimeCurveAffine, Curve}; + use pasta_curves::arithmetic::CurveExt; + + let field_elems: Value> = message + .iter() + .map(|piece| piece.field_elem().map(|elem| (elem, piece.num_words()))) + .collect(); + + let value_Q = match Q { + EccPointQ::PublicPoint(p) => Value::known(p), + EccPointQ::PrivatePoint(p) => p.point(), + }; + + field_elems + .zip(x_a.value().zip(y_a.value())) + .zip(value_Q) + .assert_if_known(|((field_elems, (x_a, y_a)), value_Q)| { + // Get message as a bitstring. + let bitstring: Vec = field_elems + .iter() + .flat_map(|(elem, num_words)| { + elem.to_le_bits().into_iter().take(K * num_words) + }) + .collect(); + + let hasher_S = pallas::Point::hash_to_curve(S_PERSONALIZATION); + let S = |chunk: &[bool]| hasher_S(&lebs2ip_k(chunk).to_le_bytes()); + + // We can use complete addition here because it differs from + // incomplete addition with negligible probability. + let expected_point = bitstring + .chunks(K) + .fold(value_Q.to_curve(), |acc, chunk| (acc + S(chunk)) + acc); + let actual_point = + pallas::Affine::from_xy(x_a.evaluate(), y_a.evaluate()).unwrap(); + expected_point.to_affine() == actual_point + }); + } + + 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, + )) + } + #[allow(clippy::type_complexity)] /// Hashes a message piece containing `piece.length` number of `K`-bit words. /// From a30596b0bab90c6c4fe52c552290b57158960838 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 13 May 2024 14:17:41 +0200 Subject: [PATCH 44/99] adjuct function orders for hash_message --- .../src/sinsemilla/chip/hash_to_point.rs | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 0c1bf9fa04..48a085e9b7 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -25,10 +25,6 @@ pub enum EccPointQ<'a> { PrivatePoint(&'a NonIdentityEccPoint), } -type HashOutput = NonIdentityEccPoint; -type CellMatrix = Vec>>; -type HashResult = Result<(HashOutput, CellMatrix), Error>; - impl SinsemillaChip where Hash: HashDomains, @@ -48,7 +44,13 @@ where { sinsemilla::K }, { sinsemilla::C }, >>::Message, - ) -> HashResult { + ) -> 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)?; @@ -177,9 +179,7 @@ where Ok((x_a, y_a, zs_sum)) } - #[allow(non_snake_case)] #[allow(unused_variables)] - // Check equivalence to result from primitives::sinsemilla::hash_to_point pub(crate) fn check_hash_result( &self, Q: EccPointQ, @@ -191,8 +191,16 @@ where x_a: X, y_a: AssignedCell, pallas::Base>, zs_sum: Vec>>, - ) -> HashResult { + ) -> Result< + ( + NonIdentityEccPoint, + Vec>>, + ), + Error, + > { #[cfg(test)] + #[allow(non_snake_case)] + // Check equivalence to result from primitives::sinsemilla::hash_to_point { use crate::sinsemilla::primitives::{K, S_PERSONALIZATION}; @@ -452,7 +460,7 @@ where } /// The x-coordinate of the accumulator in a Sinsemilla hash instance. -pub(crate) struct X(pub(crate) AssignedCell, F>); +struct X(AssignedCell, F>); impl From, F>> for X { fn from(cell_value: AssignedCell, F>) -> Self { @@ -473,7 +481,7 @@ impl Deref for X { /// This is never actually witnessed until the last round, since it /// can be derived from other variables. Thus it only exists as a field /// element, not a `CellValue`. -pub(crate) struct Y(pub(crate) Value>); +struct Y(Value>); impl From>> for Y { fn from(value: Value>) -> Self { From b3cb4531d6b6c73495cf615dc7628f5fc4d72589 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 13 May 2024 15:14:52 +0200 Subject: [PATCH 45/99] cleanup code --- halo2_gadgets/src/ecc.rs | 11 ++--- halo2_gadgets/src/sinsemilla.rs | 11 ++--- .../src/sinsemilla/chip/hash_to_point.rs | 9 ++-- halo2_gadgets/src/sinsemilla/merkle.rs | 21 +++++---- halo2_gadgets/src/sinsemilla/merkle/chip.rs | 10 ++--- halo2_gadgets/src/sinsemilla/primitives.rs | 6 +-- halo2_gadgets/src/utilities/cond_swap.rs | 14 +++--- .../src/utilities/lookup_range_check.rs | 43 ++++++++----------- halo2_gadgets/src/utilities/test_circuit.rs | 29 +++---------- halo2_proofs/src/circuit.rs | 10 ----- 10 files changed, 67 insertions(+), 97 deletions(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 2e16b3d1a6..4b7d0e291b 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -599,7 +599,7 @@ pub(crate) mod tests { FixedPoints, }; use crate::utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}; - use crate::utilities::test_circuit::{read_test_case, test_proof_size, write_test_case, Proof}; + use crate::utilities::test_circuit::{read_test_case, write_test_case, Proof}; #[derive(Debug, Eq, PartialEq, Clone)] pub(crate) struct TestFixedBases; @@ -912,7 +912,7 @@ pub(crate) mod tests { } #[test] - fn round_trip() { + fn fixed_verification_key_test() { let k = 11; let circuit = MyCircuit { test_errors: false }; @@ -929,7 +929,6 @@ pub(crate) mod tests { include_str!("vk_ecc_chip").replace("\r\n", "\n") ); } - test_proof_size(k, circuit, ¶ms, &vk) } #[test] @@ -941,6 +940,8 @@ pub(crate) mod tests { let params: Params = Params::new(11); let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + // If the environment variable CIRCUIT_TEST_GENERATE_NEW_PROOF is set, + // write the old proof in a file if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { let create_proof = || -> std::io::Result<()> { let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); @@ -952,13 +953,13 @@ pub(crate) mod tests { create_proof().expect("should be able to write new proof"); } - // Parse the hardcoded proof test case. + // Read the old proof into 'proof' let proof = { let test_case_bytes = fs::read("src/circuit_proof_test_case_ecc.bin").unwrap(); read_test_case(&test_case_bytes[..]).expect("proof must be valid") }; - assert_eq!(proof.as_ref().len(), 3872); + // Verify the old proof with the new vk assert!(proof.verify(&vk, ¶ms).is_ok()); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 8c5a4eaf37..9d5f26f18a 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -481,7 +481,7 @@ pub(crate) mod tests { use lazy_static::lazy_static; use pasta_curves::pallas; - use crate::utilities::test_circuit::{read_test_case, test_proof_size, write_test_case, Proof}; + use crate::utilities::test_circuit::{read_test_case, write_test_case, Proof}; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; use std::convert::TryInto; @@ -758,7 +758,7 @@ pub(crate) mod tests { } #[test] - fn round_trip() { + fn fixed_verification_key_test() { let k = 11; let circuit = MyCircuit {}; @@ -775,7 +775,6 @@ pub(crate) mod tests { include_str!("vk_sinsemilla_chip").replace("\r\n", "\n") ); } - test_proof_size(11, circuit, ¶ms, &vk) } #[test] @@ -787,6 +786,8 @@ pub(crate) mod tests { let params: Params = Params::new(11); let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + // If the environment variable CIRCUIT_TEST_GENERATE_NEW_PROOF is set, + // write the old proof in a file if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { let create_proof = || -> std::io::Result<()> { let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); @@ -798,13 +799,13 @@ pub(crate) mod tests { create_proof().expect("should be able to write new proof"); } - // Parse the hardcoded proof test case. + // Read the old proof into 'proof' let proof = { let test_case_bytes = fs::read("src/circuit_proof_test_case_sinsemilla.bin").unwrap(); read_test_case(&test_case_bytes[..]).expect("proof must be valid") }; - assert_eq!(proof.as_ref().len(), 4576); + // Verify the old proof with the new vk assert!(proof.verify(&vk, ¶ms).is_ok()); } diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 48a085e9b7..7efef14635 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -65,7 +65,7 @@ where /// | offset | x_A | q_sinsemilla4 | fixed_y_q | /// -------------------------------------- /// | 0 | x_Q | 1 | y_Q | - pub(crate) fn public_initialization( + fn public_initialization( &self, region: &mut Region<'_, pallas::Base>, Q: pallas::Affine, @@ -109,7 +109,7 @@ where #[allow(clippy::type_complexity)] /// Hash `message` from the initial point `Q`. - pub(crate) fn hash_all_pieces( + fn hash_all_pieces( &self, region: &mut Region<'_, pallas::Base>, mut offset: usize, @@ -180,7 +180,9 @@ where } #[allow(unused_variables)] - pub(crate) fn check_hash_result( + #[allow(non_snake_case)] + #[allow(clippy::type_complexity)] + fn check_hash_result( &self, Q: EccPointQ, message: & { #[cfg(test)] - #[allow(non_snake_case)] // Check equivalence to result from primitives::sinsemilla::hash_to_point { use crate::sinsemilla::primitives::{K, S_PERSONALIZATION}; diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 345877ec24..19fdd8d424 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -56,11 +56,11 @@ pub struct MerklePath< > where MerkleChip: MerkleInstructions + Clone, { - pub(crate) chips: [MerkleChip; PAR], - pub(crate) domain: MerkleChip::HashDomains, - pub(crate) leaf_pos: Value, + chips: [MerkleChip; PAR], + domain: MerkleChip::HashDomains, + leaf_pos: Value, // The Merkle path is ordered from leaves to root. - pub(crate) path: Value<[C::Base; PATH_LENGTH]>, + path: Value<[C::Base; PATH_LENGTH]>, } impl< @@ -200,7 +200,7 @@ pub mod tests { plonk::{Circuit, ConstraintSystem, Error}, }; - use crate::utilities::test_circuit::{read_test_case, test_proof_size, write_test_case, Proof}; + use crate::utilities::test_circuit::{read_test_case, write_test_case, Proof}; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; use rand::{rngs::OsRng, RngCore}; @@ -403,7 +403,7 @@ pub mod tests { } #[test] - fn round_trip() { + fn fixed_verification_key_test() { let k = 11; let circuit = generate_circuit(); @@ -420,9 +420,6 @@ pub mod tests { include_str!("vk_merkle_chip").replace("\r\n", "\n") ); } - - // Test that the proof size is as expected. - test_proof_size(k, circuit, ¶ms, &vk) } #[test] @@ -434,6 +431,8 @@ pub mod tests { let params: Params = Params::new(11); let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + // If the environment variable CIRCUIT_TEST_GENERATE_NEW_PROOF is set, + // write the old proof in a file if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { let create_proof = || -> std::io::Result<()> { let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); @@ -446,14 +445,14 @@ pub mod tests { create_proof().expect("should be able to write new proof"); } - // Parse the hardcoded proof test case. + // Read the old proof into 'proof' let proof = { let test_case_bytes = fs::read("src/sinsemilla/circuit_proof_test_case_merkle.bin").unwrap(); read_test_case(&test_case_bytes[..]).expect("proof must be valid") }; - assert_eq!(proof.as_ref().len(), 4160); + // Verify the old proof with the new vk assert!(proof.verify(&vk, ¶ms).is_ok()); } diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs index 5c26cff058..033967dbd7 100644 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla/merkle/chip.rs @@ -35,10 +35,10 @@ where Commit: CommitDomains, Lookup: DefaultLookupRangeCheck, { - pub(crate) advices: [Column; 5], - pub(crate) q_decompose: Selector, - pub(crate) cond_swap_config: CondSwapConfig, - pub(crate) sinsemilla_config: SinsemillaConfig, + advices: [Column; 5], + q_decompose: Selector, + pub(super) cond_swap_config: CondSwapConfig, + pub(super) sinsemilla_config: SinsemillaConfig, } /// Chip implementing `MerkleInstructions`. @@ -59,7 +59,7 @@ where Commit: CommitDomains, Lookup: DefaultLookupRangeCheck, { - pub(crate) config: MerkleConfig, + config: MerkleConfig, } impl Chip for MerkleChip diff --git a/halo2_gadgets/src/sinsemilla/primitives.rs b/halo2_gadgets/src/sinsemilla/primitives.rs index c47ac1b379..9bf6a72332 100644 --- a/halo2_gadgets/src/sinsemilla/primitives.rs +++ b/halo2_gadgets/src/sinsemilla/primitives.rs @@ -56,7 +56,7 @@ fn extract_p_bottom(point: CtOption) -> CtOption { /// Pads the given iterator (which MUST have length $\leq K * C$) with zero-bits to a /// multiple of $K$ bits. -pub(crate) struct Pad> { +struct Pad> { /// The iterator we are padding. inner: I, /// The measured length of the inner iterator. @@ -184,8 +184,8 @@ impl HashDomain { #[derive(Debug)] #[allow(non_snake_case)] pub struct CommitDomain { - pub(crate) M: HashDomain, - pub(crate) R: pallas::Point, + M: HashDomain, + R: pallas::Point, } impl CommitDomain { diff --git a/halo2_gadgets/src/utilities/cond_swap.rs b/halo2_gadgets/src/utilities/cond_swap.rs index 7712c89b2a..d733e6c4fb 100644 --- a/halo2_gadgets/src/utilities/cond_swap.rs +++ b/halo2_gadgets/src/utilities/cond_swap.rs @@ -29,7 +29,7 @@ pub trait CondSwapInstructions: UtilitiesInstructions { /// A chip implementing a conditional swap. #[derive(Clone, Debug)] pub struct CondSwapChip { - pub(crate) config: CondSwapConfig, + config: CondSwapConfig, _marker: PhantomData, } @@ -49,12 +49,12 @@ impl Chip for CondSwapChip { /// Configuration for the [`CondSwapChip`]. #[derive(Clone, Debug, PartialEq, Eq)] pub struct CondSwapConfig { - pub(crate) q_swap: Selector, - pub(crate) a: Column, - pub(crate) b: Column, - pub(crate) a_swapped: Column, - pub(crate) b_swapped: Column, - pub(crate) swap: Column, + q_swap: Selector, + a: Column, + b: Column, + a_swapped: Column, + b_swapped: Column, + swap: Column, } #[cfg(test)] diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 73e14bec06..63f97278bc 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -53,7 +53,7 @@ impl RangeConstrained> { .map(|inner| Self { inner, num_bits, - _phantom: PhantomData, + _phantom: PhantomData::default(), }) } } @@ -61,12 +61,12 @@ impl RangeConstrained> { /// Configuration that provides methods for a lookup range check. #[derive(Eq, PartialEq, Debug, Clone, Copy)] pub struct LookupRangeCheckConfig { - pub(crate) q_lookup: Selector, - pub(crate) q_running: Selector, - pub(crate) q_bitshift: Selector, - pub(crate) running_sum: Column, - pub(crate) table_idx: TableColumn, - pub(crate) _marker: PhantomData, + q_lookup: Selector, + q_running: Selector, + q_bitshift: Selector, + running_sum: Column, + table_idx: TableColumn, + _marker: PhantomData, } /// Trait that provides common methods for a lookup range check. @@ -441,7 +441,7 @@ pub trait DefaultLookupRangeCheck: impl DefaultLookupRangeCheck for LookupRangeCheckConfig {} #[cfg(test)] -pub(crate) mod tests { +mod tests { use super::{LookupRangeCheck, LookupRangeCheckConfig}; use super::super::lebs2ip; @@ -457,8 +457,7 @@ pub(crate) mod tests { use pasta_curves::pallas; use crate::utilities::test_circuit::{ - read_all_proofs, read_test_case, test_proof_size, write_all_test_case, write_test_case, - Proof, + read_all_proofs, read_test_case, write_all_test_case, write_test_case, Proof, }; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; @@ -575,6 +574,8 @@ pub(crate) mod tests { // serialized_proof_test_case { + // If the environment variable CIRCUIT_TEST_GENERATE_NEW_PROOF is set, + // write the old proof in a file if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { let create_proof = || -> std::io::Result<()> { let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); @@ -587,7 +588,7 @@ pub(crate) mod tests { }; create_proof().expect("should be able to write new proof"); } - // Parse the hardcoded proof test case. + // Read the old proof into 'proof' let proof = { let test_case_bytes = fs::read("src/utilities/circuit_proof_test_case_lookup_range_check.bin") @@ -595,12 +596,9 @@ pub(crate) mod tests { read_test_case(&test_case_bytes[..]).expect("proof must be valid") }; - assert_eq!(proof.as_ref().len(), 1888); + // Verify the old proof with the new vk assert!(proof.verify(&vk, ¶ms).is_ok()); } - - // Test that the proof size is as expected. - test_proof_size(11, circuit, ¶ms, &vk) } } @@ -651,6 +649,7 @@ pub(crate) mod tests { } } + // Read the old proofs into 'proofs' let proofs = { let test_case_bytes = fs::read("src/utilities/circuit_proof_test_case_short_range_check.bin").unwrap(); @@ -682,14 +681,12 @@ pub(crate) mod tests { include_str!("vk_short_range_check_0").replace("\r\n", "\n") ); } - // Test that the proof size is as expected. - test_proof_size(11, circuit, ¶ms, &vk); // serialized_proof_test_case { match proofs.get(0) { Some(proof) => { - assert_eq!(proof.as_ref().len(), 1888); + // Verify the old proofs[0] with the new vk assert!(proof.verify(&vk, ¶ms).is_ok()); } None => println!("Index out of bounds"), @@ -719,14 +716,12 @@ pub(crate) mod tests { include_str!("vk_short_range_check_1").replace("\r\n", "\n") ); } - // Test that the proof size is as expected. - test_proof_size(11, circuit, ¶ms, &vk); // serialized_proof_test_case { match proofs.get(1) { Some(proof) => { - assert_eq!(proof.as_ref().len(), 1888); + // Verify the old proofs[1] with the new vk assert!(proof.verify(&vk, ¶ms).is_ok()); } None => println!("Index out of bounds"), @@ -756,14 +751,12 @@ pub(crate) mod tests { include_str!("vk_short_range_check_2").replace("\r\n", "\n") ); } - // Test that the proof size is as expected. - test_proof_size(11, circuit, ¶ms, &vk); // serialized_proof_test_case { match proofs.get(2) { Some(proof) => { - assert_eq!(proof.as_ref().len(), 1888); + // Verify the old proofs[2] with the new vk assert!(proof.verify(&vk, ¶ms).is_ok()); } None => println!("Index out of bounds"), @@ -771,6 +764,8 @@ pub(crate) mod tests { } } + // If the environment variable CIRCUIT_TEST_GENERATE_NEW_PROOF is set, + // write the old proofs in a file if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { let create_proof = || -> std::io::Result<()> { let file = std::fs::File::create( diff --git a/halo2_gadgets/src/utilities/test_circuit.rs b/halo2_gadgets/src/utilities/test_circuit.rs index c42bcf0c63..b224540b72 100644 --- a/halo2_gadgets/src/utilities/test_circuit.rs +++ b/halo2_gadgets/src/utilities/test_circuit.rs @@ -54,34 +54,16 @@ impl Proof { } } -/// Test that the proof size is as expected. -#[allow(dead_code)] -pub(crate) fn test_proof_size( - k: u32, - circuit: C, - params: &Params, - vk: &VerifyingKey, -) where - C: Circuit, -{ - let circuit_cost = - halo2_proofs::dev::CircuitCost::::measure(k, &circuit); - let expected_proof_size = usize::from(circuit_cost.proof_size(1)); - - let proof = Proof::create(vk, params, circuit).unwrap(); - - assert!(proof.verify(vk, params).is_ok()); - assert_eq!(proof.as_ref().len(), expected_proof_size); -} - /// write proof to a file -pub fn write_test_case(mut w: W, proof: &Proof) -> std::io::Result<()> { +#[allow(dead_code)] +pub(crate) fn write_test_case(mut w: W, proof: &Proof) -> std::io::Result<()> { w.write_all(proof.as_ref())?; Ok(()) } /// read proof from a file -pub fn read_test_case(mut r: R) -> std::io::Result { +#[allow(dead_code)] +pub(crate) fn read_test_case(mut r: R) -> std::io::Result { let mut proof_bytes = vec![]; r.read_to_end(&mut proof_bytes)?; let proof = Proof::new(proof_bytes); @@ -99,7 +81,8 @@ pub(crate) fn write_all_test_case(mut w: W, proofs: &Vec) -> st } /// read multiple proofs from a file -pub fn read_all_proofs(mut r: R, proof_size: usize) -> io::Result> { +#[allow(dead_code)] +pub(crate) fn read_all_proofs(mut r: R, proof_size: usize) -> io::Result> { let mut proofs = Vec::new(); let mut buffer = vec![0u8; proof_size]; diff --git a/halo2_proofs/src/circuit.rs b/halo2_proofs/src/circuit.rs index 1083339fed..0822d8d8aa 100644 --- a/halo2_proofs/src/circuit.rs +++ b/halo2_proofs/src/circuit.rs @@ -139,16 +139,6 @@ impl AssignedCell, F> { } } -impl From> for AssignedCell, F> { - fn from(ac: AssignedCell) -> Self { - AssignedCell { - value: ac.value.map(|a| a.into()), - cell: ac.cell, - _marker: Default::default(), - } - } -} - impl AssignedCell where for<'v> Assigned: From<&'v V>, From cf2bd37ac8fc5b9b7b2009ee7fcf74436e52aa91 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 13 May 2024 15:21:33 +0200 Subject: [PATCH 46/99] cleanup code --- halo2_gadgets/src/sinsemilla.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 9d5f26f18a..1b51a187f6 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -289,7 +289,8 @@ pub struct HashDomain< } impl - HashDomain where + HashDomain + where SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, EccChip: EccInstructions< C, @@ -387,7 +388,8 @@ pub struct CommitDomain< } impl - CommitDomain where + CommitDomain + where SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, EccChip: EccInstructions< C, From da85c7183751b52a5a23d9e649ff8de9dc4539d0 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Mon, 13 May 2024 15:22:38 +0200 Subject: [PATCH 47/99] cleanup code --- halo2_gadgets/src/sinsemilla.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 1b51a187f6..cbeb069fd8 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -290,7 +290,7 @@ pub struct HashDomain< impl HashDomain - where +where SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, EccChip: EccInstructions< C, @@ -389,7 +389,7 @@ pub struct CommitDomain< impl CommitDomain - where +where SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, EccChip: EccInstructions< C, From a5bf5eeaa19e2093b0297b1bd3112b43f7b4d63a Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Tue, 14 May 2024 10:27:59 +0200 Subject: [PATCH 48/99] resolve review --- halo2_gadgets/src/ecc.rs | 13 ++- halo2_gadgets/src/ecc/chip.rs | 24 +++--- halo2_gadgets/src/ecc/chip/mul.rs | 10 +-- halo2_gadgets/src/ecc/chip/mul/overflow.rs | 8 +- .../src/ecc/chip/mul_fixed/base_field_elem.rs | 14 ++-- .../src/ecc/chip/mul_fixed/full_width.rs | 8 +- halo2_gadgets/src/ecc/chip/mul_fixed/short.rs | 8 +- halo2_gadgets/src/sinsemilla.rs | 13 ++- halo2_gadgets/src/sinsemilla/chip.rs | 14 ++-- .../src/sinsemilla/chip/generator_table.rs | 4 +- .../src/sinsemilla/chip/hash_to_point.rs | 4 +- halo2_gadgets/src/sinsemilla/merkle.rs | 22 +++-- halo2_gadgets/src/sinsemilla/merkle/chip.rs | 22 ++--- .../{vk_merkle_chip => vk_merkle_chip_0} | 0 .../src/utilities/lookup_range_check.rs | 80 +++++++++---------- ...up_range_check => vk_lookup_range_check_0} | 0 .../src/{vk_ecc_chip => vk_ecc_chip_0} | 0 ...k_sinsemilla_chip => vk_sinsemilla_chip_0} | 0 18 files changed, 112 insertions(+), 132 deletions(-) rename halo2_gadgets/src/sinsemilla/{vk_merkle_chip => vk_merkle_chip_0} (100%) rename halo2_gadgets/src/utilities/{vk_lookup_range_check => vk_lookup_range_check_0} (100%) rename halo2_gadgets/src/{vk_ecc_chip => vk_ecc_chip_0} (100%) rename halo2_gadgets/src/{vk_sinsemilla_chip => vk_sinsemilla_chip_0} (100%) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 4b7d0e291b..9786701d4a 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -922,13 +922,10 @@ pub(crate) mod tests { // Test that the pinned verification key (representing the circuit) // is as expected. - { - //panic!("{:#?}", vk.pinned()); - assert_eq!( - format!("{:#?}\n", vk.pinned()), - include_str!("vk_ecc_chip").replace("\r\n", "\n") - ); - } + assert_eq!( + format!("{:#?}\n", vk.pinned()), + include_str!("vk_ecc_chip_0").replace("\r\n", "\n") + ); } #[test] @@ -953,7 +950,7 @@ pub(crate) mod tests { create_proof().expect("should be able to write new proof"); } - // Read the old proof into 'proof' + // read proof from disk let proof = { let test_case_bytes = fs::read("src/circuit_proof_test_case_ecc.bin").unwrap(); read_test_case(&test_case_bytes[..]).expect("proof must be valid") diff --git a/halo2_gadgets/src/ecc/chip.rs b/halo2_gadgets/src/ecc/chip.rs index 7133bdfd78..d7a0c92219 100644 --- a/halo2_gadgets/src/ecc/chip.rs +++ b/halo2_gadgets/src/ecc/chip.rs @@ -1,7 +1,7 @@ //! Chip implementations for the ECC gadgets. use super::{BaseFitsInScalarInstructions, EccInstructions, FixedPoints}; -use crate::utilities::{lookup_range_check::DefaultLookupRangeCheck, UtilitiesInstructions}; +use crate::utilities::{lookup_range_check::PallasLookupRC, UtilitiesInstructions}; use arrayvec::ArrayVec; use ff::PrimeField; @@ -134,10 +134,7 @@ impl From for EccPoint { /// Configuration for [`EccChip`]. #[derive(Clone, Debug, Eq, PartialEq)] #[allow(non_snake_case)] -pub struct EccConfig< - FixedPoints: super::FixedPoints, - Lookup: DefaultLookupRangeCheck, -> { +pub struct EccConfig, Lookup: PallasLookupRC> { /// Advice columns needed by instructions in the ECC chip. pub advices: [Column; 10], @@ -227,13 +224,12 @@ pub trait FixedPoint: std::fmt::Debug + Eq + Clone { /// An [`EccInstructions`] chip that uses 10 advice columns. #[derive(Clone, Debug, Eq, PartialEq)] -pub struct EccChip, Lookup: DefaultLookupRangeCheck> -{ +pub struct EccChip, Lookup: PallasLookupRC> { config: EccConfig, } -impl, Lookup: DefaultLookupRangeCheck> - Chip for EccChip +impl, Lookup: PallasLookupRC> Chip + for EccChip { type Config = EccConfig; type Loaded = (); @@ -247,13 +243,13 @@ impl, Lookup: DefaultLookupRange } } -impl, Lookup: DefaultLookupRangeCheck> +impl, Lookup: PallasLookupRC> UtilitiesInstructions for EccChip { type Var = AssignedCell; } -impl, Lookup: DefaultLookupRangeCheck> +impl, Lookup: PallasLookupRC> EccChip { /// Reconstructs this chip from the given config. @@ -413,8 +409,8 @@ pub enum ScalarVar { FullWidth, } -impl, Lookup: DefaultLookupRangeCheck> - EccInstructions for EccChip +impl, Lookup: PallasLookupRC> EccInstructions + for EccChip where >::Base: FixedPoint, @@ -601,7 +597,7 @@ where } } -impl, Lookup: DefaultLookupRangeCheck> +impl, Lookup: PallasLookupRC> BaseFitsInScalarInstructions for EccChip where >::Base: diff --git a/halo2_gadgets/src/ecc/chip/mul.rs b/halo2_gadgets/src/ecc/chip/mul.rs index 02d2e2d805..70c14df284 100644 --- a/halo2_gadgets/src/ecc/chip/mul.rs +++ b/halo2_gadgets/src/ecc/chip/mul.rs @@ -1,6 +1,6 @@ use super::{add, EccPoint, NonIdentityEccPoint, ScalarVar, T_Q}; use crate::utilities::{ - lookup_range_check::DefaultLookupRangeCheck, + lookup_range_check::PallasLookupRC, {bool_check, ternary}, }; use std::{ @@ -46,7 +46,7 @@ const INCOMPLETE_LO_LEN: usize = INCOMPLETE_LEN - INCOMPLETE_HI_LEN; const COMPLETE_RANGE: Range = INCOMPLETE_LEN..(INCOMPLETE_LEN + NUM_COMPLETE_BITS); #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { +pub struct Config { // Selector used to check switching logic on LSB q_mul_lsb: Selector, // Configuration used in complete addition @@ -61,7 +61,7 @@ pub struct Config { overflow_config: overflow::Config, } -impl Config { +impl Config { pub(super) fn configure( meta: &mut ConstraintSystem, add_config: add::Config, @@ -468,7 +468,7 @@ pub mod tests { use pasta_curves::pallas; use rand::rngs::OsRng; - use crate::utilities::lookup_range_check::DefaultLookupRangeCheck; + use crate::utilities::lookup_range_check::PallasLookupRC; use crate::{ ecc::{ chip::{EccChip, EccPoint}, @@ -478,7 +478,7 @@ pub mod tests { utilities::UtilitiesInstructions, }; - pub(crate) fn test_mul( + pub(crate) fn test_mul( chip: EccChip, mut layouter: impl Layouter, p: &NonIdentityPoint>, diff --git a/halo2_gadgets/src/ecc/chip/mul/overflow.rs b/halo2_gadgets/src/ecc/chip/mul/overflow.rs index 0912bd3a39..eb5810fac5 100644 --- a/halo2_gadgets/src/ecc/chip/mul/overflow.rs +++ b/halo2_gadgets/src/ecc/chip/mul/overflow.rs @@ -1,7 +1,5 @@ use super::{T_Q, Z}; -use crate::{ - sinsemilla::primitives as sinsemilla, utilities::lookup_range_check::DefaultLookupRangeCheck, -}; +use crate::{sinsemilla::primitives as sinsemilla, utilities::lookup_range_check::PallasLookupRC}; use group::ff::PrimeField; use halo2_proofs::circuit::AssignedCell; @@ -15,7 +13,7 @@ use pasta_curves::pallas; use std::iter; #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { +pub struct Config { // Selector to check z_0 = alpha + t_q (mod p) q_mul_overflow: Selector, // 10-bit lookup table @@ -24,7 +22,7 @@ pub struct Config { advices: [Column; 3], } -impl Config { +impl Config { pub(super) fn configure( meta: &mut ConstraintSystem, lookup_config: Lookup, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs index 24f7114b4a..760ab20b9a 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs @@ -2,7 +2,7 @@ use super::super::{EccBaseFieldElemFixed, EccPoint, FixedPoints, NUM_WINDOWS, T_ use super::H_BASE; use crate::utilities::{ - bitrange_subset, bool_check, lookup_range_check::DefaultLookupRangeCheck, range_check, + bitrange_subset, bool_check, lookup_range_check::PallasLookupRC, range_check, }; use group::ff::PrimeField; @@ -16,14 +16,14 @@ use pasta_curves::pallas; use std::convert::TryInto; #[derive(Clone, Debug, Eq, PartialEq)] -pub struct Config, Lookup: DefaultLookupRangeCheck> { +pub struct Config, Lookup: PallasLookupRC> { q_mul_fixed_base_field: Selector, canon_advices: [Column; 3], lookup_config: Lookup, super_config: super::Config, } -impl, Lookup: DefaultLookupRangeCheck> Config { +impl, Lookup: PallasLookupRC> Config { pub(crate) fn configure( meta: &mut ConstraintSystem, canon_advices: [Column; 3], @@ -386,7 +386,7 @@ pub mod tests { use pasta_curves::pallas; use rand::rngs::OsRng; - use crate::utilities::lookup_range_check::DefaultLookupRangeCheck; + use crate::utilities::lookup_range_check::PallasLookupRC; use crate::{ ecc::{ chip::{EccChip, FixedPoint, H}, @@ -396,7 +396,7 @@ pub mod tests { utilities::UtilitiesInstructions, }; - pub(crate) fn test_mul_fixed_base_field( + pub(crate) fn test_mul_fixed_base_field( chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { @@ -409,7 +409,7 @@ pub mod tests { } #[allow(clippy::op_ref)] - fn test_single_base( + fn test_single_base( chip: EccChip, mut layouter: impl Layouter, base: FixedPointBaseField>, @@ -419,7 +419,7 @@ pub mod tests { let column = chip.config().advices[0]; - fn constrain_equal_non_id( + fn constrain_equal_non_id( chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs index fe2cc22094..fe0ccd8d3d 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs @@ -192,9 +192,9 @@ pub mod tests { tests::{FullWidth, TestFixedBases}, FixedPoint, NonIdentityPoint, Point, ScalarFixed, }; - use crate::utilities::lookup_range_check::DefaultLookupRangeCheck; + use crate::utilities::lookup_range_check::PallasLookupRC; - pub(crate) fn test_mul_fixed( + pub(crate) fn test_mul_fixed( chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { @@ -210,13 +210,13 @@ pub mod tests { } #[allow(clippy::op_ref)] - fn test_single_base( + fn test_single_base( chip: EccChip, mut layouter: impl Layouter, base: FixedPoint>, base_val: pallas::Affine, ) -> Result<(), Error> { - fn constrain_equal_non_id( + fn constrain_equal_non_id( chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs index acbba7cc3a..fd88bcd72b 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs @@ -253,7 +253,7 @@ pub mod tests { }; use pasta_curves::pallas; - use crate::utilities::lookup_range_check::{DefaultLookupRangeCheck, LookupRangeCheck}; + use crate::utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRC}; use crate::{ ecc::{ chip::{EccChip, FixedPoint, MagnitudeSign}, @@ -264,7 +264,7 @@ pub mod tests { }; #[allow(clippy::op_ref)] - pub(crate) fn test_mul_fixed_short( + pub(crate) fn test_mul_fixed_short( chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { @@ -272,7 +272,7 @@ pub mod tests { let base_val = Short.generator(); let test_short = FixedPointShort::from_inner(chip.clone(), Short); - fn load_magnitude_sign( + fn load_magnitude_sign( chip: EccChip, mut layouter: impl Layouter, magnitude: pallas::Base, @@ -290,7 +290,7 @@ pub mod tests { Ok((magnitude, sign)) } - fn constrain_equal_non_id( + fn constrain_equal_non_id( chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index cbeb069fd8..3877824e45 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -770,13 +770,10 @@ pub(crate) mod tests { // Test that the pinned verification key (representing the circuit) // is as expected. - { - //panic!("{:#?}", vk.pinned()); - assert_eq!( - format!("{:#?}\n", vk.pinned()), - include_str!("vk_sinsemilla_chip").replace("\r\n", "\n") - ); - } + assert_eq!( + format!("{:#?}\n", vk.pinned()), + include_str!("vk_sinsemilla_chip_0").replace("\r\n", "\n") + ); } #[test] @@ -801,7 +798,7 @@ pub(crate) mod tests { create_proof().expect("should be able to write new proof"); } - // Read the old proof into 'proof' + // read proof from disk let proof = { let test_case_bytes = fs::read("src/circuit_proof_test_case_sinsemilla.bin").unwrap(); read_test_case(&test_case_bytes[..]).expect("proof must be valid") diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs index 95e40ec0f3..b242db41be 100644 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ b/halo2_gadgets/src/sinsemilla/chip.rs @@ -9,7 +9,7 @@ use crate::{ chip::{DoubleAndAdd, NonIdentityEccPoint}, FixedPoints, }, - utilities::lookup_range_check::DefaultLookupRangeCheck, + utilities::lookup_range_check::PallasLookupRC, }; use std::marker::PhantomData; @@ -35,7 +35,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + Lookup: PallasLookupRC, { /// Binary selector used in lookup argument and in the body of the Sinsemilla hash. q_sinsemilla1: Selector, @@ -68,7 +68,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + Lookup: PallasLookupRC, { /// Returns an array of all advice columns in this config, in arbitrary order. pub(super) fn advices(&self) -> [Column; 5] { @@ -103,7 +103,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + Lookup: PallasLookupRC, { config: SinsemillaConfig, } @@ -113,7 +113,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + Lookup: PallasLookupRC, { type Config = SinsemillaConfig; type Loaded = (); @@ -132,7 +132,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + Lookup: PallasLookupRC, { /// Reconstructs this chip from the given config. pub fn construct(config: >::Config) -> Self { @@ -321,7 +321,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + Lookup: PallasLookupRC, { type CellValue = AssignedCell; diff --git a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs index 41e2f42c99..013995911c 100644 --- a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs +++ b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs @@ -8,7 +8,7 @@ use halo2_proofs::{ use super::{CommitDomains, FixedPoints, HashDomains}; use crate::{ sinsemilla::primitives::{self as sinsemilla, SINSEMILLA_S}, - utilities::lookup_range_check::DefaultLookupRangeCheck, + utilities::lookup_range_check::PallasLookupRC, }; use pasta_curves::pallas; @@ -33,7 +33,7 @@ impl GeneratorTableConfig { Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + Lookup: PallasLookupRC, { let (table_idx, table_x, table_y) = ( config.generator_table.table_idx, diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 7efef14635..709da2455d 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -3,7 +3,7 @@ use super::{NonIdentityEccPoint, SinsemillaChip}; use crate::{ ecc::FixedPoints, sinsemilla::primitives::{self as sinsemilla, lebs2ip_k, INV_TWO_POW_K, SINSEMILLA_S}, - utilities::lookup_range_check::DefaultLookupRangeCheck, + utilities::lookup_range_check::PallasLookupRC, }; use ff::Field; @@ -30,7 +30,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + Lookup: PallasLookupRC, { /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). #[allow(non_snake_case)] diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 19fdd8d424..dfb457808b 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -205,7 +205,6 @@ pub mod tests { use pasta_curves::vesta::Affine; use rand::{rngs::OsRng, RngCore}; use std::{convert::TryInto, iter}; - const MERKLE_DEPTH: usize = 32; #[derive(Default)] @@ -413,13 +412,10 @@ pub mod tests { // Test that the pinned verification key (representing the circuit) // is as expected. Which indicates the layouters are the same. - { - //panic!("{:#?}", vk.pinned()); - assert_eq!( - format!("{:#?}\n", vk.pinned()), - include_str!("vk_merkle_chip").replace("\r\n", "\n") - ); - } + assert_eq!( + format!("{:#?}\n", vk.pinned()), + include_str!("vk_merkle_chip_0").replace("\r\n", "\n") + ); } #[test] @@ -431,6 +427,8 @@ pub mod tests { let params: Params = Params::new(11); let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + let file_name = "src/sinsemilla/circuit_proof_test_case_merkle.bin"; + // If the environment variable CIRCUIT_TEST_GENERATE_NEW_PROOF is set, // write the old proof in a file if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { @@ -438,17 +436,15 @@ pub mod tests { let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); assert!(proof.verify(&vk, ¶ms).is_ok()); - let file = - std::fs::File::create("src/sinsemilla/circuit_proof_test_case_merkle.bin")?; + let file = std::fs::File::create(file_name)?; write_test_case(file, &proof) }; create_proof().expect("should be able to write new proof"); } - // Read the old proof into 'proof' + // read proof from disk let proof = { - let test_case_bytes = - fs::read("src/sinsemilla/circuit_proof_test_case_merkle.bin").unwrap(); + let test_case_bytes = fs::read(file_name).unwrap(); read_test_case(&test_case_bytes[..]).expect("proof must be valid") }; diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs index 033967dbd7..37aa4e7f99 100644 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla/merkle/chip.rs @@ -11,7 +11,7 @@ use super::MerkleInstructions; use crate::{ sinsemilla::{primitives as sinsemilla, MessagePiece}, - utilities::{lookup_range_check::DefaultLookupRangeCheck, RangeConstrained}, + utilities::{lookup_range_check::PallasLookupRC, RangeConstrained}, { ecc::FixedPoints, sinsemilla::{ @@ -33,7 +33,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + Lookup: PallasLookupRC, { advices: [Column; 5], q_decompose: Selector, @@ -57,7 +57,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + Lookup: PallasLookupRC, { config: MerkleConfig, } @@ -67,7 +67,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + Lookup: PallasLookupRC, { type Config = MerkleConfig; type Loaded = (); @@ -86,7 +86,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + Lookup: PallasLookupRC, { /// Configures the [`MerkleChip`]. pub fn configure( @@ -227,7 +227,7 @@ where Hash: HashDomains, Commit: CommitDomains, F: FixedPoints, - Lookup: DefaultLookupRangeCheck, + Lookup: PallasLookupRC, { } @@ -237,7 +237,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + Lookup: PallasLookupRC, { } @@ -255,7 +255,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + Lookup: PallasLookupRC, { #[allow(non_snake_case)] fn hash_layer( @@ -474,7 +474,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + Lookup: PallasLookupRC, { type Var = AssignedCell; } @@ -485,7 +485,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + Lookup: PallasLookupRC, { #[allow(clippy::type_complexity)] fn swap( @@ -507,7 +507,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: DefaultLookupRangeCheck, + Lookup: PallasLookupRC, { type CellValue = as SinsemillaInstructions< pallas::Affine, diff --git a/halo2_gadgets/src/sinsemilla/vk_merkle_chip b/halo2_gadgets/src/sinsemilla/vk_merkle_chip_0 similarity index 100% rename from halo2_gadgets/src/sinsemilla/vk_merkle_chip rename to halo2_gadgets/src/sinsemilla/vk_merkle_chip_0 diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 63f97278bc..36810050f3 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -291,6 +291,17 @@ impl LookupRangeCheck for LookupRangeCh self } + /// 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, @@ -431,14 +442,14 @@ impl LookupRangeCheck for LookupRangeCh } } -/// The `DefaultLookupRangeCheck` trait extends the `LookupRangeCheck` with additional +/// The `PallasLookupRC` trait extends the `LookupRangeCheck` with additional /// standard traits necessary for effective use in cryptographic contexts. -pub trait DefaultLookupRangeCheck: +pub trait PallasLookupRC: LookupRangeCheck + Eq + PartialEq + Clone + Copy + Debug { } -impl DefaultLookupRangeCheck for LookupRangeCheckConfig {} +impl PallasLookupRC for LookupRangeCheckConfig {} #[cfg(test)] mod tests { @@ -564,13 +575,10 @@ mod tests { // Test that the pinned verification key (representing the circuit) // is as expected. - { - //panic!("{:#?}", vk.pinned()); - assert_eq!( - format!("{:#?}\n", vk.pinned()), - include_str!("vk_lookup_range_check").replace("\r\n", "\n") - ); - } + assert_eq!( + format!("{:#?}\n", vk.pinned()), + include_str!("vk_lookup_range_check_0").replace("\r\n", "\n") + ); // serialized_proof_test_case { @@ -588,7 +596,7 @@ mod tests { }; create_proof().expect("should be able to write new proof"); } - // Read the old proof into 'proof' + // read proof from disk let proof = { let test_case_bytes = fs::read("src/utilities/circuit_proof_test_case_lookup_range_check.bin") @@ -649,7 +657,7 @@ mod tests { } } - // Read the old proofs into 'proofs' + // read proof from disk let proofs = { let test_case_bytes = fs::read("src/utilities/circuit_proof_test_case_short_range_check.bin").unwrap(); @@ -659,8 +667,7 @@ mod tests { // Setup phase: generate parameters let params: Params = Params::new(11); - // Edge case: zero bits - // case 0 + // Edge case: zero bits (case 0) { let circuit: MyCircuit = MyCircuit { element: Value::known(pallas::Base::ZERO), @@ -674,19 +681,16 @@ mod tests { // Test that the pinned verification key (representing the circuit) // is as expected. Which indicates the layouters are the same. - { - //panic!("{:#?}", vk.pinned()); - assert_eq!( - format!("{:#?}\n", vk.pinned()), - include_str!("vk_short_range_check_0").replace("\r\n", "\n") - ); - } + assert_eq!( + format!("{:#?}\n", vk.pinned()), + include_str!("vk_short_range_check_0").replace("\r\n", "\n") + ); // serialized_proof_test_case { match proofs.get(0) { Some(proof) => { - // Verify the old proofs[0] with the new vk + // Verify the stored proof (case 0) against the generated vk assert!(proof.verify(&vk, ¶ms).is_ok()); } None => println!("Index out of bounds"), @@ -694,8 +698,7 @@ mod tests { } } - // Edge case: K bits - // case 1 + // Edge case: K bits (case 1) { let circuit: MyCircuit = MyCircuit { element: Value::known(pallas::Base::from((1 << K) - 1)), @@ -709,19 +712,16 @@ mod tests { // Test that the pinned verification key (representing the circuit) // is as expected. Which indicates the layouters are the same. - { - //panic!("{:#?}", vk.pinned()); - assert_eq!( - format!("{:#?}\n", vk.pinned()), - include_str!("vk_short_range_check_1").replace("\r\n", "\n") - ); - } + assert_eq!( + format!("{:#?}\n", vk.pinned()), + include_str!("vk_short_range_check_1").replace("\r\n", "\n") + ); // serialized_proof_test_case { match proofs.get(1) { Some(proof) => { - // Verify the old proofs[1] with the new vk + // Verify the stored proof (case 1) against the generated vk assert!(proof.verify(&vk, ¶ms).is_ok()); } None => println!("Index out of bounds"), @@ -729,8 +729,7 @@ mod tests { } } - // Element within `num_bits` - // case 2 + // Element within `num_bits` (case 2) { let circuit: MyCircuit = MyCircuit { element: Value::known(pallas::Base::from((1 << 6) - 1)), @@ -744,19 +743,16 @@ mod tests { // Test that the pinned verification key (representing the circuit) // is as expected. Which indicates the layouters are the same. - { - //panic!("{:#?}", vk.pinned()); - assert_eq!( - format!("{:#?}\n", vk.pinned()), - include_str!("vk_short_range_check_2").replace("\r\n", "\n") - ); - } + assert_eq!( + format!("{:#?}\n", vk.pinned()), + include_str!("vk_short_range_check_2").replace("\r\n", "\n") + ); // serialized_proof_test_case { match proofs.get(2) { Some(proof) => { - // Verify the old proofs[2] with the new vk + // Verify the stored proof (case 2) against the generated vk assert!(proof.verify(&vk, ¶ms).is_ok()); } None => println!("Index out of bounds"), diff --git a/halo2_gadgets/src/utilities/vk_lookup_range_check b/halo2_gadgets/src/utilities/vk_lookup_range_check_0 similarity index 100% rename from halo2_gadgets/src/utilities/vk_lookup_range_check rename to halo2_gadgets/src/utilities/vk_lookup_range_check_0 diff --git a/halo2_gadgets/src/vk_ecc_chip b/halo2_gadgets/src/vk_ecc_chip_0 similarity index 100% rename from halo2_gadgets/src/vk_ecc_chip rename to halo2_gadgets/src/vk_ecc_chip_0 diff --git a/halo2_gadgets/src/vk_sinsemilla_chip b/halo2_gadgets/src/vk_sinsemilla_chip_0 similarity index 100% rename from halo2_gadgets/src/vk_sinsemilla_chip rename to halo2_gadgets/src/vk_sinsemilla_chip_0 From 8d27dd7c6806a1fd5978b00edd607fa42d206904 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Tue, 14 May 2024 12:00:51 +0200 Subject: [PATCH 49/99] Introduce conditionally_save_circuit_to_disk function to reuse the proof saving code in test cases --- halo2_gadgets/src/ecc.rs | 20 +++++++----------- halo2_gadgets/src/sinsemilla.rs | 20 +++++++----------- halo2_gadgets/src/sinsemilla/merkle.rs | 15 ++----------- .../src/utilities/lookup_range_check.rs | 21 +++++++------------ halo2_gadgets/src/utilities/test_circuit.rs | 21 +++++++++++++++++++ 5 files changed, 44 insertions(+), 53 deletions(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 9786701d4a..4a697ff413 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -599,7 +599,7 @@ pub(crate) mod tests { FixedPoints, }; use crate::utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}; - use crate::utilities::test_circuit::{read_test_case, write_test_case, Proof}; + use crate::utilities::test_circuit::{conditionally_save_circuit_to_disk, read_test_case}; #[derive(Debug, Eq, PartialEq, Clone)] pub(crate) struct TestFixedBases; @@ -937,18 +937,12 @@ pub(crate) mod tests { let params: Params = Params::new(11); let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); - // If the environment variable CIRCUIT_TEST_GENERATE_NEW_PROOF is set, - // write the old proof in a file - if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { - let create_proof = || -> std::io::Result<()> { - let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); - assert!(proof.verify(&vk, ¶ms).is_ok()); - - let file = std::fs::File::create("src/circuit_proof_test_case_ecc.bin")?; - write_test_case(file, &proof) - }; - create_proof().expect("should be able to write new proof"); - } + conditionally_save_circuit_to_disk( + &vk, + ¶ms, + circuit, + "src/circuit_proof_test_case_ecc.bin", + ); // read proof from disk let proof = { diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 3877824e45..52f1e4327f 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -483,7 +483,7 @@ pub(crate) mod tests { use lazy_static::lazy_static; use pasta_curves::pallas; - use crate::utilities::test_circuit::{read_test_case, write_test_case, Proof}; + use crate::utilities::test_circuit::{conditionally_save_circuit_to_disk, read_test_case}; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; use std::convert::TryInto; @@ -785,18 +785,12 @@ pub(crate) mod tests { let params: Params = Params::new(11); let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); - // If the environment variable CIRCUIT_TEST_GENERATE_NEW_PROOF is set, - // write the old proof in a file - if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { - let create_proof = || -> std::io::Result<()> { - let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); - assert!(proof.verify(&vk, ¶ms).is_ok()); - - let file = std::fs::File::create("src/circuit_proof_test_case_sinsemilla.bin")?; - write_test_case(file, &proof) - }; - create_proof().expect("should be able to write new proof"); - } + conditionally_save_circuit_to_disk( + &vk, + ¶ms, + circuit, + "src/circuit_proof_test_case_sinsemilla.bin", + ); // read proof from disk let proof = { diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index dfb457808b..95678eec0e 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -200,7 +200,7 @@ pub mod tests { plonk::{Circuit, ConstraintSystem, Error}, }; - use crate::utilities::test_circuit::{read_test_case, write_test_case, Proof}; + use crate::utilities::test_circuit::{conditionally_save_circuit_to_disk, read_test_case}; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; use rand::{rngs::OsRng, RngCore}; @@ -429,18 +429,7 @@ pub mod tests { let file_name = "src/sinsemilla/circuit_proof_test_case_merkle.bin"; - // If the environment variable CIRCUIT_TEST_GENERATE_NEW_PROOF is set, - // write the old proof in a file - if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { - let create_proof = || -> std::io::Result<()> { - let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); - assert!(proof.verify(&vk, ¶ms).is_ok()); - - let file = std::fs::File::create(file_name)?; - write_test_case(file, &proof) - }; - create_proof().expect("should be able to write new proof"); - } + conditionally_save_circuit_to_disk(&vk, ¶ms, circuit, file_name); // read proof from disk let proof = { diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 36810050f3..eedf67177e 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -468,7 +468,7 @@ mod tests { use pasta_curves::pallas; use crate::utilities::test_circuit::{ - read_all_proofs, read_test_case, write_all_test_case, write_test_case, Proof, + conditionally_save_circuit_to_disk, read_all_proofs, read_test_case, write_all_test_case, }; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; @@ -582,20 +582,13 @@ mod tests { // serialized_proof_test_case { - // If the environment variable CIRCUIT_TEST_GENERATE_NEW_PROOF is set, - // write the old proof in a file - if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { - let create_proof = || -> std::io::Result<()> { - let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); - assert!(proof.verify(&vk, ¶ms).is_ok()); + conditionally_save_circuit_to_disk( + &vk, + ¶ms, + circuit, + "src/utilities/circuit_proof_test_case_lookup_range_check.bin", + ); - let file = std::fs::File::create( - "src/utilities/circuit_proof_test_case_lookup_range_check.bin", - )?; - write_test_case(file, &proof) - }; - create_proof().expect("should be able to write new proof"); - } // read proof from disk let proof = { let test_case_bytes = diff --git a/halo2_gadgets/src/utilities/test_circuit.rs b/halo2_gadgets/src/utilities/test_circuit.rs index b224540b72..727dd58540 100644 --- a/halo2_gadgets/src/utilities/test_circuit.rs +++ b/halo2_gadgets/src/utilities/test_circuit.rs @@ -91,3 +91,24 @@ pub(crate) fn read_all_proofs(mut r: R, proof_size: usize) -> io::Resul } Ok(proofs) } + +#[cfg(test)] +pub(crate) fn conditionally_save_circuit_to_disk>( + vk: &VerifyingKey, + params: &Params, + circuit: C, + file_name: &str, +) { + // If the environment variable CIRCUIT_TEST_GENERATE_NEW_PROOF is set, + // write the old proof in a file + if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { + let create_proof = || -> std::io::Result<()> { + let proof = Proof::create(vk, params, circuit).unwrap(); + assert!(proof.verify(vk, params).is_ok()); + + let file = std::fs::File::create(file_name)?; + write_test_case(file, &proof) + }; + create_proof().expect("should be able to write new proof"); + } +} From 48f941ea5e2270b87e59c95373105fdfce274ccd Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Tue, 14 May 2024 12:03:55 +0200 Subject: [PATCH 50/99] Rename conditionally_save_circuit_to_disk function to conditionally_save_proof_to_disk --- halo2_gadgets/src/ecc.rs | 4 ++-- halo2_gadgets/src/sinsemilla.rs | 4 ++-- halo2_gadgets/src/sinsemilla/merkle.rs | 4 ++-- halo2_gadgets/src/utilities/lookup_range_check.rs | 4 ++-- halo2_gadgets/src/utilities/test_circuit.rs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 4a697ff413..fb243713c9 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -599,7 +599,7 @@ pub(crate) mod tests { FixedPoints, }; use crate::utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}; - use crate::utilities::test_circuit::{conditionally_save_circuit_to_disk, read_test_case}; + use crate::utilities::test_circuit::{conditionally_save_proof_to_disk, read_test_case}; #[derive(Debug, Eq, PartialEq, Clone)] pub(crate) struct TestFixedBases; @@ -937,7 +937,7 @@ pub(crate) mod tests { let params: Params = Params::new(11); let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); - conditionally_save_circuit_to_disk( + conditionally_save_proof_to_disk( &vk, ¶ms, circuit, diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 52f1e4327f..8199abd22b 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -483,7 +483,7 @@ pub(crate) mod tests { use lazy_static::lazy_static; use pasta_curves::pallas; - use crate::utilities::test_circuit::{conditionally_save_circuit_to_disk, read_test_case}; + use crate::utilities::test_circuit::{conditionally_save_proof_to_disk, read_test_case}; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; use std::convert::TryInto; @@ -785,7 +785,7 @@ pub(crate) mod tests { let params: Params = Params::new(11); let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); - conditionally_save_circuit_to_disk( + conditionally_save_proof_to_disk( &vk, ¶ms, circuit, diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 95678eec0e..00096f327a 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -200,7 +200,7 @@ pub mod tests { plonk::{Circuit, ConstraintSystem, Error}, }; - use crate::utilities::test_circuit::{conditionally_save_circuit_to_disk, read_test_case}; + use crate::utilities::test_circuit::{conditionally_save_proof_to_disk, read_test_case}; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; use rand::{rngs::OsRng, RngCore}; @@ -429,7 +429,7 @@ pub mod tests { let file_name = "src/sinsemilla/circuit_proof_test_case_merkle.bin"; - conditionally_save_circuit_to_disk(&vk, ¶ms, circuit, file_name); + conditionally_save_proof_to_disk(&vk, ¶ms, circuit, file_name); // read proof from disk let proof = { diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index eedf67177e..118a20fe34 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -468,7 +468,7 @@ mod tests { use pasta_curves::pallas; use crate::utilities::test_circuit::{ - conditionally_save_circuit_to_disk, read_all_proofs, read_test_case, write_all_test_case, + conditionally_save_proof_to_disk, read_all_proofs, read_test_case, write_all_test_case, }; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; @@ -582,7 +582,7 @@ mod tests { // serialized_proof_test_case { - conditionally_save_circuit_to_disk( + conditionally_save_proof_to_disk( &vk, ¶ms, circuit, diff --git a/halo2_gadgets/src/utilities/test_circuit.rs b/halo2_gadgets/src/utilities/test_circuit.rs index 727dd58540..54e7c1af89 100644 --- a/halo2_gadgets/src/utilities/test_circuit.rs +++ b/halo2_gadgets/src/utilities/test_circuit.rs @@ -93,7 +93,7 @@ pub(crate) fn read_all_proofs(mut r: R, proof_size: usize) -> io::Resul } #[cfg(test)] -pub(crate) fn conditionally_save_circuit_to_disk>( +pub(crate) fn conditionally_save_proof_to_disk>( vk: &VerifyingKey, params: &Params, circuit: C, From 58b7effca574f2240a176064b53fb7c3edade46f Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Tue, 14 May 2024 12:27:10 +0200 Subject: [PATCH 51/99] Introduce test_serialized_proof_with_vk and test_serialized_proof functions to reuse them and so avoid code duplication in serialized_proof_test_case tests --- halo2_gadgets/src/ecc.rs | 29 +++++-------------- halo2_gadgets/src/sinsemilla.rs | 29 ++++--------------- halo2_gadgets/src/sinsemilla/merkle.rs | 25 ++++------------ .../src/utilities/lookup_range_check.rs | 28 +++++------------- halo2_gadgets/src/utilities/test_circuit.rs | 21 +++++++++++++- 5 files changed, 44 insertions(+), 88 deletions(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index fb243713c9..53da5e71de 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -598,8 +598,10 @@ pub(crate) mod tests { }, FixedPoints, }; - use crate::utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}; - use crate::utilities::test_circuit::{conditionally_save_proof_to_disk, read_test_case}; + use crate::utilities::{ + lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, + test_circuit::test_serialized_proof, + }; #[derive(Debug, Eq, PartialEq, Clone)] pub(crate) struct TestFixedBases; @@ -930,29 +932,12 @@ pub(crate) mod tests { #[test] fn serialized_proof_test_case() { - use std::fs; - - let circuit = MyCircuit { test_errors: false }; - // Setup phase: generate parameters, vk for the circuit. - let params: Params = Params::new(11); - let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); - - conditionally_save_proof_to_disk( - &vk, - ¶ms, - circuit, + test_serialized_proof( + MyCircuit { test_errors: false }, "src/circuit_proof_test_case_ecc.bin", ); - - // read proof from disk - let proof = { - let test_case_bytes = fs::read("src/circuit_proof_test_case_ecc.bin").unwrap(); - read_test_case(&test_case_bytes[..]).expect("proof must be valid") - }; - - // Verify the old proof with the new vk - assert!(proof.verify(&vk, ¶ms).is_ok()); } + #[cfg(feature = "test-dev-graph")] #[test] fn print_ecc_chip() { diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 8199abd22b..791defe3eb 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -475,7 +475,10 @@ pub(crate) mod tests { tests::{FullWidth, TestFixedBases}, NonIdentityPoint, }, - utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, + utilities::{ + lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, + test_circuit::test_serialized_proof, + }, }, }; @@ -483,7 +486,6 @@ pub(crate) mod tests { use lazy_static::lazy_static; use pasta_curves::pallas; - use crate::utilities::test_circuit::{conditionally_save_proof_to_disk, read_test_case}; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; use std::convert::TryInto; @@ -778,28 +780,7 @@ pub(crate) mod tests { #[test] fn serialized_proof_test_case() { - use std::fs; - - let circuit = MyCircuit {}; - // Setup phase: generate parameters, vk for the circuit. - let params: Params = Params::new(11); - let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); - - conditionally_save_proof_to_disk( - &vk, - ¶ms, - circuit, - "src/circuit_proof_test_case_sinsemilla.bin", - ); - - // read proof from disk - let proof = { - let test_case_bytes = fs::read("src/circuit_proof_test_case_sinsemilla.bin").unwrap(); - read_test_case(&test_case_bytes[..]).expect("proof must be valid") - }; - - // Verify the old proof with the new vk - assert!(proof.verify(&vk, ¶ms).is_ok()); + test_serialized_proof(MyCircuit {}, "src/circuit_proof_test_case_sinsemilla.bin"); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 00096f327a..4cbb936095 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -187,6 +187,7 @@ pub mod tests { utilities::{ i2lebsp, lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, + test_circuit::test_serialized_proof, UtilitiesInstructions, }, }; @@ -200,7 +201,6 @@ pub mod tests { plonk::{Circuit, ConstraintSystem, Error}, }; - use crate::utilities::test_circuit::{conditionally_save_proof_to_disk, read_test_case}; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; use rand::{rngs::OsRng, RngCore}; @@ -420,25 +420,10 @@ pub mod tests { #[test] fn serialized_proof_test_case() { - use std::fs; - - let circuit = generate_circuit(); - // Setup phase: generate parameters, vk for the circuit. - let params: Params = Params::new(11); - let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); - - let file_name = "src/sinsemilla/circuit_proof_test_case_merkle.bin"; - - conditionally_save_proof_to_disk(&vk, ¶ms, circuit, file_name); - - // read proof from disk - let proof = { - let test_case_bytes = fs::read(file_name).unwrap(); - read_test_case(&test_case_bytes[..]).expect("proof must be valid") - }; - - // Verify the old proof with the new vk - assert!(proof.verify(&vk, ¶ms).is_ok()); + test_serialized_proof( + generate_circuit(), + "src/sinsemilla/circuit_proof_test_case_merkle.bin", + ); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 118a20fe34..31132976d4 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -468,7 +468,7 @@ mod tests { use pasta_curves::pallas; use crate::utilities::test_circuit::{ - conditionally_save_proof_to_disk, read_all_proofs, read_test_case, write_all_test_case, + read_all_proofs, test_serialized_proof_with_vk, write_all_test_case, }; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; @@ -580,26 +580,12 @@ mod tests { include_str!("vk_lookup_range_check_0").replace("\r\n", "\n") ); - // serialized_proof_test_case - { - conditionally_save_proof_to_disk( - &vk, - ¶ms, - circuit, - "src/utilities/circuit_proof_test_case_lookup_range_check.bin", - ); - - // read proof from disk - let proof = { - let test_case_bytes = - fs::read("src/utilities/circuit_proof_test_case_lookup_range_check.bin") - .unwrap(); - read_test_case(&test_case_bytes[..]).expect("proof must be valid") - }; - - // Verify the old proof with the new vk - assert!(proof.verify(&vk, ¶ms).is_ok()); - } + test_serialized_proof_with_vk( + &vk, + ¶ms, + circuit, + "src/utilities/circuit_proof_test_case_lookup_range_check.bin", + ); } } diff --git a/halo2_gadgets/src/utilities/test_circuit.rs b/halo2_gadgets/src/utilities/test_circuit.rs index 54e7c1af89..2d1251b768 100644 --- a/halo2_gadgets/src/utilities/test_circuit.rs +++ b/halo2_gadgets/src/utilities/test_circuit.rs @@ -93,7 +93,7 @@ pub(crate) fn read_all_proofs(mut r: R, proof_size: usize) -> io::Resul } #[cfg(test)] -pub(crate) fn conditionally_save_proof_to_disk>( +pub(crate) fn test_serialized_proof_with_vk>( vk: &VerifyingKey, params: &Params, circuit: C, @@ -111,4 +111,23 @@ pub(crate) fn conditionally_save_proof_to_disk>( }; create_proof().expect("should be able to write new proof"); } + + // read proof from disk + let proof = { + let test_case_bytes = std::fs::read(file_name).unwrap(); + read_test_case(&test_case_bytes[..]).expect("proof must be valid") + }; + + // Verify the old proof with the new vk + assert!(proof.verify(&vk, ¶ms).is_ok()); +} + +#[cfg(test)] +pub(crate) fn test_serialized_proof>(circuit: C, file_name: &str) { + // Setup phase: generate parameters, vk for the circuit. + let params: Params = Params::new(11); + + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + + test_serialized_proof_with_vk(&vk, ¶ms, circuit, file_name); } From 756bb78d37cc147c3c60ed702a2f68a98973e708 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Tue, 14 May 2024 12:31:59 +0200 Subject: [PATCH 52/99] Fix cargo clippy error --- halo2_gadgets/src/utilities/test_circuit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/halo2_gadgets/src/utilities/test_circuit.rs b/halo2_gadgets/src/utilities/test_circuit.rs index 2d1251b768..5a258c761f 100644 --- a/halo2_gadgets/src/utilities/test_circuit.rs +++ b/halo2_gadgets/src/utilities/test_circuit.rs @@ -119,7 +119,7 @@ pub(crate) fn test_serialized_proof_with_vk>( }; // Verify the old proof with the new vk - assert!(proof.verify(&vk, ¶ms).is_ok()); + assert!(proof.verify(&vk, params).is_ok()); } #[cfg(test)] From 6814fc2ebbfb5943db505f69da53fd2a2aab06c1 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Tue, 14 May 2024 13:03:14 +0200 Subject: [PATCH 53/99] rename --- halo2_gadgets/src/ecc.rs | 15 ++++------ halo2_gadgets/src/sinsemilla.rs | 11 ++++---- halo2_gadgets/src/sinsemilla/merkle.rs | 10 +++---- .../src/utilities/lookup_range_check.rs | 11 +++----- halo2_gadgets/src/utilities/test_circuit.rs | 28 +++++++++++-------- 5 files changed, 37 insertions(+), 38 deletions(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 53da5e71de..be57d50bac 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -598,10 +598,8 @@ pub(crate) mod tests { }, FixedPoints, }; - use crate::utilities::{ - lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, - test_circuit::test_serialized_proof, - }; + use crate::utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}; + use crate::utilities::test_circuit::serialized_proof_test_case_with_circuit; #[derive(Debug, Eq, PartialEq, Clone)] pub(crate) struct TestFixedBases; @@ -932,12 +930,11 @@ pub(crate) mod tests { #[test] fn serialized_proof_test_case() { - test_serialized_proof( - MyCircuit { test_errors: false }, - "src/circuit_proof_test_case_ecc.bin", - ); - } + let circuit = MyCircuit { test_errors: false }; + let file_name = "src/circuit_proof_test_case_ecc.bin"; + serialized_proof_test_case_with_circuit(circuit, file_name); + } #[cfg(feature = "test-dev-graph")] #[test] fn print_ecc_chip() { diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 791defe3eb..7bd9edc106 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -475,10 +475,7 @@ pub(crate) mod tests { tests::{FullWidth, TestFixedBases}, NonIdentityPoint, }, - utilities::{ - lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, - test_circuit::test_serialized_proof, - }, + utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, }, }; @@ -486,6 +483,7 @@ pub(crate) mod tests { use lazy_static::lazy_static; use pasta_curves::pallas; + use crate::utilities::test_circuit::serialized_proof_test_case_with_circuit; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; use std::convert::TryInto; @@ -780,7 +778,10 @@ pub(crate) mod tests { #[test] fn serialized_proof_test_case() { - test_serialized_proof(MyCircuit {}, "src/circuit_proof_test_case_sinsemilla.bin"); + let circuit = MyCircuit {}; + let file_name = "src/circuit_proof_test_case_sinsemilla.bin"; + + serialized_proof_test_case_with_circuit(circuit, file_name); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 4cbb936095..14214a6e8c 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -187,7 +187,6 @@ pub mod tests { utilities::{ i2lebsp, lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, - test_circuit::test_serialized_proof, UtilitiesInstructions, }, }; @@ -201,6 +200,7 @@ pub mod tests { plonk::{Circuit, ConstraintSystem, Error}, }; + use crate::utilities::test_circuit::serialized_proof_test_case_with_circuit; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; use rand::{rngs::OsRng, RngCore}; @@ -420,10 +420,10 @@ pub mod tests { #[test] fn serialized_proof_test_case() { - test_serialized_proof( - generate_circuit(), - "src/sinsemilla/circuit_proof_test_case_merkle.bin", - ); + let circuit = generate_circuit(); + let file_name = "src/sinsemilla/circuit_proof_test_case_merkle.bin"; + + serialized_proof_test_case_with_circuit(circuit, file_name); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 31132976d4..7ef97b6f9e 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -468,7 +468,7 @@ mod tests { use pasta_curves::pallas; use crate::utilities::test_circuit::{ - read_all_proofs, test_serialized_proof_with_vk, write_all_test_case, + read_all_proofs, serialized_proof_test_case_with_circuit, write_all_test_case, }; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; @@ -580,12 +580,9 @@ mod tests { include_str!("vk_lookup_range_check_0").replace("\r\n", "\n") ); - test_serialized_proof_with_vk( - &vk, - ¶ms, - circuit, - "src/utilities/circuit_proof_test_case_lookup_range_check.bin", - ); + // serialized_proof_test_case + let file_name = "src/utilities/circuit_proof_test_case_lookup_range_check.bin"; + serialized_proof_test_case_with_circuit(circuit, file_name); } } diff --git a/halo2_gadgets/src/utilities/test_circuit.rs b/halo2_gadgets/src/utilities/test_circuit.rs index 5a258c761f..a2877df66d 100644 --- a/halo2_gadgets/src/utilities/test_circuit.rs +++ b/halo2_gadgets/src/utilities/test_circuit.rs @@ -93,7 +93,7 @@ pub(crate) fn read_all_proofs(mut r: R, proof_size: usize) -> io::Resul } #[cfg(test)] -pub(crate) fn test_serialized_proof_with_vk>( +pub(crate) fn conditionally_save_proof_to_disk>( vk: &VerifyingKey, params: &Params, circuit: C, @@ -111,23 +111,27 @@ pub(crate) fn test_serialized_proof_with_vk>( }; create_proof().expect("should be able to write new proof"); } - - // read proof from disk - let proof = { - let test_case_bytes = std::fs::read(file_name).unwrap(); - read_test_case(&test_case_bytes[..]).expect("proof must be valid") - }; - - // Verify the old proof with the new vk - assert!(proof.verify(&vk, params).is_ok()); } #[cfg(test)] -pub(crate) fn test_serialized_proof>(circuit: C, file_name: &str) { +pub(crate) fn serialized_proof_test_case_with_circuit>( + circuit: C, + file_name: &str, +) { // Setup phase: generate parameters, vk for the circuit. let params: Params = Params::new(11); let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); - test_serialized_proof_with_vk(&vk, ¶ms, circuit, file_name); + // Conditionally save proof to disk + conditionally_save_proof_to_disk(&vk, ¶ms, circuit, file_name); + + // Read proof from disk + let proof = { + let test_case_bytes = fs::read(file_name).unwrap(); + read_test_case(&test_case_bytes[..]).expect("proof must be valid") + }; + + // Verify the old proof with the new vk + assert!(proof.verify(&vk, ¶ms).is_ok()); } From 64a8ac2f0ad42dfc7c76511e2a95a4b32bc45ab5 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Tue, 14 May 2024 13:09:10 +0200 Subject: [PATCH 54/99] fix git error --- halo2_gadgets/src/utilities/test_circuit.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/halo2_gadgets/src/utilities/test_circuit.rs b/halo2_gadgets/src/utilities/test_circuit.rs index a2877df66d..440a4474cd 100644 --- a/halo2_gadgets/src/utilities/test_circuit.rs +++ b/halo2_gadgets/src/utilities/test_circuit.rs @@ -7,8 +7,9 @@ use halo2_proofs::transcript::{Blake2bRead, Blake2bWrite}; use pasta_curves::vesta::Affine; use pasta_curves::{pallas, vesta}; use rand::rngs::OsRng; -use std::io; use std::io::{Read, Write}; +#[allow(unused_imports)] +use std::{fs, io}; /// A proof structure #[derive(Clone, Debug)] From 704d3f6b22837211e73b16c19611faa41a7be296 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Tue, 14 May 2024 13:24:30 +0200 Subject: [PATCH 55/99] Move all test .bin files and test_circuit.rs module to new tests folder in the root of src --- halo2_gadgets/src/ecc.rs | 8 +-- halo2_gadgets/src/lib.rs | 3 ++ halo2_gadgets/src/sinsemilla.rs | 19 +++---- halo2_gadgets/src/sinsemilla/merkle.rs | 4 +- .../test_circuit.rs => tests/circuit.rs} | 47 ++++++++++-------- .../circuit_proof_test_case_ecc.bin | Bin .../circuit_proof_test_case_sinsemilla.bin | Bin halo2_gadgets/src/utilities.rs | 1 - .../src/utilities/lookup_range_check.rs | 8 +-- 9 files changed, 48 insertions(+), 42 deletions(-) rename halo2_gadgets/src/{utilities/test_circuit.rs => tests/circuit.rs} (79%) rename halo2_gadgets/src/{ => tests}/circuit_proof_test_case_ecc.bin (100%) rename halo2_gadgets/src/{ => tests}/circuit_proof_test_case_sinsemilla.bin (100%) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index be57d50bac..56123d4116 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -598,8 +598,10 @@ pub(crate) mod tests { }, FixedPoints, }; - use crate::utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}; - use crate::utilities::test_circuit::serialized_proof_test_case_with_circuit; + use crate::{ + tests::circuit::serialized_proof_test_case_with_circuit, + utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, + }; #[derive(Debug, Eq, PartialEq, Clone)] pub(crate) struct TestFixedBases; @@ -931,7 +933,7 @@ pub(crate) mod tests { #[test] fn serialized_proof_test_case() { let circuit = MyCircuit { test_errors: false }; - let file_name = "src/circuit_proof_test_case_ecc.bin"; + let file_name = "src/tests/circuit_proof_test_case_ecc.bin"; serialized_proof_test_case_with_circuit(circuit, file_name); } diff --git a/halo2_gadgets/src/lib.rs b/halo2_gadgets/src/lib.rs index 2ac2623a99..cef325c385 100644 --- a/halo2_gadgets/src/lib.rs +++ b/halo2_gadgets/src/lib.rs @@ -28,3 +28,6 @@ pub mod poseidon; pub mod sha256; pub mod sinsemilla; pub mod utilities; + +#[cfg(test)] +pub mod tests; diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 7bd9edc106..f3a6cb15e0 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -467,23 +467,20 @@ pub(crate) mod tests { }; use crate::{ - ecc::ScalarFixed, - sinsemilla::primitives::{self as sinsemilla, K}, - { - ecc::{ - chip::{find_zs_and_us, EccChip, EccConfig, H, NUM_WINDOWS}, - tests::{FullWidth, TestFixedBases}, - NonIdentityPoint, - }, - utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, + ecc::{ + chip::{find_zs_and_us, EccChip, EccConfig, H, NUM_WINDOWS}, + tests::{FullWidth, TestFixedBases}, + NonIdentityPoint, ScalarFixed, }, + sinsemilla::primitives::{self as sinsemilla, K}, + tests::circuit::serialized_proof_test_case_with_circuit, + utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, }; use group::{ff::Field, Curve}; use lazy_static::lazy_static; use pasta_curves::pallas; - use crate::utilities::test_circuit::serialized_proof_test_case_with_circuit; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; use std::convert::TryInto; @@ -779,7 +776,7 @@ pub(crate) mod tests { #[test] fn serialized_proof_test_case() { let circuit = MyCircuit {}; - let file_name = "src/circuit_proof_test_case_sinsemilla.bin"; + let file_name = "src/tests/circuit_proof_test_case_sinsemilla.bin"; serialized_proof_test_case_with_circuit(circuit, file_name); } diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 14214a6e8c..18d031142b 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -184,6 +184,7 @@ pub mod tests { tests::{TestCommitDomain, TestHashDomain}, HashDomains, }, + tests::circuit::serialized_proof_test_case_with_circuit, utilities::{ i2lebsp, lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, @@ -200,7 +201,6 @@ pub mod tests { plonk::{Circuit, ConstraintSystem, Error}, }; - use crate::utilities::test_circuit::serialized_proof_test_case_with_circuit; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; use rand::{rngs::OsRng, RngCore}; @@ -421,7 +421,7 @@ pub mod tests { #[test] fn serialized_proof_test_case() { let circuit = generate_circuit(); - let file_name = "src/sinsemilla/circuit_proof_test_case_merkle.bin"; + let file_name = "src/tests/circuit_proof_test_case_merkle.bin"; serialized_proof_test_case_with_circuit(circuit, file_name); } diff --git a/halo2_gadgets/src/utilities/test_circuit.rs b/halo2_gadgets/src/tests/circuit.rs similarity index 79% rename from halo2_gadgets/src/utilities/test_circuit.rs rename to halo2_gadgets/src/tests/circuit.rs index 440a4474cd..136b1efb2b 100644 --- a/halo2_gadgets/src/utilities/test_circuit.rs +++ b/halo2_gadgets/src/tests/circuit.rs @@ -1,15 +1,26 @@ //! functions used for circuit test -use halo2_proofs::plonk; -use halo2_proofs::plonk::{Circuit, SingleVerifier, VerifyingKey}; -use halo2_proofs::poly::commitment::Params; -use halo2_proofs::transcript::{Blake2bRead, Blake2bWrite}; -use pasta_curves::vesta::Affine; -use pasta_curves::{pallas, vesta}; +use std::{ + env, fs, + io::{ + self, {Read, Write}, + }, +}; + use rand::rngs::OsRng; -use std::io::{Read, Write}; -#[allow(unused_imports)] -use std::{fs, io}; + +use pasta_curves::{ + vesta::Affine, + {pallas, vesta}, +}; + +use halo2_proofs::{ + plonk::{ + self, {Circuit, SingleVerifier, VerifyingKey}, + }, + poly::commitment::Params, + transcript::{Blake2bRead, Blake2bWrite}, +}; /// A proof structure #[derive(Clone, Debug)] @@ -56,15 +67,13 @@ impl Proof { } /// write proof to a file -#[allow(dead_code)] -pub(crate) fn write_test_case(mut w: W, proof: &Proof) -> std::io::Result<()> { +fn write_test_case(mut w: W, proof: &Proof) -> io::Result<()> { w.write_all(proof.as_ref())?; Ok(()) } /// read proof from a file -#[allow(dead_code)] -pub(crate) fn read_test_case(mut r: R) -> std::io::Result { +fn read_test_case(mut r: R) -> io::Result { let mut proof_bytes = vec![]; r.read_to_end(&mut proof_bytes)?; let proof = Proof::new(proof_bytes); @@ -73,8 +82,7 @@ pub(crate) fn read_test_case(mut r: R) -> std::io::Result { } /// write multiple proofs to a file -#[allow(dead_code)] -pub(crate) fn write_all_test_case(mut w: W, proofs: &Vec) -> std::io::Result<()> { +pub(crate) fn write_all_test_case(mut w: W, proofs: &Vec) -> io::Result<()> { for proof in proofs { w.write_all(proof.as_ref())?; } @@ -82,7 +90,6 @@ pub(crate) fn write_all_test_case(mut w: W, proofs: &Vec) -> st } /// read multiple proofs from a file -#[allow(dead_code)] pub(crate) fn read_all_proofs(mut r: R, proof_size: usize) -> io::Result> { let mut proofs = Vec::new(); let mut buffer = vec![0u8; proof_size]; @@ -93,7 +100,6 @@ pub(crate) fn read_all_proofs(mut r: R, proof_size: usize) -> io::Resul Ok(proofs) } -#[cfg(test)] pub(crate) fn conditionally_save_proof_to_disk>( vk: &VerifyingKey, params: &Params, @@ -102,19 +108,18 @@ pub(crate) fn conditionally_save_proof_to_disk>( ) { // If the environment variable CIRCUIT_TEST_GENERATE_NEW_PROOF is set, // write the old proof in a file - if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { - let create_proof = || -> std::io::Result<()> { + if env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { + let create_proof = || -> io::Result<()> { let proof = Proof::create(vk, params, circuit).unwrap(); assert!(proof.verify(vk, params).is_ok()); - let file = std::fs::File::create(file_name)?; + let file = fs::File::create(file_name)?; write_test_case(file, &proof) }; create_proof().expect("should be able to write new proof"); } } -#[cfg(test)] pub(crate) fn serialized_proof_test_case_with_circuit>( circuit: C, file_name: &str, diff --git a/halo2_gadgets/src/circuit_proof_test_case_ecc.bin b/halo2_gadgets/src/tests/circuit_proof_test_case_ecc.bin similarity index 100% rename from halo2_gadgets/src/circuit_proof_test_case_ecc.bin rename to halo2_gadgets/src/tests/circuit_proof_test_case_ecc.bin diff --git a/halo2_gadgets/src/circuit_proof_test_case_sinsemilla.bin b/halo2_gadgets/src/tests/circuit_proof_test_case_sinsemilla.bin similarity index 100% rename from halo2_gadgets/src/circuit_proof_test_case_sinsemilla.bin rename to halo2_gadgets/src/tests/circuit_proof_test_case_sinsemilla.bin diff --git a/halo2_gadgets/src/utilities.rs b/halo2_gadgets/src/utilities.rs index 515b02caaa..739f4411de 100644 --- a/halo2_gadgets/src/utilities.rs +++ b/halo2_gadgets/src/utilities.rs @@ -12,7 +12,6 @@ use std::ops::Range; pub mod cond_swap; pub mod decompose_running_sum; pub mod lookup_range_check; -pub mod test_circuit; /// A type that has a value at either keygen or proving time. pub trait FieldValue { diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 7ef97b6f9e..57b8bb8dec 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -467,7 +467,7 @@ mod tests { }; use pasta_curves::pallas; - use crate::utilities::test_circuit::{ + use crate::tests::circuit::{ read_all_proofs, serialized_proof_test_case_with_circuit, write_all_test_case, }; use halo2_proofs::poly::commitment::Params; @@ -581,7 +581,7 @@ mod tests { ); // serialized_proof_test_case - let file_name = "src/utilities/circuit_proof_test_case_lookup_range_check.bin"; + let file_name = "src/tests/circuit_proof_test_case_lookup_range_check.bin"; serialized_proof_test_case_with_circuit(circuit, file_name); } } @@ -636,7 +636,7 @@ mod tests { // read proof from disk let proofs = { let test_case_bytes = - fs::read("src/utilities/circuit_proof_test_case_short_range_check.bin").unwrap(); + fs::read("src/tests/circuit_proof_test_case_short_range_check.bin").unwrap(); read_all_proofs(&test_case_bytes[..], 1888).expect("proof must be valid") }; @@ -741,7 +741,7 @@ mod tests { if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { let create_proof = || -> std::io::Result<()> { let file = std::fs::File::create( - "src/utilities/circuit_proof_test_case_short_range_check.bin", + "src/tests/circuit_proof_test_case_short_range_check.bin", )?; write_all_test_case(file, &proofs) }; From d0d3a6f7857558f96a7b7e2fd65bc3af816bca6a Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Tue, 14 May 2024 13:34:34 +0200 Subject: [PATCH 56/99] Add missed files --- halo2_gadgets/src/tests.rs | 1 + 1 file changed, 1 insertion(+) create mode 100644 halo2_gadgets/src/tests.rs diff --git a/halo2_gadgets/src/tests.rs b/halo2_gadgets/src/tests.rs new file mode 100644 index 0000000000..a9af55fc06 --- /dev/null +++ b/halo2_gadgets/src/tests.rs @@ -0,0 +1 @@ +pub(crate) mod circuit; From 35f161db606dd6586d1b904fe300c12ae448061d Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Tue, 14 May 2024 13:46:03 +0200 Subject: [PATCH 57/99] Move all .bin and vk_ test data files into src/tests folder --- halo2_gadgets/src/ecc.rs | 2 +- halo2_gadgets/src/sinsemilla.rs | 2 +- halo2_gadgets/src/sinsemilla/merkle.rs | 2 +- .../circuit_proof_test_case_lookup_range_check.bin | Bin .../circuit_proof_test_case_merkle.bin | Bin .../circuit_proof_test_case_short_range_check.bin | Bin halo2_gadgets/src/{ => tests}/vk_ecc_chip_0 | 0 .../{utilities => tests}/vk_lookup_range_check_0 | 0 .../src/{sinsemilla => tests}/vk_merkle_chip_0 | 0 .../src/{utilities => tests}/vk_short_range_check_0 | 0 .../src/{utilities => tests}/vk_short_range_check_1 | 0 .../src/{utilities => tests}/vk_short_range_check_2 | 0 halo2_gadgets/src/{ => tests}/vk_sinsemilla_chip_0 | 0 halo2_gadgets/src/utilities/lookup_range_check.rs | 8 ++++---- 14 files changed, 7 insertions(+), 7 deletions(-) rename halo2_gadgets/src/{utilities => tests}/circuit_proof_test_case_lookup_range_check.bin (100%) rename halo2_gadgets/src/{sinsemilla => tests}/circuit_proof_test_case_merkle.bin (100%) rename halo2_gadgets/src/{utilities => tests}/circuit_proof_test_case_short_range_check.bin (100%) rename halo2_gadgets/src/{ => tests}/vk_ecc_chip_0 (100%) rename halo2_gadgets/src/{utilities => tests}/vk_lookup_range_check_0 (100%) rename halo2_gadgets/src/{sinsemilla => tests}/vk_merkle_chip_0 (100%) rename halo2_gadgets/src/{utilities => tests}/vk_short_range_check_0 (100%) rename halo2_gadgets/src/{utilities => tests}/vk_short_range_check_1 (100%) rename halo2_gadgets/src/{utilities => tests}/vk_short_range_check_2 (100%) rename halo2_gadgets/src/{ => tests}/vk_sinsemilla_chip_0 (100%) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 56123d4116..1fdd2dbec0 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -926,7 +926,7 @@ pub(crate) mod tests { // is as expected. assert_eq!( format!("{:#?}\n", vk.pinned()), - include_str!("vk_ecc_chip_0").replace("\r\n", "\n") + include_str!("tests/vk_ecc_chip_0").replace("\r\n", "\n") ); } diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index f3a6cb15e0..685d7f872c 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -769,7 +769,7 @@ pub(crate) mod tests { // is as expected. assert_eq!( format!("{:#?}\n", vk.pinned()), - include_str!("vk_sinsemilla_chip_0").replace("\r\n", "\n") + include_str!("tests/vk_sinsemilla_chip_0").replace("\r\n", "\n") ); } diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 18d031142b..9bc56e9b04 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -414,7 +414,7 @@ pub mod tests { // is as expected. Which indicates the layouters are the same. assert_eq!( format!("{:#?}\n", vk.pinned()), - include_str!("vk_merkle_chip_0").replace("\r\n", "\n") + include_str!("../tests/vk_merkle_chip_0").replace("\r\n", "\n") ); } diff --git a/halo2_gadgets/src/utilities/circuit_proof_test_case_lookup_range_check.bin b/halo2_gadgets/src/tests/circuit_proof_test_case_lookup_range_check.bin similarity index 100% rename from halo2_gadgets/src/utilities/circuit_proof_test_case_lookup_range_check.bin rename to halo2_gadgets/src/tests/circuit_proof_test_case_lookup_range_check.bin diff --git a/halo2_gadgets/src/sinsemilla/circuit_proof_test_case_merkle.bin b/halo2_gadgets/src/tests/circuit_proof_test_case_merkle.bin similarity index 100% rename from halo2_gadgets/src/sinsemilla/circuit_proof_test_case_merkle.bin rename to halo2_gadgets/src/tests/circuit_proof_test_case_merkle.bin diff --git a/halo2_gadgets/src/utilities/circuit_proof_test_case_short_range_check.bin b/halo2_gadgets/src/tests/circuit_proof_test_case_short_range_check.bin similarity index 100% rename from halo2_gadgets/src/utilities/circuit_proof_test_case_short_range_check.bin rename to halo2_gadgets/src/tests/circuit_proof_test_case_short_range_check.bin diff --git a/halo2_gadgets/src/vk_ecc_chip_0 b/halo2_gadgets/src/tests/vk_ecc_chip_0 similarity index 100% rename from halo2_gadgets/src/vk_ecc_chip_0 rename to halo2_gadgets/src/tests/vk_ecc_chip_0 diff --git a/halo2_gadgets/src/utilities/vk_lookup_range_check_0 b/halo2_gadgets/src/tests/vk_lookup_range_check_0 similarity index 100% rename from halo2_gadgets/src/utilities/vk_lookup_range_check_0 rename to halo2_gadgets/src/tests/vk_lookup_range_check_0 diff --git a/halo2_gadgets/src/sinsemilla/vk_merkle_chip_0 b/halo2_gadgets/src/tests/vk_merkle_chip_0 similarity index 100% rename from halo2_gadgets/src/sinsemilla/vk_merkle_chip_0 rename to halo2_gadgets/src/tests/vk_merkle_chip_0 diff --git a/halo2_gadgets/src/utilities/vk_short_range_check_0 b/halo2_gadgets/src/tests/vk_short_range_check_0 similarity index 100% rename from halo2_gadgets/src/utilities/vk_short_range_check_0 rename to halo2_gadgets/src/tests/vk_short_range_check_0 diff --git a/halo2_gadgets/src/utilities/vk_short_range_check_1 b/halo2_gadgets/src/tests/vk_short_range_check_1 similarity index 100% rename from halo2_gadgets/src/utilities/vk_short_range_check_1 rename to halo2_gadgets/src/tests/vk_short_range_check_1 diff --git a/halo2_gadgets/src/utilities/vk_short_range_check_2 b/halo2_gadgets/src/tests/vk_short_range_check_2 similarity index 100% rename from halo2_gadgets/src/utilities/vk_short_range_check_2 rename to halo2_gadgets/src/tests/vk_short_range_check_2 diff --git a/halo2_gadgets/src/vk_sinsemilla_chip_0 b/halo2_gadgets/src/tests/vk_sinsemilla_chip_0 similarity index 100% rename from halo2_gadgets/src/vk_sinsemilla_chip_0 rename to halo2_gadgets/src/tests/vk_sinsemilla_chip_0 diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 57b8bb8dec..5f408e0e65 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -577,7 +577,7 @@ mod tests { // is as expected. assert_eq!( format!("{:#?}\n", vk.pinned()), - include_str!("vk_lookup_range_check_0").replace("\r\n", "\n") + include_str!("../tests/vk_lookup_range_check_0").replace("\r\n", "\n") ); // serialized_proof_test_case @@ -659,7 +659,7 @@ mod tests { // is as expected. Which indicates the layouters are the same. assert_eq!( format!("{:#?}\n", vk.pinned()), - include_str!("vk_short_range_check_0").replace("\r\n", "\n") + include_str!("../tests/vk_short_range_check_0").replace("\r\n", "\n") ); // serialized_proof_test_case @@ -690,7 +690,7 @@ mod tests { // is as expected. Which indicates the layouters are the same. assert_eq!( format!("{:#?}\n", vk.pinned()), - include_str!("vk_short_range_check_1").replace("\r\n", "\n") + include_str!("../tests/vk_short_range_check_1").replace("\r\n", "\n") ); // serialized_proof_test_case @@ -721,7 +721,7 @@ mod tests { // is as expected. Which indicates the layouters are the same. assert_eq!( format!("{:#?}\n", vk.pinned()), - include_str!("vk_short_range_check_2").replace("\r\n", "\n") + include_str!("../tests/vk_short_range_check_2").replace("\r\n", "\n") ); // serialized_proof_test_case From 497c29000305825fc77ac11d9690b9a775476e0b Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Tue, 14 May 2024 15:43:26 +0200 Subject: [PATCH 58/99] add tests for short range check --- halo2_gadgets/src/tests/circuit.rs | 20 ------ ...cuit_proof_test_case_short_range_check.bin | Bin 5664 -> 0 bytes ...it_proof_test_case_short_range_check_0.bin | Bin 0 -> 1888 bytes ...it_proof_test_case_short_range_check_1.bin | Bin 0 -> 1888 bytes ...it_proof_test_case_short_range_check_2.bin | Bin 0 -> 1888 bytes .../src/utilities/lookup_range_check.rs | 58 +++--------------- 6 files changed, 8 insertions(+), 70 deletions(-) delete mode 100644 halo2_gadgets/src/tests/circuit_proof_test_case_short_range_check.bin create mode 100644 halo2_gadgets/src/tests/circuit_proof_test_case_short_range_check_0.bin create mode 100644 halo2_gadgets/src/tests/circuit_proof_test_case_short_range_check_1.bin create mode 100644 halo2_gadgets/src/tests/circuit_proof_test_case_short_range_check_2.bin diff --git a/halo2_gadgets/src/tests/circuit.rs b/halo2_gadgets/src/tests/circuit.rs index 136b1efb2b..649f775e74 100644 --- a/halo2_gadgets/src/tests/circuit.rs +++ b/halo2_gadgets/src/tests/circuit.rs @@ -81,25 +81,6 @@ fn read_test_case(mut r: R) -> io::Result { Ok(proof) } -/// write multiple proofs to a file -pub(crate) fn write_all_test_case(mut w: W, proofs: &Vec) -> io::Result<()> { - for proof in proofs { - w.write_all(proof.as_ref())?; - } - Ok(()) -} - -/// read multiple proofs from a file -pub(crate) fn read_all_proofs(mut r: R, proof_size: usize) -> io::Result> { - let mut proofs = Vec::new(); - let mut buffer = vec![0u8; proof_size]; - - while let Ok(()) = r.read_exact(&mut buffer) { - proofs.push(Proof::new(buffer.clone())); - } - Ok(proofs) -} - pub(crate) fn conditionally_save_proof_to_disk>( vk: &VerifyingKey, params: &Params, @@ -126,7 +107,6 @@ pub(crate) fn serialized_proof_test_case_with_circuit>( ) { // Setup phase: generate parameters, vk for the circuit. let params: Params = Params::new(11); - let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); // Conditionally save proof to disk diff --git a/halo2_gadgets/src/tests/circuit_proof_test_case_short_range_check.bin b/halo2_gadgets/src/tests/circuit_proof_test_case_short_range_check.bin deleted file mode 100644 index 61d4e7caaba6043cb67921e1daa37134ef44273d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5664 zcmajgg*zOM1AuWcb-FuFclVu+VcN!+9!^b7$8=419LJpQHr?IbX4-T&zu$lGegB5{ zc|LB9veqe0LWv=DPRAT0->+$X{WBIHoV^h1AV&l!e8%CRs^kr$6(oJ z{LxOjJh#fR=k>-7q*yEWBFd-6-7(fkVd4>8q=j?n0VO>$yyShJVbb`A)e^(Qr40W) zLX7vi!9h|g9>TU2RzqBszC5mk;*pl~9D<>I^y6>JZps%tzl?;gb~#Sp2no{aiF13x z`VVqIHj;ZY#y@WV=1)7{Z9SU~@EMrQ4zd_9^|k3c$s9xFwjwNxDSdq_?yXA^l4o({U?OL(`PkoSS-5W-?;f;T2L1MvSwc<}(K9K2cm|pLKK%q?T zwIUB*e~DjU91JUGTZw*3bliwEm!WhBcdmqgt)XgVgd?;qpc5ID#C+OAz0d9)+@q(4 ze3U9qx0*lOOOQ;CR1J}5k;?$#V(+oxT_qLV_Xr>Jiy$01bC=X|89e4a1~{C&*Gw3_ zZbYg^If)BDvXtS06y919Jyj5WCE&nujn9Pkd=~)w*S%a&Vo3?>ga%?B`*U+>Cr?X} z0Npa2o*fk}d<;yo^d@w!7}$SqoO7jV0qIM!1j7qsaD!@R)?N5+mk0|YITV}DXCF*n zSabG4ySTq)w7e#Zg)0;zT#dP~Iq%n9gx}G3$CyUiiTrEWG-Cl#IkB0Y5bpIv8s%6y z#Lv*FF^XJXiE9cD1+{Z)bEDbLNxW>+U?coTmUvD6cmE3SA*C$q|tx^pA?H1A22 z?`jf{gNfWp_KOUhbc>QqDOdMestPTc^aW5&*)heCCs_SIKh1Aqnu6`l3hr1wKHcCN zm~jZKg}zqTwz7urMjf?}8CnpMH&bel=KINP1jTa?21_lh37Wx}<-Dn>P-GCXQY23} zF-(dHI(1k`@1VBU^(XNJ2=dtoVG(0IQa=VbKt^&nzfJy7PTr@r|@bsT=N7KNUHe z2>)7L@8fC-Xc@`9O5UJTFB4hKJ8hp@8^%gR(uh3OEb$1bWu=*7Wf1MPj6S$zueftEFEl5Bb9AEB`qjN5HExIuxKt}fYT)pU+qp7U(c z(i!`-w|-TWxF&ewc!+lKMMkA~JbDr;{wa;6*gU4YWVT!D)M0wfHU82L2I0vp^rVOR z=#5){FWSFgDLe3xnb9*)B{5xHm~>W05TukzkcL_@4a>8g*#vMs+Pr@K`f8*tmNn4* zX=|}m)c;Kx>!bV`e#`x?Fx~hDI)$F?X$T6M2Cc zdG^1G0{k+B)~SVBEyp98kLewgSrvM7m%u5E0!+ehNlPt%#S%^L)%F;Pvyl#l^33TU z9_rXr48Eh|Wd z(88~A=eFjN#vg05K^;8e##0YN=~Rj=)+%)jAgKrr60|?=^bVx>n9VyAYJvW@qgIHX z$Gl?cQmO17=ZV2FTt2AD!L|yPS?XB##PAz6{(5#pnwnS)z;TDlgD{uO9l&8Nj@1S+gV$@B=x{Xg<5qnDoA+zv=wIQ7pL9qzG|FR~uht!V7+q4WP_I22%k+ zHn`d_-*OdJJ;g=@9WoHy<);PQbzX*RwXcH5vB;&;aaHRWaE)_WY!#t;8mT38v@ujSNjI(rx;+GlDQGO>Z`)U% zY!7pB5N{zhyVD8OCa`@F%~BN zOqY{@kLZ(b@75R8_DIxA{9VT=tocuwseEiPC_6Dpo?w?$HV#F7QlcLgM9-3X;-(N# z@3D)F`@@_uMGs?S(`vg!xHadJWEeM%EG0ShpANrIZhVzBh)bsBghLP$P9Avez{b@Fd)B2Na@ zk8})tLr++QTzB{!Tv}?{LEj25s~5>2m|A!W(PQJ#l7`%;b!J9xRqlJ%?ldC*q4K;d zgZPaP27a87ow8;-@}tUNdeAepzAV`MRBv|k$TV^BDrB=bE+A_G7hMS5*}KiM!i08@ zHFxGKs!IaXfD@1Ixn7Gzd*(O9#m(aN8c9|9M&B8T|26kl_pkk&kDG^r8gIySd>yu zi6hrzX11`b3QZBjH+*C|djrA_6!sEt5nu8KRv6KKxACJTqIZf6HdHjC!s(Q{TI&rU zsy7tQy=)@D;Xdl@>Bw(Ebb5H{O1P|;`Bb$MxDw7DI%~-YiEmeo$2NRo!}>RpXt$q8 zDb=5NCn+P?gfhQMU}Gx4>h~lavCRL*4*6(0R+p6bbFt>OOQEeX6&VJx)ZucKTjIWL zno^>m1#KPi4^DfA?xijx3H7dJVClo6{r3kIBnThD$H0^J+9a&x{U-#NH}5IsOpdHgD?qfIIOk{8#(Uh6ea^@MsbgAu zY=s>qU!fPD-(pp*nfQ${0&6J$EHDJ~qxP(O zmB{QfoA)XV!_+Z>L#ebFpHwORSx!I8%c_Kun$=>#I=G{qk+&v}QQ4@H*Wi4@v+xOr zq*{y_@?GzIkM#!I)w{aF=Z|;p>f=1QoxUM8o1NluffT1fEMz-I1rSWyX6---j3wHa z;yP@)rF^WhrcJ;{Zf;!2t_e@H@Fl5E9%ktHTJz~n4qFVo8U0QB$RZ)xDf*$^z#=)3 zlatLVzA_==_#_o{t)j@}4aVonF5RBWdV9U_g850v#sScJ<&v*u<7HJ&N3MaGS1?lk z1?6vOUWezNSZOU{L&p)NR1m^|E{KyKk0K{o62YbR)#1){;+VCsp7MvT8+-O_xLoqY zvyiu`d11kKo_fS7V=)FIWcMjg9=$|HupY*jI_9>Fkl;;@4)Rk%!>u zs%uV2=B>m1#tE8R739Skx7|+s0)iEU1*n%!qb^B=m$79PH%7LRMexcM2T zrV|{Rj55=Ddz8v3X5E&tMM&yN@E+?XNeW%SxIl7KKX=~qy`~+8HqtgD`S6I9?bOES zm7jG6Ody&!qJlroKT6)WA#03Yg@F+pVi~Jh13xs77FGbVP7btfHu)<%+*=nU%r|U% z$&PTrAKB1wbhxCj029?e)gk`W z^{Vi2Y-HpZ3;)C70KAY1?;!AxF|vE%Ohc?aa~kwzq-DEvIt{~@pBiZszkGn==|3vF zl0h@q6tSQIo|}bO=b)ITJ*Q&%ed9f{TB$>@`vDlRGGCUD*GlxOLdS=#^fMcHNH4Si zuM0K5@s+X!2iAA?N;JB0w-0=%RN?NKFXRqZa3I^JQ#!V57^*`R&?`u8$+Jzr7AFsr z98E{djw>E37*2!#+Q9hbSSr9=s+gxr#}T8+=u%Gak6fNC&7H#MLcu*^f@mH)eL&#U z4#w9UyvsX9GtahO4$qy$m-!cfCM_9i23&+u5xeAgnl*e^EJ=;rQD*;bklKR(`R@pd z9Y_F}oaJ#;mtyOGd}O>hGio2dGD=SZZb?ljbEgAhif*D9@z5u4cJJ;l1Cqo1w7t@P z*t1Nh-)GuqCyZh1*?1$}7J}9W{yifs<5x@IwgsE*bGO5hnalcM1QL7S$!ETAqjr zZ34klz}nICtCo=W&2imWUi)-UCI9y9jnEU4DisSWu)-->v%YL&VS(D{u!;h=PjFt1 z!mHapg+x@Y7(rXM$I;v&^Y;H2ojWNcS~RLlK1TF{+Gjm+xG(po1BwO^qF@+`pP8!5 z5i6#AiT}vgj*N`$_1*=`4co8ZF{L8R3PkU#aQ>IC zy*qS2pSftuL>-SNQ%z|)x>;)TXL&4A^=P(svTDm&-LZOe==5pLQtC8rWnVM;6iL@5 zw&qtSyosq1f#^V@!!2s-#A!F-k*)bf=e#p+HmbWlem}8c69wkZMdcwnK1u=XdL{Zq zO?|ur!OqE2jlyRPZNmyU7>uB6=f=|$lnG1`^*#w$VeILNh8`Tv-%I-XM6mx?6HE`WLxT0@$g%-irPyaeT0VxR)XGdgDxPPcNb4znF43mM zEa?Bbl8c?Q;ZxXMMW&<2Wrstqf(8-CW(mv6`f|{@j`yVPFb0;1lva0a>(?%BNc*Gr;I;O|Cokdq$y)!|)<+p&=A*J;1IAneaWnWg~ar= zh5P7|z)?BeM5BwBkVcv`muYT}`KQ^LF;kJy=)j@^PupI2;tv&UI;I_ppQlBq6{}^q z%W=TPM5YhIeVg$VQSVdG-v!LHx^w(04@A0mh4xS4BD#G9FH8w-q2Rlk4S&mPq<7K* z*Hp=8)^zrgpI(A={MpSYkk~j^pI}7i#*Y1w= z?n@#uvI)vM0{W6WrjL@D-zY)GH%KqqXLh~y4^_N|b=mrHlfLuvj${drZ8~Yxh&*Tl z?DG1LG0)Q6xLCl@^+w5K+pGl4n9TrNmV&gv-2*(hz_VI$57EtWS<2Kdd-PrJZaQmj zhk*1*P(@{FXNVldGM{nhocSGm4{tML@chwi$l$!~l(&#;R52W%4@oO|BlY z=4(e(vopsjkAOK2=d8VoV;gn$@;(;7aAUq|LWoIyTFh+8ZQOBj}h=_mRnC)Ap zIV=If=R)_K6cS!hkIfR%jvdXU@IWy{_A&~@g>&3re(aCYqYEqRqfR^NZx7dRSfa|B zi-N0>cP?(Lm^qWpNM7Q+{NBq9`KvGpD9ALQcikGuw-CG;|0e7atFR*+>eNi-UX}F- zI`|~_yv`|++_Nb~g8M2-ppaxck^}(j6=T zeQT_geHGu#syZSFo|3}VI}9_QV@48EYp_n?j8ZO(hju~JFVnE)S3U`hq8_$)@uye_)ANRuV@FmJxf<7p#RK|aK&>G$69lWU5m%1^IMxJfe;Z3i}nEsoJ(o$2n+*FDt=(u-W z;nxpeTu|>E*8_Lw$(AfcfYdSnu}7aq!?D0%Jh(7fXtYN`3x))6WT5Ayi@^7N*8_k?QkvBzbc{opQ)76X2bPo^)a_0fPj9g z!jj5?QtwF;V8#LDGVm@LE=%RHw1SCd#90Kts1x19n#(T!G3W2*-WD*leUd`0m7Uz- zPHZVj#qR^QHP>Mr@nezl`H9(RE#O@(9gY7Ul6yd1-}ZxuuSE!EwM@er1Dg%_LMQ}C za5*3KI`hxC3W>^d$*@vca$gCqN;ywAjm&|N@H#p}SFgLK#o5^eeJjZlCUW4iffp7) zvGH`0)xGCJyd0hPV;j6NV;kqO8Wpr&oG5YoT7@nE0000000000000000000000000 z00000000000002m`=qgV(jwYQdGwgC^WmI4C@2^C4~*&R(sv%B=p`j=dq#!lG&rPy zq?|}S@mtA9spA=a8J8B!gK@C3E29!?&FSDzXLu`|)2YBBcVZ_M^iuRYNA$3zqtGyE z%CiCQs-{@%**^QPOQH7rO^@S7pW)$^ZRBd6xD1zz>qiCeqqw&MPXY(egvhsqtT2TY z@=Kt3Rppntfz;@^UdI9w%enK0UFx&?O#||w;hS%CpoPVluh!izl1IIz1hBPIxQ;!gNrgab=J*-Zij*E2-~Ad6R?R$;)?G| zBVW)v`yqkjec=G?1s#*yJ5MaZR}jsrZSmPcnfX^MN2~o7^K!R)k!==CPpb*!JgVT8 zF$^Pt8nyW1;_KsAOkvg*c9$wu9|1Y7PfJR!0xowRyW%M%cSjs^4$+Ly7DDilS%xyj z*R>5)9eOQ%={*y;L@oN%o>GFbw`PXTvNlKGwOG#T@u{;HZYJ+s@Tl@1}5gPNRgBDx@lkLXi*jUWsR=Hv%--gQQfxCW16g_t^a`V{2Vyn|A5 z;oI}Kb?A!z1evVKwLFlD29TrginyRnXo+hq+AjTp4Rx~9lG#6HyFWw!5 z33Sm0|Eh96Ln*q99#Ea+$Gzlxj8Or}j-@F-7ICSeW zC>bw=krVeF(a6dmr=_??97nZfA=rs^M-na;@`?9u?CkX+8cPQd;u2~)6o*@ zeb;QCjA_H1_3Y;S#3O*TCfz965#iqyDs;nEIm~`;eKw6OyfLoXm57>uMOI{vLPP*R zr>bFy=|17aJzisn%_2|(ph?ge7jG&_BnRv?jdzyQ&id-8&y_~6R4Oz!1P1W+#81h; z!z$}yoQrT0z3~`lGeWAX;u79wg^K>bwl4dWe(vt^bARnlL; azfNaNQ7wk9H5{#vasf)>7IoK39~UZb5^tMyi=_t7`Dfe0sH)Twt;%m9pq4_ZX5I?xwPyWNC1 z?zs46F-khB2Eo;s)Q*ZFY7#gIGQ9f}z6Yv{Y>^wZe?bhI1BnbYn@slUg#5s3a9D}0 zst(&^<#Qkm1*VguP&bFCkkW+vnb}}y=?mFjot_7|)aE=Y+3g_>{{NVFgtR)!J9^*;`P1U~kf4NT%jcb-D} zh#qEbKxD|L7$P1jQ9hj%&iS4eTt0aD=nS|K$O}R`{|sgRZPffEGX>RI&jBqehY>^D zVylMiCS!uKf?J2C@EtG-U12nU#GBS{ROC1&1~x9?ZiZ!aOl)^K2%kGdL)0-Eick)M z`8W_f59mCpf^50W#UNgT{K5EB@4YrghA(jBRUkC|IjKJFrSI+-ysy@?f3?L>J{d?r=pg^#l(#FvUQB=5$&eaAhwwc z<b1mWU91zUSi17Ts+)@Ze%HVmLhG z5@A>5L=$`xEVRi8L4PEtZi#O`{JB;iJF&w(aJ$?*&~`fjOo21}3_A3xd<6|uiE3U& z@E$;~xH2Ka1vPnyj)3wB>jZX&DUK!j5xrn0M!?qnR_M< z8MtBhTq|mM0|ty~E(3TXY9uPX6Ha_gz!|d#0XB`kio!lQhlOGQGtujateuBv7IS)n zaffY%QKoTEUlJ`dk++huj+}eVNB?9v>FjDm2hfgr-)FG=mKi#y+OsgJ*W8W&M`8Y! z?gMiLf>TOjT+O}fY1pAcL{s?A{|yg?JuI8|6Zb8k=OpGst<3qeDgv7z*h$-uC8@8T zjfpaLIXQ0Oo`KL=r0blWFo&HkR~Ml)OM3sIn(|=&9hDuWjlnRjPWIs=l=e3@fIP+Z zl*6|gLRsBInwvg*-7S!SFR_;j?lz>5+jsR2X2YuH9hjuJWV}x!Mv-Teo0~%^CX)< zm+#1PQtl;t6{iGL$!+8Y$xI_mPl%$8)CAD$`FMLu1ckPd^RWrG;n@stajD*A_Y%&f z(H7`a4F}mXL8&BMKkpu$lgB;hJHslu^fW$RTjM6~1N}%%5=GVlR(^VK?Cq6@cdphX z?D(x%3oT1xPy`+b)z1rb9b3Su7Bbzb4OH7$K00XJ zb}X-m^IBl3mt>K=GddC4Jvd-$A9J7CL#G^)WV?c7j!)~d!!s9~bE^s7@LI3TQ@lNz zDk&jRaG^b1n9!0DoelFImrU;31gQ^?sGO|Bhg>rwQ}w5?2Ey$&q~;-Xi%G@ZOJLEo zjuTJ4jS27Y$>D|)Qf22m`mW@|5*v(^t&pD z;{)NoU+M-4DsnCjg`U1^4HG6^R*`rgCL90Z12~z@QmOhaDTrQ3wkv@=J@E0VgMuVc z##BR6K;|z-4)+k^51J6ba+Tf2T4}awx`GIHK8!{KXo0BvE literal 0 HcmV?d00001 diff --git a/halo2_gadgets/src/tests/circuit_proof_test_case_short_range_check_2.bin b/halo2_gadgets/src/tests/circuit_proof_test_case_short_range_check_2.bin new file mode 100644 index 0000000000000000000000000000000000000000..37f223f7c236cdd365ac3a8512eacc2f987b96c0 GIT binary patch literal 1888 zcmV-m2cP(S&XXZm_z|2wJl$9lZC$Ub!)y+=zZjf5A;5lKQ6i7J$4=he2(ukKuaHlY zs9~c1i_zFX^|SxG8U>*`e18%1A~+Xyca6I;D#~ZeBk`dBgsr~>j;QF^)?5{osYwd| zOHrj}>o0kXUk>PV$gopruNklt8FzLR6={)v2Fe!uFEQ`lav7zOO*nI$D-+Q8l^ALc zF0|3|(e2~>p&Fa5H@erwK(qniiSl_r;JNl%uBHq^Xn+3&(3l$RADo}GeKY8~_?ZFM zYHrSOlKgC@BVag-7*;PsPBY&We`$;rr)-U>ZoK15X!fNoO>5KBDq`#3$es(*<&$8t zFUuzi6ui6@1GEa4{&z|)(#9*Lzo{p!?SvMy9|`79jV6rb0@jkfU?ac>EqhdV`)VZ= zD>W94Z-@A<#Htlv`<|7fA^m*3{?U%L-bCzu@l2i($z2f+Pjc%!i_n4rOlouG9 zu$4iqPTeZqB@8Hj6m{y$k*Qd6rWq7?@?{T|HYy$atY6Iwo{q~7N5Jj(|CX6-krxr6 zy_oEZ@-qZcOKNJXq(55_1#3?@3(-Cc_-)3tk~hQZgKZuOtF*ASx1sj(TjKvMwa_F~{A951_0000000000000000000000000 z00000000000001meqJUjlWP1T08`5MlJ4s1yzaq!QH`HapYOH2Mie;L%Mn^4#e7{{ zWf}XgA2*4Rg*Kq}l{TBA6x3i@d&Z)jwGL1m=h`Un|0fQ!Y z%j+Va=VhyIM2Jzpf&hWyCKShUB^=AJDfBL!b=1qDY>_HM_CZ+6V1i=@V(sLuq#`dJ z?(Y6IBml>lI#_$U=It;5f9g~No_GvtL?!f}La;VbeJY-mx_IbM8h`|#vJOk~ zYr8@PL9>eqnbqUF{$sz2$2w-Ry@%_RtY34grQ2p_@%JMQr zmWl}zEfgAPge`f5Z`M*Iya6$7CghlOcgkZ;SFD{u>AcPk0tF5|e*GpR;?bnye(&$4b6I$` z5mZ08cS@pUG#-&8OPGJ+OAz_7{UW3dK~>UBtU>bxgol?am6VS(rab&ga);$qvi@{# zV;kufZgxo&pJ=I8Oa8P_W!#Zpwx$VwMLSP0IvT7x^2p4&GM(mVz@#qb&-){Xl7&%3 zIHWn+L}D*01chENDTnzmjdw=smquEWDEN`HeBs&Y|^x(s_@LY6?qyYneU#fsK zW|wLkxABJ1q@xMfst+s8i+!5G=sBAhOt{E6ti`AvZ|d%V@+#$CHfWzpVGmi8pZ(Pm zk`0?{Y}0DCJOsV z+wIh;)<4BqzbHo*DyO4EA(FIeJfAnql1f-~FIwic|C*XXUe?hb^txkfXR#Q|(=gSN2V>P7HCBCC(y3arQ^3!37{jmklZ zP#shh=pTLGSsU_u3pO+^XFG!ObmHpPI8&E?40U`VoYj*ubNRoJ7|zPq(@EfxeGfRo z%**Q9wqf(r9FcV7nx2}g8IVR<0z}s48XSf)w!%E5CzPe5!o>L0V3!l89>aUvezC<9 zU384R*R^_P?ai_zTJERi^#E2j@VTT3tu-{mI>n`xnnV*Ktm+Ax;W|9#!r`H{1o?JT amHr9D2DTd1g`_$k-1=#$`nay2l7%QM6`VH! literal 0 HcmV?d00001 diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 5f408e0e65..40741ea7c4 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -467,12 +467,10 @@ mod tests { }; use pasta_curves::pallas; - use crate::tests::circuit::{ - read_all_proofs, serialized_proof_test_case_with_circuit, write_all_test_case, - }; + use crate::tests::circuit::serialized_proof_test_case_with_circuit; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; - use std::{convert::TryInto, fs, marker::PhantomData}; + use std::{convert::TryInto, marker::PhantomData}; #[test] fn lookup_range_check() { @@ -633,13 +631,6 @@ mod tests { } } - // read proof from disk - let proofs = { - let test_case_bytes = - fs::read("src/tests/circuit_proof_test_case_short_range_check.bin").unwrap(); - read_all_proofs(&test_case_bytes[..], 1888).expect("proof must be valid") - }; - // Setup phase: generate parameters let params: Params = Params::new(11); @@ -663,15 +654,8 @@ mod tests { ); // serialized_proof_test_case - { - match proofs.get(0) { - Some(proof) => { - // Verify the stored proof (case 0) against the generated vk - assert!(proof.verify(&vk, ¶ms).is_ok()); - } - None => println!("Index out of bounds"), - } - } + let file_name = "src/tests/circuit_proof_test_case_short_range_check_0.bin"; + serialized_proof_test_case_with_circuit(circuit, file_name); } // Edge case: K bits (case 1) @@ -694,15 +678,8 @@ mod tests { ); // serialized_proof_test_case - { - match proofs.get(1) { - Some(proof) => { - // Verify the stored proof (case 1) against the generated vk - assert!(proof.verify(&vk, ¶ms).is_ok()); - } - None => println!("Index out of bounds"), - } - } + let file_name = "src/tests/circuit_proof_test_case_short_range_check_1.bin"; + serialized_proof_test_case_with_circuit(circuit, file_name); } // Element within `num_bits` (case 2) @@ -725,27 +702,8 @@ mod tests { ); // serialized_proof_test_case - { - match proofs.get(2) { - Some(proof) => { - // Verify the stored proof (case 2) against the generated vk - assert!(proof.verify(&vk, ¶ms).is_ok()); - } - None => println!("Index out of bounds"), - } - } - } - - // If the environment variable CIRCUIT_TEST_GENERATE_NEW_PROOF is set, - // write the old proofs in a file - if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { - let create_proof = || -> std::io::Result<()> { - let file = std::fs::File::create( - "src/tests/circuit_proof_test_case_short_range_check.bin", - )?; - write_all_test_case(file, &proofs) - }; - create_proof().expect("should be able to write new proof"); + let file_name = "src/tests/circuit_proof_test_case_short_range_check_2.bin"; + serialized_proof_test_case_with_circuit(circuit, file_name); } // Element larger than `num_bits` but within K bits From d3a9d4edcc689b627846b32c29b92fddea4f6b38 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Wed, 15 May 2024 11:33:15 +0200 Subject: [PATCH 59/99] Add fixed_verification_key_test_with_circuit function to generalize VK tests like the proof tests are generalized with serialized_proof_test_case_with_circuit --- halo2_gadgets/src/ecc.rs | 20 ++----- halo2_gadgets/src/sinsemilla.rs | 20 ++----- halo2_gadgets/src/sinsemilla/merkle.rs | 20 ++----- halo2_gadgets/src/tests/circuit.rs | 16 ++++++ .../src/utilities/lookup_range_check.rs | 55 +++---------------- 5 files changed, 38 insertions(+), 93 deletions(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 1fdd2dbec0..005e9e8b18 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -580,16 +580,13 @@ pub(crate) mod tests { use ff::PrimeField; use group::{prime::PrimeCurveAffine, Curve, Group}; - use halo2_proofs::poly::commitment::Params; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, dev::MockProver, - plonk, plonk::{Circuit, ConstraintSystem, Error}, }; use lazy_static::lazy_static; use pasta_curves::pallas; - use pasta_curves::vesta::Affine; use super::{ chip::{ @@ -599,7 +596,9 @@ pub(crate) mod tests { FixedPoints, }; use crate::{ - tests::circuit::serialized_proof_test_case_with_circuit, + tests::circuit::{ + fixed_verification_key_test_with_circuit, serialized_proof_test_case_with_circuit, + }, utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, }; @@ -915,19 +914,10 @@ pub(crate) mod tests { #[test] fn fixed_verification_key_test() { - let k = 11; let circuit = MyCircuit { test_errors: false }; + let file_name = "src/tests/vk_ecc_chip_0"; - // Setup phase: generate parameters, vk for the circuit. - let params: Params = Params::new(k); - let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); - - // Test that the pinned verification key (representing the circuit) - // is as expected. - assert_eq!( - format!("{:#?}\n", vk.pinned()), - include_str!("tests/vk_ecc_chip_0").replace("\r\n", "\n") - ); + fixed_verification_key_test_with_circuit(&circuit, file_name); } #[test] diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 685d7f872c..0288a42fe8 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -456,7 +456,6 @@ pub(crate) mod tests { use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, dev::MockProver, - plonk, plonk::{Circuit, ConstraintSystem, Error}, }; use rand::rngs::OsRng; @@ -473,7 +472,9 @@ pub(crate) mod tests { NonIdentityPoint, ScalarFixed, }, sinsemilla::primitives::{self as sinsemilla, K}, - tests::circuit::serialized_proof_test_case_with_circuit, + tests::circuit::{ + fixed_verification_key_test_with_circuit, serialized_proof_test_case_with_circuit, + }, utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, }; @@ -481,8 +482,6 @@ pub(crate) mod tests { use lazy_static::lazy_static; use pasta_curves::pallas; - use halo2_proofs::poly::commitment::Params; - use pasta_curves::vesta::Affine; use std::convert::TryInto; pub(crate) const PERSONALIZATION: &str = "MerkleCRH"; @@ -758,19 +757,10 @@ pub(crate) mod tests { #[test] fn fixed_verification_key_test() { - let k = 11; let circuit = MyCircuit {}; + let file_name = "src/tests/vk_sinsemilla_chip_0"; - // Setup phase: generate parameters, vk for the circuit. - let params: Params = Params::new(k); - let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); - - // Test that the pinned verification key (representing the circuit) - // is as expected. - assert_eq!( - format!("{:#?}\n", vk.pinned()), - include_str!("tests/vk_sinsemilla_chip_0").replace("\r\n", "\n") - ); + fixed_verification_key_test_with_circuit(&circuit, file_name); } #[test] diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 9bc56e9b04..c399e608a8 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -184,7 +184,9 @@ pub mod tests { tests::{TestCommitDomain, TestHashDomain}, HashDomains, }, - tests::circuit::serialized_proof_test_case_with_circuit, + tests::circuit::{ + fixed_verification_key_test_with_circuit, serialized_proof_test_case_with_circuit, + }, utilities::{ i2lebsp, lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, @@ -197,12 +199,9 @@ pub mod tests { circuit::{Layouter, SimpleFloorPlanner, Value}, dev::MockProver, pasta::pallas, - plonk, plonk::{Circuit, ConstraintSystem, Error}, }; - use halo2_proofs::poly::commitment::Params; - use pasta_curves::vesta::Affine; use rand::{rngs::OsRng, RngCore}; use std::{convert::TryInto, iter}; const MERKLE_DEPTH: usize = 32; @@ -403,19 +402,10 @@ pub mod tests { #[test] fn fixed_verification_key_test() { - let k = 11; let circuit = generate_circuit(); + let file_name = "src/tests/vk_merkle_chip_0"; - // Setup phase: generate parameters, vk for the circuit. - let params: Params = Params::new(k); - let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); - - // Test that the pinned verification key (representing the circuit) - // is as expected. Which indicates the layouters are the same. - assert_eq!( - format!("{:#?}\n", vk.pinned()), - include_str!("../tests/vk_merkle_chip_0").replace("\r\n", "\n") - ); + fixed_verification_key_test_with_circuit(&circuit, file_name); } #[test] diff --git a/halo2_gadgets/src/tests/circuit.rs b/halo2_gadgets/src/tests/circuit.rs index 649f775e74..e429c97be6 100644 --- a/halo2_gadgets/src/tests/circuit.rs +++ b/halo2_gadgets/src/tests/circuit.rs @@ -66,6 +66,22 @@ impl Proof { } } +pub(crate) fn fixed_verification_key_test_with_circuit>( + circuit: &C, + file_name: &str, +) { + // Setup phase: generate parameters, vk for the circuit. + let params: Params = Params::new(11); + let vk = plonk::keygen_vk(¶ms, circuit).unwrap(); + + // Test that the pinned verification key (representing the circuit) + // is as expected. + assert_eq!( + format!("{:#?}\n", vk.pinned()), + fs::read_to_string(file_name).unwrap().replace("\r\n", "\n") + ); +} + /// write proof to a file fn write_test_case(mut w: W, proof: &Proof) -> io::Result<()> { w.write_all(proof.as_ref())?; diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 40741ea7c4..4a82dcc6ba 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -462,14 +462,13 @@ mod tests { use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, dev::{FailureLocation, MockProver, VerifyFailure}, - plonk, plonk::{Circuit, ConstraintSystem, Error}, }; use pasta_curves::pallas; - use crate::tests::circuit::serialized_proof_test_case_with_circuit; - use halo2_proofs::poly::commitment::Params; - use pasta_curves::vesta::Affine; + use crate::tests::circuit::{ + fixed_verification_key_test_with_circuit, serialized_proof_test_case_with_circuit, + }; use std::{convert::TryInto, marker::PhantomData}; #[test] @@ -567,18 +566,8 @@ mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - // Setup phase: generate parameters, vk for the circuit. - let params: Params = Params::new(11); - let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); - - // Test that the pinned verification key (representing the circuit) - // is as expected. - assert_eq!( - format!("{:#?}\n", vk.pinned()), - include_str!("../tests/vk_lookup_range_check_0").replace("\r\n", "\n") - ); + fixed_verification_key_test_with_circuit(&circuit, "src/tests/vk_lookup_range_check_0"); - // serialized_proof_test_case let file_name = "src/tests/circuit_proof_test_case_lookup_range_check.bin"; serialized_proof_test_case_with_circuit(circuit, file_name); } @@ -631,9 +620,6 @@ mod tests { } } - // Setup phase: generate parameters - let params: Params = Params::new(11); - // Edge case: zero bits (case 0) { let circuit: MyCircuit = MyCircuit { @@ -643,17 +629,8 @@ mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - // generate vk - let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); - - // Test that the pinned verification key (representing the circuit) - // is as expected. Which indicates the layouters are the same. - assert_eq!( - format!("{:#?}\n", vk.pinned()), - include_str!("../tests/vk_short_range_check_0").replace("\r\n", "\n") - ); + fixed_verification_key_test_with_circuit(&circuit, "src/tests/vk_short_range_check_0"); - // serialized_proof_test_case let file_name = "src/tests/circuit_proof_test_case_short_range_check_0.bin"; serialized_proof_test_case_with_circuit(circuit, file_name); } @@ -667,17 +644,8 @@ mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - // generate vk - let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); - - // Test that the pinned verification key (representing the circuit) - // is as expected. Which indicates the layouters are the same. - assert_eq!( - format!("{:#?}\n", vk.pinned()), - include_str!("../tests/vk_short_range_check_1").replace("\r\n", "\n") - ); + fixed_verification_key_test_with_circuit(&circuit, "src/tests/vk_short_range_check_1"); - // serialized_proof_test_case let file_name = "src/tests/circuit_proof_test_case_short_range_check_1.bin"; serialized_proof_test_case_with_circuit(circuit, file_name); } @@ -691,17 +659,8 @@ mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - // generate vk - let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); - - // Test that the pinned verification key (representing the circuit) - // is as expected. Which indicates the layouters are the same. - assert_eq!( - format!("{:#?}\n", vk.pinned()), - include_str!("../tests/vk_short_range_check_2").replace("\r\n", "\n") - ); + fixed_verification_key_test_with_circuit(&circuit, "src/tests/vk_short_range_check_2"); - // serialized_proof_test_case let file_name = "src/tests/circuit_proof_test_case_short_range_check_2.bin"; serialized_proof_test_case_with_circuit(circuit, file_name); } From cf8aca05e1293abda75d44f06c47cc695491ec12 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Wed, 15 May 2024 12:07:48 +0200 Subject: [PATCH 60/99] Avoid duplicating test data folder name src/tests in every file name, use TEST_DATA_DIR const in test module instead (make the full file name from the fiule names passed, the dir name const and extention (bin for proofs) --- halo2_gadgets/src/ecc.rs | 9 ++--- halo2_gadgets/src/sinsemilla.rs | 8 +--- halo2_gadgets/src/sinsemilla/merkle.rs | 8 +--- halo2_gadgets/src/tests/circuit.rs | 39 ++++++++++++++----- .../src/utilities/lookup_range_check.rs | 32 +++++++++------ 5 files changed, 57 insertions(+), 39 deletions(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 005e9e8b18..9b464459e9 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -915,18 +915,15 @@ pub(crate) mod tests { #[test] fn fixed_verification_key_test() { let circuit = MyCircuit { test_errors: false }; - let file_name = "src/tests/vk_ecc_chip_0"; - - fixed_verification_key_test_with_circuit(&circuit, file_name); + fixed_verification_key_test_with_circuit(&circuit, "vk_ecc_chip_0"); } #[test] fn serialized_proof_test_case() { let circuit = MyCircuit { test_errors: false }; - let file_name = "src/tests/circuit_proof_test_case_ecc.bin"; - - serialized_proof_test_case_with_circuit(circuit, file_name); + serialized_proof_test_case_with_circuit(circuit, "circuit_proof_test_case_ecc"); } + #[cfg(feature = "test-dev-graph")] #[test] fn print_ecc_chip() { diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 0288a42fe8..47c6c169d8 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -758,17 +758,13 @@ pub(crate) mod tests { #[test] fn fixed_verification_key_test() { let circuit = MyCircuit {}; - let file_name = "src/tests/vk_sinsemilla_chip_0"; - - fixed_verification_key_test_with_circuit(&circuit, file_name); + fixed_verification_key_test_with_circuit(&circuit, "vk_sinsemilla_chip_0"); } #[test] fn serialized_proof_test_case() { let circuit = MyCircuit {}; - let file_name = "src/tests/circuit_proof_test_case_sinsemilla.bin"; - - serialized_proof_test_case_with_circuit(circuit, file_name); + serialized_proof_test_case_with_circuit(circuit, "circuit_proof_test_case_sinsemilla"); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index c399e608a8..26ddfd42ec 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -403,17 +403,13 @@ pub mod tests { #[test] fn fixed_verification_key_test() { let circuit = generate_circuit(); - let file_name = "src/tests/vk_merkle_chip_0"; - - fixed_verification_key_test_with_circuit(&circuit, file_name); + fixed_verification_key_test_with_circuit(&circuit, "vk_merkle_chip_0"); } #[test] fn serialized_proof_test_case() { let circuit = generate_circuit(); - let file_name = "src/tests/circuit_proof_test_case_merkle.bin"; - - serialized_proof_test_case_with_circuit(circuit, file_name); + serialized_proof_test_case_with_circuit(circuit, "circuit_proof_test_case_merkle"); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/tests/circuit.rs b/halo2_gadgets/src/tests/circuit.rs index e429c97be6..995c37f3bf 100644 --- a/halo2_gadgets/src/tests/circuit.rs +++ b/halo2_gadgets/src/tests/circuit.rs @@ -5,6 +5,7 @@ use std::{ io::{ self, {Read, Write}, }, + path::Path, }; use rand::rngs::OsRng; @@ -22,6 +23,8 @@ use halo2_proofs::{ transcript::{Blake2bRead, Blake2bWrite}, }; +const TEST_DATA_DIR: &str = "src/tests"; + /// A proof structure #[derive(Clone, Debug)] pub struct Proof(Vec); @@ -70,16 +73,26 @@ pub(crate) fn fixed_verification_key_test_with_circuit> circuit: &C, file_name: &str, ) { + let full_file_name = Path::new(TEST_DATA_DIR).join(file_name); + // Setup phase: generate parameters, vk for the circuit. let params: Params = Params::new(11); let vk = plonk::keygen_vk(¶ms, circuit).unwrap(); - // Test that the pinned verification key (representing the circuit) - // is as expected. - assert_eq!( - format!("{:#?}\n", vk.pinned()), - fs::read_to_string(file_name).unwrap().replace("\r\n", "\n") - ); + let vk_text = format!("{:#?}\n", vk.pinned()); + + if env::var_os("CIRCUIT_TEST_GENERATE_NEW_VK").is_some() { + fs::write(full_file_name, vk_text).expect("Unable to write vk test file") + } else { + // Test that the pinned verification key (representing the circuit) + // is as expected. + assert_eq!( + vk_text, + fs::read_to_string(full_file_name) + .expect("Unable to read vk test file") + .replace("\r\n", "\n") + ); + } } /// write proof to a file @@ -97,12 +110,16 @@ fn read_test_case(mut r: R) -> io::Result { Ok(proof) } -pub(crate) fn conditionally_save_proof_to_disk>( +fn conditionally_save_proof_to_disk>( vk: &VerifyingKey, params: &Params, circuit: C, file_name: &str, ) { + let full_file_name = Path::new(TEST_DATA_DIR) + .join(file_name) + .with_extension("bin"); + // If the environment variable CIRCUIT_TEST_GENERATE_NEW_PROOF is set, // write the old proof in a file if env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { @@ -110,7 +127,7 @@ pub(crate) fn conditionally_save_proof_to_disk>( let proof = Proof::create(vk, params, circuit).unwrap(); assert!(proof.verify(vk, params).is_ok()); - let file = fs::File::create(file_name)?; + let file = fs::File::create(full_file_name).expect("Unable to write proof test file"); write_test_case(file, &proof) }; create_proof().expect("should be able to write new proof"); @@ -121,6 +138,10 @@ pub(crate) fn serialized_proof_test_case_with_circuit>( circuit: C, file_name: &str, ) { + let full_file_name = Path::new(TEST_DATA_DIR) + .join(file_name) + .with_extension("bin"); + // Setup phase: generate parameters, vk for the circuit. let params: Params = Params::new(11); let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); @@ -130,7 +151,7 @@ pub(crate) fn serialized_proof_test_case_with_circuit>( // Read proof from disk let proof = { - let test_case_bytes = fs::read(file_name).unwrap(); + let test_case_bytes = fs::read(full_file_name).expect("Unable to read proof test file"); read_test_case(&test_case_bytes[..]).expect("proof must be valid") }; diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 4a82dcc6ba..ae6c9d0c99 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -566,10 +566,12 @@ mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - fixed_verification_key_test_with_circuit(&circuit, "src/tests/vk_lookup_range_check_0"); + fixed_verification_key_test_with_circuit(&circuit, "vk_lookup_range_check_0"); - let file_name = "src/tests/circuit_proof_test_case_lookup_range_check.bin"; - serialized_proof_test_case_with_circuit(circuit, file_name); + serialized_proof_test_case_with_circuit( + circuit, + "circuit_proof_test_case_lookup_range_check", + ); } } @@ -629,10 +631,12 @@ mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - fixed_verification_key_test_with_circuit(&circuit, "src/tests/vk_short_range_check_0"); + fixed_verification_key_test_with_circuit(&circuit, "vk_short_range_check_0"); - let file_name = "src/tests/circuit_proof_test_case_short_range_check_0.bin"; - serialized_proof_test_case_with_circuit(circuit, file_name); + serialized_proof_test_case_with_circuit( + circuit, + "circuit_proof_test_case_short_range_check_0", + ); } // Edge case: K bits (case 1) @@ -644,10 +648,12 @@ mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - fixed_verification_key_test_with_circuit(&circuit, "src/tests/vk_short_range_check_1"); + fixed_verification_key_test_with_circuit(&circuit, "vk_short_range_check_1"); - let file_name = "src/tests/circuit_proof_test_case_short_range_check_1.bin"; - serialized_proof_test_case_with_circuit(circuit, file_name); + serialized_proof_test_case_with_circuit( + circuit, + "circuit_proof_test_case_short_range_check_1", + ); } // Element within `num_bits` (case 2) @@ -659,10 +665,12 @@ mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - fixed_verification_key_test_with_circuit(&circuit, "src/tests/vk_short_range_check_2"); + fixed_verification_key_test_with_circuit(&circuit, "vk_short_range_check_2"); - let file_name = "src/tests/circuit_proof_test_case_short_range_check_2.bin"; - serialized_proof_test_case_with_circuit(circuit, file_name); + serialized_proof_test_case_with_circuit( + circuit, + "circuit_proof_test_case_short_range_check_2", + ); } // Element larger than `num_bits` but within K bits From b7c7261a815dfc41a2adaa19e1abd6a9c0f57375 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Wed, 15 May 2024 12:15:20 +0200 Subject: [PATCH 61/99] Remove 'else' in fixed_verification_key_test_with_circuit function, to read after write if env var set and so check the writing --- halo2_gadgets/src/tests/circuit.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/halo2_gadgets/src/tests/circuit.rs b/halo2_gadgets/src/tests/circuit.rs index 995c37f3bf..9b0cb8d11d 100644 --- a/halo2_gadgets/src/tests/circuit.rs +++ b/halo2_gadgets/src/tests/circuit.rs @@ -83,16 +83,16 @@ pub(crate) fn fixed_verification_key_test_with_circuit> if env::var_os("CIRCUIT_TEST_GENERATE_NEW_VK").is_some() { fs::write(full_file_name, vk_text).expect("Unable to write vk test file") - } else { - // Test that the pinned verification key (representing the circuit) - // is as expected. - assert_eq!( - vk_text, - fs::read_to_string(full_file_name) - .expect("Unable to read vk test file") - .replace("\r\n", "\n") - ); } + + // Test that the pinned verification key (representing the circuit) + // is as expected. + assert_eq!( + vk_text, + fs::read_to_string(full_file_name) + .expect("Unable to read vk test file") + .replace("\r\n", "\n") + ); } /// write proof to a file From d3c7eb0a6b7ae175bbc2b2673341ab6d929e81ab Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Wed, 15 May 2024 12:38:54 +0200 Subject: [PATCH 62/99] Use fs::read, fs::write instad of read_test_case and write_test_case --- halo2_gadgets/src/tests/circuit.rs | 47 ++++++------------------------ 1 file changed, 9 insertions(+), 38 deletions(-) diff --git a/halo2_gadgets/src/tests/circuit.rs b/halo2_gadgets/src/tests/circuit.rs index 9b0cb8d11d..2fc01ab0ab 100644 --- a/halo2_gadgets/src/tests/circuit.rs +++ b/halo2_gadgets/src/tests/circuit.rs @@ -2,10 +2,7 @@ use std::{ env, fs, - io::{ - self, {Read, Write}, - }, - path::Path, + path::{Path, PathBuf}, }; use rand::rngs::OsRng; @@ -82,7 +79,7 @@ pub(crate) fn fixed_verification_key_test_with_circuit> let vk_text = format!("{:#?}\n", vk.pinned()); if env::var_os("CIRCUIT_TEST_GENERATE_NEW_VK").is_some() { - fs::write(full_file_name, vk_text).expect("Unable to write vk test file") + fs::write(&full_file_name, &vk_text).expect("Unable to write vk test file") } // Test that the pinned verification key (representing the circuit) @@ -95,42 +92,19 @@ pub(crate) fn fixed_verification_key_test_with_circuit> ); } -/// write proof to a file -fn write_test_case(mut w: W, proof: &Proof) -> io::Result<()> { - w.write_all(proof.as_ref())?; - Ok(()) -} - -/// read proof from a file -fn read_test_case(mut r: R) -> io::Result { - let mut proof_bytes = vec![]; - r.read_to_end(&mut proof_bytes)?; - let proof = Proof::new(proof_bytes); - - Ok(proof) -} - fn conditionally_save_proof_to_disk>( vk: &VerifyingKey, params: &Params, circuit: C, - file_name: &str, + full_file_name: &PathBuf, ) { - let full_file_name = Path::new(TEST_DATA_DIR) - .join(file_name) - .with_extension("bin"); - // If the environment variable CIRCUIT_TEST_GENERATE_NEW_PROOF is set, // write the old proof in a file if env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { - let create_proof = || -> io::Result<()> { - let proof = Proof::create(vk, params, circuit).unwrap(); - assert!(proof.verify(vk, params).is_ok()); - - let file = fs::File::create(full_file_name).expect("Unable to write proof test file"); - write_test_case(file, &proof) - }; - create_proof().expect("should be able to write new proof"); + let proof = Proof::create(vk, params, circuit).unwrap(); + assert!(proof.verify(vk, params).is_ok()); + + fs::write(full_file_name, proof.as_ref()).expect("Unable to write proof test file"); } } @@ -147,13 +121,10 @@ pub(crate) fn serialized_proof_test_case_with_circuit>( let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); // Conditionally save proof to disk - conditionally_save_proof_to_disk(&vk, ¶ms, circuit, file_name); + conditionally_save_proof_to_disk(&vk, ¶ms, circuit, &full_file_name); // Read proof from disk - let proof = { - let test_case_bytes = fs::read(full_file_name).expect("Unable to read proof test file"); - read_test_case(&test_case_bytes[..]).expect("proof must be valid") - }; + let proof = Proof::new(fs::read(full_file_name).expect("Unable to read proof test file")); // Verify the old proof with the new vk assert!(proof.verify(&vk, ¶ms).is_ok()); From 5248a0ab6c5e641dd96ffdf735491dbbaa33eac8 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Wed, 15 May 2024 13:06:03 +0200 Subject: [PATCH 63/99] revert .github/workflows/ci.yml --- .github/workflows/ci.yml | 56 ++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7cb0e84e71..8f6231d4ec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -125,33 +125,33 @@ jobs: - name: Test halo2 book run: mdbook test -L target/debug/deps book/ -# codecov: -# name: Code coverage -# runs-on: ubuntu-latest -# -# steps: -# - uses: actions/checkout@v3 -# # Use stable for this to ensure that cargo-tarpaulin can be built. -# - id: prepare -# uses: ./.github/actions/prepare -# with: -# toolchain: stable -# nightly-features: true -# - name: Install cargo-tarpaulin -# uses: actions-rs/cargo@v1 -# with: -# command: install -# args: cargo-tarpaulin -# - name: Generate coverage report -# uses: actions-rs/cargo@v1 -# with: -# command: tarpaulin -# args: > -# ${{ steps.prepare.outputs.feature-flags }} -# --timeout 600 -# --out Xml -# - name: Upload coverage to Codecov -# uses: codecov/codecov-action@v3.1.4 + codecov: + name: Code coverage + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + # Use stable for this to ensure that cargo-tarpaulin can be built. + - id: prepare + uses: ./.github/actions/prepare + with: + toolchain: stable + nightly-features: true + - name: Install cargo-tarpaulin + uses: actions-rs/cargo@v1 + with: + command: install + args: cargo-tarpaulin + - name: Generate coverage report + uses: actions-rs/cargo@v1 + with: + command: tarpaulin + args: > + ${{ steps.prepare.outputs.feature-flags }} + --timeout 600 + --out Xml + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3.1.4 doc-links: name: Intra-doc links @@ -184,4 +184,4 @@ jobs: - uses: actions-rs/cargo@v1 with: command: fmt - args: --all -- --check + args: --all -- --check \ No newline at end of file From 8a68152afe953361c491bcd6eedb69f2ea057195 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Wed, 15 May 2024 13:07:47 +0200 Subject: [PATCH 64/99] rename circuit.rs --- halo2_gadgets/src/ecc.rs | 2 +- halo2_gadgets/src/sinsemilla.rs | 2 +- halo2_gadgets/src/sinsemilla/merkle.rs | 2 +- halo2_gadgets/src/tests.rs | 2 +- halo2_gadgets/src/tests/{circuit.rs => test_utils.rs} | 0 halo2_gadgets/src/utilities/lookup_range_check.rs | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) rename halo2_gadgets/src/tests/{circuit.rs => test_utils.rs} (100%) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 9b464459e9..31101e65cd 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -596,7 +596,7 @@ pub(crate) mod tests { FixedPoints, }; use crate::{ - tests::circuit::{ + tests::test_utils::{ fixed_verification_key_test_with_circuit, serialized_proof_test_case_with_circuit, }, utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 47c6c169d8..ad323865d8 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -472,7 +472,7 @@ pub(crate) mod tests { NonIdentityPoint, ScalarFixed, }, sinsemilla::primitives::{self as sinsemilla, K}, - tests::circuit::{ + tests::test_utils::{ fixed_verification_key_test_with_circuit, serialized_proof_test_case_with_circuit, }, utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 26ddfd42ec..fd1e6f2bad 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -184,7 +184,7 @@ pub mod tests { tests::{TestCommitDomain, TestHashDomain}, HashDomains, }, - tests::circuit::{ + tests::test_utils::{ fixed_verification_key_test_with_circuit, serialized_proof_test_case_with_circuit, }, utilities::{ diff --git a/halo2_gadgets/src/tests.rs b/halo2_gadgets/src/tests.rs index a9af55fc06..1d00cc79b7 100644 --- a/halo2_gadgets/src/tests.rs +++ b/halo2_gadgets/src/tests.rs @@ -1 +1 @@ -pub(crate) mod circuit; +pub(crate) mod test_utils; diff --git a/halo2_gadgets/src/tests/circuit.rs b/halo2_gadgets/src/tests/test_utils.rs similarity index 100% rename from halo2_gadgets/src/tests/circuit.rs rename to halo2_gadgets/src/tests/test_utils.rs diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index ae6c9d0c99..5f74a5bdca 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -466,7 +466,7 @@ mod tests { }; use pasta_curves::pallas; - use crate::tests::circuit::{ + use crate::tests::test_utils::{ fixed_verification_key_test_with_circuit, serialized_proof_test_case_with_circuit, }; use std::{convert::TryInto, marker::PhantomData}; From 8dbb582e20e468db41166844dfa23926a7fc9177 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Wed, 15 May 2024 13:09:20 +0200 Subject: [PATCH 65/99] add a line --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8f6231d4ec..8f3dad2ffa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -184,4 +184,5 @@ jobs: - uses: actions-rs/cargo@v1 with: command: fmt - args: --all -- --check \ No newline at end of file + args: --all -- --check + \ No newline at end of file From 32842df1ed44891d281b725e967c65a28f725e5a Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Wed, 15 May 2024 13:13:11 +0200 Subject: [PATCH 66/99] fix ci.yml --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8f3dad2ffa..d2ecd3ba57 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -185,4 +185,3 @@ jobs: with: command: fmt args: --all -- --check - \ No newline at end of file From 3324348b1a332d2ba52b63ea95fdd760c75dedd1 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Wed, 15 May 2024 14:48:41 +0200 Subject: [PATCH 67/99] Rename PallasLookupRC LookupRangeCheck trait alias to PallasLookup. Add and use PallasLookupConfig type alias for LookupRangeCheckConfigspecialized with pallas::Base and sinsemilla::K --- halo2_gadgets/src/ecc.rs | 19 +++++----- halo2_gadgets/src/ecc/chip.rs | 16 ++++----- halo2_gadgets/src/ecc/chip/mul.rs | 10 +++--- halo2_gadgets/src/ecc/chip/mul/overflow.rs | 6 ++-- .../src/ecc/chip/mul_fixed/base_field_elem.rs | 14 ++++---- .../src/ecc/chip/mul_fixed/full_width.rs | 8 ++--- halo2_gadgets/src/ecc/chip/mul_fixed/short.rs | 29 +++++++-------- halo2_gadgets/src/sinsemilla.rs | 35 +++++++------------ halo2_gadgets/src/sinsemilla/chip.rs | 14 ++++---- .../src/sinsemilla/chip/generator_table.rs | 4 +-- .../src/sinsemilla/chip/hash_to_point.rs | 4 +-- halo2_gadgets/src/sinsemilla/merkle.rs | 20 +++-------- halo2_gadgets/src/sinsemilla/merkle/chip.rs | 22 ++++++------ .../src/utilities/lookup_range_check.rs | 16 ++++++--- 14 files changed, 102 insertions(+), 115 deletions(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 31101e65cd..7724c21d5a 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -599,7 +599,7 @@ pub(crate) mod tests { tests::test_utils::{ fixed_verification_key_test_with_circuit, serialized_proof_test_case_with_circuit, }, - utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, + utilities::lookup_range_check::{LookupRangeCheck, PallasLookupConfig}, }; #[derive(Debug, Eq, PartialEq, Clone)] @@ -734,10 +734,7 @@ pub(crate) mod tests { #[allow(non_snake_case)] impl Circuit for MyCircuit { - type Config = EccConfig< - TestFixedBases, - LookupRangeCheckConfig, - >; + type Config = EccConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -772,11 +769,13 @@ pub(crate) mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table); - EccChip::< - TestFixedBases, - LookupRangeCheckConfig, - >::configure(meta, advices, lagrange_coeffs, range_check) + let range_check = PallasLookupConfig::configure(meta, advices[9], lookup_table); + EccChip::::configure( + meta, + advices, + lagrange_coeffs, + range_check, + ) } fn synthesize( diff --git a/halo2_gadgets/src/ecc/chip.rs b/halo2_gadgets/src/ecc/chip.rs index d7a0c92219..0c8d0902d7 100644 --- a/halo2_gadgets/src/ecc/chip.rs +++ b/halo2_gadgets/src/ecc/chip.rs @@ -1,7 +1,7 @@ //! Chip implementations for the ECC gadgets. use super::{BaseFitsInScalarInstructions, EccInstructions, FixedPoints}; -use crate::utilities::{lookup_range_check::PallasLookupRC, UtilitiesInstructions}; +use crate::utilities::{lookup_range_check::PallasLookup, UtilitiesInstructions}; use arrayvec::ArrayVec; use ff::PrimeField; @@ -134,7 +134,7 @@ impl From for EccPoint { /// Configuration for [`EccChip`]. #[derive(Clone, Debug, Eq, PartialEq)] #[allow(non_snake_case)] -pub struct EccConfig, Lookup: PallasLookupRC> { +pub struct EccConfig, Lookup: PallasLookup> { /// Advice columns needed by instructions in the ECC chip. pub advices: [Column; 10], @@ -224,11 +224,11 @@ pub trait FixedPoint: std::fmt::Debug + Eq + Clone { /// An [`EccInstructions`] chip that uses 10 advice columns. #[derive(Clone, Debug, Eq, PartialEq)] -pub struct EccChip, Lookup: PallasLookupRC> { +pub struct EccChip, Lookup: PallasLookup> { config: EccConfig, } -impl, Lookup: PallasLookupRC> Chip +impl, Lookup: PallasLookup> Chip for EccChip { type Config = EccConfig; @@ -243,13 +243,13 @@ impl, Lookup: PallasLookupRC> Ch } } -impl, Lookup: PallasLookupRC> +impl, Lookup: PallasLookup> UtilitiesInstructions for EccChip { type Var = AssignedCell; } -impl, Lookup: PallasLookupRC> +impl, Lookup: PallasLookup> EccChip { /// Reconstructs this chip from the given config. @@ -409,7 +409,7 @@ pub enum ScalarVar { FullWidth, } -impl, Lookup: PallasLookupRC> EccInstructions +impl, Lookup: PallasLookup> EccInstructions for EccChip where >::Base: @@ -597,7 +597,7 @@ where } } -impl, Lookup: PallasLookupRC> +impl, Lookup: PallasLookup> BaseFitsInScalarInstructions for EccChip where >::Base: diff --git a/halo2_gadgets/src/ecc/chip/mul.rs b/halo2_gadgets/src/ecc/chip/mul.rs index 70c14df284..49f19900d0 100644 --- a/halo2_gadgets/src/ecc/chip/mul.rs +++ b/halo2_gadgets/src/ecc/chip/mul.rs @@ -1,6 +1,6 @@ use super::{add, EccPoint, NonIdentityEccPoint, ScalarVar, T_Q}; use crate::utilities::{ - lookup_range_check::PallasLookupRC, + lookup_range_check::PallasLookup, {bool_check, ternary}, }; use std::{ @@ -46,7 +46,7 @@ const INCOMPLETE_LO_LEN: usize = INCOMPLETE_LEN - INCOMPLETE_HI_LEN; const COMPLETE_RANGE: Range = INCOMPLETE_LEN..(INCOMPLETE_LEN + NUM_COMPLETE_BITS); #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { +pub struct Config { // Selector used to check switching logic on LSB q_mul_lsb: Selector, // Configuration used in complete addition @@ -61,7 +61,7 @@ pub struct Config { overflow_config: overflow::Config, } -impl Config { +impl Config { pub(super) fn configure( meta: &mut ConstraintSystem, add_config: add::Config, @@ -468,7 +468,7 @@ pub mod tests { use pasta_curves::pallas; use rand::rngs::OsRng; - use crate::utilities::lookup_range_check::PallasLookupRC; + use crate::utilities::lookup_range_check::PallasLookup; use crate::{ ecc::{ chip::{EccChip, EccPoint}, @@ -478,7 +478,7 @@ pub mod tests { utilities::UtilitiesInstructions, }; - pub(crate) fn test_mul( + pub(crate) fn test_mul( chip: EccChip, mut layouter: impl Layouter, p: &NonIdentityPoint>, diff --git a/halo2_gadgets/src/ecc/chip/mul/overflow.rs b/halo2_gadgets/src/ecc/chip/mul/overflow.rs index eb5810fac5..53cde0f10d 100644 --- a/halo2_gadgets/src/ecc/chip/mul/overflow.rs +++ b/halo2_gadgets/src/ecc/chip/mul/overflow.rs @@ -1,5 +1,5 @@ use super::{T_Q, Z}; -use crate::{sinsemilla::primitives as sinsemilla, utilities::lookup_range_check::PallasLookupRC}; +use crate::{sinsemilla::primitives as sinsemilla, utilities::lookup_range_check::PallasLookup}; use group::ff::PrimeField; use halo2_proofs::circuit::AssignedCell; @@ -13,7 +13,7 @@ use pasta_curves::pallas; use std::iter; #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { +pub struct Config { // Selector to check z_0 = alpha + t_q (mod p) q_mul_overflow: Selector, // 10-bit lookup table @@ -22,7 +22,7 @@ pub struct Config { advices: [Column; 3], } -impl Config { +impl Config { pub(super) fn configure( meta: &mut ConstraintSystem, lookup_config: Lookup, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs index 760ab20b9a..917d8836a2 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs @@ -2,7 +2,7 @@ use super::super::{EccBaseFieldElemFixed, EccPoint, FixedPoints, NUM_WINDOWS, T_ use super::H_BASE; use crate::utilities::{ - bitrange_subset, bool_check, lookup_range_check::PallasLookupRC, range_check, + bitrange_subset, bool_check, lookup_range_check::PallasLookup, range_check, }; use group::ff::PrimeField; @@ -16,14 +16,14 @@ use pasta_curves::pallas; use std::convert::TryInto; #[derive(Clone, Debug, Eq, PartialEq)] -pub struct Config, Lookup: PallasLookupRC> { +pub struct Config, Lookup: PallasLookup> { q_mul_fixed_base_field: Selector, canon_advices: [Column; 3], lookup_config: Lookup, super_config: super::Config, } -impl, Lookup: PallasLookupRC> Config { +impl, Lookup: PallasLookup> Config { pub(crate) fn configure( meta: &mut ConstraintSystem, canon_advices: [Column; 3], @@ -386,7 +386,7 @@ pub mod tests { use pasta_curves::pallas; use rand::rngs::OsRng; - use crate::utilities::lookup_range_check::PallasLookupRC; + use crate::utilities::lookup_range_check::PallasLookup; use crate::{ ecc::{ chip::{EccChip, FixedPoint, H}, @@ -396,7 +396,7 @@ pub mod tests { utilities::UtilitiesInstructions, }; - pub(crate) fn test_mul_fixed_base_field( + pub(crate) fn test_mul_fixed_base_field( chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { @@ -409,7 +409,7 @@ pub mod tests { } #[allow(clippy::op_ref)] - fn test_single_base( + fn test_single_base( chip: EccChip, mut layouter: impl Layouter, base: FixedPointBaseField>, @@ -419,7 +419,7 @@ pub mod tests { let column = chip.config().advices[0]; - fn constrain_equal_non_id( + fn constrain_equal_non_id( chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs index fe0ccd8d3d..0b7f64c635 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs @@ -192,9 +192,9 @@ pub mod tests { tests::{FullWidth, TestFixedBases}, FixedPoint, NonIdentityPoint, Point, ScalarFixed, }; - use crate::utilities::lookup_range_check::PallasLookupRC; + use crate::utilities::lookup_range_check::PallasLookup; - pub(crate) fn test_mul_fixed( + pub(crate) fn test_mul_fixed( chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { @@ -210,13 +210,13 @@ pub mod tests { } #[allow(clippy::op_ref)] - fn test_single_base( + fn test_single_base( chip: EccChip, mut layouter: impl Layouter, base: FixedPoint>, base_val: pallas::Affine, ) -> Result<(), Error> { - fn constrain_equal_non_id( + fn constrain_equal_non_id( chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs index fd88bcd72b..5697b6840b 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs @@ -253,18 +253,20 @@ pub mod tests { }; use pasta_curves::pallas; - use crate::utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRC}; use crate::{ ecc::{ chip::{EccChip, FixedPoint, MagnitudeSign}, tests::{Short, TestFixedBases}, FixedPointShort, NonIdentityPoint, Point, ScalarFixedShort, }, - utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions}, + utilities::{ + lookup_range_check::{LookupRangeCheck, PallasLookup, PallasLookupConfig}, + UtilitiesInstructions, + }, }; #[allow(clippy::op_ref)] - pub(crate) fn test_mul_fixed_short( + pub(crate) fn test_mul_fixed_short( chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { @@ -272,7 +274,7 @@ pub mod tests { let base_val = Short.generator(); let test_short = FixedPointShort::from_inner(chip.clone(), Short); - fn load_magnitude_sign( + fn load_magnitude_sign( chip: EccChip, mut layouter: impl Layouter, magnitude: pallas::Base, @@ -290,7 +292,7 @@ pub mod tests { Ok((magnitude, sign)) } - fn constrain_equal_non_id( + fn constrain_equal_non_id( chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, @@ -426,10 +428,7 @@ pub mod tests { } impl Circuit for MyCircuit { - type Config = EccConfig< - TestFixedBases, - LookupRangeCheckConfig, - >; + type Config = EccConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -465,11 +464,13 @@ pub mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table); - EccChip::< - TestFixedBases, - LookupRangeCheckConfig, - >::configure(meta, advices, lagrange_coeffs, range_check) + let range_check = PallasLookupConfig::configure(meta, advices[9], lookup_table); + EccChip::::configure( + meta, + advices, + lagrange_coeffs, + range_check, + ) } fn synthesize( diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index ad323865d8..98274f7d0e 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -475,7 +475,7 @@ pub(crate) mod tests { tests::test_utils::{ fixed_verification_key_test_with_circuit, serialized_proof_test_case_with_circuit, }, - utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, + utilities::lookup_range_check::{LookupRangeCheck, PallasLookupConfig}, }; use group::{ff::Field, Curve}; @@ -521,22 +521,9 @@ pub(crate) mod tests { impl Circuit for MyCircuit { #[allow(clippy::type_complexity)] type Config = ( - EccConfig< - TestFixedBases, - LookupRangeCheckConfig, - >, - SinsemillaConfig< - TestHashDomain, - TestCommitDomain, - TestFixedBases, - LookupRangeCheckConfig, - >, - SinsemillaConfig< - TestHashDomain, - TestCommitDomain, - TestFixedBases, - LookupRangeCheckConfig, - >, + EccConfig, + SinsemillaConfig, + SinsemillaConfig, ); type FloorPlanner = SimpleFloorPlanner; @@ -582,12 +569,14 @@ pub(crate) mod tests { meta.lookup_table_column(), ); - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx); + let range_check = PallasLookupConfig::configure(meta, advices[9], table_idx); - let ecc_config = EccChip::< - TestFixedBases, - LookupRangeCheckConfig, - >::configure(meta, advices, lagrange_coeffs, range_check); + let ecc_config = EccChip::::configure( + meta, + advices, + lagrange_coeffs, + range_check, + ); let config1 = SinsemillaChip::configure( meta, @@ -622,7 +611,7 @@ pub(crate) mod tests { TestHashDomain, TestCommitDomain, TestFixedBases, - LookupRangeCheckConfig, + PallasLookupConfig, >::load(config.1.clone(), &mut layouter)?; // This MerkleCRH example is purely for illustrative purposes. diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs index b242db41be..19af2e9bd1 100644 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ b/halo2_gadgets/src/sinsemilla/chip.rs @@ -9,7 +9,7 @@ use crate::{ chip::{DoubleAndAdd, NonIdentityEccPoint}, FixedPoints, }, - utilities::lookup_range_check::PallasLookupRC, + utilities::lookup_range_check::PallasLookup, }; use std::marker::PhantomData; @@ -35,7 +35,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookup, { /// Binary selector used in lookup argument and in the body of the Sinsemilla hash. q_sinsemilla1: Selector, @@ -68,7 +68,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookup, { /// Returns an array of all advice columns in this config, in arbitrary order. pub(super) fn advices(&self) -> [Column; 5] { @@ -103,7 +103,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookup, { config: SinsemillaConfig, } @@ -113,7 +113,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookup, { type Config = SinsemillaConfig; type Loaded = (); @@ -132,7 +132,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookup, { /// Reconstructs this chip from the given config. pub fn construct(config: >::Config) -> Self { @@ -321,7 +321,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookup, { type CellValue = AssignedCell; diff --git a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs index 013995911c..5ec7278bf8 100644 --- a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs +++ b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs @@ -8,7 +8,7 @@ use halo2_proofs::{ use super::{CommitDomains, FixedPoints, HashDomains}; use crate::{ sinsemilla::primitives::{self as sinsemilla, SINSEMILLA_S}, - utilities::lookup_range_check::PallasLookupRC, + utilities::lookup_range_check::PallasLookup, }; use pasta_curves::pallas; @@ -33,7 +33,7 @@ impl GeneratorTableConfig { Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookup, { let (table_idx, table_x, table_y) = ( config.generator_table.table_idx, diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 709da2455d..1cff0a423c 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -3,7 +3,7 @@ use super::{NonIdentityEccPoint, SinsemillaChip}; use crate::{ ecc::FixedPoints, sinsemilla::primitives::{self as sinsemilla, lebs2ip_k, INV_TWO_POW_K, SINSEMILLA_S}, - utilities::lookup_range_check::PallasLookupRC, + utilities::lookup_range_check::PallasLookup, }; use ff::Field; @@ -30,7 +30,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookup, { /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). #[allow(non_snake_case)] diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index fd1e6f2bad..b113e5908e 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -189,7 +189,7 @@ pub mod tests { }, utilities::{ i2lebsp, - lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, + lookup_range_check::{LookupRangeCheck, PallasLookupConfig}, UtilitiesInstructions, }, }; @@ -215,18 +215,8 @@ pub mod tests { impl Circuit for MyCircuit { type Config = ( - MerkleConfig< - TestHashDomain, - TestCommitDomain, - TestFixedBases, - LookupRangeCheckConfig, - >, - MerkleConfig< - TestHashDomain, - TestCommitDomain, - TestFixedBases, - LookupRangeCheckConfig, - >, + MerkleConfig, + MerkleConfig, ); type FloorPlanner = SimpleFloorPlanner; @@ -264,7 +254,7 @@ pub mod tests { meta.lookup_table_column(), ); - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup.0); + let range_check = PallasLookupConfig::configure(meta, advices[9], lookup.0); let sinsemilla_config_1 = SinsemillaChip::configure( meta, @@ -299,7 +289,7 @@ pub mod tests { TestHashDomain, TestCommitDomain, TestFixedBases, - LookupRangeCheckConfig, + PallasLookupConfig, >::load(config.0.sinsemilla_config.clone(), &mut layouter)?; // Construct Merkle chips which will be placed side-by-side in the circuit. diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs index 37aa4e7f99..93f0fc8175 100644 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla/merkle/chip.rs @@ -11,7 +11,7 @@ use super::MerkleInstructions; use crate::{ sinsemilla::{primitives as sinsemilla, MessagePiece}, - utilities::{lookup_range_check::PallasLookupRC, RangeConstrained}, + utilities::{lookup_range_check::PallasLookup, RangeConstrained}, { ecc::FixedPoints, sinsemilla::{ @@ -33,7 +33,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookup, { advices: [Column; 5], q_decompose: Selector, @@ -57,7 +57,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookup, { config: MerkleConfig, } @@ -67,7 +67,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookup, { type Config = MerkleConfig; type Loaded = (); @@ -86,7 +86,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookup, { /// Configures the [`MerkleChip`]. pub fn configure( @@ -227,7 +227,7 @@ where Hash: HashDomains, Commit: CommitDomains, F: FixedPoints, - Lookup: PallasLookupRC, + Lookup: PallasLookup, { } @@ -237,7 +237,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookup, { } @@ -255,7 +255,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookup, { #[allow(non_snake_case)] fn hash_layer( @@ -474,7 +474,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookup, { type Var = AssignedCell; } @@ -485,7 +485,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookup, { #[allow(clippy::type_complexity)] fn swap( @@ -507,7 +507,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookup, { type CellValue = as SinsemillaInstructions< pallas::Affine, diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 5f74a5bdca..a0c77629d0 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -442,14 +442,22 @@ impl LookupRangeCheck for LookupRangeCh } } -/// The `PallasLookupRC` trait extends the `LookupRangeCheck` with additional -/// standard traits necessary for effective use in cryptographic contexts. -pub trait PallasLookupRC: +/// This trait is a shorthand for `LookupRangeCheck` specialized with `pallas::Base` and +/// `sinsemilla::K`. In this crate, `LookupRangeCheck` is always used with these parameters. +/// By defining this trait, we reduce verbosity and improve readability. Besides, it extends +/// the `LookupRangeCheck` with additional standard traits necessary for effective use in +/// cryptographic contexts. +pub trait PallasLookup: LookupRangeCheck + Eq + PartialEq + Clone + Copy + Debug { } -impl PallasLookupRC for LookupRangeCheckConfig {} +/// In this crate, `LookupRangeCheckConfig` is always used with `pallas::Base` as the prime field +/// and the constant `K` from the `sinsemilla` module. To reduce verbosity and improve readability, +/// we introduce this alias and use it instead of that long construction. +pub type PallasLookupConfig = LookupRangeCheckConfig; + +impl PallasLookup for PallasLookupConfig {} #[cfg(test)] mod tests { From 92922becd0cb0c7ff329edb9f238f00365d6fa8d Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Wed, 15 May 2024 16:53:11 +0200 Subject: [PATCH 68/99] Move circuit test data to tests/circuit_reference_data folder, fix names of the test data files to follow the same convention: .proof.bin for proof tests, .vk.txt for verifying key/layout tests --- halo2_gadgets/src/ecc.rs | 4 ++-- halo2_gadgets/src/sinsemilla.rs | 4 ++-- halo2_gadgets/src/sinsemilla/merkle.rs | 4 ++-- .../ecc_chip.proof.bin} | Bin .../ecc_chip.vk.txt} | 0 .../lookup_range_check.proof.bin} | Bin .../lookup_range_check.vk.txt} | 0 .../merkle_chip.proof.bin} | Bin .../merkle_chip.vk.txt} | 0 .../short_range_check_0.proof.bin} | Bin .../short_range_check_0.vk.txt} | 0 .../short_range_check_1.proof.bin} | Bin .../short_range_check_1.vk.txt} | 0 .../short_range_check_2.proof.bin} | Bin .../short_range_check_2.vk.txt} | 0 .../sinsemilla_chip.proof.bin} | Bin .../sinsemilla_chip.vk.txt} | 0 halo2_gadgets/src/tests/test_utils.rs | 8 +++++--- .../src/utilities/lookup_range_check.rs | 16 ++++++++-------- 19 files changed, 19 insertions(+), 17 deletions(-) rename halo2_gadgets/src/tests/{circuit_proof_test_case_ecc.bin => circuit_reference_data/ecc_chip.proof.bin} (100%) rename halo2_gadgets/src/tests/{vk_ecc_chip_0 => circuit_reference_data/ecc_chip.vk.txt} (100%) rename halo2_gadgets/src/tests/{circuit_proof_test_case_lookup_range_check.bin => circuit_reference_data/lookup_range_check.proof.bin} (100%) rename halo2_gadgets/src/tests/{vk_lookup_range_check_0 => circuit_reference_data/lookup_range_check.vk.txt} (100%) rename halo2_gadgets/src/tests/{circuit_proof_test_case_merkle.bin => circuit_reference_data/merkle_chip.proof.bin} (100%) rename halo2_gadgets/src/tests/{vk_merkle_chip_0 => circuit_reference_data/merkle_chip.vk.txt} (100%) rename halo2_gadgets/src/tests/{circuit_proof_test_case_short_range_check_0.bin => circuit_reference_data/short_range_check_0.proof.bin} (100%) rename halo2_gadgets/src/tests/{vk_short_range_check_0 => circuit_reference_data/short_range_check_0.vk.txt} (100%) rename halo2_gadgets/src/tests/{circuit_proof_test_case_short_range_check_1.bin => circuit_reference_data/short_range_check_1.proof.bin} (100%) rename halo2_gadgets/src/tests/{vk_short_range_check_1 => circuit_reference_data/short_range_check_1.vk.txt} (100%) rename halo2_gadgets/src/tests/{circuit_proof_test_case_short_range_check_2.bin => circuit_reference_data/short_range_check_2.proof.bin} (100%) rename halo2_gadgets/src/tests/{vk_short_range_check_2 => circuit_reference_data/short_range_check_2.vk.txt} (100%) rename halo2_gadgets/src/tests/{circuit_proof_test_case_sinsemilla.bin => circuit_reference_data/sinsemilla_chip.proof.bin} (100%) rename halo2_gadgets/src/tests/{vk_sinsemilla_chip_0 => circuit_reference_data/sinsemilla_chip.vk.txt} (100%) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 7724c21d5a..23c4cbf479 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -914,13 +914,13 @@ pub(crate) mod tests { #[test] fn fixed_verification_key_test() { let circuit = MyCircuit { test_errors: false }; - fixed_verification_key_test_with_circuit(&circuit, "vk_ecc_chip_0"); + fixed_verification_key_test_with_circuit(&circuit, "ecc_chip"); } #[test] fn serialized_proof_test_case() { let circuit = MyCircuit { test_errors: false }; - serialized_proof_test_case_with_circuit(circuit, "circuit_proof_test_case_ecc"); + serialized_proof_test_case_with_circuit(circuit, "ecc_chip"); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 98274f7d0e..5f2ab2f268 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -747,13 +747,13 @@ pub(crate) mod tests { #[test] fn fixed_verification_key_test() { let circuit = MyCircuit {}; - fixed_verification_key_test_with_circuit(&circuit, "vk_sinsemilla_chip_0"); + fixed_verification_key_test_with_circuit(&circuit, "sinsemilla_chip"); } #[test] fn serialized_proof_test_case() { let circuit = MyCircuit {}; - serialized_proof_test_case_with_circuit(circuit, "circuit_proof_test_case_sinsemilla"); + serialized_proof_test_case_with_circuit(circuit, "sinsemilla_chip"); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index b113e5908e..83f284352d 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -393,13 +393,13 @@ pub mod tests { #[test] fn fixed_verification_key_test() { let circuit = generate_circuit(); - fixed_verification_key_test_with_circuit(&circuit, "vk_merkle_chip_0"); + fixed_verification_key_test_with_circuit(&circuit, "merkle_chip"); } #[test] fn serialized_proof_test_case() { let circuit = generate_circuit(); - serialized_proof_test_case_with_circuit(circuit, "circuit_proof_test_case_merkle"); + serialized_proof_test_case_with_circuit(circuit, "merkle_chip"); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/tests/circuit_proof_test_case_ecc.bin b/halo2_gadgets/src/tests/circuit_reference_data/ecc_chip.proof.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_proof_test_case_ecc.bin rename to halo2_gadgets/src/tests/circuit_reference_data/ecc_chip.proof.bin diff --git a/halo2_gadgets/src/tests/vk_ecc_chip_0 b/halo2_gadgets/src/tests/circuit_reference_data/ecc_chip.vk.txt similarity index 100% rename from halo2_gadgets/src/tests/vk_ecc_chip_0 rename to halo2_gadgets/src/tests/circuit_reference_data/ecc_chip.vk.txt diff --git a/halo2_gadgets/src/tests/circuit_proof_test_case_lookup_range_check.bin b/halo2_gadgets/src/tests/circuit_reference_data/lookup_range_check.proof.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_proof_test_case_lookup_range_check.bin rename to halo2_gadgets/src/tests/circuit_reference_data/lookup_range_check.proof.bin diff --git a/halo2_gadgets/src/tests/vk_lookup_range_check_0 b/halo2_gadgets/src/tests/circuit_reference_data/lookup_range_check.vk.txt similarity index 100% rename from halo2_gadgets/src/tests/vk_lookup_range_check_0 rename to halo2_gadgets/src/tests/circuit_reference_data/lookup_range_check.vk.txt diff --git a/halo2_gadgets/src/tests/circuit_proof_test_case_merkle.bin b/halo2_gadgets/src/tests/circuit_reference_data/merkle_chip.proof.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_proof_test_case_merkle.bin rename to halo2_gadgets/src/tests/circuit_reference_data/merkle_chip.proof.bin diff --git a/halo2_gadgets/src/tests/vk_merkle_chip_0 b/halo2_gadgets/src/tests/circuit_reference_data/merkle_chip.vk.txt similarity index 100% rename from halo2_gadgets/src/tests/vk_merkle_chip_0 rename to halo2_gadgets/src/tests/circuit_reference_data/merkle_chip.vk.txt diff --git a/halo2_gadgets/src/tests/circuit_proof_test_case_short_range_check_0.bin b/halo2_gadgets/src/tests/circuit_reference_data/short_range_check_0.proof.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_proof_test_case_short_range_check_0.bin rename to halo2_gadgets/src/tests/circuit_reference_data/short_range_check_0.proof.bin diff --git a/halo2_gadgets/src/tests/vk_short_range_check_0 b/halo2_gadgets/src/tests/circuit_reference_data/short_range_check_0.vk.txt similarity index 100% rename from halo2_gadgets/src/tests/vk_short_range_check_0 rename to halo2_gadgets/src/tests/circuit_reference_data/short_range_check_0.vk.txt diff --git a/halo2_gadgets/src/tests/circuit_proof_test_case_short_range_check_1.bin b/halo2_gadgets/src/tests/circuit_reference_data/short_range_check_1.proof.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_proof_test_case_short_range_check_1.bin rename to halo2_gadgets/src/tests/circuit_reference_data/short_range_check_1.proof.bin diff --git a/halo2_gadgets/src/tests/vk_short_range_check_1 b/halo2_gadgets/src/tests/circuit_reference_data/short_range_check_1.vk.txt similarity index 100% rename from halo2_gadgets/src/tests/vk_short_range_check_1 rename to halo2_gadgets/src/tests/circuit_reference_data/short_range_check_1.vk.txt diff --git a/halo2_gadgets/src/tests/circuit_proof_test_case_short_range_check_2.bin b/halo2_gadgets/src/tests/circuit_reference_data/short_range_check_2.proof.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_proof_test_case_short_range_check_2.bin rename to halo2_gadgets/src/tests/circuit_reference_data/short_range_check_2.proof.bin diff --git a/halo2_gadgets/src/tests/vk_short_range_check_2 b/halo2_gadgets/src/tests/circuit_reference_data/short_range_check_2.vk.txt similarity index 100% rename from halo2_gadgets/src/tests/vk_short_range_check_2 rename to halo2_gadgets/src/tests/circuit_reference_data/short_range_check_2.vk.txt diff --git a/halo2_gadgets/src/tests/circuit_proof_test_case_sinsemilla.bin b/halo2_gadgets/src/tests/circuit_reference_data/sinsemilla_chip.proof.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_proof_test_case_sinsemilla.bin rename to halo2_gadgets/src/tests/circuit_reference_data/sinsemilla_chip.proof.bin diff --git a/halo2_gadgets/src/tests/vk_sinsemilla_chip_0 b/halo2_gadgets/src/tests/circuit_reference_data/sinsemilla_chip.vk.txt similarity index 100% rename from halo2_gadgets/src/tests/vk_sinsemilla_chip_0 rename to halo2_gadgets/src/tests/circuit_reference_data/sinsemilla_chip.vk.txt diff --git a/halo2_gadgets/src/tests/test_utils.rs b/halo2_gadgets/src/tests/test_utils.rs index 2fc01ab0ab..962bcc23d3 100644 --- a/halo2_gadgets/src/tests/test_utils.rs +++ b/halo2_gadgets/src/tests/test_utils.rs @@ -20,7 +20,7 @@ use halo2_proofs::{ transcript::{Blake2bRead, Blake2bWrite}, }; -const TEST_DATA_DIR: &str = "src/tests"; +const TEST_DATA_DIR: &str = "src/tests/circuit_reference_data"; /// A proof structure #[derive(Clone, Debug)] @@ -70,7 +70,9 @@ pub(crate) fn fixed_verification_key_test_with_circuit> circuit: &C, file_name: &str, ) { - let full_file_name = Path::new(TEST_DATA_DIR).join(file_name); + let full_file_name = Path::new(TEST_DATA_DIR) + .join(file_name) + .with_extension("vk.txt"); // Setup phase: generate parameters, vk for the circuit. let params: Params = Params::new(11); @@ -114,7 +116,7 @@ pub(crate) fn serialized_proof_test_case_with_circuit>( ) { let full_file_name = Path::new(TEST_DATA_DIR) .join(file_name) - .with_extension("bin"); + .with_extension("proof.bin"); // Setup phase: generate parameters, vk for the circuit. let params: Params = Params::new(11); diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index a0c77629d0..2ffe4eb942 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -574,11 +574,11 @@ mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - fixed_verification_key_test_with_circuit(&circuit, "vk_lookup_range_check_0"); + fixed_verification_key_test_with_circuit(&circuit, "lookup_range_check"); serialized_proof_test_case_with_circuit( circuit, - "circuit_proof_test_case_lookup_range_check", + "lookup_range_check", ); } } @@ -639,11 +639,11 @@ mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - fixed_verification_key_test_with_circuit(&circuit, "vk_short_range_check_0"); + fixed_verification_key_test_with_circuit(&circuit, "short_range_check_0"); serialized_proof_test_case_with_circuit( circuit, - "circuit_proof_test_case_short_range_check_0", + "short_range_check_0", ); } @@ -656,11 +656,11 @@ mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - fixed_verification_key_test_with_circuit(&circuit, "vk_short_range_check_1"); + fixed_verification_key_test_with_circuit(&circuit, "short_range_check_1"); serialized_proof_test_case_with_circuit( circuit, - "circuit_proof_test_case_short_range_check_1", + "short_range_check_1", ); } @@ -673,11 +673,11 @@ mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - fixed_verification_key_test_with_circuit(&circuit, "vk_short_range_check_2"); + fixed_verification_key_test_with_circuit(&circuit, "short_range_check_2"); serialized_proof_test_case_with_circuit( circuit, - "circuit_proof_test_case_short_range_check_2", + "short_range_check_2", ); } From 6c7713f9f52ffc1bcb46207ab2195100a77343a8 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Wed, 15 May 2024 17:06:31 +0200 Subject: [PATCH 69/99] Rename circuit_reference_data to circuit_data --- .../ecc_chip.proof.bin | Bin .../ecc_chip.vk.txt | 0 .../lookup_range_check.proof.bin | Bin .../lookup_range_check.vk.txt | 0 .../merkle_chip.proof.bin | Bin .../merkle_chip.vk.txt | 0 .../short_range_check_0.proof.bin | Bin .../short_range_check_0.vk.txt | 0 .../short_range_check_1.proof.bin | Bin .../short_range_check_1.vk.txt | 0 .../short_range_check_2.proof.bin | Bin .../short_range_check_2.vk.txt | 0 .../sinsemilla_chip.proof.bin | Bin .../sinsemilla_chip.vk.txt | 0 halo2_gadgets/src/tests/test_utils.rs | 2 +- 15 files changed, 1 insertion(+), 1 deletion(-) rename halo2_gadgets/src/tests/{circuit_reference_data => circuit_data}/ecc_chip.proof.bin (100%) rename halo2_gadgets/src/tests/{circuit_reference_data => circuit_data}/ecc_chip.vk.txt (100%) rename halo2_gadgets/src/tests/{circuit_reference_data => circuit_data}/lookup_range_check.proof.bin (100%) rename halo2_gadgets/src/tests/{circuit_reference_data => circuit_data}/lookup_range_check.vk.txt (100%) rename halo2_gadgets/src/tests/{circuit_reference_data => circuit_data}/merkle_chip.proof.bin (100%) rename halo2_gadgets/src/tests/{circuit_reference_data => circuit_data}/merkle_chip.vk.txt (100%) rename halo2_gadgets/src/tests/{circuit_reference_data => circuit_data}/short_range_check_0.proof.bin (100%) rename halo2_gadgets/src/tests/{circuit_reference_data => circuit_data}/short_range_check_0.vk.txt (100%) rename halo2_gadgets/src/tests/{circuit_reference_data => circuit_data}/short_range_check_1.proof.bin (100%) rename halo2_gadgets/src/tests/{circuit_reference_data => circuit_data}/short_range_check_1.vk.txt (100%) rename halo2_gadgets/src/tests/{circuit_reference_data => circuit_data}/short_range_check_2.proof.bin (100%) rename halo2_gadgets/src/tests/{circuit_reference_data => circuit_data}/short_range_check_2.vk.txt (100%) rename halo2_gadgets/src/tests/{circuit_reference_data => circuit_data}/sinsemilla_chip.proof.bin (100%) rename halo2_gadgets/src/tests/{circuit_reference_data => circuit_data}/sinsemilla_chip.vk.txt (100%) diff --git a/halo2_gadgets/src/tests/circuit_reference_data/ecc_chip.proof.bin b/halo2_gadgets/src/tests/circuit_data/ecc_chip.proof.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_reference_data/ecc_chip.proof.bin rename to halo2_gadgets/src/tests/circuit_data/ecc_chip.proof.bin diff --git a/halo2_gadgets/src/tests/circuit_reference_data/ecc_chip.vk.txt b/halo2_gadgets/src/tests/circuit_data/ecc_chip.vk.txt similarity index 100% rename from halo2_gadgets/src/tests/circuit_reference_data/ecc_chip.vk.txt rename to halo2_gadgets/src/tests/circuit_data/ecc_chip.vk.txt diff --git a/halo2_gadgets/src/tests/circuit_reference_data/lookup_range_check.proof.bin b/halo2_gadgets/src/tests/circuit_data/lookup_range_check.proof.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_reference_data/lookup_range_check.proof.bin rename to halo2_gadgets/src/tests/circuit_data/lookup_range_check.proof.bin diff --git a/halo2_gadgets/src/tests/circuit_reference_data/lookup_range_check.vk.txt b/halo2_gadgets/src/tests/circuit_data/lookup_range_check.vk.txt similarity index 100% rename from halo2_gadgets/src/tests/circuit_reference_data/lookup_range_check.vk.txt rename to halo2_gadgets/src/tests/circuit_data/lookup_range_check.vk.txt diff --git a/halo2_gadgets/src/tests/circuit_reference_data/merkle_chip.proof.bin b/halo2_gadgets/src/tests/circuit_data/merkle_chip.proof.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_reference_data/merkle_chip.proof.bin rename to halo2_gadgets/src/tests/circuit_data/merkle_chip.proof.bin diff --git a/halo2_gadgets/src/tests/circuit_reference_data/merkle_chip.vk.txt b/halo2_gadgets/src/tests/circuit_data/merkle_chip.vk.txt similarity index 100% rename from halo2_gadgets/src/tests/circuit_reference_data/merkle_chip.vk.txt rename to halo2_gadgets/src/tests/circuit_data/merkle_chip.vk.txt diff --git a/halo2_gadgets/src/tests/circuit_reference_data/short_range_check_0.proof.bin b/halo2_gadgets/src/tests/circuit_data/short_range_check_0.proof.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_reference_data/short_range_check_0.proof.bin rename to halo2_gadgets/src/tests/circuit_data/short_range_check_0.proof.bin diff --git a/halo2_gadgets/src/tests/circuit_reference_data/short_range_check_0.vk.txt b/halo2_gadgets/src/tests/circuit_data/short_range_check_0.vk.txt similarity index 100% rename from halo2_gadgets/src/tests/circuit_reference_data/short_range_check_0.vk.txt rename to halo2_gadgets/src/tests/circuit_data/short_range_check_0.vk.txt diff --git a/halo2_gadgets/src/tests/circuit_reference_data/short_range_check_1.proof.bin b/halo2_gadgets/src/tests/circuit_data/short_range_check_1.proof.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_reference_data/short_range_check_1.proof.bin rename to halo2_gadgets/src/tests/circuit_data/short_range_check_1.proof.bin diff --git a/halo2_gadgets/src/tests/circuit_reference_data/short_range_check_1.vk.txt b/halo2_gadgets/src/tests/circuit_data/short_range_check_1.vk.txt similarity index 100% rename from halo2_gadgets/src/tests/circuit_reference_data/short_range_check_1.vk.txt rename to halo2_gadgets/src/tests/circuit_data/short_range_check_1.vk.txt diff --git a/halo2_gadgets/src/tests/circuit_reference_data/short_range_check_2.proof.bin b/halo2_gadgets/src/tests/circuit_data/short_range_check_2.proof.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_reference_data/short_range_check_2.proof.bin rename to halo2_gadgets/src/tests/circuit_data/short_range_check_2.proof.bin diff --git a/halo2_gadgets/src/tests/circuit_reference_data/short_range_check_2.vk.txt b/halo2_gadgets/src/tests/circuit_data/short_range_check_2.vk.txt similarity index 100% rename from halo2_gadgets/src/tests/circuit_reference_data/short_range_check_2.vk.txt rename to halo2_gadgets/src/tests/circuit_data/short_range_check_2.vk.txt diff --git a/halo2_gadgets/src/tests/circuit_reference_data/sinsemilla_chip.proof.bin b/halo2_gadgets/src/tests/circuit_data/sinsemilla_chip.proof.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_reference_data/sinsemilla_chip.proof.bin rename to halo2_gadgets/src/tests/circuit_data/sinsemilla_chip.proof.bin diff --git a/halo2_gadgets/src/tests/circuit_reference_data/sinsemilla_chip.vk.txt b/halo2_gadgets/src/tests/circuit_data/sinsemilla_chip.vk.txt similarity index 100% rename from halo2_gadgets/src/tests/circuit_reference_data/sinsemilla_chip.vk.txt rename to halo2_gadgets/src/tests/circuit_data/sinsemilla_chip.vk.txt diff --git a/halo2_gadgets/src/tests/test_utils.rs b/halo2_gadgets/src/tests/test_utils.rs index 962bcc23d3..0999cba67f 100644 --- a/halo2_gadgets/src/tests/test_utils.rs +++ b/halo2_gadgets/src/tests/test_utils.rs @@ -20,7 +20,7 @@ use halo2_proofs::{ transcript::{Blake2bRead, Blake2bWrite}, }; -const TEST_DATA_DIR: &str = "src/tests/circuit_reference_data"; +const TEST_DATA_DIR: &str = "src/tests/circuit_data"; /// A proof structure #[derive(Clone, Debug)] From 8922ed6436b5e73088969d1eec72f80d30fc6e77 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Wed, 15 May 2024 17:09:57 +0200 Subject: [PATCH 70/99] Fix cargo fmt issues --- .../src/utilities/lookup_range_check.rs | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 2ffe4eb942..c1f6647b1f 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -576,10 +576,7 @@ mod tests { fixed_verification_key_test_with_circuit(&circuit, "lookup_range_check"); - serialized_proof_test_case_with_circuit( - circuit, - "lookup_range_check", - ); + serialized_proof_test_case_with_circuit(circuit, "lookup_range_check"); } } @@ -641,10 +638,7 @@ mod tests { fixed_verification_key_test_with_circuit(&circuit, "short_range_check_0"); - serialized_proof_test_case_with_circuit( - circuit, - "short_range_check_0", - ); + serialized_proof_test_case_with_circuit(circuit, "short_range_check_0"); } // Edge case: K bits (case 1) @@ -658,10 +652,7 @@ mod tests { fixed_verification_key_test_with_circuit(&circuit, "short_range_check_1"); - serialized_proof_test_case_with_circuit( - circuit, - "short_range_check_1", - ); + serialized_proof_test_case_with_circuit(circuit, "short_range_check_1"); } // Element within `num_bits` (case 2) @@ -675,10 +666,7 @@ mod tests { fixed_verification_key_test_with_circuit(&circuit, "short_range_check_2"); - serialized_proof_test_case_with_circuit( - circuit, - "short_range_check_2", - ); + serialized_proof_test_case_with_circuit(circuit, "short_range_check_2"); } // Element larger than `num_bits` but within K bits From f75b054dac309474e80c59e04ae424d12c8a19d4 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Thu, 16 May 2024 15:10:34 +0200 Subject: [PATCH 71/99] Try to increase cargo-tarpaulin timeout in ci.yml from 600 to 1800 to see if it helps to resolve test failing on GitHub --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d2ecd3ba57..f41730f6e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -148,7 +148,7 @@ jobs: command: tarpaulin args: > ${{ steps.prepare.outputs.feature-flags }} - --timeout 600 + --timeout 1800 --out Xml - name: Upload coverage to Codecov uses: codecov/codecov-action@v3.1.4 From 5414d9526c0e774b0d0597b3fcfea06b656f4ab3 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Fri, 17 May 2024 09:51:33 +0200 Subject: [PATCH 72/99] Add default generic arguments for PallasLookup to improve backward compatibility This change adds default generic arguments for types implementing the PallasLookup trait, assigning them to PallasLookupConfig by default. This adjustment allows existing code to function without requiring users to explicitly specify PallasLookupConfig, thus minimizing breaking changes. Users will still need to bring the PallasLookup trait into scope using 'use ... PallasLookup'. --- halo2_gadgets/src/ecc/chip.rs | 15 ++++++++++++--- halo2_gadgets/src/ecc/chip/mul.rs | 4 ++-- halo2_gadgets/src/ecc/chip/mul/overflow.rs | 7 +++++-- .../src/ecc/chip/mul_fixed/base_field_elem.rs | 6 ++++-- halo2_gadgets/src/sinsemilla/chip.rs | 6 +++--- halo2_gadgets/src/sinsemilla/merkle/chip.rs | 9 ++++++--- 6 files changed, 32 insertions(+), 15 deletions(-) diff --git a/halo2_gadgets/src/ecc/chip.rs b/halo2_gadgets/src/ecc/chip.rs index 0c8d0902d7..abfb75538e 100644 --- a/halo2_gadgets/src/ecc/chip.rs +++ b/halo2_gadgets/src/ecc/chip.rs @@ -1,7 +1,10 @@ //! Chip implementations for the ECC gadgets. use super::{BaseFitsInScalarInstructions, EccInstructions, FixedPoints}; -use crate::utilities::{lookup_range_check::PallasLookup, UtilitiesInstructions}; +use crate::utilities::{ + lookup_range_check::{PallasLookup, PallasLookupConfig}, + UtilitiesInstructions, +}; use arrayvec::ArrayVec; use ff::PrimeField; @@ -134,7 +137,10 @@ impl From for EccPoint { /// Configuration for [`EccChip`]. #[derive(Clone, Debug, Eq, PartialEq)] #[allow(non_snake_case)] -pub struct EccConfig, Lookup: PallasLookup> { +pub struct EccConfig< + FixedPoints: super::FixedPoints, + Lookup: PallasLookup = PallasLookupConfig, +> { /// Advice columns needed by instructions in the ECC chip. pub advices: [Column; 10], @@ -224,7 +230,10 @@ pub trait FixedPoint: std::fmt::Debug + Eq + Clone { /// An [`EccInstructions`] chip that uses 10 advice columns. #[derive(Clone, Debug, Eq, PartialEq)] -pub struct EccChip, Lookup: PallasLookup> { +pub struct EccChip< + FixedPoints: super::FixedPoints, + Lookup: PallasLookup = PallasLookupConfig, +> { config: EccConfig, } diff --git a/halo2_gadgets/src/ecc/chip/mul.rs b/halo2_gadgets/src/ecc/chip/mul.rs index 49f19900d0..2826719267 100644 --- a/halo2_gadgets/src/ecc/chip/mul.rs +++ b/halo2_gadgets/src/ecc/chip/mul.rs @@ -1,6 +1,6 @@ use super::{add, EccPoint, NonIdentityEccPoint, ScalarVar, T_Q}; use crate::utilities::{ - lookup_range_check::PallasLookup, + lookup_range_check::{PallasLookup, PallasLookupConfig}, {bool_check, ternary}, }; use std::{ @@ -46,7 +46,7 @@ const INCOMPLETE_LO_LEN: usize = INCOMPLETE_LEN - INCOMPLETE_HI_LEN; const COMPLETE_RANGE: Range = INCOMPLETE_LEN..(INCOMPLETE_LEN + NUM_COMPLETE_BITS); #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { +pub struct Config { // Selector used to check switching logic on LSB q_mul_lsb: Selector, // Configuration used in complete addition diff --git a/halo2_gadgets/src/ecc/chip/mul/overflow.rs b/halo2_gadgets/src/ecc/chip/mul/overflow.rs index 53cde0f10d..75b81f9d14 100644 --- a/halo2_gadgets/src/ecc/chip/mul/overflow.rs +++ b/halo2_gadgets/src/ecc/chip/mul/overflow.rs @@ -1,5 +1,8 @@ use super::{T_Q, Z}; -use crate::{sinsemilla::primitives as sinsemilla, utilities::lookup_range_check::PallasLookup}; +use crate::{ + sinsemilla::primitives as sinsemilla, + utilities::lookup_range_check::{PallasLookup, PallasLookupConfig}, +}; use group::ff::PrimeField; use halo2_proofs::circuit::AssignedCell; @@ -13,7 +16,7 @@ use pasta_curves::pallas; use std::iter; #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { +pub struct Config { // Selector to check z_0 = alpha + t_q (mod p) q_mul_overflow: Selector, // 10-bit lookup table diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs index 917d8836a2..1618f2b474 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs @@ -2,7 +2,9 @@ use super::super::{EccBaseFieldElemFixed, EccPoint, FixedPoints, NUM_WINDOWS, T_ use super::H_BASE; use crate::utilities::{ - bitrange_subset, bool_check, lookup_range_check::PallasLookup, range_check, + bitrange_subset, bool_check, + lookup_range_check::{PallasLookup, PallasLookupConfig}, + range_check, }; use group::ff::PrimeField; @@ -16,7 +18,7 @@ use pasta_curves::pallas; use std::convert::TryInto; #[derive(Clone, Debug, Eq, PartialEq)] -pub struct Config, Lookup: PallasLookup> { +pub struct Config, Lookup: PallasLookup = PallasLookupConfig> { q_mul_fixed_base_field: Selector, canon_advices: [Column; 3], lookup_config: Lookup, diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs index 19af2e9bd1..a87fc67cc5 100644 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ b/halo2_gadgets/src/sinsemilla/chip.rs @@ -9,7 +9,7 @@ use crate::{ chip::{DoubleAndAdd, NonIdentityEccPoint}, FixedPoints, }, - utilities::lookup_range_check::PallasLookup, + utilities::lookup_range_check::{PallasLookup, PallasLookupConfig}, }; use std::marker::PhantomData; @@ -30,7 +30,7 @@ mod hash_to_point; /// Configuration for the Sinsemilla hash chip #[derive(Eq, PartialEq, Clone, Debug)] -pub struct SinsemillaConfig +pub struct SinsemillaConfig where Hash: HashDomains, F: FixedPoints, @@ -98,7 +98,7 @@ where /// /// [Chip description](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html#plonk--halo-2-constraints). #[derive(Eq, PartialEq, Clone, Debug)] -pub struct SinsemillaChip +pub struct SinsemillaChip where Hash: HashDomains, Fixed: FixedPoints, diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs index 93f0fc8175..6cf1b647f5 100644 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla/merkle/chip.rs @@ -11,7 +11,10 @@ use super::MerkleInstructions; use crate::{ sinsemilla::{primitives as sinsemilla, MessagePiece}, - utilities::{lookup_range_check::PallasLookup, RangeConstrained}, + utilities::{ + lookup_range_check::{PallasLookup, PallasLookupConfig}, + RangeConstrained, + }, { ecc::FixedPoints, sinsemilla::{ @@ -28,7 +31,7 @@ use group::ff::PrimeField; /// Configuration for the `MerkleChip` implementation. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct MerkleConfig +pub struct MerkleConfig where Hash: HashDomains, Fixed: FixedPoints, @@ -52,7 +55,7 @@ where /// This chip does **NOT** constrain `left⋆` and `right⋆` to be canonical encodings of /// `left` and `right`. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct MerkleChip +pub struct MerkleChip where Hash: HashDomains, Fixed: FixedPoints, From 396bbdea5db073f12aea172a60f5533951611944 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Wed, 22 May 2024 09:34:05 +0200 Subject: [PATCH 73/99] Try to increase cargo-tarpaulin timeout in ci.yml from to 3600 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f41730f6e1..9c2efa385d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -148,7 +148,7 @@ jobs: command: tarpaulin args: > ${{ steps.prepare.outputs.feature-flags }} - --timeout 1800 + --timeout 3600 --out Xml - name: Upload coverage to Codecov uses: codecov/codecov-action@v3.1.4 From 1ae0a3135f548cfe3e1e71e2056aae799b97090c Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Tue, 28 May 2024 11:41:51 +0200 Subject: [PATCH 74/99] update --- halo2_gadgets/src/ecc.rs | 14 +++---- halo2_gadgets/src/ecc/chip.rs | 16 ++++---- halo2_gadgets/src/ecc/chip/mul.rs | 10 ++--- halo2_gadgets/src/ecc/chip/mul/overflow.rs | 6 +-- .../src/ecc/chip/mul_fixed/base_field_elem.rs | 14 +++---- .../src/ecc/chip/mul_fixed/full_width.rs | 8 ++-- halo2_gadgets/src/ecc/chip/mul_fixed/short.rs | 14 +++---- halo2_gadgets/src/sinsemilla.rs | 20 +++++----- halo2_gadgets/src/sinsemilla/chip.rs | 15 +++---- .../src/sinsemilla/chip/generator_table.rs | 4 +- .../src/sinsemilla/chip/hash_to_point.rs | 4 +- halo2_gadgets/src/sinsemilla/merkle.rs | 16 ++++---- halo2_gadgets/src/sinsemilla/merkle/chip.rs | 25 ++++++------ ...{ecc_chip.proof.bin => proof_ecc_chip.bin} | Bin ...proof.bin => proof_lookup_range_check.bin} | Bin ...e_chip.proof.bin => proof_merkle_chip.bin} | Bin ...roof.bin => proof_short_range_check_0.bin} | Bin ...roof.bin => proof_short_range_check_1.bin} | Bin ...roof.bin => proof_short_range_check_2.bin} | Bin ...ip.proof.bin => proof_sinsemilla_chip.bin} | Bin .../{ecc_chip.vk.txt => vk_ecc_chip.rdata} | 0 ...eck.vk.txt => vk_lookup_range_check.rdata} | 0 ...erkle_chip.vk.txt => vk_merkle_chip.rdata} | 0 ..._0.vk.txt => vk_short_range_check_0.rdata} | 0 ..._1.vk.txt => vk_short_range_check_1.rdata} | 0 ..._2.vk.txt => vk_short_range_check_2.rdata} | 0 ...a_chip.vk.txt => vk_sinsemilla_chip.rdata} | 0 halo2_gadgets/src/tests/test_utils.rs | 30 +++++++------- .../src/utilities/lookup_range_check.rs | 37 ++++++++---------- 29 files changed, 116 insertions(+), 117 deletions(-) rename halo2_gadgets/src/tests/circuit_data/{ecc_chip.proof.bin => proof_ecc_chip.bin} (100%) rename halo2_gadgets/src/tests/circuit_data/{lookup_range_check.proof.bin => proof_lookup_range_check.bin} (100%) rename halo2_gadgets/src/tests/circuit_data/{merkle_chip.proof.bin => proof_merkle_chip.bin} (100%) rename halo2_gadgets/src/tests/circuit_data/{short_range_check_0.proof.bin => proof_short_range_check_0.bin} (100%) rename halo2_gadgets/src/tests/circuit_data/{short_range_check_1.proof.bin => proof_short_range_check_1.bin} (100%) rename halo2_gadgets/src/tests/circuit_data/{short_range_check_2.proof.bin => proof_short_range_check_2.bin} (100%) rename halo2_gadgets/src/tests/circuit_data/{sinsemilla_chip.proof.bin => proof_sinsemilla_chip.bin} (100%) rename halo2_gadgets/src/tests/circuit_data/{ecc_chip.vk.txt => vk_ecc_chip.rdata} (100%) rename halo2_gadgets/src/tests/circuit_data/{lookup_range_check.vk.txt => vk_lookup_range_check.rdata} (100%) rename halo2_gadgets/src/tests/circuit_data/{merkle_chip.vk.txt => vk_merkle_chip.rdata} (100%) rename halo2_gadgets/src/tests/circuit_data/{short_range_check_0.vk.txt => vk_short_range_check_0.rdata} (100%) rename halo2_gadgets/src/tests/circuit_data/{short_range_check_1.vk.txt => vk_short_range_check_1.rdata} (100%) rename halo2_gadgets/src/tests/circuit_data/{short_range_check_2.vk.txt => vk_short_range_check_2.rdata} (100%) rename halo2_gadgets/src/tests/circuit_data/{sinsemilla_chip.vk.txt => vk_sinsemilla_chip.rdata} (100%) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 23c4cbf479..58b9acc4ef 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -597,9 +597,9 @@ pub(crate) mod tests { }; use crate::{ tests::test_utils::{ - fixed_verification_key_test_with_circuit, serialized_proof_test_case_with_circuit, + test_against_stored_vk, test_against_stored_proof, }, - utilities::lookup_range_check::{LookupRangeCheck, PallasLookupConfig}, + utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRC10b}, }; #[derive(Debug, Eq, PartialEq, Clone)] @@ -734,7 +734,7 @@ pub(crate) mod tests { #[allow(non_snake_case)] impl Circuit for MyCircuit { - type Config = EccConfig; + type Config = EccConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -769,8 +769,8 @@ pub(crate) mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); - let range_check = PallasLookupConfig::configure(meta, advices[9], lookup_table); - EccChip::::configure( + let range_check = PallasLookupRC10b::configure(meta, advices[9], lookup_table); + EccChip::::configure( meta, advices, lagrange_coeffs, @@ -914,13 +914,13 @@ pub(crate) mod tests { #[test] fn fixed_verification_key_test() { let circuit = MyCircuit { test_errors: false }; - fixed_verification_key_test_with_circuit(&circuit, "ecc_chip"); + test_against_stored_vk(&circuit, "ecc_chip"); } #[test] fn serialized_proof_test_case() { let circuit = MyCircuit { test_errors: false }; - serialized_proof_test_case_with_circuit(circuit, "ecc_chip"); + test_against_stored_proof(circuit, "ecc_chip"); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/ecc/chip.rs b/halo2_gadgets/src/ecc/chip.rs index 0c8d0902d7..d7a0c92219 100644 --- a/halo2_gadgets/src/ecc/chip.rs +++ b/halo2_gadgets/src/ecc/chip.rs @@ -1,7 +1,7 @@ //! Chip implementations for the ECC gadgets. use super::{BaseFitsInScalarInstructions, EccInstructions, FixedPoints}; -use crate::utilities::{lookup_range_check::PallasLookup, UtilitiesInstructions}; +use crate::utilities::{lookup_range_check::PallasLookupRC, UtilitiesInstructions}; use arrayvec::ArrayVec; use ff::PrimeField; @@ -134,7 +134,7 @@ impl From for EccPoint { /// Configuration for [`EccChip`]. #[derive(Clone, Debug, Eq, PartialEq)] #[allow(non_snake_case)] -pub struct EccConfig, Lookup: PallasLookup> { +pub struct EccConfig, Lookup: PallasLookupRC> { /// Advice columns needed by instructions in the ECC chip. pub advices: [Column; 10], @@ -224,11 +224,11 @@ pub trait FixedPoint: std::fmt::Debug + Eq + Clone { /// An [`EccInstructions`] chip that uses 10 advice columns. #[derive(Clone, Debug, Eq, PartialEq)] -pub struct EccChip, Lookup: PallasLookup> { +pub struct EccChip, Lookup: PallasLookupRC> { config: EccConfig, } -impl, Lookup: PallasLookup> Chip +impl, Lookup: PallasLookupRC> Chip for EccChip { type Config = EccConfig; @@ -243,13 +243,13 @@ impl, Lookup: PallasLookup> Chip } } -impl, Lookup: PallasLookup> +impl, Lookup: PallasLookupRC> UtilitiesInstructions for EccChip { type Var = AssignedCell; } -impl, Lookup: PallasLookup> +impl, Lookup: PallasLookupRC> EccChip { /// Reconstructs this chip from the given config. @@ -409,7 +409,7 @@ pub enum ScalarVar { FullWidth, } -impl, Lookup: PallasLookup> EccInstructions +impl, Lookup: PallasLookupRC> EccInstructions for EccChip where >::Base: @@ -597,7 +597,7 @@ where } } -impl, Lookup: PallasLookup> +impl, Lookup: PallasLookupRC> BaseFitsInScalarInstructions for EccChip where >::Base: diff --git a/halo2_gadgets/src/ecc/chip/mul.rs b/halo2_gadgets/src/ecc/chip/mul.rs index 49f19900d0..70c14df284 100644 --- a/halo2_gadgets/src/ecc/chip/mul.rs +++ b/halo2_gadgets/src/ecc/chip/mul.rs @@ -1,6 +1,6 @@ use super::{add, EccPoint, NonIdentityEccPoint, ScalarVar, T_Q}; use crate::utilities::{ - lookup_range_check::PallasLookup, + lookup_range_check::PallasLookupRC, {bool_check, ternary}, }; use std::{ @@ -46,7 +46,7 @@ const INCOMPLETE_LO_LEN: usize = INCOMPLETE_LEN - INCOMPLETE_HI_LEN; const COMPLETE_RANGE: Range = INCOMPLETE_LEN..(INCOMPLETE_LEN + NUM_COMPLETE_BITS); #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { +pub struct Config { // Selector used to check switching logic on LSB q_mul_lsb: Selector, // Configuration used in complete addition @@ -61,7 +61,7 @@ pub struct Config { overflow_config: overflow::Config, } -impl Config { +impl Config { pub(super) fn configure( meta: &mut ConstraintSystem, add_config: add::Config, @@ -468,7 +468,7 @@ pub mod tests { use pasta_curves::pallas; use rand::rngs::OsRng; - use crate::utilities::lookup_range_check::PallasLookup; + use crate::utilities::lookup_range_check::PallasLookupRC; use crate::{ ecc::{ chip::{EccChip, EccPoint}, @@ -478,7 +478,7 @@ pub mod tests { utilities::UtilitiesInstructions, }; - pub(crate) fn test_mul( + pub(crate) fn test_mul( chip: EccChip, mut layouter: impl Layouter, p: &NonIdentityPoint>, diff --git a/halo2_gadgets/src/ecc/chip/mul/overflow.rs b/halo2_gadgets/src/ecc/chip/mul/overflow.rs index 53cde0f10d..eb5810fac5 100644 --- a/halo2_gadgets/src/ecc/chip/mul/overflow.rs +++ b/halo2_gadgets/src/ecc/chip/mul/overflow.rs @@ -1,5 +1,5 @@ use super::{T_Q, Z}; -use crate::{sinsemilla::primitives as sinsemilla, utilities::lookup_range_check::PallasLookup}; +use crate::{sinsemilla::primitives as sinsemilla, utilities::lookup_range_check::PallasLookupRC}; use group::ff::PrimeField; use halo2_proofs::circuit::AssignedCell; @@ -13,7 +13,7 @@ use pasta_curves::pallas; use std::iter; #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { +pub struct Config { // Selector to check z_0 = alpha + t_q (mod p) q_mul_overflow: Selector, // 10-bit lookup table @@ -22,7 +22,7 @@ pub struct Config { advices: [Column; 3], } -impl Config { +impl Config { pub(super) fn configure( meta: &mut ConstraintSystem, lookup_config: Lookup, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs index 917d8836a2..760ab20b9a 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs @@ -2,7 +2,7 @@ use super::super::{EccBaseFieldElemFixed, EccPoint, FixedPoints, NUM_WINDOWS, T_ use super::H_BASE; use crate::utilities::{ - bitrange_subset, bool_check, lookup_range_check::PallasLookup, range_check, + bitrange_subset, bool_check, lookup_range_check::PallasLookupRC, range_check, }; use group::ff::PrimeField; @@ -16,14 +16,14 @@ use pasta_curves::pallas; use std::convert::TryInto; #[derive(Clone, Debug, Eq, PartialEq)] -pub struct Config, Lookup: PallasLookup> { +pub struct Config, Lookup: PallasLookupRC> { q_mul_fixed_base_field: Selector, canon_advices: [Column; 3], lookup_config: Lookup, super_config: super::Config, } -impl, Lookup: PallasLookup> Config { +impl, Lookup: PallasLookupRC> Config { pub(crate) fn configure( meta: &mut ConstraintSystem, canon_advices: [Column; 3], @@ -386,7 +386,7 @@ pub mod tests { use pasta_curves::pallas; use rand::rngs::OsRng; - use crate::utilities::lookup_range_check::PallasLookup; + use crate::utilities::lookup_range_check::PallasLookupRC; use crate::{ ecc::{ chip::{EccChip, FixedPoint, H}, @@ -396,7 +396,7 @@ pub mod tests { utilities::UtilitiesInstructions, }; - pub(crate) fn test_mul_fixed_base_field( + pub(crate) fn test_mul_fixed_base_field( chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { @@ -409,7 +409,7 @@ pub mod tests { } #[allow(clippy::op_ref)] - fn test_single_base( + fn test_single_base( chip: EccChip, mut layouter: impl Layouter, base: FixedPointBaseField>, @@ -419,7 +419,7 @@ pub mod tests { let column = chip.config().advices[0]; - fn constrain_equal_non_id( + fn constrain_equal_non_id( chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs index 0b7f64c635..fe0ccd8d3d 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs @@ -192,9 +192,9 @@ pub mod tests { tests::{FullWidth, TestFixedBases}, FixedPoint, NonIdentityPoint, Point, ScalarFixed, }; - use crate::utilities::lookup_range_check::PallasLookup; + use crate::utilities::lookup_range_check::PallasLookupRC; - pub(crate) fn test_mul_fixed( + pub(crate) fn test_mul_fixed( chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { @@ -210,13 +210,13 @@ pub mod tests { } #[allow(clippy::op_ref)] - fn test_single_base( + fn test_single_base( chip: EccChip, mut layouter: impl Layouter, base: FixedPoint>, base_val: pallas::Affine, ) -> Result<(), Error> { - fn constrain_equal_non_id( + fn constrain_equal_non_id( chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs index 5697b6840b..d7e78c3090 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs @@ -260,13 +260,13 @@ pub mod tests { FixedPointShort, NonIdentityPoint, Point, ScalarFixedShort, }, utilities::{ - lookup_range_check::{LookupRangeCheck, PallasLookup, PallasLookupConfig}, + lookup_range_check::{LookupRangeCheck, PallasLookupRC, PallasLookupRC10b}, UtilitiesInstructions, }, }; #[allow(clippy::op_ref)] - pub(crate) fn test_mul_fixed_short( + pub(crate) fn test_mul_fixed_short( chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { @@ -274,7 +274,7 @@ pub mod tests { let base_val = Short.generator(); let test_short = FixedPointShort::from_inner(chip.clone(), Short); - fn load_magnitude_sign( + fn load_magnitude_sign( chip: EccChip, mut layouter: impl Layouter, magnitude: pallas::Base, @@ -292,7 +292,7 @@ pub mod tests { Ok((magnitude, sign)) } - fn constrain_equal_non_id( + fn constrain_equal_non_id( chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, @@ -428,7 +428,7 @@ pub mod tests { } impl Circuit for MyCircuit { - type Config = EccConfig; + type Config = EccConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -464,8 +464,8 @@ pub mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); - let range_check = PallasLookupConfig::configure(meta, advices[9], lookup_table); - EccChip::::configure( + let range_check = PallasLookupRC10b::configure(meta, advices[9], lookup_table); + EccChip::::configure( meta, advices, lagrange_coeffs, diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 5f2ab2f268..d3ab13312a 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -473,9 +473,9 @@ pub(crate) mod tests { }, sinsemilla::primitives::{self as sinsemilla, K}, tests::test_utils::{ - fixed_verification_key_test_with_circuit, serialized_proof_test_case_with_circuit, + test_against_stored_vk, test_against_stored_proof, }, - utilities::lookup_range_check::{LookupRangeCheck, PallasLookupConfig}, + utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRC10b}, }; use group::{ff::Field, Curve}; @@ -521,9 +521,9 @@ pub(crate) mod tests { impl Circuit for MyCircuit { #[allow(clippy::type_complexity)] type Config = ( - EccConfig, - SinsemillaConfig, - SinsemillaConfig, + EccConfig, + SinsemillaConfig, + SinsemillaConfig, ); type FloorPlanner = SimpleFloorPlanner; @@ -569,9 +569,9 @@ pub(crate) mod tests { meta.lookup_table_column(), ); - let range_check = PallasLookupConfig::configure(meta, advices[9], table_idx); + let range_check = PallasLookupRC10b::configure(meta, advices[9], table_idx); - let ecc_config = EccChip::::configure( + let ecc_config = EccChip::::configure( meta, advices, lagrange_coeffs, @@ -611,7 +611,7 @@ pub(crate) mod tests { TestHashDomain, TestCommitDomain, TestFixedBases, - PallasLookupConfig, + PallasLookupRC10b, >::load(config.1.clone(), &mut layouter)?; // This MerkleCRH example is purely for illustrative purposes. @@ -747,13 +747,13 @@ pub(crate) mod tests { #[test] fn fixed_verification_key_test() { let circuit = MyCircuit {}; - fixed_verification_key_test_with_circuit(&circuit, "sinsemilla_chip"); + test_against_stored_vk(&circuit, "sinsemilla_chip"); } #[test] fn serialized_proof_test_case() { let circuit = MyCircuit {}; - serialized_proof_test_case_with_circuit(circuit, "sinsemilla_chip"); + test_against_stored_proof(circuit, "sinsemilla_chip"); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs index 19af2e9bd1..72a9159e61 100644 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ b/halo2_gadgets/src/sinsemilla/chip.rs @@ -9,7 +9,7 @@ use crate::{ chip::{DoubleAndAdd, NonIdentityEccPoint}, FixedPoints, }, - utilities::lookup_range_check::PallasLookup, + utilities::lookup_range_check::PallasLookupRC, }; use std::marker::PhantomData; @@ -35,7 +35,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookup, + Lookup: PallasLookupRC, { /// Binary selector used in lookup argument and in the body of the Sinsemilla hash. q_sinsemilla1: Selector, @@ -68,7 +68,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookup, + Lookup: PallasLookupRC, { /// Returns an array of all advice columns in this config, in arbitrary order. pub(super) fn advices(&self) -> [Column; 5] { @@ -103,7 +103,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookup, + Lookup: PallasLookupRC, { config: SinsemillaConfig, } @@ -113,7 +113,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookup, + Lookup: PallasLookupRC, { type Config = SinsemillaConfig; type Loaded = (); @@ -132,7 +132,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookup, + Lookup: PallasLookupRC, { /// Reconstructs this chip from the given config. pub fn construct(config: >::Config) -> Self { @@ -220,6 +220,7 @@ where config } + /// Assign y_q to a fixed column #[allow(non_snake_case)] fn create_initial_y_q_gate( meta: &mut ConstraintSystem, @@ -321,7 +322,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookup, + Lookup: PallasLookupRC, { type CellValue = AssignedCell; diff --git a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs index 5ec7278bf8..013995911c 100644 --- a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs +++ b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs @@ -8,7 +8,7 @@ use halo2_proofs::{ use super::{CommitDomains, FixedPoints, HashDomains}; use crate::{ sinsemilla::primitives::{self as sinsemilla, SINSEMILLA_S}, - utilities::lookup_range_check::PallasLookup, + utilities::lookup_range_check::PallasLookupRC, }; use pasta_curves::pallas; @@ -33,7 +33,7 @@ impl GeneratorTableConfig { Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookup, + Lookup: PallasLookupRC, { let (table_idx, table_x, table_y) = ( config.generator_table.table_idx, diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 1cff0a423c..709da2455d 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -3,7 +3,7 @@ use super::{NonIdentityEccPoint, SinsemillaChip}; use crate::{ ecc::FixedPoints, sinsemilla::primitives::{self as sinsemilla, lebs2ip_k, INV_TWO_POW_K, SINSEMILLA_S}, - utilities::lookup_range_check::PallasLookup, + utilities::lookup_range_check::PallasLookupRC, }; use ff::Field; @@ -30,7 +30,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookup, + Lookup: PallasLookupRC, { /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). #[allow(non_snake_case)] diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 83f284352d..32be00e0da 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -185,11 +185,11 @@ pub mod tests { HashDomains, }, tests::test_utils::{ - fixed_verification_key_test_with_circuit, serialized_proof_test_case_with_circuit, + test_against_stored_vk, test_against_stored_proof, }, utilities::{ i2lebsp, - lookup_range_check::{LookupRangeCheck, PallasLookupConfig}, + lookup_range_check::{LookupRangeCheck, PallasLookupRC10b}, UtilitiesInstructions, }, }; @@ -215,8 +215,8 @@ pub mod tests { impl Circuit for MyCircuit { type Config = ( - MerkleConfig, - MerkleConfig, + MerkleConfig, + MerkleConfig, ); type FloorPlanner = SimpleFloorPlanner; @@ -254,7 +254,7 @@ pub mod tests { meta.lookup_table_column(), ); - let range_check = PallasLookupConfig::configure(meta, advices[9], lookup.0); + let range_check = PallasLookupRC10b::configure(meta, advices[9], lookup.0); let sinsemilla_config_1 = SinsemillaChip::configure( meta, @@ -289,7 +289,7 @@ pub mod tests { TestHashDomain, TestCommitDomain, TestFixedBases, - PallasLookupConfig, + PallasLookupRC10b, >::load(config.0.sinsemilla_config.clone(), &mut layouter)?; // Construct Merkle chips which will be placed side-by-side in the circuit. @@ -393,13 +393,13 @@ pub mod tests { #[test] fn fixed_verification_key_test() { let circuit = generate_circuit(); - fixed_verification_key_test_with_circuit(&circuit, "merkle_chip"); + test_against_stored_vk(&circuit, "merkle_chip"); } #[test] fn serialized_proof_test_case() { let circuit = generate_circuit(); - serialized_proof_test_case_with_circuit(circuit, "merkle_chip"); + test_against_stored_proof(circuit, "merkle_chip"); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs index 93f0fc8175..04c7c57d68 100644 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla/merkle/chip.rs @@ -11,7 +11,7 @@ use super::MerkleInstructions; use crate::{ sinsemilla::{primitives as sinsemilla, MessagePiece}, - utilities::{lookup_range_check::PallasLookup, RangeConstrained}, + utilities::{lookup_range_check::PallasLookupRC, RangeConstrained}, { ecc::FixedPoints, sinsemilla::{ @@ -33,7 +33,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookup, + Lookup: PallasLookupRC, { advices: [Column; 5], q_decompose: Selector, @@ -57,7 +57,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookup, + Lookup: PallasLookupRC, { config: MerkleConfig, } @@ -67,7 +67,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookup, + Lookup: PallasLookupRC, { type Config = MerkleConfig; type Loaded = (); @@ -86,7 +86,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookup, + Lookup: PallasLookupRC, { /// Configures the [`MerkleChip`]. pub fn configure( @@ -200,8 +200,7 @@ where } } -/// The MerkleSinsemillaInstructions trait extends the capabilities of SinsemillaInstructions, -/// for specific cryptographic operations involving generic lookup. +/// Defines the concrete types of `SinsemillaInstructions` required by the `MerkleCRH`. pub(crate) trait MerkleSinsemillaInstructions where Self: SinsemillaInstructions< @@ -227,7 +226,7 @@ where Hash: HashDomains, Commit: CommitDomains, F: FixedPoints, - Lookup: PallasLookup, + Lookup: PallasLookupRC, { } @@ -237,7 +236,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookup, + Lookup: PallasLookupRC, { } @@ -255,7 +254,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookup, + Lookup: PallasLookupRC, { #[allow(non_snake_case)] fn hash_layer( @@ -474,7 +473,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookup, + Lookup: PallasLookupRC, { type Var = AssignedCell; } @@ -485,7 +484,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookup, + Lookup: PallasLookupRC, { #[allow(clippy::type_complexity)] fn swap( @@ -507,7 +506,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookup, + Lookup: PallasLookupRC, { type CellValue = as SinsemillaInstructions< pallas::Affine, diff --git a/halo2_gadgets/src/tests/circuit_data/ecc_chip.proof.bin b/halo2_gadgets/src/tests/circuit_data/proof_ecc_chip.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/ecc_chip.proof.bin rename to halo2_gadgets/src/tests/circuit_data/proof_ecc_chip.bin diff --git a/halo2_gadgets/src/tests/circuit_data/lookup_range_check.proof.bin b/halo2_gadgets/src/tests/circuit_data/proof_lookup_range_check.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/lookup_range_check.proof.bin rename to halo2_gadgets/src/tests/circuit_data/proof_lookup_range_check.bin diff --git a/halo2_gadgets/src/tests/circuit_data/merkle_chip.proof.bin b/halo2_gadgets/src/tests/circuit_data/proof_merkle_chip.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/merkle_chip.proof.bin rename to halo2_gadgets/src/tests/circuit_data/proof_merkle_chip.bin diff --git a/halo2_gadgets/src/tests/circuit_data/short_range_check_0.proof.bin b/halo2_gadgets/src/tests/circuit_data/proof_short_range_check_0.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/short_range_check_0.proof.bin rename to halo2_gadgets/src/tests/circuit_data/proof_short_range_check_0.bin diff --git a/halo2_gadgets/src/tests/circuit_data/short_range_check_1.proof.bin b/halo2_gadgets/src/tests/circuit_data/proof_short_range_check_1.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/short_range_check_1.proof.bin rename to halo2_gadgets/src/tests/circuit_data/proof_short_range_check_1.bin diff --git a/halo2_gadgets/src/tests/circuit_data/short_range_check_2.proof.bin b/halo2_gadgets/src/tests/circuit_data/proof_short_range_check_2.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/short_range_check_2.proof.bin rename to halo2_gadgets/src/tests/circuit_data/proof_short_range_check_2.bin diff --git a/halo2_gadgets/src/tests/circuit_data/sinsemilla_chip.proof.bin b/halo2_gadgets/src/tests/circuit_data/proof_sinsemilla_chip.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/sinsemilla_chip.proof.bin rename to halo2_gadgets/src/tests/circuit_data/proof_sinsemilla_chip.bin diff --git a/halo2_gadgets/src/tests/circuit_data/ecc_chip.vk.txt b/halo2_gadgets/src/tests/circuit_data/vk_ecc_chip.rdata similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/ecc_chip.vk.txt rename to halo2_gadgets/src/tests/circuit_data/vk_ecc_chip.rdata diff --git a/halo2_gadgets/src/tests/circuit_data/lookup_range_check.vk.txt b/halo2_gadgets/src/tests/circuit_data/vk_lookup_range_check.rdata similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/lookup_range_check.vk.txt rename to halo2_gadgets/src/tests/circuit_data/vk_lookup_range_check.rdata diff --git a/halo2_gadgets/src/tests/circuit_data/merkle_chip.vk.txt b/halo2_gadgets/src/tests/circuit_data/vk_merkle_chip.rdata similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/merkle_chip.vk.txt rename to halo2_gadgets/src/tests/circuit_data/vk_merkle_chip.rdata diff --git a/halo2_gadgets/src/tests/circuit_data/short_range_check_0.vk.txt b/halo2_gadgets/src/tests/circuit_data/vk_short_range_check_0.rdata similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/short_range_check_0.vk.txt rename to halo2_gadgets/src/tests/circuit_data/vk_short_range_check_0.rdata diff --git a/halo2_gadgets/src/tests/circuit_data/short_range_check_1.vk.txt b/halo2_gadgets/src/tests/circuit_data/vk_short_range_check_1.rdata similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/short_range_check_1.vk.txt rename to halo2_gadgets/src/tests/circuit_data/vk_short_range_check_1.rdata diff --git a/halo2_gadgets/src/tests/circuit_data/short_range_check_2.vk.txt b/halo2_gadgets/src/tests/circuit_data/vk_short_range_check_2.rdata similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/short_range_check_2.vk.txt rename to halo2_gadgets/src/tests/circuit_data/vk_short_range_check_2.rdata diff --git a/halo2_gadgets/src/tests/circuit_data/sinsemilla_chip.vk.txt b/halo2_gadgets/src/tests/circuit_data/vk_sinsemilla_chip.rdata similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/sinsemilla_chip.vk.txt rename to halo2_gadgets/src/tests/circuit_data/vk_sinsemilla_chip.rdata diff --git a/halo2_gadgets/src/tests/test_utils.rs b/halo2_gadgets/src/tests/test_utils.rs index 0999cba67f..8f23eefbe2 100644 --- a/halo2_gadgets/src/tests/test_utils.rs +++ b/halo2_gadgets/src/tests/test_utils.rs @@ -21,6 +21,8 @@ use halo2_proofs::{ }; const TEST_DATA_DIR: &str = "src/tests/circuit_data"; +const GEN_ENV_VAR_VK: &str = "CIRCUIT_TEST_GENERATE_NEW_VK"; +const GEN_ENV_VAR_PROOF: &str = "CIRCUIT_TEST_GENERATE_NEW_PROOF"; /// A proof structure #[derive(Clone, Debug)] @@ -66,13 +68,14 @@ impl Proof { } } -pub(crate) fn fixed_verification_key_test_with_circuit>( +/// Test the generated vk against the stored vk. +pub(crate) fn test_against_stored_vk>( circuit: &C, - file_name: &str, + circuit_name: &str, ) { let full_file_name = Path::new(TEST_DATA_DIR) - .join(file_name) - .with_extension("vk.txt"); + .join(format!("vk_{circuit_name}")) + .with_extension("rdata"); // Setup phase: generate parameters, vk for the circuit. let params: Params = Params::new(11); @@ -80,12 +83,10 @@ pub(crate) fn fixed_verification_key_test_with_circuit> let vk_text = format!("{:#?}\n", vk.pinned()); - if env::var_os("CIRCUIT_TEST_GENERATE_NEW_VK").is_some() { + if env::var_os(GEN_ENV_VAR_VK).is_some() { fs::write(&full_file_name, &vk_text).expect("Unable to write vk test file") } - // Test that the pinned verification key (representing the circuit) - // is as expected. assert_eq!( vk_text, fs::read_to_string(full_file_name) @@ -94,15 +95,15 @@ pub(crate) fn fixed_verification_key_test_with_circuit> ); } +/// If the environment variable GEN_ENV_VAR_PROOF is set, +/// write the old proof in a file fn conditionally_save_proof_to_disk>( vk: &VerifyingKey, params: &Params, circuit: C, full_file_name: &PathBuf, ) { - // If the environment variable CIRCUIT_TEST_GENERATE_NEW_PROOF is set, - // write the old proof in a file - if env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { + if env::var_os(GEN_ENV_VAR_PROOF).is_some() { let proof = Proof::create(vk, params, circuit).unwrap(); assert!(proof.verify(vk, params).is_ok()); @@ -110,13 +111,14 @@ fn conditionally_save_proof_to_disk>( } } -pub(crate) fn serialized_proof_test_case_with_circuit>( +/// Test the generated circuit against the stored proof. +pub(crate) fn test_against_stored_proof>( circuit: C, - file_name: &str, + circuit_name: &str, ) { let full_file_name = Path::new(TEST_DATA_DIR) - .join(file_name) - .with_extension("proof.bin"); + .join(format!("proof_{circuit_name}")) + .with_extension("bin"); // Setup phase: generate parameters, vk for the circuit. let params: Params = Params::new(11); diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index c1f6647b1f..0344d3873f 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -442,22 +442,19 @@ impl LookupRangeCheck for LookupRangeCh } } -/// This trait is a shorthand for `LookupRangeCheck` specialized with `pallas::Base` and -/// `sinsemilla::K`. In this crate, `LookupRangeCheck` is always used with these parameters. -/// By defining this trait, we reduce verbosity and improve readability. Besides, it extends -/// the `LookupRangeCheck` with additional standard traits necessary for effective use in -/// cryptographic contexts. -pub trait PallasLookup: +/// `PallasLookupRC` a shorthand for `LookupRangeCheck` specialized with `pallas::Base` and +/// `sinsemilla::K` and used to improve readability. In addition, it extends +/// the `LookupRangeCheck` with additional standard traits. +pub trait PallasLookupRC: LookupRangeCheck + Eq + PartialEq + Clone + Copy + Debug { } -/// In this crate, `LookupRangeCheckConfig` is always used with `pallas::Base` as the prime field -/// and the constant `K` from the `sinsemilla` module. To reduce verbosity and improve readability, -/// we introduce this alias and use it instead of that long construction. -pub type PallasLookupConfig = LookupRangeCheckConfig; +/// `PallasLookupRC10b` is a shorthand for `LookupRangeCheckConfig` specialized with +/// `pallas::Base` and `sinsemilla::K` and used to improve readability``` +pub type PallasLookupRC10b = LookupRangeCheckConfig; -impl PallasLookup for PallasLookupConfig {} +impl PallasLookupRC for PallasLookupRC10b {} #[cfg(test)] mod tests { @@ -475,7 +472,7 @@ mod tests { use pasta_curves::pallas; use crate::tests::test_utils::{ - fixed_verification_key_test_with_circuit, serialized_proof_test_case_with_circuit, + test_against_stored_vk, test_against_stored_proof, }; use std::{convert::TryInto, marker::PhantomData}; @@ -574,9 +571,9 @@ mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - fixed_verification_key_test_with_circuit(&circuit, "lookup_range_check"); + test_against_stored_vk(&circuit, "lookup_range_check"); - serialized_proof_test_case_with_circuit(circuit, "lookup_range_check"); + test_against_stored_proof(circuit, "lookup_range_check"); } } @@ -636,9 +633,9 @@ mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - fixed_verification_key_test_with_circuit(&circuit, "short_range_check_0"); + test_against_stored_vk(&circuit, "short_range_check_0"); - serialized_proof_test_case_with_circuit(circuit, "short_range_check_0"); + test_against_stored_proof(circuit, "short_range_check_0"); } // Edge case: K bits (case 1) @@ -650,9 +647,9 @@ mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - fixed_verification_key_test_with_circuit(&circuit, "short_range_check_1"); + test_against_stored_vk(&circuit, "short_range_check_1"); - serialized_proof_test_case_with_circuit(circuit, "short_range_check_1"); + test_against_stored_proof(circuit, "short_range_check_1"); } // Element within `num_bits` (case 2) @@ -664,9 +661,9 @@ mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - fixed_verification_key_test_with_circuit(&circuit, "short_range_check_2"); + test_against_stored_vk(&circuit, "short_range_check_2"); - serialized_proof_test_case_with_circuit(circuit, "short_range_check_2"); + test_against_stored_proof(circuit, "short_range_check_2"); } // Element larger than `num_bits` but within K bits From adf4d0d9891ed59f7e212e6dc8270df6524193bd Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Tue, 28 May 2024 11:56:50 +0200 Subject: [PATCH 75/99] cargo fmt --- halo2_gadgets/src/ecc.rs | 4 +--- halo2_gadgets/src/sinsemilla.rs | 4 +--- halo2_gadgets/src/sinsemilla/merkle.rs | 4 +--- halo2_gadgets/src/tests/test_utils.rs | 10 ++-------- halo2_gadgets/src/utilities/lookup_range_check.rs | 4 +--- 5 files changed, 6 insertions(+), 20 deletions(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 58b9acc4ef..879ac803a7 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -596,9 +596,7 @@ pub(crate) mod tests { FixedPoints, }; use crate::{ - tests::test_utils::{ - test_against_stored_vk, test_against_stored_proof, - }, + tests::test_utils::{test_against_stored_proof, test_against_stored_vk}, utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRC10b}, }; diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index d3ab13312a..299c16bdd4 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -472,9 +472,7 @@ pub(crate) mod tests { NonIdentityPoint, ScalarFixed, }, sinsemilla::primitives::{self as sinsemilla, K}, - tests::test_utils::{ - test_against_stored_vk, test_against_stored_proof, - }, + tests::test_utils::{test_against_stored_proof, test_against_stored_vk}, utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRC10b}, }; diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 32be00e0da..05130b878e 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -184,9 +184,7 @@ pub mod tests { tests::{TestCommitDomain, TestHashDomain}, HashDomains, }, - tests::test_utils::{ - test_against_stored_vk, test_against_stored_proof, - }, + tests::test_utils::{test_against_stored_proof, test_against_stored_vk}, utilities::{ i2lebsp, lookup_range_check::{LookupRangeCheck, PallasLookupRC10b}, diff --git a/halo2_gadgets/src/tests/test_utils.rs b/halo2_gadgets/src/tests/test_utils.rs index 8f23eefbe2..9dfbf5908c 100644 --- a/halo2_gadgets/src/tests/test_utils.rs +++ b/halo2_gadgets/src/tests/test_utils.rs @@ -69,10 +69,7 @@ impl Proof { } /// Test the generated vk against the stored vk. -pub(crate) fn test_against_stored_vk>( - circuit: &C, - circuit_name: &str, -) { +pub(crate) fn test_against_stored_vk>(circuit: &C, circuit_name: &str) { let full_file_name = Path::new(TEST_DATA_DIR) .join(format!("vk_{circuit_name}")) .with_extension("rdata"); @@ -112,10 +109,7 @@ fn conditionally_save_proof_to_disk>( } /// Test the generated circuit against the stored proof. -pub(crate) fn test_against_stored_proof>( - circuit: C, - circuit_name: &str, -) { +pub(crate) fn test_against_stored_proof>(circuit: C, circuit_name: &str) { let full_file_name = Path::new(TEST_DATA_DIR) .join(format!("proof_{circuit_name}")) .with_extension("bin"); diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 0344d3873f..bc0db35182 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -471,9 +471,7 @@ mod tests { }; use pasta_curves::pallas; - use crate::tests::test_utils::{ - test_against_stored_vk, test_against_stored_proof, - }; + use crate::tests::test_utils::{test_against_stored_proof, test_against_stored_vk}; use std::{convert::TryInto, marker::PhantomData}; #[test] From 1bb0b844887b19d07045309e4d516595ec630c42 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Tue, 28 May 2024 14:17:44 +0200 Subject: [PATCH 76/99] add index to proofs --- .github/workflows/ci.yml | 1 + halo2_gadgets/src/ecc.rs | 2 +- halo2_gadgets/src/sinsemilla.rs | 2 +- halo2_gadgets/src/sinsemilla/merkle.rs | 2 +- .../{proof_ecc_chip.bin => proof_ecc_chip_0.bin} | Bin ..._check.bin => proof_lookup_range_check_0.bin} | Bin ...f_merkle_chip.bin => proof_merkle_chip_0.bin} | Bin ...0.bin => proof_short_range_check_case0_0.bin} | Bin ...1.bin => proof_short_range_check_case1_0.bin} | Bin ...2.bin => proof_short_range_check_case2_0.bin} | Bin ...illa_chip.bin => proof_sinsemilla_chip_0.bin} | Bin ..._0.rdata => vk_short_range_check_case0.rdata} | 0 ..._1.rdata => vk_short_range_check_case1.rdata} | 0 ..._2.rdata => vk_short_range_check_case2.rdata} | 0 halo2_gadgets/src/tests/test_utils.rs | 15 +++++++++------ .../src/utilities/lookup_range_check.rs | 14 +++++++------- 16 files changed, 20 insertions(+), 16 deletions(-) rename halo2_gadgets/src/tests/circuit_data/{proof_ecc_chip.bin => proof_ecc_chip_0.bin} (100%) rename halo2_gadgets/src/tests/circuit_data/{proof_lookup_range_check.bin => proof_lookup_range_check_0.bin} (100%) rename halo2_gadgets/src/tests/circuit_data/{proof_merkle_chip.bin => proof_merkle_chip_0.bin} (100%) rename halo2_gadgets/src/tests/circuit_data/{proof_short_range_check_0.bin => proof_short_range_check_case0_0.bin} (100%) rename halo2_gadgets/src/tests/circuit_data/{proof_short_range_check_1.bin => proof_short_range_check_case1_0.bin} (100%) rename halo2_gadgets/src/tests/circuit_data/{proof_short_range_check_2.bin => proof_short_range_check_case2_0.bin} (100%) rename halo2_gadgets/src/tests/circuit_data/{proof_sinsemilla_chip.bin => proof_sinsemilla_chip_0.bin} (100%) rename halo2_gadgets/src/tests/circuit_data/{vk_short_range_check_0.rdata => vk_short_range_check_case0.rdata} (100%) rename halo2_gadgets/src/tests/circuit_data/{vk_short_range_check_1.rdata => vk_short_range_check_case1.rdata} (100%) rename halo2_gadgets/src/tests/circuit_data/{vk_short_range_check_2.rdata => vk_short_range_check_case2.rdata} (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c2efa385d..ce5cafc981 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -146,6 +146,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: tarpaulin + # Extend the timeout to 3600 to ensure the code coverage test pass args: > ${{ steps.prepare.outputs.feature-flags }} --timeout 3600 diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 879ac803a7..45bf63acf6 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -918,7 +918,7 @@ pub(crate) mod tests { #[test] fn serialized_proof_test_case() { let circuit = MyCircuit { test_errors: false }; - test_against_stored_proof(circuit, "ecc_chip"); + test_against_stored_proof(circuit, "ecc_chip", 0); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 299c16bdd4..46cd2ad659 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -751,7 +751,7 @@ pub(crate) mod tests { #[test] fn serialized_proof_test_case() { let circuit = MyCircuit {}; - test_against_stored_proof(circuit, "sinsemilla_chip"); + test_against_stored_proof(circuit, "sinsemilla_chip", 0); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 05130b878e..5c453a81ac 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -397,7 +397,7 @@ pub mod tests { #[test] fn serialized_proof_test_case() { let circuit = generate_circuit(); - test_against_stored_proof(circuit, "merkle_chip"); + test_against_stored_proof(circuit, "merkle_chip", 0); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/tests/circuit_data/proof_ecc_chip.bin b/halo2_gadgets/src/tests/circuit_data/proof_ecc_chip_0.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/proof_ecc_chip.bin rename to halo2_gadgets/src/tests/circuit_data/proof_ecc_chip_0.bin diff --git a/halo2_gadgets/src/tests/circuit_data/proof_lookup_range_check.bin b/halo2_gadgets/src/tests/circuit_data/proof_lookup_range_check_0.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/proof_lookup_range_check.bin rename to halo2_gadgets/src/tests/circuit_data/proof_lookup_range_check_0.bin diff --git a/halo2_gadgets/src/tests/circuit_data/proof_merkle_chip.bin b/halo2_gadgets/src/tests/circuit_data/proof_merkle_chip_0.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/proof_merkle_chip.bin rename to halo2_gadgets/src/tests/circuit_data/proof_merkle_chip_0.bin diff --git a/halo2_gadgets/src/tests/circuit_data/proof_short_range_check_0.bin b/halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case0_0.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/proof_short_range_check_0.bin rename to halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case0_0.bin diff --git a/halo2_gadgets/src/tests/circuit_data/proof_short_range_check_1.bin b/halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case1_0.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/proof_short_range_check_1.bin rename to halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case1_0.bin diff --git a/halo2_gadgets/src/tests/circuit_data/proof_short_range_check_2.bin b/halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case2_0.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/proof_short_range_check_2.bin rename to halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case2_0.bin diff --git a/halo2_gadgets/src/tests/circuit_data/proof_sinsemilla_chip.bin b/halo2_gadgets/src/tests/circuit_data/proof_sinsemilla_chip_0.bin similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/proof_sinsemilla_chip.bin rename to halo2_gadgets/src/tests/circuit_data/proof_sinsemilla_chip_0.bin diff --git a/halo2_gadgets/src/tests/circuit_data/vk_short_range_check_0.rdata b/halo2_gadgets/src/tests/circuit_data/vk_short_range_check_case0.rdata similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/vk_short_range_check_0.rdata rename to halo2_gadgets/src/tests/circuit_data/vk_short_range_check_case0.rdata diff --git a/halo2_gadgets/src/tests/circuit_data/vk_short_range_check_1.rdata b/halo2_gadgets/src/tests/circuit_data/vk_short_range_check_case1.rdata similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/vk_short_range_check_1.rdata rename to halo2_gadgets/src/tests/circuit_data/vk_short_range_check_case1.rdata diff --git a/halo2_gadgets/src/tests/circuit_data/vk_short_range_check_2.rdata b/halo2_gadgets/src/tests/circuit_data/vk_short_range_check_case2.rdata similarity index 100% rename from halo2_gadgets/src/tests/circuit_data/vk_short_range_check_2.rdata rename to halo2_gadgets/src/tests/circuit_data/vk_short_range_check_case2.rdata diff --git a/halo2_gadgets/src/tests/test_utils.rs b/halo2_gadgets/src/tests/test_utils.rs index 9dfbf5908c..d9a2ead12f 100644 --- a/halo2_gadgets/src/tests/test_utils.rs +++ b/halo2_gadgets/src/tests/test_utils.rs @@ -21,8 +21,7 @@ use halo2_proofs::{ }; const TEST_DATA_DIR: &str = "src/tests/circuit_data"; -const GEN_ENV_VAR_VK: &str = "CIRCUIT_TEST_GENERATE_NEW_VK"; -const GEN_ENV_VAR_PROOF: &str = "CIRCUIT_TEST_GENERATE_NEW_PROOF"; +const GEN_ENV_VAR: &str = "CIRCUIT_TEST_GENERATE_NEW_DATA"; /// A proof structure #[derive(Clone, Debug)] @@ -80,7 +79,7 @@ pub(crate) fn test_against_stored_vk>(circuit: &C, circ let vk_text = format!("{:#?}\n", vk.pinned()); - if env::var_os(GEN_ENV_VAR_VK).is_some() { + if env::var_os(GEN_ENV_VAR).is_some() { fs::write(&full_file_name, &vk_text).expect("Unable to write vk test file") } @@ -100,7 +99,7 @@ fn conditionally_save_proof_to_disk>( circuit: C, full_file_name: &PathBuf, ) { - if env::var_os(GEN_ENV_VAR_PROOF).is_some() { + if env::var_os(GEN_ENV_VAR).is_some() { let proof = Proof::create(vk, params, circuit).unwrap(); assert!(proof.verify(vk, params).is_ok()); @@ -109,9 +108,13 @@ fn conditionally_save_proof_to_disk>( } /// Test the generated circuit against the stored proof. -pub(crate) fn test_against_stored_proof>(circuit: C, circuit_name: &str) { +pub(crate) fn test_against_stored_proof>( + circuit: C, + circuit_name: &str, + index: usize, +) { let full_file_name = Path::new(TEST_DATA_DIR) - .join(format!("proof_{circuit_name}")) + .join(format!("proof_{circuit_name}_{index}")) .with_extension("bin"); // Setup phase: generate parameters, vk for the circuit. diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index bc0db35182..7ed6386d9a 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -571,7 +571,7 @@ mod tests { test_against_stored_vk(&circuit, "lookup_range_check"); - test_against_stored_proof(circuit, "lookup_range_check"); + test_against_stored_proof(circuit, "lookup_range_check", 0); } } @@ -631,9 +631,9 @@ mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - test_against_stored_vk(&circuit, "short_range_check_0"); + test_against_stored_vk(&circuit, "short_range_check_case0"); - test_against_stored_proof(circuit, "short_range_check_0"); + test_against_stored_proof(circuit, "short_range_check_case0", 0); } // Edge case: K bits (case 1) @@ -645,9 +645,9 @@ mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - test_against_stored_vk(&circuit, "short_range_check_1"); + test_against_stored_vk(&circuit, "short_range_check_case1"); - test_against_stored_proof(circuit, "short_range_check_1"); + test_against_stored_proof(circuit, "short_range_check_case1", 0); } // Element within `num_bits` (case 2) @@ -659,9 +659,9 @@ mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - test_against_stored_vk(&circuit, "short_range_check_2"); + test_against_stored_vk(&circuit, "short_range_check_case2"); - test_against_stored_proof(circuit, "short_range_check_2"); + test_against_stored_proof(circuit, "short_range_check_case2", 0); } // Element larger than `num_bits` but within K bits From 923293b0d51651ab04bd9f9e40905bcd0b308723 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Thu, 30 May 2024 11:27:36 +0200 Subject: [PATCH 77/99] rename PallasLookupRC10b to PallasLookupRCConfig --- halo2_gadgets/src/ecc.rs | 8 +++---- halo2_gadgets/src/ecc/chip.rs | 6 ++--- halo2_gadgets/src/ecc/chip/mul.rs | 4 ++-- halo2_gadgets/src/ecc/chip/mul/overflow.rs | 4 ++-- .../src/ecc/chip/mul_fixed/base_field_elem.rs | 5 ++-- halo2_gadgets/src/ecc/chip/mul_fixed/short.rs | 8 +++---- halo2_gadgets/src/sinsemilla.rs | 24 +++++++++++++------ halo2_gadgets/src/sinsemilla/chip.rs | 6 ++--- halo2_gadgets/src/sinsemilla/merkle.rs | 10 ++++---- halo2_gadgets/src/sinsemilla/merkle/chip.rs | 6 ++--- .../src/utilities/lookup_range_check.rs | 6 ++--- 11 files changed, 49 insertions(+), 38 deletions(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 45bf63acf6..b6e68b40e4 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -597,7 +597,7 @@ pub(crate) mod tests { }; use crate::{ tests::test_utils::{test_against_stored_proof, test_against_stored_vk}, - utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRC10b}, + utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRCConfig}, }; #[derive(Debug, Eq, PartialEq, Clone)] @@ -732,7 +732,7 @@ pub(crate) mod tests { #[allow(non_snake_case)] impl Circuit for MyCircuit { - type Config = EccConfig; + type Config = EccConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -767,8 +767,8 @@ pub(crate) mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); - let range_check = PallasLookupRC10b::configure(meta, advices[9], lookup_table); - EccChip::::configure( + let range_check = PallasLookupRCConfig::configure(meta, advices[9], lookup_table); + EccChip::::configure( meta, advices, lagrange_coeffs, diff --git a/halo2_gadgets/src/ecc/chip.rs b/halo2_gadgets/src/ecc/chip.rs index c168e0f45e..926da7906e 100644 --- a/halo2_gadgets/src/ecc/chip.rs +++ b/halo2_gadgets/src/ecc/chip.rs @@ -2,7 +2,7 @@ use super::{BaseFitsInScalarInstructions, EccInstructions, FixedPoints}; use crate::utilities::{ - lookup_range_check::{PallasLookupRC, PallasLookupRC10b}, + lookup_range_check::{PallasLookupRC, PallasLookupRCConfig}, UtilitiesInstructions, }; use arrayvec::ArrayVec; @@ -139,7 +139,7 @@ impl From for EccPoint { #[allow(non_snake_case)] pub struct EccConfig< FixedPoints: super::FixedPoints, - Lookup: PallasLookupRC = PallasLookupRC10b, + Lookup: PallasLookupRC = PallasLookupRCConfig, > { /// Advice columns needed by instructions in the ECC chip. pub advices: [Column; 10], @@ -232,7 +232,7 @@ pub trait FixedPoint: std::fmt::Debug + Eq + Clone { #[derive(Clone, Debug, Eq, PartialEq)] pub struct EccChip< FixedPoints: super::FixedPoints, - Lookup: PallasLookupRC = PallasLookupRC10b, + Lookup: PallasLookupRC = PallasLookupRCConfig, > { config: EccConfig, } diff --git a/halo2_gadgets/src/ecc/chip/mul.rs b/halo2_gadgets/src/ecc/chip/mul.rs index bc2c00e7c6..e4e2004882 100644 --- a/halo2_gadgets/src/ecc/chip/mul.rs +++ b/halo2_gadgets/src/ecc/chip/mul.rs @@ -1,6 +1,6 @@ use super::{add, EccPoint, NonIdentityEccPoint, ScalarVar, T_Q}; use crate::utilities::{ - lookup_range_check::{PallasLookupRC, PallasLookupRC10b}, + lookup_range_check::{PallasLookupRC, PallasLookupRCConfig}, {bool_check, ternary}, }; use std::{ @@ -46,7 +46,7 @@ const INCOMPLETE_LO_LEN: usize = INCOMPLETE_LEN - INCOMPLETE_HI_LEN; const COMPLETE_RANGE: Range = INCOMPLETE_LEN..(INCOMPLETE_LEN + NUM_COMPLETE_BITS); #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { +pub struct Config { // Selector used to check switching logic on LSB q_mul_lsb: Selector, // Configuration used in complete addition diff --git a/halo2_gadgets/src/ecc/chip/mul/overflow.rs b/halo2_gadgets/src/ecc/chip/mul/overflow.rs index 8853439bd3..482594e62b 100644 --- a/halo2_gadgets/src/ecc/chip/mul/overflow.rs +++ b/halo2_gadgets/src/ecc/chip/mul/overflow.rs @@ -1,7 +1,7 @@ use super::{T_Q, Z}; use crate::{ sinsemilla::primitives as sinsemilla, - utilities::lookup_range_check::{PallasLookupRC, PallasLookupRC10b}, + utilities::lookup_range_check::{PallasLookupRC, PallasLookupRCConfig}, }; use group::ff::PrimeField; @@ -16,7 +16,7 @@ use pasta_curves::pallas; use std::iter; #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { +pub struct Config { // Selector to check z_0 = alpha + t_q (mod p) q_mul_overflow: Selector, // 10-bit lookup table diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs index 1116497aba..e6060ec426 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs @@ -3,7 +3,7 @@ use super::H_BASE; use crate::utilities::{ bitrange_subset, bool_check, - lookup_range_check::{PallasLookupRC, PallasLookupRC10b}, + lookup_range_check::{PallasLookupRC, PallasLookupRCConfig}, range_check, }; @@ -18,7 +18,8 @@ use pasta_curves::pallas; use std::convert::TryInto; #[derive(Clone, Debug, Eq, PartialEq)] -pub struct Config, Lookup: PallasLookupRC = PallasLookupRC10b> { +pub struct Config, Lookup: PallasLookupRC = PallasLookupRCConfig> +{ q_mul_fixed_base_field: Selector, canon_advices: [Column; 3], lookup_config: Lookup, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs index d7e78c3090..eb402d0f27 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs @@ -260,7 +260,7 @@ pub mod tests { FixedPointShort, NonIdentityPoint, Point, ScalarFixedShort, }, utilities::{ - lookup_range_check::{LookupRangeCheck, PallasLookupRC, PallasLookupRC10b}, + lookup_range_check::{LookupRangeCheck, PallasLookupRC, PallasLookupRCConfig}, UtilitiesInstructions, }, }; @@ -428,7 +428,7 @@ pub mod tests { } impl Circuit for MyCircuit { - type Config = EccConfig; + type Config = EccConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -464,8 +464,8 @@ pub mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); - let range_check = PallasLookupRC10b::configure(meta, advices[9], lookup_table); - EccChip::::configure( + let range_check = PallasLookupRCConfig::configure(meta, advices[9], lookup_table); + EccChip::::configure( meta, advices, lagrange_coeffs, diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 46cd2ad659..e79797b612 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -473,7 +473,7 @@ pub(crate) mod tests { }, sinsemilla::primitives::{self as sinsemilla, K}, tests::test_utils::{test_against_stored_proof, test_against_stored_vk}, - utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRC10b}, + utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRCConfig}, }; use group::{ff::Field, Curve}; @@ -519,9 +519,19 @@ pub(crate) mod tests { impl Circuit for MyCircuit { #[allow(clippy::type_complexity)] type Config = ( - EccConfig, - SinsemillaConfig, - SinsemillaConfig, + EccConfig, + SinsemillaConfig< + TestHashDomain, + TestCommitDomain, + TestFixedBases, + PallasLookupRCConfig, + >, + SinsemillaConfig< + TestHashDomain, + TestCommitDomain, + TestFixedBases, + PallasLookupRCConfig, + >, ); type FloorPlanner = SimpleFloorPlanner; @@ -567,9 +577,9 @@ pub(crate) mod tests { meta.lookup_table_column(), ); - let range_check = PallasLookupRC10b::configure(meta, advices[9], table_idx); + let range_check = PallasLookupRCConfig::configure(meta, advices[9], table_idx); - let ecc_config = EccChip::::configure( + let ecc_config = EccChip::::configure( meta, advices, lagrange_coeffs, @@ -609,7 +619,7 @@ pub(crate) mod tests { TestHashDomain, TestCommitDomain, TestFixedBases, - PallasLookupRC10b, + PallasLookupRCConfig, >::load(config.1.clone(), &mut layouter)?; // This MerkleCRH example is purely for illustrative purposes. diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs index 454b6c9151..069c115b2b 100644 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ b/halo2_gadgets/src/sinsemilla/chip.rs @@ -9,7 +9,7 @@ use crate::{ chip::{DoubleAndAdd, NonIdentityEccPoint}, FixedPoints, }, - utilities::lookup_range_check::{PallasLookupRC, PallasLookupRC10b}, + utilities::lookup_range_check::{PallasLookupRC, PallasLookupRCConfig}, }; use std::marker::PhantomData; @@ -30,7 +30,7 @@ mod hash_to_point; /// Configuration for the Sinsemilla hash chip #[derive(Eq, PartialEq, Clone, Debug)] -pub struct SinsemillaConfig +pub struct SinsemillaConfig where Hash: HashDomains, F: FixedPoints, @@ -98,7 +98,7 @@ where /// /// [Chip description](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html#plonk--halo-2-constraints). #[derive(Eq, PartialEq, Clone, Debug)] -pub struct SinsemillaChip +pub struct SinsemillaChip where Hash: HashDomains, Fixed: FixedPoints, diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 5c453a81ac..95e9e401b9 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -187,7 +187,7 @@ pub mod tests { tests::test_utils::{test_against_stored_proof, test_against_stored_vk}, utilities::{ i2lebsp, - lookup_range_check::{LookupRangeCheck, PallasLookupRC10b}, + lookup_range_check::{LookupRangeCheck, PallasLookupRCConfig}, UtilitiesInstructions, }, }; @@ -213,8 +213,8 @@ pub mod tests { impl Circuit for MyCircuit { type Config = ( - MerkleConfig, - MerkleConfig, + MerkleConfig, + MerkleConfig, ); type FloorPlanner = SimpleFloorPlanner; @@ -252,7 +252,7 @@ pub mod tests { meta.lookup_table_column(), ); - let range_check = PallasLookupRC10b::configure(meta, advices[9], lookup.0); + let range_check = PallasLookupRCConfig::configure(meta, advices[9], lookup.0); let sinsemilla_config_1 = SinsemillaChip::configure( meta, @@ -287,7 +287,7 @@ pub mod tests { TestHashDomain, TestCommitDomain, TestFixedBases, - PallasLookupRC10b, + PallasLookupRCConfig, >::load(config.0.sinsemilla_config.clone(), &mut layouter)?; // Construct Merkle chips which will be placed side-by-side in the circuit. diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs index 2410f8f726..b8ea59ead7 100644 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla/merkle/chip.rs @@ -12,7 +12,7 @@ use super::MerkleInstructions; use crate::{ sinsemilla::{primitives as sinsemilla, MessagePiece}, utilities::{ - lookup_range_check::{PallasLookupRC, PallasLookupRC10b}, + lookup_range_check::{PallasLookupRC, PallasLookupRCConfig}, RangeConstrained, }, { @@ -31,7 +31,7 @@ use group::ff::PrimeField; /// Configuration for the `MerkleChip` implementation. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct MerkleConfig +pub struct MerkleConfig where Hash: HashDomains, Fixed: FixedPoints, @@ -55,7 +55,7 @@ where /// This chip does **NOT** constrain `left⋆` and `right⋆` to be canonical encodings of /// `left` and `right`. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct MerkleChip +pub struct MerkleChip where Hash: HashDomains, Fixed: FixedPoints, diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 7ed6386d9a..10a302e82b 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -450,11 +450,11 @@ pub trait PallasLookupRC: { } -/// `PallasLookupRC10b` is a shorthand for `LookupRangeCheckConfig` specialized with +/// `PallasLookupRCConfig` is a shorthand for `LookupRangeCheckConfig` specialized with /// `pallas::Base` and `sinsemilla::K` and used to improve readability``` -pub type PallasLookupRC10b = LookupRangeCheckConfig; +pub type PallasLookupRCConfig = LookupRangeCheckConfig; -impl PallasLookupRC for PallasLookupRC10b {} +impl PallasLookupRC for PallasLookupRCConfig {} #[cfg(test)] mod tests { From 9ecbd6513163175efb4b699f9e80e0a14e70c1e6 Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Thu, 30 May 2024 11:46:40 +0200 Subject: [PATCH 78/99] resolve some comments --- halo2_gadgets/src/tests/test_utils.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/halo2_gadgets/src/tests/test_utils.rs b/halo2_gadgets/src/tests/test_utils.rs index d9a2ead12f..ed73cc3c17 100644 --- a/halo2_gadgets/src/tests/test_utils.rs +++ b/halo2_gadgets/src/tests/test_utils.rs @@ -23,9 +23,9 @@ use halo2_proofs::{ const TEST_DATA_DIR: &str = "src/tests/circuit_data"; const GEN_ENV_VAR: &str = "CIRCUIT_TEST_GENERATE_NEW_DATA"; -/// A proof structure #[derive(Clone, Debug)] pub struct Proof(Vec); + impl AsRef<[u8]> for Proof { fn as_ref(&self) -> &[u8] { &self.0 @@ -61,6 +61,7 @@ impl Proof { let mut transcript = Blake2bRead::init(&self.0[..]); plonk::verify_proof(params, vk, strategy, &[&[]], &mut transcript) } + /// Constructs a new Proof value. pub fn new(bytes: Vec) -> Self { Proof(bytes) @@ -91,8 +92,7 @@ pub(crate) fn test_against_stored_vk>(circuit: &C, circ ); } -/// If the environment variable GEN_ENV_VAR_PROOF is set, -/// write the old proof in a file +/// If the env variable GEN_ENV_VAR is set, write the `Proof` to a file fn conditionally_save_proof_to_disk>( vk: &VerifyingKey, params: &Params, @@ -121,12 +121,11 @@ pub(crate) fn test_against_stored_proof>( let params: Params = Params::new(11); let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); - // Conditionally save proof to disk conditionally_save_proof_to_disk(&vk, ¶ms, circuit, &full_file_name); - // Read proof from disk + // Read the proof from storage let proof = Proof::new(fs::read(full_file_name).expect("Unable to read proof test file")); - // Verify the old proof with the new vk + // Verify the stored proof with the generated vk assert!(proof.verify(&vk, ¶ms).is_ok()); } From 5800687720d44ed6374f0b08cf95c47931a6eeff Mon Sep 17 00:00:00 2001 From: YaoGalteland Date: Tue, 4 Jun 2024 09:42:50 +0200 Subject: [PATCH 79/99] Fix error in ci.yml --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce5cafc981..7ed590bc01 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,8 +52,10 @@ jobs: with: beta-features: ${{ matrix.stage == 'beta' }} nightly-features: ${{ matrix.stage == 'nightly' }} + - name: Update apt + run: sudo apt-get update - name: Install cross-platform support dependencies - run: sudo apt install gcc-multilib + run: sudo apt-get install gcc-multilib - run: rustup target add i686-unknown-linux-gnu - name: Run tests run: > From 3ed08fb09400133e136d75a9f705513589f6c999 Mon Sep 17 00:00:00 2001 From: Constance Date: Tue, 11 Jun 2024 20:52:47 +0200 Subject: [PATCH 80/99] Cleanup code and some renamings --- halo2_gadgets/src/ecc/chip/mul.rs | 6 +- .../src/sinsemilla/chip/hash_to_point.rs | 11 ++-- halo2_gadgets/src/sinsemilla/merkle.rs | 2 + halo2_gadgets/src/tests/test_utils.rs | 65 ++++++++----------- 4 files changed, 38 insertions(+), 46 deletions(-) diff --git a/halo2_gadgets/src/ecc/chip/mul.rs b/halo2_gadgets/src/ecc/chip/mul.rs index e4e2004882..9cf8391dc5 100644 --- a/halo2_gadgets/src/ecc/chip/mul.rs +++ b/halo2_gadgets/src/ecc/chip/mul.rs @@ -460,22 +460,20 @@ pub mod tests { ff::{Field, PrimeField}, Curve, }; - use halo2_proofs::circuit::Chip; use halo2_proofs::{ - circuit::{Layouter, Value}, + circuit::{Chip, Layouter, Value}, plonk::Error, }; use pasta_curves::pallas; use rand::rngs::OsRng; - use crate::utilities::lookup_range_check::PallasLookupRC; use crate::{ ecc::{ chip::{EccChip, EccPoint}, tests::TestFixedBases, EccInstructions, NonIdentityPoint, Point, ScalarVar, }, - utilities::UtilitiesInstructions, + utilities::{lookup_range_check::PallasLookupRC, UtilitiesInstructions}, }; pub(crate) fn test_mul( diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 709da2455d..1470b33a5f 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -17,7 +17,7 @@ use pasta_curves::{arithmetic::CurveAffine, pallas}; use std::ops::Deref; -/// Define an enum that can hold either type +/// Define an enum that can hold either a public or a private ECC Point #[derive(Debug, Clone)] #[allow(dead_code)] pub enum EccPointQ<'a> { @@ -51,7 +51,7 @@ where ), Error, > { - let (offset, x_a, y_a) = self.public_initialization(region, Q)?; + let (offset, x_a, y_a) = self.public_q_initialization(region, Q)?; let (x_a, y_a, zs_sum) = self.hash_all_pieces(region, offset, message, x_a, y_a)?; @@ -59,13 +59,14 @@ where } #[allow(non_snake_case)] - /// Assign the coordinates of the initial public point `Q`, - /// y_Q to a fixed column + /// Assign the coordinates of the initial public point `Q` + /// - `x_Q` in a advice column, and + /// - `y_Q` in a fixed column. /// /// | offset | x_A | q_sinsemilla4 | fixed_y_q | /// -------------------------------------- /// | 0 | x_Q | 1 | y_Q | - fn public_initialization( + fn public_q_initialization( &self, region: &mut Region<'_, pallas::Base>, Q: pallas::Affine, diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 95e9e401b9..c87514a51c 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -202,6 +202,7 @@ pub mod tests { use rand::{rngs::OsRng, RngCore}; use std::{convert::TryInto, iter}; + const MERKLE_DEPTH: usize = 32; #[derive(Default)] @@ -360,6 +361,7 @@ pub mod tests { Ok(()) } } + fn generate_circuit() -> MyCircuit { let mut rng = OsRng; diff --git a/halo2_gadgets/src/tests/test_utils.rs b/halo2_gadgets/src/tests/test_utils.rs index ed73cc3c17..085f695f08 100644 --- a/halo2_gadgets/src/tests/test_utils.rs +++ b/halo2_gadgets/src/tests/test_utils.rs @@ -1,9 +1,6 @@ -//! functions used for circuit test +//! Functions used for circuit test. -use std::{ - env, fs, - path::{Path, PathBuf}, -}; +use std::{env, fs, path::Path}; use rand::rngs::OsRng; @@ -33,14 +30,14 @@ impl AsRef<[u8]> for Proof { } impl Proof { - /// Creates a proof for the given circuits and instances. + /// Creates a proof for the given circuit and instances. pub fn create( vk: &VerifyingKey, params: &Params, circuit: C, ) -> Result - where - C: Circuit, + where + C: Circuit, { let pk = plonk::keygen_pk(params, vk.clone(), &circuit).unwrap(); @@ -69,8 +66,10 @@ impl Proof { } /// Test the generated vk against the stored vk. +/// +/// If the env variable GEN_ENV_VAR is set, save `vk` into a file. pub(crate) fn test_against_stored_vk>(circuit: &C, circuit_name: &str) { - let full_file_name = Path::new(TEST_DATA_DIR) + let file_path = Path::new(TEST_DATA_DIR) .join(format!("vk_{circuit_name}")) .with_extension("rdata"); @@ -81,39 +80,26 @@ pub(crate) fn test_against_stored_vk>(circuit: &C, circ let vk_text = format!("{:#?}\n", vk.pinned()); if env::var_os(GEN_ENV_VAR).is_some() { - fs::write(&full_file_name, &vk_text).expect("Unable to write vk test file") - } - - assert_eq!( - vk_text, - fs::read_to_string(full_file_name) - .expect("Unable to read vk test file") - .replace("\r\n", "\n") - ); -} - -/// If the env variable GEN_ENV_VAR is set, write the `Proof` to a file -fn conditionally_save_proof_to_disk>( - vk: &VerifyingKey, - params: &Params, - circuit: C, - full_file_name: &PathBuf, -) { - if env::var_os(GEN_ENV_VAR).is_some() { - let proof = Proof::create(vk, params, circuit).unwrap(); - assert!(proof.verify(vk, params).is_ok()); - - fs::write(full_file_name, proof.as_ref()).expect("Unable to write proof test file"); + fs::write(&file_path, &vk_text).expect("Unable to write vk test file"); + } else { + assert_eq!( + vk_text, + fs::read_to_string(file_path) + .expect("Unable to read vk test file") + .replace("\r\n", "\n") + ); } } /// Test the generated circuit against the stored proof. +/// +/// If the env variable GEN_ENV_VAR is set, save `vk` into a file. pub(crate) fn test_against_stored_proof>( circuit: C, circuit_name: &str, index: usize, ) { - let full_file_name = Path::new(TEST_DATA_DIR) + let file_path = Path::new(TEST_DATA_DIR) .join(format!("proof_{circuit_name}_{index}")) .with_extension("bin"); @@ -121,10 +107,15 @@ pub(crate) fn test_against_stored_proof>( let params: Params = Params::new(11); let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); - conditionally_save_proof_to_disk(&vk, ¶ms, circuit, &full_file_name); - - // Read the proof from storage - let proof = Proof::new(fs::read(full_file_name).expect("Unable to read proof test file")); + let proof = if env::var_os(GEN_ENV_VAR).is_some() { + // Create the proof and save it into a file + let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); + fs::write(&file_path, proof.as_ref()).expect("Unable to write proof test file"); + proof + } else { + // Read the proof from storage + Proof::new(fs::read(file_path).expect("Unable to read proof test file")) + }; // Verify the stored proof with the generated vk assert!(proof.verify(&vk, ¶ms).is_ok()); From 65b3ae4329da5f20ab285f6348b80cb4c92afc78 Mon Sep 17 00:00:00 2001 From: Constance Date: Tue, 11 Jun 2024 21:01:21 +0200 Subject: [PATCH 81/99] rust fmt --- halo2_gadgets/src/tests/test_utils.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/halo2_gadgets/src/tests/test_utils.rs b/halo2_gadgets/src/tests/test_utils.rs index 085f695f08..33ad75670f 100644 --- a/halo2_gadgets/src/tests/test_utils.rs +++ b/halo2_gadgets/src/tests/test_utils.rs @@ -36,8 +36,8 @@ impl Proof { params: &Params, circuit: C, ) -> Result - where - C: Circuit, + where + C: Circuit, { let pk = plonk::keygen_pk(params, vk.clone(), &circuit).unwrap(); From 80dd7a1aa9c09a43ffcfe61d509ca231fc0831f1 Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Tue, 2 Jul 2024 13:52:59 +0200 Subject: [PATCH 82/99] Put together test_against_stored_vk/proof into test_against_stored_circuit Previously, the functions test_against_stored_vk and test_against_stored_proof each generated a verification key (vk). This operation can be quite slow. We are combining these two tests to generate the vk only once. --- halo2_gadgets/src/ecc.rs | 12 +- halo2_gadgets/src/sinsemilla.rs | 12 +- halo2_gadgets/src/sinsemilla/merkle.rs | 12 +- .../src/tests/circuit_data/proof_ecc_chip.bin | Bin 0 -> 3872 bytes .../tests/circuit_data/proof_ecc_chip_0.bin | Bin 3872 -> 0 bytes .../circuit_data/proof_lookup_range_check.bin | Bin 0 -> 1888 bytes .../proof_lookup_range_check_0.bin | Bin 1888 -> 0 bytes .../tests/circuit_data/proof_merkle_chip.bin | Bin 0 -> 4160 bytes .../circuit_data/proof_merkle_chip_0.bin | Bin 4160 -> 0 bytes .../proof_short_range_check_case0.bin | Bin 0 -> 1888 bytes .../proof_short_range_check_case0_0.bin | Bin 1888 -> 0 bytes .../proof_short_range_check_case1.bin | Bin 0 -> 1888 bytes .../proof_short_range_check_case1_0.bin | Bin 1888 -> 0 bytes .../proof_short_range_check_case2.bin | Bin 0 -> 1888 bytes .../proof_short_range_check_case2_0.bin | Bin 1888 -> 0 bytes .../circuit_data/proof_sinsemilla_chip.bin | Bin 0 -> 4576 bytes .../circuit_data/proof_sinsemilla_chip_0.bin | Bin 4576 -> 0 bytes halo2_gadgets/src/tests/test_utils.rs | 42 +- .../src/utilities/lookup_range_check.rs | 450 +++++++++--------- 19 files changed, 254 insertions(+), 274 deletions(-) create mode 100644 halo2_gadgets/src/tests/circuit_data/proof_ecc_chip.bin delete mode 100644 halo2_gadgets/src/tests/circuit_data/proof_ecc_chip_0.bin create mode 100644 halo2_gadgets/src/tests/circuit_data/proof_lookup_range_check.bin delete mode 100644 halo2_gadgets/src/tests/circuit_data/proof_lookup_range_check_0.bin create mode 100644 halo2_gadgets/src/tests/circuit_data/proof_merkle_chip.bin delete mode 100644 halo2_gadgets/src/tests/circuit_data/proof_merkle_chip_0.bin create mode 100644 halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case0.bin delete mode 100644 halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case0_0.bin create mode 100644 halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case1.bin delete mode 100644 halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case1_0.bin create mode 100644 halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case2.bin delete mode 100644 halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case2_0.bin create mode 100644 halo2_gadgets/src/tests/circuit_data/proof_sinsemilla_chip.bin delete mode 100644 halo2_gadgets/src/tests/circuit_data/proof_sinsemilla_chip_0.bin diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index b6e68b40e4..ec6e939d0b 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -596,7 +596,7 @@ pub(crate) mod tests { FixedPoints, }; use crate::{ - tests::test_utils::{test_against_stored_proof, test_against_stored_vk}, + tests::test_utils::test_against_stored_circuit, utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRCConfig}, }; @@ -910,15 +910,9 @@ pub(crate) mod tests { } #[test] - fn fixed_verification_key_test() { + fn test_ecc_chip_against_stored_circuit() { let circuit = MyCircuit { test_errors: false }; - test_against_stored_vk(&circuit, "ecc_chip"); - } - - #[test] - fn serialized_proof_test_case() { - let circuit = MyCircuit { test_errors: false }; - test_against_stored_proof(circuit, "ecc_chip", 0); + test_against_stored_circuit(circuit, "ecc_chip", 3872); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index e79797b612..8b1be58365 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -472,7 +472,7 @@ pub(crate) mod tests { NonIdentityPoint, ScalarFixed, }, sinsemilla::primitives::{self as sinsemilla, K}, - tests::test_utils::{test_against_stored_proof, test_against_stored_vk}, + tests::test_utils::test_against_stored_circuit, utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRCConfig}, }; @@ -753,15 +753,9 @@ pub(crate) mod tests { } #[test] - fn fixed_verification_key_test() { + fn test_sinsemilla_chip_against_stored_circuit() { let circuit = MyCircuit {}; - test_against_stored_vk(&circuit, "sinsemilla_chip"); - } - - #[test] - fn serialized_proof_test_case() { - let circuit = MyCircuit {}; - test_against_stored_proof(circuit, "sinsemilla_chip", 0); + test_against_stored_circuit(circuit, "sinsemilla_chip", 4576); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index c87514a51c..1bb63d4f1a 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -184,7 +184,7 @@ pub mod tests { tests::{TestCommitDomain, TestHashDomain}, HashDomains, }, - tests::test_utils::{test_against_stored_proof, test_against_stored_vk}, + tests::test_utils::test_against_stored_circuit, utilities::{ i2lebsp, lookup_range_check::{LookupRangeCheck, PallasLookupRCConfig}, @@ -391,15 +391,9 @@ pub mod tests { } #[test] - fn fixed_verification_key_test() { + fn test_merkle_chip_against_stored_circuit() { let circuit = generate_circuit(); - test_against_stored_vk(&circuit, "merkle_chip"); - } - - #[test] - fn serialized_proof_test_case() { - let circuit = generate_circuit(); - test_against_stored_proof(circuit, "merkle_chip", 0); + test_against_stored_circuit(circuit, "merkle_chip", 4160); } #[cfg(feature = "test-dev-graph")] diff --git a/halo2_gadgets/src/tests/circuit_data/proof_ecc_chip.bin b/halo2_gadgets/src/tests/circuit_data/proof_ecc_chip.bin new file mode 100644 index 0000000000000000000000000000000000000000..49272038e506e1429d61f760438a8d93594aa0c1 GIT binary patch literal 3872 zcmajd_ahXJ!@zNl>&{NrAsnJ3dyh-FqcStj-kd$Itc;R%_9!cRi?hkzBbgoIkbI0B zWtF{op8w$c{`K|i+v-0bDY8k@qgY0>B#93qantsbD-(o%(fF$ZW8Ogq!H59)!5b*4 z*krGPK97@5v%m5T^ii@J$=rqe1&Mn@W!U( zjZTU&uxI{c<@%q>wXpq`Uo$0KP^!<-a^fvd9Zi0U^8`076ZfM_pBg;q4iYE8-PsvhtvA;xpOz zhGq|voYDh~V6|+H@rUV~Mg_yyn19#@zU*palXV1zF1D~D@f}H2M3Ule{m&PD#T@&J zkux{a#Xo$P>4|gV7=U!9QAtNPkR-&27ZxGkS|7d>^`UB^Y)VFp+7%+&i~wxDEx3M> zSi4OJ4%$*X^*UNJ5VYw$*yr;*0cS)i{Xkb$JlD925_PFWQ@gTgG$vi*#{ml&k4V6? zg=rP)=^}wKTv|2HhMaJmcBl55E7LOkn^3wddXY8(*WmP1c^Yy9ajg*EU%$lnSTFWF z=(~tY4me(zV<442*$btp%77>CdqelN*$>M_~(+;at}9{%5*}Zk6SQ zOF?!J+aHzbZhm844Y&KqLzuqGT!4Cl)Cu~(3;vSm47b=%dV#dD_b=`TJwTRE#NMv{ z+MQmVq(WJg>m7eDvUEst+w2AQxl(PF#a`ln_MIEV3X{p`n%<2Qr^{zhG;YcVH27jy zZ1E>OYCIkH@G8Lb(7Rh%*`ZIPU$+lrHGaZ+($I)iQ&#GSyBOSb4UZ6U)*_;wy+GUZ;i_q9e?E=cC*(_~<{U|pqz>gV0L__+h zTyIe(Q4prWFoWMlq4w2V;?* zkS$>6${T1uGFQ>4E;xQ6yk9KcgmWBY3@g;fmJm3|(4Il)4`A9{IeP= z>_vB3FK2}Ma{%psEEBmkB}6HYIv34Ykw0~)+%U%LO_m`+)(L=T1AZsD;)8YTc59|S zEUzbL15@Eb5WKf3!4jJi^D@=Hjx$w`KKApeE@r*9t^nn$jg1XtNacENz*kbYMw3;p zg0LYcw1@uf|1*zX`U*agEx8Uv=`rZTE5+KQZ8wkiw$gjwLr{Zzfqx#L^0bGQJ$#N`}lejqCB*R*yTl4>{v^8d7`dK{mO86>FMDtY3=~-6Y=XKGg26lGH&s+X z1kOy8a&G3SCbC+Bl(|}Q)4&!q_DRBLDQv{#*V6lCh-5}H5egqr<9r!-zF}9pL zf}e$XB1ex5FwOA?rT21w-5O7pS=`Qx(;E!_CdcClyBH4_0g-$ywzqfFxfPeKM}76_T-H0i%P0-| z_-{)7zW>bac*iT=I^>Gs?>ay)$_XWE_h4c3kh$lFBVEy?WGieUlRsnq#i{_8clj{= z3OgKq3_n(#={^>HHd$)kyJpwSq;YQ0A>;_>r|Ku3DCC46c-&^_E60Fmd)Bge*c3jP zr)>?Svar+ht!skl1s{a9goIfLV8&0h)y3%l)SNr0-SM)09G=f*VMt*@vUkTmJ7Vrb zZlyx;>g<+Ut!3#6m+^A@0wD7q`L!!Y#~gOkG9tM8hL(@klj-ekTtz#sL{L<9Z^)mC zFf-3u=j@~D9tPr^<+SNkUVZIf*E z>4+aZEM7=IrUApL*5GrdDXYtniJ2%zuS$@e1gx?lz+sWG&ll7O83C1#FeV-!|9yke z(2!g{b5kz_7-S_qah1VHuJ!07Edzub{khb~dB~D}lPeewMaQAfI7Sb$7xnR+AbGl7 z2?|Ad)yK~64feGcFq8@fl&-1XnoZa)OeDhX+o&q@IQs`X)b-8{G^pSmqFIXS;BM})eDt;oulMUv_;ib2@dj$WDafUd*S#JEOF|F(l z3cs zyP6C;2Y3&marhH+hCD6`5xp;T`Qnx~p2~r=ykYCGfo&?*JDR)&m#|%aY~&z zwo4clwFEK6siBXXNg|7h?||3+iHrcSaS=uF4Mo9Hqv9|5?T!|88^tCSb(kT2QTy&5@yzZ-4T4)N(@^_#wbSc4z|7+o}_$&AqbA8W*nNkT-v z@tC+Qj_Q4rNJk%o8q6$7@`-In)j;@7L< z<|^^@n*?avo)XR1s`s15f743AGQ+7cou^JNuq!|L(NiCB@o2z|cOpp{)0gvgQWn4SPK)MK)GN~X|9=_z>n}IJoI8=JbxDL@cnn$wL}%sAED(bIHbTbkFFcc^GZ^fe z8b_AgivyQmg>@xH4*pehKRg0_ynQYuuTNUvLXEYO*)4{Ih@EUlC{z|mdN4!(_TL9| Wy1#q$4?j<2C^TkYC~uogp#4AXK2;U~ literal 0 HcmV?d00001 diff --git a/halo2_gadgets/src/tests/circuit_data/proof_ecc_chip_0.bin b/halo2_gadgets/src/tests/circuit_data/proof_ecc_chip_0.bin deleted file mode 100644 index 1565f2935cce5a184ba1b5fff88f3c95b78b319d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3872 zcmajf^&=dP!@%)#hI6{R>on6bZ8+VN6Z^<99AlW7c1)j+VRAYqrn|eDIC0u^jPpGI z!T0^^>-V?q_e8w4C}4ICqTXr}J5QJp_da;Q#I^XElH-0UN|>ruwQzKx(`ZJP8<}@odUSts!Z zt`{UP6O#CamZaWlRM>mFheBT^+ZAw{1I5S^;}Rt{ZaVYB)IF}3f+|X9;wcti^qlCl z7jg<=nx#jxV8(-zQVk8~-1xuYGUd+1uK{2`*U8Xx<{2vZHu9Fr_UEI!-YzTlc?w%A(46cLB74M&_(OvFd*43Fe4mN6XU)Z%1j(IJ#qg zpD9}Cs)DONgSZ^D#VUsXGT(;^i8ES!@*)iM)1`dTlD)7CIKrQ)l*ZPclXH15wVNW z%;&%W6xZxx>vVLam0u~m=nwNVax?uihswcjYdPtY?<5!QWVP4X!>5Ir$iJ;`ARP3# z>I7>GQC|kLx+|vLkQf5ihL6@=yT+OV>|Z>aXQ5&rtxm zhaM)Q_4&E0F8fk*)+tYP}Hyq`bV2s zA5HSCDxpLVQTzBX%jd4Xy$?qZL!xD{veWqF9NysV$2jyC-Ii`XMPqnrrD|1qe5;KZ z8b8+GtxxIl61toDv-R1BEkLALC1UJ{Yg{4xl2O-_) z6b!5S?u~_IN7azd--iR+S_$||)H;2P~;YpK1Ao45* zxOuLeDf<%2$aT2a!(arg?#bx50>Lj^@A;?oS%iCF+biKUt?VvvRz5OBhP|v8&tU?f z&RhX!jMT!-AL;8|{DC|dWQ`fxl@11qWejMykjXFzWOmr+xc46|OZ+@hBOSEYWfmjD zh-#OWro}6^N@nYv60O#&k3rQ%D7n;{{+4-dM>hO$m1@L>BXvdmVvgcF^|?zN9RcAV zCtQrDf%j^s$@G2yp?a}YT22|qYJeU4kiZ&?uNczd_M!xCNs_Y3DKdktHS6q}2%qoa zl=Ku;A_;Lv)i(t+DU6hRIMPH3e<@*Js7v<9WrRsa(Z?vRr4P78GU(>CF$QuN(BI^C z8G`LoN%3V(K^OOCH#MX;P<;$^!h1neWurNHk7Lr=2p=in zY3@xAz0PMg496A-6))SA5@7lAZL+AOY)ttSG^+sU*c>Hxy;AKP2ef?!0W~t9w`Wz~ zc!+wbmlgB{*m3_Vu(?j- zRpAO!em9)aOv=^mO`%5Z9`%WMA#sLJFCVCv-bj1oKt61Zlx4pEYlja;s(m_QX}X~Z z>1?|=j=djZdd$Nu813VXzf`2<%B;&v)cD{Gn8XZF2bh1mw7eLBrTse}m*(JMyeYa- z99WZ5AQqZaI5?)rHX>GHFuSi9R61bE(3Wvx!SG-@)m>@u9Bu!dmfnoB7h+MpYothH&C|;j4WqRMnO^0Uu>QYQWWm{bc6R{AmjMe+ zJ;kDaNUZ;ArR|lr7P?f9Ju^aN8QP2Q1`I_$rY)*bAZTeL?m*%n6hApVcnwc-=4ER% z0_*52{5{+X4=XbuH(L92t=y2pJ!X8Fn%4CMMI2&JP;DbnP$~8io4e&owjVN$C{~T@_gvVO+C)vAH7nWpGe5z1XnE zzaQQcjI2A$rZcl1O#M<^mXu8<23I`0rmGC}n93DTSFx4bS+W3wBW~|1?Qk=>*$ljx zB*Ckx);{WI6Zz=12ZzSVDTBfE>55x1e(9M?EvKwtO6KvS_)mny8@vX;ffD>DlKFa@ z`y(HhaHUqS%PBcnt%)xKMaQu>th|~caEdnu8jy+_{5& z{o;a!nQ_BE&zF0Ia>+yFbklGKEFR?l_k&4ileR@H&e%xvaDN0 zSzL}1Ni+%VE$1Wr3xsBdJ%;eOeV< zS;_UkJcUPaqRV?{VWSO|GCc_~7J@ku1}Z_IFk-wV38J{Qrc-8?H>P`CSZb~=Yhd7v?`IN{K3m4@YRT))!;B#x6gW zo6wQEeR5gdLt{KG2=6)-t;5X~Zr}~lPsk>xZ7W*q6KKYX9xBg+-YG@aue%?4u<{Zn zrC$~AOr|uA>?m}jRVLCNFi#7*`0iJIdV;mOqPcMcn(lnxlxB^2t^sidBt-)h7&UHT z*|WC<#(cCFJ~CdH?yP1Ghgf|Jg_I9Qa6{+qa^Cv2&i+-`SCWR+Gz>+?D4zR&Ri}Q6 zIDvZ(KiE1Wu_VXKb|Jp-+oxWP@4#P`^F8eP``cD+*8B);uBEq%{F0l>!YUUJC;xuF z$tBdv;zID&OKkV;$+KE>@G_c;>6=dygU%8Ck%v1gRd|SgPfx)WO^@9J7fZ6v+c6lC zFN-|x#F)1~?a6=NPx;!^?AYdm7~Go)4J<-#Xg3??y1L z2_#DCku6Yy zkF6+dlMVkmG8GjmA7pb>nD>Wzc~z(1bTNQoL$hLdWvM{rlDGvB?0()9adyTFCXsS; zS-G3Qs?m!JTCrxe+1eu5AmiBJ$n8nwACV>S9;fN)<27JBV#XmV%3Y=Z51CR~O%El` z)9l$doR6gBkqkL;&PGqCLTw8n!yt~RzXLgS;L?`v6w%ZwY9NJ%aK;BVT7r?<&e1Hy7zYXJg-If#%p z3KtQbP>gI{EL9traegG!Q%;w6p#mbD{~Ay+|Nkq%>?9vZtjg==N3LSnlBaN%A9JKq-8q>Z@{(e_7=G6jT~vSO(i%lt45nuR<;6hy zS_ICSWb0BSJtR%z&TJ#R#NP_1nFRul={QqD${ewa)81?Vr{+;oY*khD+%(cgJ7qs|tJM1Ebo zlS`GBnoE|)W!J>t233fb_G5Xh>8~ac0ZL|&S+{a9|CVj#1=s7d8(Cd=WNG^^J4;v9 z^k)8uryXq;3(Vq6BK%;=f&jpf(AS9fB2YzZ!pElbr(Xxxo4PPr0RAFe#`!bU=G3X4 zrin0tf+i3>U@?~~D#TfxPb2Xw>W8WlQKCYA@GI(K$EhT;+mui)!5o-U;~HH@L%s9w z<~UYSHQj(i55#5^OEpJgz_|TJtpZ+@d?{nq-d>Z)M6UmR{iZ!?h@mHKejZyLk?;#% zeNd-E==MCtGcwxj$l20sbaGyd(;D3SiI1jd8dupr0o+;hm7=~0XGhot- zHwd=r6-eaByj-cQ4l#+Jd0RX4dabTD}qxyI|=v zYj01+bff=smrSUcGnl3Xsk4?hQcWB7a&3ycZrIt+jCx*6-Yj^%+x90+xfvwzXurB1 zp4R3~(71!wAXpPsa>?etil*eJ9{htN3VccHKg_+8rN@dt^tB{QVl|>9F|7e_u=7MzBoRsH8b0WyPCd z;u7vY^<7_L#1Zl4aFSMaPqeMzJwali-uqh{Hb5?h0pz|F4uq-OHTv!)YDvTH{3EBv zUW{7!#GcSbSi%yJDvy56zlYHqBwOUhn#Yw}2J?6sob&nwbabKoN3TjP4oC*HH)R;~ znZ|6;60Pwi^)I7Ivmx0P5j>>=9fT!mFzr@eyFo=S8?nLWOSHA)_1mG{28kz5V>gL} z9w8iH&p zHMfwvO=F4Nw|;*@-?yI^UnuK0?*ySAcsVK=s6)G*@bhkZz?NzDY=a+ITlIZRygm72 zD|&2W<~H@3ic+dL9Q)4?t3HieB!E75rw=U`3*N%-30o8#wzTH<3EUA=FzsDQnw*$S zXICwVK{Dqi!%<|m zoWr))0|_tJOEkLX3lfY=CGY!`yf}Z0I+m*bXi|~b31Y$94pnk>?Ju+c?(#(e?ry;j z)h{VSu#i^dO%5+DSaC#7aeoLl%gJ|4E<g z_M3&Cw#>Z=B}1bKCR^+opK(T2*Po4h0>B25vMRB1J=acjRT6{*vS{ItnVI zDlA7iw}eY%jwbGY2g@eAvr6#lz%~?K-ROM2@pPC$b%LD%=MR)~DP0dw+>4^9EArpV z8BaWBg#YG$*)v5=+n4j#-5a7g+l9(7lhyWGDJKt$HMQ(1_w2-1HO02J@BLcP9n4xT ze7Ps1{-1xtGQBvtB)ui~4nvOQSH|gnVJTUh*}elhvP5#GDgENks7(;ug?TQ#+tgcC zgviD>Zyc+v3}IZqWB9m6LI?}D^5$MCh08uPQ(1xCwv&}p#|g|=IvfeEGVvf|uVyrr5FO(bw4#MnG9+9#!Q6 zob`|PKzj7JRhZ7y$Xfn~TB)skpBb44$;yibp}_^=%ny;qpntt5W!2>JIZ&^l2E4ai zg0D`_KOMQ*@~E9T$RHA7=)>m-#6#A*+dnBXbFc>_&8lu}XFrP5LP^xu1n!hfww){{ z92{k8>x8^rJXN@ewS{GTzNu&16A}V1KMidiWcVTpcY!Rij0Jh?D$o;0(C0o7;6Ep< z+FG4&jmjl?HbtCu9Yt?@>EIW=j5#CB^*LKgU}F7ukViB{wPxb$4e{}@W$F^stVjxk z4Nv(jkgMz2MFEL980#T4kZ4h?65uFW zA%_Ic7D=8LK}WMkNai-))0G$6Xu?ggr;H7y%B9l4fd+y^;fMbbcN!fO{>P9$FEqH5u{;xw4{p?}53~Wj`=| zYJsQ^m9@_jbx(2dZ>Fn@!4(+RCp?l>UG3(E{d;q*udhS=tCU=Xx|>OjWSUAwL`NIJ z^)X;vcry+E6*--gmvYRX-F*_@*G=U0UNKB+RDJRCLy>P;>isvKT7?VPR9J*9=iHr^ z8YyJX3<$t`x+LI%ichq`f``>I0(+QiLroh}&~tZod-(uQ;xS-3ou>&_n)$ukZ95D*ni(+y z&da5OY9O)dg9g2i($6fTGIE;YlTTdS&XXedh33R$-j6Xk(Asc}E*T&PFmT6%Ct{WS z>80yGh#OVOweTsI-%=f^pOdz$<2FL+*24j6zw~AB;xO;T{fg&fy+qj6B{{Qi9rV#> z0eBqItEn*6;PE_~1Wm8mYU81l)u0XC@wz|#-GlAY-ANZ$VgFv_Bo literal 0 HcmV?d00001 diff --git a/halo2_gadgets/src/tests/circuit_data/proof_lookup_range_check_0.bin b/halo2_gadgets/src/tests/circuit_data/proof_lookup_range_check_0.bin deleted file mode 100644 index f3e6a81189e600346b32d64655193c7a8b72c077..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1888 zcmajY=OY^k1AuX}u?aOATPRvY%$&3(sBtA%HEOgqYuBi8A!0PI*u=Qjp0PrtO6}-t z#-?aFwbDlI+M_7g&@L7M7>MSJkbu4MX;N0(G z4C*WJ_V!)`W-6{HY5m5QZ%6$XHSAdFD%g{EKXjiZzk=j$^Htr0Okbm1z~jHMEs?O; z3uXdizV)Fgef3SDoLqh)ny%}{goA2*p!GqcJjbtX$LnxdB=>9GFP(aG>2^uYj!P4W z&eOSl)dBCQDB6Obpk!Ae4mjhx-OR}DMIIS+NW8hz_9RGs!b4%%*?^VY_;axHrP=jX zORsaZ+S!>rAEQs32<$nH4gI3$Etp+(=jQTgnC(eAmEWyk3SInT#_KTr-(imMS>dre z-_9V+oQ}cpo@rTbEV+vm2KX5k^@&x`-cQ;y@@1<0hQHR*6Fi`_;UCo(5u#?iATdg< zjB3QLnJANo;8$bDEPp|L4RWdEM-}RBTry28aA;T6E3j6o7uS~V3v}h^uT)|9O*Y4w zh#xd=hvr;+A0>eu?nu3^=i9SWu11H_*eR?lkF4*{FvHgYQx z_YQzHsJjA$R>d?B%TZAYF|Z_ zrbEp|=H1}MN>r!ZG@c+u@V?|lU*FmJrJYE>5r>uf+&+OrMiBugq&Wemrl{^;`+K}! z=k^BDy^{+o8_~++@0k!8s<3oh!Vf#ALK|Mptw{t_OK?4_OPYvmg(z#z zb{+p{rcG>GOhB5%!vytO){?nE?NGgbSI+f!fyx-{EN3FYxZi0=E;{lY5JN5d>le`_ zFRe(Il^4}$qY`8me(6a4l}hbBWd<5xl?Zhd$S~SRhF_5f)9appyvAQ5zG|_4Ayg=f z2Lr8FuKr3(hZG?hZT(YVc8gy;+7)WmL`#_Z8gxA1vZ1uSCewJo#Yq})y~RC)G?{yH zWt`o*MCgConHp4%nI?=4wc&0{k}TB#5d8(GIP(J%*Ju#0^}G2L%e%&N%BwkvhRx)V zM0D=H+L8`pVSz!sG=%23*2Zj3J0SNz%XZ)vR zuIELg0bCCzof341(+Y*za>}|@_{HVx(mwg2V&#h^btFeH;ogr+2)eY-Li7IRRh$O zy!RKQMVcraHr84jz&B_LQwGILX^d6RT*V|p+!>r5Nrhs9cphpS< z`lGi@bhjDEO}Fp|%QHO@shln6ff{c)vp3mLks?;f@+t~?lT{w%Kw6MQ=?^=ZJkPrO zV;;4wb_M#52i-ux%7Gg{i zn4Y~+J;WNa&1f|nBf*w&S=03;1ouZEcyxE5FZt6}|3DNx7=H)n-q8r!si#sHntf7{ zAypWd5mcY8?cIX#w&5!sBcD`r)|Q((`j1#Pn1XYQ$h-6j)#BpnkcX@voX`2kTW!kt zay88}`673{r5Yn9+Aw0LRR^VE8dI|wjNbY~Gu|Uo1);(M2cYc%e?2$Cv`Lyl)7ho| z37=f0wAvtzN+RME7c2D&c~zr_p*_dF(gsmaYck+s8Z7h1->Ab$vwS@GYWRGXL{jX( zd1BDbks}QqCG9WW3sTBkiH#IvCHj+A^{sT~ox+*=YHn8(ie7Y|?HI$ZqKV)Jc(|j` oQy2?#m@J6xLrjmKUTR(WX%ECLzZp+Qm324~kUyg~@qcjs2ZeNn=l}o! diff --git a/halo2_gadgets/src/tests/circuit_data/proof_merkle_chip.bin b/halo2_gadgets/src/tests/circuit_data/proof_merkle_chip.bin new file mode 100644 index 0000000000000000000000000000000000000000..abce3ef943168b62042ef5cefb2d26f08868bc2d GIT binary patch literal 4160 zcmV-G5Wnvsp!3fBWHj26G4xr*=@lU=BY659h@5&A?k85&A|`brYqE=@ zH-C%!Ezf=C6oAD`@o_#7{_oigP*$H$n)js)ocauX1{FZKWE;A{;j_l@9)!1Gy)W5f zm;St~j@pPla@PqG5I>xy2b6jtF;QETEDSY&j&Jc~^y)yQC3v06NswlXZlmdR9gCP* zvZSG9T-gileJ9wI@#)^|^&-EvZc?C5gR@XC*E#rPmg4gp=&LvC-r*13^bCadVl`^V z4pGvm&9hsQQcHSXYAv%4nrZ+dq9n`;`@C2@2&^ETXe)&Di&pEVW5F$lU%AkV<>?ZQ zs*9@ch{F&_JP}+jiQFt~YDF~rJ|ja*cz@SJ+Q5@%7pO5F9qxgvlA>NLYDl58MllrI zHMJogfIpH3h|mrr%RCudSUG~d#buo{#WcM+Q!G3kwEl!?u;!|*!*FcRtxkB$OCET3swFyM%-<6C=|09T* z=p0Ysid~n*m0C{^Sd#rjQC_zD`hIucp~Ja*5#||*rarLgu+bX5I;C&0jXgJ_=Ciz|!^Bi|<|S!bFC3mlG@7O1K-Lk?nPHuT&Tb-C6Y3JSBYIVaD|t zdg+_oCxiP;y^f0R1UudXq(3U%Yrv!Jit7n>YZKwe!Hy#^Ay)-tD|#Hehc+QgHl(p~ z1(|xuP#r1Z{f%iSPY)OY6pVH7UQ)2mDsJ;8R`R!>CpaUR;IpDl1i|00rziIp(EDYQ+(nItrizTjEO#HmLTbER^dARBet`X>?M!cnkSx|n|MLf z3F*@^WX~J`xJ`Tr;~))%*!1Wx&%#vz6n>?%Yu$vs?+iX~Y~wGeC@4e)919-CyyVp^}n&<7xwLSZO_+pKu^>?iSclg# z1|Uc=Ko25_l#=D82QS`=2||iJc3Kof6<+XQfihT3ztyVi;KnH`Whx=mv0^9i^RKG= z*JaQ8Har7&A*cx1Nw{vzkUbL?!gXBcl{SAeowRlPW0J0Yn=U|En>5_Xu_fy)QNllb zIJS_4PZiXSXm7^{XJQWDpo8pqyIqNz=?Hv}9G@=27NQ=wMc!VG0;G_FF<2d=j8K^@ zndX|)#usX(w}vLtj70A|`~6}jHN30g4``7O$mwpuMc%EMN66CG!9yPgB&Y%dC# zOVK`ryiikl(F0WY;tMSgNC1cGXV~uxRba3Xt!9_9e3kBp>~w=AfzpuxTBim1o<=WQ z{1TSx4w6@=5tWXPgTU04HW`uM zoYTkZiGD4)1`)yB-|TlztXW<2E_Q%b2^+x?m%K@Qe*DE0DvLFh!Cid?ALXiegQ6sI znn1^WuYN?Mt^$|!J1L#m&X^s$7Ey^J&>&~>|9XlIcYLL!F|fv`;dO{Q1>yALBKI{M zZ#VHbs#I~y6%cZ)=*WS0zzrTS)0ujv^K~h6opC2M5a*>Q?s=hVoXk`ZguWWY>v9HK zwTjT&bRX`R|0Ei2x~|q%fJK_3sNFOvbqCGME}v+I&#umd8T+hn`T{L$HhbPn=VQ*^ zWS^00000000000000000000000000000000000 z0001dL=|&+wi)>k(J{BNA70Aqk%o8UD#h?tgm>KokeD!vcN;hzKE>Rf=K-70<`nEE ze^Fj2Um;*rB=J*as1q=1PlCTn6nr$q;t}*Qe=v%`$=QVky_LXSE(QnXvb-0P){f@* zP5x;0EDE%#5tldx)neyFO?PsTr<&lxo_rUT?ZZaj+vO71DRVtr_~!b}8POL0#PxnY zLey)77*;qY2^Hl^VKQmztHZV<^`)2aYx}4_x&;Z#AhXqUq+mLxuKx0Bpv{XAzUEx8 z10`BWwp@jTp|yQw$+k{3e26{{p&nQVeF%-vewX;;dVsyXlD&+_pdUD&xguDEP=g=; zc!J12h0t8W#W_3zA)#?i@lHq`t|Jxo8TKB~pRPVff%7rY@}L6jTjW&iNm4E6A3Jw` zUF+n=TUOS{x@#Lc&Ns%pc?3nFY^$ao%;)Y(X9kF0#o?5)ajxvFa2*i{xJyx5ZG3Q3 z`#R-Vo|NopUy}0yPVToZ0RjC16g4-F3H1l9Wz~pGPmhyDd6!7KgDk7^l*r5EgUV^A zvpy8Z8Yskt1rqjGR&b&ed!dq^UFa5Xfw7bN_V?`Q%SR;MLgIkh3l%g_DXPc#r!9O` z4b|jD(}h*_N=KS|-+urmMV2fMELWT$-$ly)XOBbf?O_Vd<=us=Ft|yt>)A8fnh^#< z@9T0D)|Uxc)TUyrPwk{Vf;Cji#AHB5WkNoF19E&{=^v#HOYPt9Fcox-z>rWx)sMZ9 z&t0(3a&#J~CY63m+Bh1EOrvl^D+wceHdY39CBXeaqE4edyekfJ3xeQ|Mu?|C$V-bTxJ5( zfkJ*)Rw!B)^#mw2IAJ7*HaVb9D;<$Wm|SG{pr#!|%o!E88${p6wwP@OIy7Q`+1i|~ zIqeot+Ieu(ViOPUKX>KhcXI|Udqy&#ukTkdEcIo|Fl8PA6y zNAh`W6(7QBFqCcIk`@G~1B9z}_ymQRa_$>$HuV8F>qMudjgQGRhjvB_x!XPfu_l~> z+T0`1vXnIZh*$`NK~$Hf;xd*BKRAe0&_NXxh8*V(P~x_svm0K8PW=g?TUZ^vW~koR zOhpIJTMrx)J#sV!aMe@kd^)dH(<#2>kMqt)Jj4sLZD%hoc-J6^F08jGV9*PH(qltj z(u>a8Efe^b)yGec#xNWKrso8Kl*Nvl({rfYWx+{Bu%@4SB*B8^RhQV?`TN{t~=J; zOUQ`{I$NQQfWavsw?Vpl1Bp;RkzChXfHac1wnJp*CBoQI9e*4{yIu&N_JL4HdYYLu z5N(>bYVPqq?%=q~%^Jwhr$a_1iK-XvINW+lalhKD>KNyguik%CO4w%JTQHbL`NID% zGW{Ar;Y!+{JaJi25K;D0^n3BVq{DN?Z@eKI#3lUyR8EX*7KR_3vt;%YbXo%Vy^=A@ zGdzOygsA`K@+vR=Oq?_w6`0e#=(>YDXUXkrM@dQQsdvxj1qcLiM>o*m<`6sOSxng+ zKepw*t<@|o(iLS*_5~5`*b<8zG~3vQaCH)FWf_13(8m8v9{Ua%aX<`{_g-u1%I-CU z>gs;8*X0YXN?Fcs%b6w;Z?djG)}sj0wP*$U4PbpfUkkKV8G1c7i;zQ`1aNmP+qkww z1!-ZZ3tezEz1jp98|Jpn6L+LSm^r0xBr0omL)*Ak-~q$^u+!@-l+xKEAkEMOMw5>- z6saUo+Z9THkhXX$85G6`5dzLM8eWl~AJTcyHNCqs9Wl(FR4#St`bG<-tD=htNwZV+ z68QT9eUK{COCdCXC$a7u^-^+5hl0!>>lga446303Awx1nk{2 zNJTYNlBnO$L8=px8^L;mTadwl2{o{rm&_@L3aTU5`W}RV^yQeOdj_dtZ|gMC#TC|c zsR^;F0p4DFdVN;ahBa{}tH}hFY5vwLmX z91Y6Zs-!i_DM@qNO3oh~EY~G!9*iOGfg%~$oj0FU39k7{r0j>pe%XGK#(=;Cnv#SId?Jez$Pdt2qvN^-bBNyTQ>z7 zOrZy`pU3@(igO?NU?SeYzBLi{b8Ch~H3277S`H@Uk(86cb$Uq$HS_d3nA@q^>>`&! z;aOt!j~f58{_@BZyb81AXQ}uDd-@t<&SkpYn|ql%VuB^1P%ZW=0y_$uuQL-b48tvA zm5PRurbyOg6uS!7N&W>tGW*UEy!|twke%P@_0RW9N{y#{GncOFz@;3})nd;rElw#s z%QY`FS0W}=Z+sD7N89OCt^|-1`=q=C843Vg=k*Q1in)5Lw@&anf@?p<+D~4d&M@V6PGy@FAER`b?1B^XSZDItX^|=o?29>Y%M~y8@ KttWXO;X@?@WY8G^ literal 0 HcmV?d00001 diff --git a/halo2_gadgets/src/tests/circuit_data/proof_merkle_chip_0.bin b/halo2_gadgets/src/tests/circuit_data/proof_merkle_chip_0.bin deleted file mode 100644 index df788aebfabd74cf7f76ccb1d5b2a90bec188121..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4160 zcmV-G5Wny4=>7~%D@Lc7iCnR=YbMU7yNI4&6~;@f8m`)O5%{gcATZeKTivT6q2y>p zFNs7p(YX|qdRv-Te;tudO3kpeIK}j9{Y^~}uBbzqj5foa`jN*^x7i=dJgl1Y=YK3H zGPQ!(-*y6kt%_A0Clp4RR9WaZbGfWm)Ox85osc@St)!LA{9FZi za5frlWc>}61UM@VBy61Z2x<0BGceF@ONv_HmXizt_OvB_Ffbrn6m(H_{a-RcSiX+u(f~h>&qW z!#y}%BSoh4C-Rgj7-X=&iGM~nC>q=WfsR5>XI04893Hf=u~0SHeVW?)%sQo1637R5 z1ztJ}!k#y!c>vhTzbU&NgR`1M-JS}UfsechME6?*ET@T=VdhMUgcD_&Nm%6V%03GD zT6Mfs3J+i*qD9Ts zkfW8xO5zO%z8yIDqFgkZEqf;)Uc%QqSy(e2wOaeGz5!`Ki+3JHBG`?wI~XdXBcuyE zPId-&wp|3h#iR4YUt}!Igv&mD>hR>k`>J4sub3`$F(Eb8!%*=6p*oPPDgY86J4Bfy zNQv`i{K-bytck!=U=tx5w0UwexuyJImYs9=bsa;#G0kre6%6Vg^&Ke=7Pa~Mf@DZ2zk3+6_ezr<=7>MB+=)jG4$TXm}&K~PP|wY zXmTJQ>pG~PEm;i`MZ)G#s7?<&^^^%kGEF`|;RkS6z_A-wX#6(vW+Di&1qp2HG&Q~< z%jYsWPBFb(+;rV?PCY!61(nOrHrRJc{cJzmq@3$NbVqxRCL~Z=cp3Y0RAUP$*1i~L z$6jcKEhriVL!pZH6u;XC$I{AZ-di1uy@nzGomzkwnTsN-M%uaw3#sE7pxQgfz`=q$ z-RHdqc7`m_%aIgyuV>F)F$Dt~h342K{7U+8Dt(ENZrt9%ElL!~l-V@+K1r@^gkLil z->*DO1SNcyb*iO~uS^*@uh1`s}5aIA(tNS~{C>tgMT##D;>MR?8)yfHg@eOKXFeRq$v2VMQ~|)qPyC z&$F>lq6Oebza=#<;vFRQEg16esR)q3*6&jd*!+pAK$UTP*B5F@$q^PD9TwSH#bkEH9Co{IsMj{db00000000000000000000000000000000000 z0001+toi0)73lruYG|V&+zej(`1X7iE26b zl?)g3k4Lj6yCgm0+_ z=s1>pc}O>IiR&2bqli{vKj zfP?Kk4O(w+FTbAN`>tNylnv+4zz9sxurR5T=7I?n$ZY(kmd7#NbO2MpqJlQaEntV+SCrI#0j2Z}D6G*+&)Tzw(Zp(2(#o z`8C_|Th+{kx1ghe4E6Q81dNFTJJl|_r9<-}bS@DgL$WJ7mWYFw3x(>;@}Vuqg+0S+ z#1<5m>>#tQ*n1QCoRvJ1dP#NL~T5Md)cCwgH`_7Qw@B0E)iG zHo~kdaGBAE72G1T&1wk1W03BN>CaCi$fgJJYF_Y9ZnNAS)|Ew}Fi>PFWQH1)?O(qw zA-pz-dV{h-%$qD~+Ix)fykj7t)b;c2n;k4~9}Q45Ol}^GXR2BhvC~Dv$2MxO2NZOv zW1Z4pWtu<#5 z`+iP+iC1l=p3R$=mxz_t8pl-e zAb)O^8*Zq_FYyRSU+!VT9e47U)uiS+iDay`W6`3JPqlt{F>1v3?JsX%#9vHw6S_Hsfi?K+BUwY9^v z0W=Z%azi?do>PUo&jp9rbWKxtFGdDTgu0OQMUumH`_C1~SyvxfrZxMLGvXtnis^m7 zKQ+IIEvnCcrpzo1+zd4Ce;vWi=z(f?1|cXa%pYQ#x1^HZg+nM{{?i*juqx{E6a_1ah_@6b*|8Rn2@SAo7EaUerp5;x(@d`G zBYL_C`wKAo!g4rI*cvWs3HzAIpZC!d9yDC|$L?=Om7&%lA^)5a{j39_KhEs0w!tOe zdjj)J;^ZbKyLf}*0HUmdWdr2qWHt)SOB|PQMUJpPX>h7@BIye+O zLij>OV{kk)gxXbckJgkl``NuJ6iL_i*fHM|+vrikX%SA)bbQ6%e^Jgkh$yaHQ;P!S zZfzI_+e*{C$tk0#lE0}^&N;1rdwYXIiOYDXsr5MP!D|0DePh8o=o2%{8RQ%$9a6ZK zMvF+zaKevj1_cS4^lXH?F&F8MQRIyYrHVN)UcXLJmZY7Zo@1-1SksSLH~U{Ncs8cL zJ7z5ZYyE`iGFWKZa+V^D?gh*1mnAd^H4w}FSaae#FZ9OS{6Y)!^W)gP{OcXYZMlM4%o2H1@Sed zlW?xf`Dxp#e)}^h4@ikhiL_LeSfOd`Um4SFkcpKI+vQyWwNunqB~cad9SaNNZ9}O$vJPb9H>3O4LCXobEfW6ucAOrJ64{t%hq$H4@(NA=bKFsy#~eHud6& zZ;8iB0PeG_=sq4INnWGsr$Wov&@b%Rx(;=Z5N=Mhk2>~DfU+*IzEBS|mWjw7{Vk=k zL~9%{A9E(`S)Xm)`V#^Db+Z%l;MYC$bo8Yv{hRwk_fb5GVQ8e;aKP}-CAB|dzzDN|JSNV zayp*xqt#6Wbso+fYQS#1)Y8Fs9kOz>H@g&WOwge|^|1gm`BlvAL*Z$&PCO-jnw67q2$@l;O diff --git a/halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case0.bin b/halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case0.bin new file mode 100644 index 0000000000000000000000000000000000000000..4505de5607ad3789289a29ee3ea577bdbfc5ba04 GIT binary patch literal 1888 zcmV-m2cP&EY&`a#dN(}vFEXKw_@XVksHXc^Wj=l|Gf%zFeoPj3Lhe=G#+IU`r1GtX zzTq*v59T&=7TEU4qwkQ3Xp4vR@Eh`Di(rFMe5L4B@C=_Z!RgMQ$c51sHf(wptK}RP ztAlOI3HyV@L9$CLHz*0<7nKLyXoQ)+6b>iom;IR2KE?(mn_w-@BfMFR^61%BtB{n# zju=T*IF&H?3j3t`@uKOG%9u>C^i6r8nknj+s`BYl@O|p}~deJX%0M zurTEg>CvuQ{80=bq~R$PWOnq=ysWUs8il5UPY)lnUmTJVq-1w<)DPQ#pR9umg6+Z7 zx0SHDn1%nz@c5yiwd#Slf9j0_i>6cm`|+Dnxl7i!ELa_X;iEbTqe0pQZ%f-JL@4_0 zl(Ni8O$IuAwUUD!j_gBMVRiVJ9$qR}%K#L;N-w z85;!hagPU{15hDi{mK1VcJS7Ea7RDc+wSHwJ*w7!d{F zJU)%{jMO!9?O%9o7m_soWFigzF1iV&jkb6g=)`f5U#!hRTa+RvQ~7$#>hcO`Hsk4d zfR{aBr|n?ViUXVcG4NBaa|YEx_b_r(FU>Dc0i(|~g-+}S{Y}|z1b06)T>s+Wq~Z!G`=iiD%+#9 z_W~gRx@@DmjV%WKU#Ockp4S^g;hIj^H<{9tq=U;vj&0>u=JK>mMA1_;Hw&;-PfDAT@aq2uK~h_ z=v>B`#`AU|IB_lns&^cDxQ5bkGuF2MZn-9D$J#ru_B=|uXA`X_JZJ7g($c7v+|6@_ z!>Q9qV5;|8=>BZBCoLv`URdM_?bA2PR%$W!^-h?1wdK>5YXpC^jlPBTzlY~a5A*Jx z*F(R%-ZekXk{~AJK${weGWt%`u%AZZYZ-U;A8WqNuPX2{p8Em9k+WvfA7xvIrF_ah zSHQD;?NO_M(;kfIn-M#Xr7$*;q8R7+hQ4iG8zdY~iQGqbLa2qz*C7MQQq4=aI9LtV zW0e$1*pGtnfqGrZN$QavIQng=1Nx&($UF4~hX4#wR>$KC7bp9wtm>|9Y4~2&tfP2T z#3Js%4kAd?O^*+}f(iqF!(4;iNZ*^`AWI+v#(ID9_4+3lUITdW;k+ki_;n(UWgmN? ziL(qghLHqU%PT{0Kcp0)$G1CfAJH`_pJE=)FAFx(rB_>RS8SkUP!J!74ZWpyqFl|8 zZX&-gX&$wC29^Be|6*MV{-Bc!8US&29+YAcB;3uF*^8FL!FV_U2fW}#$KfJEof#kJ zdo|y5Me5Nid0u^_Dz~(>lulWCo9)qtxC#P`_j0Ve`@o;My9D|jT77p;Yf>!N=F_{k z1NJBmh04l!Lv9L*zx};;n>vy*a=tc=M;AL-+lUr{zzQE&a18|+I=?}s%G??`mi$Uc zeGWhpDCD@+d8v)ftpysUHycDy4}_tLw*#}G7{qvfijD6FEqNg|5dQzAm8rihs>URs zvyow3tDzl?lJrD6yq0Q*C|(a6NuWE3f8mHM4hDWN0ZR>dP&br8MrKV5A)M;t2n`cX zzcD`)S}2ca**}@%!*_hyk>SDsXdzW8?Yjneii&{1sI$aU(O0TP&%&qzz)V_pAJ8ib zQ}rkay!I;*OVgi6UFWF5zp~K|W%NlsQNU{&pJF5xTLP4jkCH%Vf|xMMhTF6oUXyvl aEc2mF3I#z8VyqF2rMM3G%1^IMxJfe;Z3i}nEsoJ(o$2n+*FDt=(u-W z;nxpeTu|>E*8_Lw$(AfcfYdSnu}7aq!?D0%Jh(7fXtYN`3x))6WT5Ayi@^7N*8_k?QkvBzbc{opQ)76X2bPo^)a_0fPj9g z!jj5?QtwF;V8#LDGVm@LE=%RHw1SCd#90Kts1x19n#(T!G3W2*-WD*leUd`0m7Uz- zPHZVj#qR^QHP>Mr@nezl`H9(RE#O@(9gY7Ul6yd1-}ZxuuSE!EwM@er1Dg%_LMQ}C za5*3KI`hxC3W>^d$*@vca$gCqN;ywAjm&|N@H#p}SFgLK#o5^eeJjZlCUW4iffp7) zvGH`0)xGCJyd0hPV;j6NV;kqO8Wpr&oG5YoT7@nE0000000000000000000000000 z00000000000002m`=qgV(jwYQdGwgC^WmI4C@2^C4~*&R(sv%B=p`j=dq#!lG&rPy zq?|}S@mtA9spA=a8J8B!gK@C3E29!?&FSDzXLu`|)2YBBcVZ_M^iuRYNA$3zqtGyE z%CiCQs-{@%**^QPOQH7rO^@S7pW)$^ZRBd6xD1zz>qiCeqqw&MPXY(egvhsqtT2TY z@=Kt3Rppntfz;@^UdI9w%enK0UFx&?O#||w;hS%CpoPVluh!izl1IIz1hBPIxQ;!gNrgab=J*-Zij*E2-~Ad6R?R$;)?G| zBVW)v`yqkjec=G?1s#*yJ5MaZR}jsrZSmPcnfX^MN2~o7^K!R)k!==CPpb*!JgVT8 zF$^Pt8nyW1;_KsAOkvg*c9$wu9|1Y7PfJR!0xowRyW%M%cSjs^4$+Ly7DDilS%xyj z*R>5)9eOQ%={*y;L@oN%o>GFbw`PXTvNlKGwOG#T@u{;HZYJ+s@Tl@1}5gPNRgBDx@lkLXi*jUWsR=Hv%--gQQfxCW16g_t^a`V{2Vyn|A5 z;oI}Kb?A!z1evVKwLFlD29TrginyRnXo+hq+AjTp4Rx~9lG#6HyFWw!5 z33Sm0|Eh96Ln*q99#Ea+$Gzlxj8Or}j-@F-7ICSeW zC>bw=krVeF(a6dmr=_??97nZfA=rs^M-na;@`?9u?CkX+8cPQd;u2~)6o*@ zeb;QCjA_H1_3Y;S#3O*TCfz965#iqyDs;nEIm~`;eKw6OyfLoXm57>uMOI{vLPP*R zr>bFy=|17aJzisn%_2|(ph?ge7jG&_BnRv?jdzyQ&id-8&y_~6R4Oz!1P1W+#81h; z!z$}yoQrT0z3~`lGeWAX;u79wg^K>bwl4dWe(vt^bARnlL; azfNaNQ7wk55x66X%`Rs$FXki6jWuRd$o^bKkGCf zInqkJ;`~tfD<_46M_TOB?bBKbM(e@(SLXx=qe~5}LoLXHJg@P06xQ8@VNjjjCWl&t z{7EwL{$6|Q>ywH9J6;cOpbVUqi?+-!d1B#b1cLk2-?a#=I0IzFzCo83*u(FOLmDML zWsY<(^*k6zA4*xmtDs>p^(58>96ym!8IHfor`zaPF*5JZ`wyF2bR2WY&O5_$f5A1q z$Evd{J(;i@#^7z06`0S%nj$_vCMwl%sIYGtS}PIj3fZsnr<%M+fQYOR=V-@R0JKb- zr}LYD1QQ=-`1p@puE8WpY{!bAe+jBHDAUF-*U_MBKX^le)$?^ zk(R{{AmS{sd=;_qMNA0+#D~N^jd;9=hA{-YZ(EZkcfWqf+$1<``%z6XRR=b7oGk?2 zE_&U1fZr;lo8Lg+N{yvK=maAWY%fKMACQXF5g>7E5cHYZYr6%m*$V_1k)Zi%uM-4y zbI=s^$HsPx(E`nD%`oskWb4W$ha(ub8|)V9ou2^!0000000000000000000000000 z00000000000001{#p28yI(h{z=013x6<3Z3J+^44EpoJm6-UlRQ2Q8bgmx#eE9k?q}4da|LxajB&m;{g( zT|ssey*(^*nV0ByRVl2>A7w97{YVvn46>@1`-AkxNmfed{cJRrtSB;%ZbsShE& z*^}N(Q;_8LI9trb^m$w#s4XdosAH32*5r)8(`w#cxm29Yq=h6?2$5qoT7QXto zAP^ZWrXCH6oP9k5MV>v%TfBLx$zUyh&Vuhw79r7$Me|}0{#g%Z$m1#JQR!an^3#Cs ziv2UK(Lji8YD|X_T_{)<^H+G~sukzD;9VjU!HNrneBy@}t-ko@hTl?!)Ny{%WlXn( z$s3#_=I>=YcQ%m##?!P zO~lTCWiZW-L+_5cDm@`(k>o;1M%_;Y*ML5fyKD11a+8!60ssJ7l^}7e@q1N`XD>aP z8Bu|?GZ{GS#|THpjrikNkht4!S59mB$HMiq+*i(R(az(| z$RXH}L*eUzjPk(JFLG-+4E&XV!>t2eBrc%fAd$19Mp6%XR;Q7kfAh#2&LW{ zpAZUjXCM7iF=Gn@e{t-=cA84q%0*S7vwgF!dI(Jhxkw0^rk>+%Es>PmFq~&3@tO)k z&*FCNU}T)wwyAnbFmopPht5#P{60WtJN^54SRZ3m8UIG!g^h;OO`p2kAL@X6_2tx7 zLPJh7#@b+MjmI6m75&^l06eclSAD|7&Fa83I~nUGzAu`p>_l$NV0^Yoy~LHJq%obk zT!{&88PFo`ya`<|32)P>Hl!;!(awH(HQn!)SRc7PGjo(O8K6v1c*?JIs~!ZMAKGlS z@p{w8t%)&C8@s!F>`tOxBm$t~ZY|`t{2{)y1!+>r*Wm6el?%dC@uvV!E;qDzH5MTl a4MXS8NS3@sB~itJaqctBxPl%$JO~vxgp^zW literal 0 HcmV?d00001 diff --git a/halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case1_0.bin b/halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case1_0.bin deleted file mode 100644 index b3d61e60e4bf41bbbf4d0914f2840cc485fe20f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1888 zcmV-m2cP);G2c}yn=Oj)WQT4xNX3N=Sj3?u>9H5{#vasf)>7IoK39~UZb5^tMyi=_t7`Dfe0sH)Twt;%m9pq4_ZX5I?xwPyWNC1 z?zs46F-khB2Eo;s)Q*ZFY7#gIGQ9f}z6Yv{Y>^wZe?bhI1BnbYn@slUg#5s3a9D}0 zst(&^<#Qkm1*VguP&bFCkkW+vnb}}y=?mFjot_7|)aE=Y+3g_>{{NVFgtR)!J9^*;`P1U~kf4NT%jcb-D} zh#qEbKxD|L7$P1jQ9hj%&iS4eTt0aD=nS|K$O}R`{|sgRZPffEGX>RI&jBqehY>^D zVylMiCS!uKf?J2C@EtG-U12nU#GBS{ROC1&1~x9?ZiZ!aOl)^K2%kGdL)0-Eick)M z`8W_f59mCpf^50W#UNgT{K5EB@4YrghA(jBRUkC|IjKJFrSI+-ysy@?f3?L>J{d?r=pg^#l(#FvUQB=5$&eaAhwwc z<b1mWU91zUSi17Ts+)@Ze%HVmLhG z5@A>5L=$`xEVRi8L4PEtZi#O`{JB;iJF&w(aJ$?*&~`fjOo21}3_A3xd<6|uiE3U& z@E$;~xH2Ka1vPnyj)3wB>jZX&DUK!j5xrn0M!?qnR_M< z8MtBhTq|mM0|ty~E(3TXY9uPX6Ha_gz!|d#0XB`kio!lQhlOGQGtujateuBv7IS)n zaffY%QKoTEUlJ`dk++huj+}eVNB?9v>FjDm2hfgr-)FG=mKi#y+OsgJ*W8W&M`8Y! z?gMiLf>TOjT+O}fY1pAcL{s?A{|yg?JuI8|6Zb8k=OpGst<3qeDgv7z*h$-uC8@8T zjfpaLIXQ0Oo`KL=r0blWFo&HkR~Ml)OM3sIn(|=&9hDuWjlnRjPWIs=l=e3@fIP+Z zl*6|gLRsBInwvg*-7S!SFR_;j?lz>5+jsR2X2YuH9hjuJWV}x!Mv-Teo0~%^CX)< zm+#1PQtl;t6{iGL$!+8Y$xI_mPl%$8)CAD$`FMLu1ckPd^RWrG;n@stajD*A_Y%&f z(H7`a4F}mXL8&BMKkpu$lgB;hJHslu^fW$RTjM6~1N}%%5=GVlR(^VK?Cq6@cdphX z?D(x%3oT1xPy`+b)z1rb9b3Su7Bbzb4OH7$K00XJ zb}X-m^IBl3mt>K=GddC4Jvd-$A9J7CL#G^)WV?c7j!)~d!!s9~bE^s7@LI3TQ@lNz zDk&jRaG^b1n9!0DoelFImrU;31gQ^?sGO|Bhg>rwQ}w5?2Ey$&q~;-Xi%G@ZOJLEo zjuTJ4jS27Y$>D|)Qf22m`mW@|5*v(^t&pD z;{)NoU+M-4DsnCjg`U1^4HG6^R*`rgCL90Z12~z@QmOhaDTrQ3wkv@=J@E0VgMuVc z##BR6K;|z-4)+k^51J6ba+Tf2T4}awx`GIHK8!{KXo0BvE diff --git a/halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case2.bin b/halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case2.bin new file mode 100644 index 0000000000000000000000000000000000000000..f3fecdd64dce5fcb3c4b9cd0fcd904c559cb7590 GIT binary patch literal 1888 zcmV-m2cP(artVZQDm%u)kTQd2cS1Xy0c%G~)USZ6rhn&rc#*$LRu`u3&mp(ldn?|S zD9>i5n%ot+wzzo^@ak8O*XtYxIncYIn72qs8p9;)6uyCo2gNdjAhZBPHxVpM?8YOQ z(U6@PbG8>K<j`7Yo>C*TY03 z?$K+PRl*Rv-gdts*#SxDGtBJ+i3T6w%gmD-6c8-$eWDTfdXKJS?=uf9Z;(BsrY`WN z(v7&H$c1~^Yw3olYD&?zyCE0JwJk)kVx1s^85hup37=2R8I>j8Z59@`0Rrr`+QmLk<#K3|`iCVbAuztcj zT+g=}-*di}j$}xEd}LyhrrOj_qI_`+ZD19*Bh$v4Djm2lCfWE%2Y29Q&uPBTiU}(K zW*m2hI|T`S?<{kw z_mdwLJ05?w3Tec?nO7}LEe0;$>Uyuy4x}B$155^C;eJyok_p9Y{Phzq=kZvt0{uE5 z33DWmo>DP>_`B?}?#kyIp)GPvut}NC6fqn^h;j}90000000000000000000000000 z00000000000000ET3KK_dm?r*+*Hk8fqX04+n%be0tbH_rAo#&HRlYT^V~T%br5HP z{#;oW2k8Cb1)*{`YF4IMzsp@@L4z>+?KVkP>Vw#(6(>Ihz}iSwHB{U1w>XqFvWEiO zzffFz)%no1(5Y5$@2V5G&#Ql5T3P1jyK^-k-(u-bQey6bl6m{=eSIqrA(8=QL{`vQ z;j~=yNk2q@A>P=ey#zZmdMpmxBln|4zIGf0?}$uM-7_nhkbaNIb&-xJ^af%i>)N&w zl0bn)*lHyhMGH)GgAQfUrO++pA)oc`tM}Rr_x%io|i15!vmXT=EBE{qir3RUrGHjpGcs zJ8w{zGS^yb-L8{HF2|Sj(Wac6Tng(-lwDIK!OMzCXLyRws<~lVQ+zu5+(NpWB9Uvy z8H~6Wk?umf88JMfQl0-_U0YKY^Mg_W6ex{KJ3kv(T!rVktRM>#9;-%x*vo%gp%MvX zXoe}AM~?S^k$L|ohi;0`GVEylU?5m2_TxUkQ4+YY zS3PE(0;q4&cesjC``#AtDlX1W>pp;w!Kkk|L7adzC1;Vc^kB46FZ(!3MI@>j$qR@n z9rnla=Q^U^qjnZc=11BpQ6e{zx~bvO|M9)dQOIQ+MQOL1+Vd(iz6@oI98z*Nxe1q&cUX z|LuFyD1aXt{A#hfN=e}NQ*!D*~dNr?lcMEMvUlcCr!@^CWjna(}9 z36D#tZ%yL6W*mhcGY0m9oyJexbi{rqV;*q23e6AwAd6Y_tFjFo^Kv`6%p%%^jT<0s z0k{OuP_w>TQRjc-?fCErbiPX)sg1V*k;QLaoaa_SuKT{QJ!WW;R_sG#|`i z;Q}f9jKW;L`TL!D5dQ(E@*&&@MD_)^>g}M9Z!9PSgXHVQBbwh5f#%4d_^njOUbK9; zx36ba0|NmPhT}+jGVhpb#D6#-UftroNC<>CsEpN4m9&MBRR8li( zZxFt_Xc{aDy2nWt&i*w`YHPckZTuZn?2fEe#xgfhrFN0-wz^&pNVYAR!N a!775fmHX+w(lz)CXM;(LpM;=7);R*S>4@t9 literal 0 HcmV?d00001 diff --git a/halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case2_0.bin b/halo2_gadgets/src/tests/circuit_data/proof_short_range_check_case2_0.bin deleted file mode 100644 index 37f223f7c236cdd365ac3a8512eacc2f987b96c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1888 zcmV-m2cP(S&XXZm_z|2wJl$9lZC$Ub!)y+=zZjf5A;5lKQ6i7J$4=he2(ukKuaHlY zs9~c1i_zFX^|SxG8U>*`e18%1A~+Xyca6I;D#~ZeBk`dBgsr~>j;QF^)?5{osYwd| zOHrj}>o0kXUk>PV$gopruNklt8FzLR6={)v2Fe!uFEQ`lav7zOO*nI$D-+Q8l^ALc zF0|3|(e2~>p&Fa5H@erwK(qniiSl_r;JNl%uBHq^Xn+3&(3l$RADo}GeKY8~_?ZFM zYHrSOlKgC@BVag-7*;PsPBY&We`$;rr)-U>ZoK15X!fNoO>5KBDq`#3$es(*<&$8t zFUuzi6ui6@1GEa4{&z|)(#9*Lzo{p!?SvMy9|`79jV6rb0@jkfU?ac>EqhdV`)VZ= zD>W94Z-@A<#Htlv`<|7fA^m*3{?U%L-bCzu@l2i($z2f+Pjc%!i_n4rOlouG9 zu$4iqPTeZqB@8Hj6m{y$k*Qd6rWq7?@?{T|HYy$atY6Iwo{q~7N5Jj(|CX6-krxr6 zy_oEZ@-qZcOKNJXq(55_1#3?@3(-Cc_-)3tk~hQZgKZuOtF*ASx1sj(TjKvMwa_F~{A951_0000000000000000000000000 z00000000000001meqJUjlWP1T08`5MlJ4s1yzaq!QH`HapYOH2Mie;L%Mn^4#e7{{ zWf}XgA2*4Rg*Kq}l{TBA6x3i@d&Z)jwGL1m=h`Un|0fQ!Y z%j+Va=VhyIM2Jzpf&hWyCKShUB^=AJDfBL!b=1qDY>_HM_CZ+6V1i=@V(sLuq#`dJ z?(Y6IBml>lI#_$U=It;5f9g~No_GvtL?!f}La;VbeJY-mx_IbM8h`|#vJOk~ zYr8@PL9>eqnbqUF{$sz2$2w-Ry@%_RtY34grQ2p_@%JMQr zmWl}zEfgAPge`f5Z`M*Iya6$7CghlOcgkZ;SFD{u>AcPk0tF5|e*GpR;?bnye(&$4b6I$` z5mZ08cS@pUG#-&8OPGJ+OAz_7{UW3dK~>UBtU>bxgol?am6VS(rab&ga);$qvi@{# zV;kufZgxo&pJ=I8Oa8P_W!#Zpwx$VwMLSP0IvT7x^2p4&GM(mVz@#qb&-){Xl7&%3 zIHWn+L}D*01chENDTnzmjdw=smquEWDEN`HeBs&Y|^x(s_@LY6?qyYneU#fsK zW|wLkxABJ1q@xMfst+s8i+!5G=sBAhOt{E6ti`AvZ|d%V@+#$CHfWzpVGmi8pZ(Pm zk`0?{Y}0DCJOsV z+wIh;)<4BqzbHo*DyO4EA(FIeJfAnql1f-~FIwic|C*XXUe?hb^txkfXR#Q|(=gSN2V>P7HCBCC(y3arQ^3!37{jmklZ zP#shh=pTLGSsU_u3pO+^XFG!ObmHpPI8&E?40U`VoYj*ubNRoJ7|zPq(@EfxeGfRo z%**Q9wqf(r9FcV7nx2}g8IVR<0z}s48XSf)w!%E5CzPe5!o>L0V3!l89>aUvezC<9 zU384R*R^_P?ai_zTJERi^#E2j@VTT3tu-{mI>n`xnnV*Ktm+Ax;W|9#!r`H{1o?JT amHr9D2DTd1g`_$k-1=#$`nay2l7%QM6`VH! diff --git a/halo2_gadgets/src/tests/circuit_data/proof_sinsemilla_chip.bin b/halo2_gadgets/src/tests/circuit_data/proof_sinsemilla_chip.bin new file mode 100644 index 0000000000000000000000000000000000000000..7c0faeff43a281deefd1d4df58f755600f201b5e GIT binary patch literal 4576 zcmbu+g+CmQ!@zN8>NKZoy8BK~Gbg4^PPh5$?zpMxKHYJXGdVFPP92UhF^uWXVR)YZ z;rICq-mllEdT;nm(02bRQ%~p-ug~u0v~n7fGU#-YxSeV^wo@goYOC%~{M-(UqIcC* zh6+JZk6fsCIYt-)>w9&{p*c%Q*unR#xEQYE$g$hGEO5HQ`WC&gpDQ^Q%_&1N6?J*gcB96#1xfP-lYom$9QGR)gbHwR1rxMm7*&N>pXY zqpy z0dx8`obVUUJHwC{gY7`l>e{?tg`d|&bi~5OCzy^5914u%4IU%cm&7Ok2s{nVY>N!UFKP0z>r3Dh9Wm`k$8dzeQ zmSSK(Rjb|$X3Hk8rWS+%qj;?Ti((wT^xikP#m)Z-aZ8Jco?p$`5csWO+vF(5reh4M zRf@bEwylVWZ^&3zfK7i%>t(XnaQ#o299C6qV%X+MZ7a-zJ3$!m_xVtfK)5Avz=wSrMmb1_o^<^G2pX155B3CGb2s5I92TGOhN&l zctU#byZOm)vhAh`6{gs)=rbGvWOe_YxGgvCw5$(_V_8I-cTtVyl8&u&Q)o++#ehZA z+WL2>RToW4LL9$+mT2Ikf_RJNLedi z$L%DwHn}f%`3?%kFI-9|zW-;K@XIK>x~`#C%SgaZ5SA&g092}A4YGuo>?yU<_`?2m zL=5aZcPrvZjf&J%JY-5oWUp+^tr%Dw0EOPX!GsMOu3S&g&iv?wU*9h(!Y18(BY=Oa zq5aE9J*tm!CMc?!Lp~1SKVkjk4{ijzo#u^^&_Q+%nU^Ospid2is}0M75}+_*fgbv`&p-)Q_Xa&d9p*)!E75*wJyGT&%#^zQ9r}@< zI+9Yx_#<9?p%m;1Te#3>j%RJ%L^rV7m*JH-&)i|SYqvfb^Bs1VxMtB<2wQ3VCZPye z`X|Y-R-1nctFtq$@%sE=&-z_t5~sK41xCs*xz=u#)d#cv0XMxCv{)27ullSar<)sz znP!m+gY@m+?-TBnw)ajo%VaONZTy9{?@9t!K5|vPm2XVlm|)w`v2xn3h5^FU;4?YG zFFxJe|K9AmJTzc$IAvX|(&bCcq4b$#V4RJsYDAuThGF%yo8-<^9B;NJELz(&oH5xL z8OvegR|`2#psrEjKO@TK;WnZ!0ZI!ZtN$^3#*pncdiWQ+#r*#4Mh7I{VJIRtIqg_P)p2qRCk+2wHP(0C*fiXnw0Y?E&28!^f*XQfsf@6bv2)D-yG zdSH*FLv z5s{|l|HF;hzcO8k6}1#;OW`5@iJLLZN=H)AAZJY5$CmVbA^Y`4po#3zTqY$SJ(jD3 zZ`AV;8<0^sWBLQ?m}oP;_KmnZ5D&@A;#^>%Hbm&39Eri!7p-v@FA{P* z^MsPUqRD5+p8}Iwh8R?xv8{46amf13XV#a@cG<*2a87}7g=-2e*0y2f%xl3Oaz_%q z1g12xdRJtoOXbrr4Kn6RSNL+$ic2ir$|a6>XR z$pH9BC!mO8&x=eU-`#6^q2NJL`705_E29D?Jf(ZZ#O=`QWbX%Rln(=m+^vZPzY@yK zL^)x^baN{8hJ0D3#lk_-`iZ47&wyzbY#egfJ+Um9_ppI(T!fdvS}3C39HpG>D90f$ z*SX89A!y0UFN58dM5KERY5P%yc9XH1BYwKJ>A5mH5~K)>sK6}iU9Y!BW;K|nglrtM zIThv_nh;SYWOyN~1ewZ(9JJ+WE(2vXsGY+sRWk(-vUW#gRfZg$=sx<)P#k2re=%&N z-e&&g)H1_tkKOrV!o4P66|k^9uGgt*$_`lJdb`WGRP7v{U<|y?MH(oX*>$;ju(+DQ z7wIfRg=X4D=WRse`?c)&CLWfK9HC6mcRmcxwm*lIzP7P5h`#h2%M`pdMoWY#b+4FT z$TTuLm3t#g$vtJ2T#IGC5@W4pWM!grWbXgoHfXQ~>iAd(raX!3``?vLy8#TUIQkUj z^nqUu%r^_g53R8t9k$=&TArkUjpPN$G9SJw;}{CzeePPYaq%!w(m;%y$z~3E29E28 zF67TNi%L^lGGY9W{k(A2zhn>uK_ZL=9d+LBik;7A2jqFTp59Bmotn$xq z1fZy*Mn9eyCqFOcvZTJFba@c=M}NKg|MN$`$8Brx=~@CxH9WR9zEGy0{^jiQF|lva zgVJ?keHh&}dspPXDovpx^CWAH_(L53rR2OO`Ks%4OsSO=;s40Tn5fV}zb%^|98GiY z4^9P$!&lnM_2b$hBaND{9#$aER7zrG;`vgt5B{daV=YUu(=m5xh0WRd6ZXD_2HPv% zRnzPHvW>99W^08e{At3=*)57x2d*Zu!ySiuHI_YqQKmb=+3w=qFT%>}(HfF+M@CBT zR4HrIQEO7@b-oTwB(h=n>Q`Q#bC@G;L19=0?rPx&dYsfWpg@WbfdLh5b;r(ZcAm9r znPN;Mu}v+4vsToM$*6p z7=VKk7GJ-p-!X||P6Z`6k+ucA+2o#A8?6e+_}i2YhjqGWwZ2)d-7FG}{5UZywB(TzJ&^lX+0qAq{0gIt@EXyvA+_Yi?wl>E3Rm~mNwsbG(O#_<={@rc7M@!sobH)_}HoQEKJ(B&|tcifKH4&@}dky^4r|1Oub^;qt;y0KZt zT>Emm7&LU1CHLy^9Mscq5`-enNHy>KaU2m(dpPN;JQ()s5EB(ZwIFgG#A8FEW|eeZ z;u|f~wu>G7)Yz<^YyB9=$4~q08p6_XElSq1i_#sAQ4!uG>`U(QE3p;QbL#5J00HXO zTu;ke_%BK!IsQ}RDO1V#T`>-BbbVF;ehIpaQOMBgm*@u%jv_KE_x`{aHdLk(jN=cx zuW8VGqj;IhS{k$zj!tc2N+IuLD~w^ z3oKR60@!PvQUdG-#HWNi-YXc9^0*&w$F4O`Ub*G$&kmA7xe~zQ>LFs4wvGh{<34`` ze0r{evWT}wKm7aAZWr|DKBJFksvK{?=rj$Q8yZ4|9f)I!D!w%Y24;@5)ZI(AL=k|zH-HvNYBrz;`EttD+%6F3f`m)x_{AuZO1aRwV9kOXBOgPUoSc z?8hZE3j*Sov%Xj4H?F9rUFU3Z_msogQrk;URyX-`+bhWg+bH()FI5HjPaVd073jHOFtten1(tiddBoP(D5z&nI|$L&?UO zNxyY>bK_iltTm>MU}-HzK(sE-tEesuW6WtmQJtdYYg-9p>>b%FDiZAoe@w;Nze0K1 zVc)mT!h)zTG05{iu_#d`zUJr-ny8;$fOEW&C^lbM9<}`Op`4IETJxXc1g{?8TeptX z2Pk>Dfy-&BK|}u{Uu>P#Zk?Azhpsk6n}9U8I^0AaF9Q{szB(35p5J%K{L@_&@LElq(+AX=O5V^1y472~sdEX2o%|IFyJQ0w&y0l`sfTK4Gd^$&P z0eY`_lfxa*3*_>p3_G|JI<`Wd1+}y;#rC8J)Gnd9JK^?{iI|_61(V{hdV~LDQQtjMBBUSM9cTuk|I5B;P)7>4LnCTbOH63HRC#IPk z>>MS%YahFJpo^AY4cI(XL}>+#PHsd7ISu@1*FD0oU9^9HRJU33S0jy;G!iI64e^hx zfKxmI?wU_y?1t-(#*6WiK52TjO{_gRTGHDSi(bi?Xs}LTKsQ(3+2VH&6D0%=OfW6AjQ{z^kr1|j23;owuolx!wr0H zn$KC;3B{UJ2-1nl)4wwA3gtKee@@wMWS%>?W3*8@qL-10WJ4Cz5}H>!DNbJ52?u-C zecyiq>_6hPmnFR_UsCz}PZ!qT?X!GB8CieEqJ&-))nVNt$lC?3J8R~5dvQbUh+7Fl zmNP9hkR3^YeuaN77BNT(B^veR^>L|18Qt;WtY!38j`Uu}D-gEV26`d( z_!?IDu)a*63}b8WEe!XqcT1KiGI_FN^|Ez=Tht;FIR8?jv zsC)e~^7uy9*#T$oZSRIXHw?hvR!~9Cds2^IgtaHgr6LRl%fu4?o^h;J^n(RwUZRTd zVLCCCYDo~8Nk%%Rk12|NX66>U&CD@(mWh#IS$R2jdg`7%e&o<64Nc#)n<3*1@_Mib zWSlMB<1wmh07F&k+*~kh4d0FtJ2Y*2ZdP&VrtPJ&nnV#GY|ViC>P=q>B5NoP6T?{v z;6kLkz5oqQe&}iMjK?zL_n>}TuE9i*zdJDrmI%X%f_%9p>#F2}{Ij+nGA3*#$Tk5VHf|he-MCaJ#(MX*BbTo|H zm*jTDH-*(O^fDtmmFGqF}3h zi1TI|VA$P_cGVjh-5_Whcg9;ED@8Wb&!?r>|^I4RfzKt#xx32m_5+1rUp`g0?K}c?$_P|W( zm@sqnIaLYj1$eOkz`twAo?yV#oqp5&qUd^9nM9g(!zkccRBk?d$>&d7t@&w}M(p31 z*-Mh73eCgBwaePMg-?xW@IKvW-*U(5Sd*`TTe)X3$Nc#>GxH2XFJvXd{48edAal#` zFQvTiSPV+=cgRCrac3$c=YT_uhk zX7R3+=dSZB&z{rZ(&et!2hHhJhNrv<>QNH(P4|A(ixMI+rGR4EHKOeUe>~ktlWg(? z!qA_Nh-JXJWCF)iE&OV?_tV&VG#+q+qWE(IrQh!8eA-jb{tw^Ve$HjQcNAG}SmAuy zgX6IHKqQCmQ0|IfNiW}?Z%)oiINfxX4ReSNH0CTQX7Nxcxbei_2#=mu!ZVDzgKx#+ zhf!SJTr6hG7sSuT4-Q*;LB3q=EdWnej1jCRYmKXU3f4aRmDs}MB;Q}!EKf%j(lb;5 z5HB+aUDj?@4RQQ19rC;Z5#K>iIx0D$xDOXl;u8f|d3ld!fJRsMWq2Dsqw}#1i|F*G zsL@C8hx#7l>o7%?k;J)BdS!gm$uWZi+8$mOVW5t>gR79szNp}vJ+d`o(wU3~q%l*J z?j7<~XTPhgL=SPh%GHv+pYzLYE8RN&qSZ`~2NA@}mJ=qvG2UHAN<~ikBmQP5>B=8F zssAlW;7$gkr*BlTIA^SSz%mNmgd=tN>dA8C(>w5D2sB@*7=C8KNDB-At1OsI6=DQd;hiZ5Vp|cNrDh%uk{_+Rxf+-B6^yev>K zeu|%nuc@>qA#iRn+)HQ)#UE`fpqY9*wB5Ai(G^a6Baa((KSO9tk;@|D!SlS_00fL0=wV zi+1r}ZC#!9cG}8p7qK8!OY&+|E4KY2M3ZGYP9551)Yl945kf`g55VI|fw$N%Ab0b8 z8zjbzxeiwO+HsGC#PYBaUxq*GV+eI4$G42}R#(ga-anRVUK-1KS% z(Hq>A=ZG`=zYcD1U_kabj%F!($ukrw8~B$fBE=L>O@$F&G5(5-U5{6cLPk50)pp

|d3_{PK*bWd z;qCX3_|1d@M{I(Ub+E!OPKjtVCI;Oez&WARj%Snh)Jcp7%?$|$q2jW3eTXid?j6jf z8cEpJ4)k0Hgj2AnVp4G9u_?4!QosHc*eH+lEiF?DKTJ$DM^HLM=Ut8Ud69%ojR|~| znwuFbOp0sY5%8n|UG$OGT?hW8_=Wsjd^z!6X?#5psEV$f!y!6c$b|1<${P{NntOku zra)25KBd;dMu^SEf-54zQgjYt(V~TyF!zOSd=hF34HAYUF2jRz2XXi8mxK(*j3r`lGyf!&88_ zSK$DkDF^cw@eY_Q*fAxmC;_VfFXp(kKlAjHcDdy3?$0&~dN8mg*<6o_c3yd3{J(0$ za(=c~Md?pf5w;zg6oA4+Hid5kg&`LQqh)`vBks=zC-gCSM>7C@V zgb0X#$e|@J}(cIm{v}e9mi=Y2-b3MUXd5X&vv_V1J^5iOs!|h^y$A43^GQ`WtD8 zdwu{)rGg`&WspK~?5>$^mqYAYrWi)Ucwd{)O7Tz*ftVfX@N_Q6>B)ezO1aOJFkxk5!?egb#aseDw zbDqJ$*q-hmgX)uqwX7>jw;QJ982u4S%8StDi;$t@jIeDkfD1$rPyX$id=*O=P*u76 zR@5~&GsLcnSDb0WcyeD%LbY}xX=mX+H&)V?Do-m)V*pCWUVc@yDk!zT)hMx`; zG8-R&rv4XpUu+34<@x5cmCh;~OJp1-Oh#sFgvQOW~9&Wk3HuNbBgH?`mjFQ zVwk;`ta82klwfn6FymoJGXx;FM6PeOdXYa)%fn`wLyu!t*`e3rMamXav{O`*3 z+wXC2>)a;!*FJDkew96QoxRI*tE19&y{X(Uw6T_LYay{CG;?+vRO) zT#pTgR(;9fB^h8!Co$Em4E_6Y)m5B>>-n*)7Ri2(XzlfN{^djDDR+QLceC&;3*%K? zh}SyG)g9N-V*Czf`i$q{`i7QXr0dL8w!Co`>>X_kj;3b8UMLCT!VJFM!L7~ekETX1zvXit1!AdB&>UAV9*FT>^uz1$xn z&KCBQEhbaswZ}xqzLp7=q)c>;{aZce9FE437W*5>XH!RuC%D3?Dc!poNZ zqYY2%4qZjALYCidQ!bOeo9l1I5<9ONjTB!8(*erW#*6x>i){VaHdG`(iS0Aal39ZL zN9?Xw-gJY<_%Cx2j^Rq6Q2e`hIYY}+9RM-?VARrOd`?@N#}=bc^^;I1ao4( z12we#*$_$y{Z9@0B_Sdyx&t9y=_WBu%I-YRb+ZAd$;n%zGs&+XEW+3GO zXqltNfEVRL*Nv)QTn7?qEw8atZfe3b_(y-R@LSL*wDR@A!Kn7I)Bfi|k_4A6xB1r_ zSc4c3n(*&ia&3#>vnu|%@mttTQGgLw=ZOVCNse5>C?BN^6Sl$Pu^=IxXOVlk`#I#3 z>WRkCXJJ;~m|irzwHU`BtS1pE{}I))x%YuceJwLDSk50aP-0)~$bKM?Qsr*9w%=8N ze=9CSHl5ca6n(L^gA7+Qxsk!%9I1At!L;agc?%5z0;b;-D|fzu|8<{USzvy>iR8Q5ygka&-295yPOz+Z(aN1&aRHregmC9L;-> diff --git a/halo2_gadgets/src/tests/test_utils.rs b/halo2_gadgets/src/tests/test_utils.rs index 33ad75670f..8ee5224cd5 100644 --- a/halo2_gadgets/src/tests/test_utils.rs +++ b/halo2_gadgets/src/tests/test_utils.rs @@ -65,58 +65,50 @@ impl Proof { } } -/// Test the generated vk against the stored vk. +/// Test the generated vk and the generated proof against the stored vk and the stored proof. /// -/// If the env variable GEN_ENV_VAR is set, save `vk` into a file. -pub(crate) fn test_against_stored_vk>(circuit: &C, circuit_name: &str) { - let file_path = Path::new(TEST_DATA_DIR) +/// If the env variable GEN_ENV_VAR is set, save `vk` and `proof` into a file. +pub(crate) fn test_against_stored_circuit>( + circuit: C, + circuit_name: &str, + expected_proof_size: usize, +) { + let vk_file_path = Path::new(TEST_DATA_DIR) .join(format!("vk_{circuit_name}")) .with_extension("rdata"); // Setup phase: generate parameters, vk for the circuit. let params: Params = Params::new(11); - let vk = plonk::keygen_vk(¶ms, circuit).unwrap(); + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); let vk_text = format!("{:#?}\n", vk.pinned()); if env::var_os(GEN_ENV_VAR).is_some() { - fs::write(&file_path, &vk_text).expect("Unable to write vk test file"); + fs::write(&vk_file_path, &vk_text).expect("Unable to write vk test file"); } else { assert_eq!( vk_text, - fs::read_to_string(file_path) + fs::read_to_string(vk_file_path) .expect("Unable to read vk test file") .replace("\r\n", "\n") ); } -} -/// Test the generated circuit against the stored proof. -/// -/// If the env variable GEN_ENV_VAR is set, save `vk` into a file. -pub(crate) fn test_against_stored_proof>( - circuit: C, - circuit_name: &str, - index: usize, -) { - let file_path = Path::new(TEST_DATA_DIR) - .join(format!("proof_{circuit_name}_{index}")) + let proof_file_path = Path::new(TEST_DATA_DIR) + .join(format!("proof_{circuit_name}")) .with_extension("bin"); - // Setup phase: generate parameters, vk for the circuit. - let params: Params = Params::new(11); - let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); - let proof = if env::var_os(GEN_ENV_VAR).is_some() { // Create the proof and save it into a file let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); - fs::write(&file_path, proof.as_ref()).expect("Unable to write proof test file"); + fs::write(&proof_file_path, proof.as_ref()).expect("Unable to write proof test file"); proof } else { // Read the proof from storage - Proof::new(fs::read(file_path).expect("Unable to read proof test file")) + Proof::new(fs::read(proof_file_path).expect("Unable to read proof test file")) }; - // Verify the stored proof with the generated vk + // Verify the stored proof with the generated or stored vk. assert!(proof.verify(&vk, ¶ms).is_ok()); + assert_eq!(proof.0.len(), expected_proof_size); } diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 10a302e82b..a91afed75c 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -471,272 +471,278 @@ mod tests { }; use pasta_curves::pallas; - use crate::tests::test_utils::{test_against_stored_proof, test_against_stored_vk}; + use crate::tests::test_utils::test_against_stored_circuit; use std::{convert::TryInto, marker::PhantomData}; - #[test] - fn lookup_range_check() { - #[derive(Clone, Copy)] - struct MyCircuit { - num_words: usize, - _marker: PhantomData, - } + #[derive(Clone, Copy)] + struct MyLookupCircuit { + num_words: usize, + _marker: PhantomData, + } - impl Circuit for MyCircuit { - type Config = LookupRangeCheckConfig; - type FloorPlanner = SimpleFloorPlanner; + impl Circuit for MyLookupCircuit { + type Config = LookupRangeCheckConfig; + type FloorPlanner = SimpleFloorPlanner; - fn without_witnesses(&self) -> Self { - *self - } + fn without_witnesses(&self) -> Self { + *self + } - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let running_sum = meta.advice_column(); - let table_idx = meta.lookup_table_column(); - let constants = meta.fixed_column(); - meta.enable_constant(constants); + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let running_sum = meta.advice_column(); + let table_idx = meta.lookup_table_column(); + let constants = meta.fixed_column(); + meta.enable_constant(constants); - LookupRangeCheckConfig::::configure(meta, running_sum, table_idx) - } + LookupRangeCheckConfig::::configure(meta, running_sum, table_idx) + } - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // Load table_idx - config.load(&mut layouter)?; - - // Lookup constraining element to be no longer than num_words * K bits. - let elements_and_expected_final_zs = [ - (F::from((1 << (self.num_words * K)) - 1), F::ZERO, true), // a word that is within self.num_words * K bits long - (F::from(1 << (self.num_words * K)), F::ONE, false), // a word that is just over self.num_words * K bits long - ]; - - fn expected_zs( - element: F, - num_words: usize, - ) -> Vec { - let chunks = { - element - .to_le_bits() - .iter() - .by_vals() - .take(num_words * K) - .collect::>() - .chunks_exact(K) - .map(|chunk| F::from(lebs2ip::(chunk.try_into().unwrap()))) - .collect::>() - }; - let expected_zs = { - let inv_two_pow_k = F::from(1 << K).invert().unwrap(); - chunks.iter().fold(vec![element], |mut zs, a_i| { - // z_{i + 1} = (z_i - a_i) / 2^{K} - let z = (zs[zs.len() - 1] - a_i) * inv_two_pow_k; - zs.push(z); - zs - }) - }; - expected_zs - } + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + // Load table_idx + config.load(&mut layouter)?; + + // Lookup constraining element to be no longer than num_words * K bits. + let elements_and_expected_final_zs = [ + (F::from((1 << (self.num_words * K)) - 1), F::ZERO, true), // a word that is within self.num_words * K bits long + (F::from(1 << (self.num_words * K)), F::ONE, false), // a word that is just over self.num_words * K bits long + ]; + + fn expected_zs( + element: F, + num_words: usize, + ) -> Vec { + let chunks = { + element + .to_le_bits() + .iter() + .by_vals() + .take(num_words * K) + .collect::>() + .chunks_exact(K) + .map(|chunk| F::from(lebs2ip::(chunk.try_into().unwrap()))) + .collect::>() + }; + let expected_zs = { + let inv_two_pow_k = F::from(1 << K).invert().unwrap(); + chunks.iter().fold(vec![element], |mut zs, a_i| { + // z_{i + 1} = (z_i - a_i) / 2^{K} + let z = (zs[zs.len() - 1] - a_i) * inv_two_pow_k; + zs.push(z); + zs + }) + }; + expected_zs + } - for (element, expected_final_z, strict) in elements_and_expected_final_zs.iter() { - let expected_zs = expected_zs::(*element, self.num_words); + for (element, expected_final_z, strict) in elements_and_expected_final_zs.iter() { + let expected_zs = expected_zs::(*element, self.num_words); - let zs = config.witness_check( - layouter.namespace(|| format!("Lookup {:?}", self.num_words)), - Value::known(*element), - self.num_words, - *strict, - )?; + let zs = config.witness_check( + layouter.namespace(|| format!("Lookup {:?}", self.num_words)), + Value::known(*element), + self.num_words, + *strict, + )?; - assert_eq!(*expected_zs.last().unwrap(), *expected_final_z); + assert_eq!(*expected_zs.last().unwrap(), *expected_final_z); - for (expected_z, z) in expected_zs.into_iter().zip(zs.iter()) { - z.value().assert_if_known(|z| &&expected_z == z); - } + for (expected_z, z) in expected_zs.into_iter().zip(zs.iter()) { + z.value().assert_if_known(|z| &&expected_z == z); } - Ok(()) } + Ok(()) } + } - { - let circuit: MyCircuit = MyCircuit { - num_words: 6, - _marker: PhantomData, - }; - - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - - test_against_stored_vk(&circuit, "lookup_range_check"); + #[test] + fn lookup_range_check() { + let circuit: MyLookupCircuit = MyLookupCircuit { + num_words: 6, + _marker: PhantomData, + }; - test_against_stored_proof(circuit, "lookup_range_check", 0); - } + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), Ok(())); } #[test] - fn short_range_check() { - #[derive(Clone, Copy)] - struct MyCircuit { - element: Value, - num_bits: usize, - } - - impl Circuit for MyCircuit { - type Config = LookupRangeCheckConfig; - type FloorPlanner = SimpleFloorPlanner; + fn test_lookup_range_check_against_stored_circuit() { + let circuit: MyLookupCircuit = MyLookupCircuit { + num_words: 6, + _marker: PhantomData, + }; + test_against_stored_circuit(circuit, "lookup_range_check", 1888); + } - fn without_witnesses(&self) -> Self { - MyCircuit { - element: Value::unknown(), - num_bits: self.num_bits, - } - } + #[derive(Clone, Copy)] + struct MyShortRangeCheckCircuit { + element: Value, + num_bits: usize, + } - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let running_sum = meta.advice_column(); - let table_idx = meta.lookup_table_column(); - let constants = meta.fixed_column(); - meta.enable_constant(constants); + impl Circuit for MyShortRangeCheckCircuit { + type Config = LookupRangeCheckConfig; + type FloorPlanner = SimpleFloorPlanner; - LookupRangeCheckConfig::::configure(meta, running_sum, table_idx) + fn without_witnesses(&self) -> Self { + MyShortRangeCheckCircuit { + element: Value::unknown(), + num_bits: self.num_bits, } + } - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // Load table_idx - config.load(&mut layouter)?; - - // Lookup constraining element to be no longer than num_bits. - config.witness_short_check( - layouter.namespace(|| format!("Lookup {:?} bits", self.num_bits)), - self.element, - self.num_bits, - )?; + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let running_sum = meta.advice_column(); + let table_idx = meta.lookup_table_column(); + let constants = meta.fixed_column(); + meta.enable_constant(constants); - Ok(()) - } + LookupRangeCheckConfig::::configure(meta, running_sum, table_idx) } - // Edge case: zero bits (case 0) - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::ZERO), - num_bits: 0, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + // Load table_idx + config.load(&mut layouter)?; + + // Lookup constraining element to be no longer than num_bits. + config.witness_short_check( + layouter.namespace(|| format!("Lookup {:?} bits", self.num_bits)), + self.element, + self.num_bits, + )?; + + Ok(()) + } + } - test_against_stored_vk(&circuit, "short_range_check_case0"); + fn test_short_range_check( + element: pallas::Base, + num_bits: usize, + proof_result: &Result<(), Vec>, + circuit_name: &str, + expected_proof_size: usize, + ) { + let circuit: MyShortRangeCheckCircuit = MyShortRangeCheckCircuit { + element: Value::known(element), + num_bits, + }; + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), *proof_result); - test_against_stored_proof(circuit, "short_range_check_case0", 0); + if proof_result.is_ok() { + test_against_stored_circuit(circuit, circuit_name, expected_proof_size); } + } - // Edge case: K bits (case 1) - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from((1 << K) - 1)), - num_bits: K, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); + #[test] + fn short_range_check() { + let proof_size = 1888; - test_against_stored_vk(&circuit, "short_range_check_case1"); + // Edge case: zero bits (case 0) + let element = pallas::Base::ZERO; + let num_bits = 0; + test_short_range_check( + element, + num_bits, + &Ok(()), + "short_range_check_case0", + proof_size, + ); - test_against_stored_proof(circuit, "short_range_check_case1", 0); - } + // Edge case: K bits (case 1) + let element = pallas::Base::from((1 << K) - 1); + let num_bits = K; + test_short_range_check( + element, + num_bits, + &Ok(()), + "short_range_check_case1", + proof_size, + ); // Element within `num_bits` (case 2) - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from((1 << 6) - 1)), - num_bits: 6, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - - test_against_stored_vk(&circuit, "short_range_check_case2"); - - test_against_stored_proof(circuit, "short_range_check_case2", 0); - } + let element = pallas::Base::from((1 << 6) - 1); + let num_bits = 6; + test_short_range_check( + element, + num_bits, + &Ok(()), + "short_range_check_case2", + proof_size, + ); // Element larger than `num_bits` but within K bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from(1 << 6)), - num_bits: 6, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![VerifyFailure::Lookup { + let element = pallas::Base::from(1 << 6); + let num_bits = 6; + test_short_range_check( + element, + num_bits, + &Err(vec![VerifyFailure::Lookup { + lookup_index: 0, + location: FailureLocation::InRegion { + region: (1, "Range check 6 bits").into(), + offset: 1, + }, + }]), + "not_saved", + proof_size, + ); + + // Element larger than K bits + let element = pallas::Base::from(1 << K); + let num_bits = 6; + test_short_range_check( + element, + num_bits, + &Err(vec![ + VerifyFailure::Lookup { lookup_index: 0, location: FailureLocation::InRegion { region: (1, "Range check 6 bits").into(), - offset: 1, - }, - }]) - ); - } - - // Element larger than K bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from(1 << K)), - num_bits: 6, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![ - VerifyFailure::Lookup { - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 0, - }, - }, - VerifyFailure::Lookup { - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 1, - }, + offset: 0, }, - ]) - ); - } - - // Element which is not within `num_bits`, but which has a shifted value within - // num_bits - { - let num_bits = 6; - let shifted = pallas::Base::from((1 << num_bits) - 1); - // Recall that shifted = element * 2^{K-s} - // => element = shifted * 2^{s-K} - let element = shifted - * pallas::Base::from(1 << (K as u64 - num_bits)) - .invert() - .unwrap(); - let circuit: MyCircuit = MyCircuit { - element: Value::known(element), - num_bits: num_bits as usize, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![VerifyFailure::Lookup { + }, + VerifyFailure::Lookup { lookup_index: 0, location: FailureLocation::InRegion { region: (1, "Range check 6 bits").into(), - offset: 0, + offset: 1, }, - }]) - ); - } + }, + ]), + "not_saved", + proof_size, + ); + + // Element which is not within `num_bits`, but which has a shifted value within num_bits + let num_bits = 6; + let shifted = pallas::Base::from((1 << num_bits) - 1); + // Recall that shifted = element * 2^{K-s} + // => element = shifted * 2^{s-K} + let element = shifted + * pallas::Base::from(1 << (K as u64 - num_bits)) + .invert() + .unwrap(); + test_short_range_check( + element, + num_bits as usize, + &Err(vec![VerifyFailure::Lookup { + lookup_index: 0, + location: FailureLocation::InRegion { + region: (1, "Range check 6 bits").into(), + offset: 0, + }, + }]), + "not_saved", + proof_size, + ); } } From e0822c5aa1721a283ce4d44c0f7542250afa2eba Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Tue, 2 Jul 2024 14:06:59 +0200 Subject: [PATCH 83/99] Refactor --- halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs index fe0ccd8d3d..9ad7ce1686 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs @@ -187,12 +187,14 @@ pub mod tests { use pasta_curves::pallas; use rand::rngs::OsRng; - use crate::ecc::{ - chip::{EccChip, FixedPoint as _, H}, - tests::{FullWidth, TestFixedBases}, - FixedPoint, NonIdentityPoint, Point, ScalarFixed, + use crate::{ + ecc::{ + chip::{EccChip, FixedPoint as _, H}, + tests::{FullWidth, TestFixedBases}, + FixedPoint, NonIdentityPoint, Point, ScalarFixed, + }, + utilities::lookup_range_check::PallasLookupRC, }; - use crate::utilities::lookup_range_check::PallasLookupRC; pub(crate) fn test_mul_fixed( chip: EccChip, From aef19cfa1fa2200c4df5904cc0da671cac2d79ea Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Tue, 2 Jul 2024 14:13:42 +0200 Subject: [PATCH 84/99] Remove MerkleSinsemillaInstructions --- halo2_gadgets/src/sinsemilla/merkle/chip.rs | 55 ++------------------- 1 file changed, 4 insertions(+), 51 deletions(-) diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs index b8ea59ead7..ad19b24c4e 100644 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla/merkle/chip.rs @@ -203,60 +203,13 @@ where } } -/// Defines the concrete types of `SinsemillaInstructions` required by the `MerkleCRH`. -pub(crate) trait MerkleSinsemillaInstructions -where - Self: SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - MessagePiece = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::MessagePiece, - RunningSum = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::RunningSum, - X = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::X, - >, - Hash: HashDomains, - Commit: CommitDomains, - F: FixedPoints, - Lookup: PallasLookupRC, -{ -} - -impl MerkleSinsemillaInstructions - for MerkleChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, - Lookup: PallasLookupRC, -{ -} - -impl +impl MerkleInstructions - for InstructionsChip + for MerkleChip where - InstructionsChip: MerkleSinsemillaInstructions - + UtilitiesInstructions> - + CondSwapInstructions - + Chip> - + Eq - + Clone - + std::fmt::Debug, - Hash: HashDomains, + Hash: HashDomains + Eq, Fixed: FixedPoints, - Commit: CommitDomains, + Commit: CommitDomains + Eq, Lookup: PallasLookupRC, { #[allow(non_snake_case)] From 5a517a51a13a36d3fcdb72a0dfbfe0ba19c925c2 Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Tue, 2 Jul 2024 14:50:47 +0200 Subject: [PATCH 85/99] Remove small functions in SinsemillaChip --- halo2_gadgets/src/sinsemilla/chip.rs | 61 ++++------------------------ 1 file changed, 8 insertions(+), 53 deletions(-) diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs index 069c115b2b..af29f3319a 100644 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ b/halo2_gadgets/src/sinsemilla/chip.rs @@ -161,31 +161,6 @@ where fixed_y_q: Column, lookup: (TableColumn, TableColumn, TableColumn), range_check: Lookup, - ) -> >::Config { - // create SinsemillaConfig - let config = Self::create_config( - meta, - advices, - witness_pieces, - fixed_y_q, - lookup, - range_check, - ); - - Self::create_initial_y_q_gate(meta, &config); - - Self::create_sinsemilla_gate(meta, &config); - - config - } - - pub(crate) fn create_config( - meta: &mut ConstraintSystem, - advices: [Column; 5], - witness_pieces: Column, - fixed_y_q: Column, - lookup: (TableColumn, TableColumn, TableColumn), - range_check: Lookup, ) -> >::Config { // Enable equality on all advice columns for advice in advices.iter() { @@ -217,17 +192,14 @@ where // Set up lookup argument GeneratorTableConfig::configure(meta, config.clone()); - config - } - - /// Assign y_q to a fixed column - #[allow(non_snake_case)] - fn create_initial_y_q_gate( - meta: &mut ConstraintSystem, - config: &SinsemillaConfig, - ) { let two = pallas::Base::from(2); + // Closures for expressions that are derived multiple times + // x_r = lambda_1^2 - x_a - x_p + let x_r = |meta: &mut VirtualCells, rotation| { + config.double_and_add.x_r(meta, rotation) + }; + // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) let Y_A = |meta: &mut VirtualCells, rotation| { config.double_and_add.Y_A(meta, rotation) @@ -247,25 +219,6 @@ where Constraints::with_selector(q_s4, Some(("init_y_q_check", init_y_q_check))) }); - } - - #[allow(non_snake_case)] - pub(crate) fn create_sinsemilla_gate( - meta: &mut ConstraintSystem, - config: &SinsemillaConfig, - ) { - let two = pallas::Base::from(2); - - // Closures for expressions that are derived multiple times - // x_r = lambda_1^2 - x_a - x_p - let x_r = |meta: &mut VirtualCells, rotation| { - config.double_and_add.x_r(meta, rotation) - }; - - // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) - let Y_A = |meta: &mut VirtualCells, rotation| { - config.double_and_add.Y_A(meta, rotation) - }; // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial meta.create_gate("Sinsemilla gate", |meta| { @@ -311,6 +264,8 @@ where Constraints::with_selector(q_s1, [("Secant line", secant_line), ("y check", y_check)]) }); + + config } } From 372c216c021957b3d3a44cd6d2ae17049a9083cc Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Tue, 2 Jul 2024 14:55:34 +0200 Subject: [PATCH 86/99] Refactor in lookup_range_check --- halo2_gadgets/src/utilities/lookup_range_check.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index a91afed75c..8203ea4b74 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -34,8 +34,8 @@ impl RangeConstrained> { /// # Panics /// /// Panics if `bitrange.len() >= K`. - pub fn witness_short>( - lookup_config: &L, + pub fn witness_short>( + lookup_config: &Lookup, layouter: impl Layouter, value: Value<&F>, bitrange: Range, @@ -458,10 +458,7 @@ impl PallasLookupRC for PallasLookupRCConfig {} #[cfg(test)] mod tests { - use super::{LookupRangeCheck, LookupRangeCheckConfig}; - use super::super::lebs2ip; - use crate::sinsemilla::primitives::K; use ff::{Field, PrimeFieldBits}; use halo2_proofs::{ @@ -471,7 +468,12 @@ mod tests { }; use pasta_curves::pallas; - use crate::tests::test_utils::test_against_stored_circuit; + use crate::{ + sinsemilla::primitives::K, + tests::test_utils::test_against_stored_circuit, + utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, + }; + use std::{convert::TryInto, marker::PhantomData}; #[derive(Clone, Copy)] From 1fe46805d27569190e08495d5f74474d159e82bd Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Tue, 2 Jul 2024 15:07:33 +0200 Subject: [PATCH 87/99] Rename PallasLookupRC(Config) PallasLookupRangeCheck <- PallasLookupRC PallasLookupRangeCheckConfig <- PallasLookupRCConfig --- halo2_gadgets/src/ecc.rs | 9 ++++---- halo2_gadgets/src/ecc/chip.rs | 20 ++++++++--------- halo2_gadgets/src/ecc/chip/mul.rs | 10 ++++----- halo2_gadgets/src/ecc/chip/mul/overflow.rs | 6 ++--- .../src/ecc/chip/mul_fixed/base_field_elem.rs | 18 ++++++++------- .../src/ecc/chip/mul_fixed/full_width.rs | 8 +++---- halo2_gadgets/src/ecc/chip/mul_fixed/short.rs | 17 ++++++++------ halo2_gadgets/src/sinsemilla.rs | 14 ++++++------ halo2_gadgets/src/sinsemilla/chip.rs | 18 +++++++-------- .../src/sinsemilla/chip/generator_table.rs | 4 ++-- .../src/sinsemilla/chip/hash_to_point.rs | 4 ++-- halo2_gadgets/src/sinsemilla/merkle.rs | 20 ++++++++++++----- halo2_gadgets/src/sinsemilla/merkle/chip.rs | 22 +++++++++---------- .../src/utilities/lookup_range_check.rs | 10 ++++----- 14 files changed, 98 insertions(+), 82 deletions(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index ec6e939d0b..067ef916c7 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -597,7 +597,7 @@ pub(crate) mod tests { }; use crate::{ tests::test_utils::test_against_stored_circuit, - utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRCConfig}, + utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRangeCheckConfig}, }; #[derive(Debug, Eq, PartialEq, Clone)] @@ -732,7 +732,7 @@ pub(crate) mod tests { #[allow(non_snake_case)] impl Circuit for MyCircuit { - type Config = EccConfig; + type Config = EccConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -767,8 +767,9 @@ pub(crate) mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); - let range_check = PallasLookupRCConfig::configure(meta, advices[9], lookup_table); - EccChip::::configure( + let range_check = + PallasLookupRangeCheckConfig::configure(meta, advices[9], lookup_table); + EccChip::::configure( meta, advices, lagrange_coeffs, diff --git a/halo2_gadgets/src/ecc/chip.rs b/halo2_gadgets/src/ecc/chip.rs index 926da7906e..8f731fd859 100644 --- a/halo2_gadgets/src/ecc/chip.rs +++ b/halo2_gadgets/src/ecc/chip.rs @@ -2,7 +2,7 @@ use super::{BaseFitsInScalarInstructions, EccInstructions, FixedPoints}; use crate::utilities::{ - lookup_range_check::{PallasLookupRC, PallasLookupRCConfig}, + lookup_range_check::{PallasLookupRangeCheck, PallasLookupRangeCheckConfig}, UtilitiesInstructions, }; use arrayvec::ArrayVec; @@ -139,7 +139,7 @@ impl From for EccPoint { #[allow(non_snake_case)] pub struct EccConfig< FixedPoints: super::FixedPoints, - Lookup: PallasLookupRC = PallasLookupRCConfig, + Lookup: PallasLookupRangeCheck = PallasLookupRangeCheckConfig, > { /// Advice columns needed by instructions in the ECC chip. pub advices: [Column; 10], @@ -232,13 +232,13 @@ pub trait FixedPoint: std::fmt::Debug + Eq + Clone { #[derive(Clone, Debug, Eq, PartialEq)] pub struct EccChip< FixedPoints: super::FixedPoints, - Lookup: PallasLookupRC = PallasLookupRCConfig, + Lookup: PallasLookupRangeCheck = PallasLookupRangeCheckConfig, > { config: EccConfig, } -impl, Lookup: PallasLookupRC> Chip - for EccChip +impl, Lookup: PallasLookupRangeCheck> + Chip for EccChip { type Config = EccConfig; type Loaded = (); @@ -252,13 +252,13 @@ impl, Lookup: PallasLookupRC> Ch } } -impl, Lookup: PallasLookupRC> +impl, Lookup: PallasLookupRangeCheck> UtilitiesInstructions for EccChip { type Var = AssignedCell; } -impl, Lookup: PallasLookupRC> +impl, Lookup: PallasLookupRangeCheck> EccChip { /// Reconstructs this chip from the given config. @@ -418,8 +418,8 @@ pub enum ScalarVar { FullWidth, } -impl, Lookup: PallasLookupRC> EccInstructions - for EccChip +impl, Lookup: PallasLookupRangeCheck> + EccInstructions for EccChip where >::Base: FixedPoint, @@ -606,7 +606,7 @@ where } } -impl, Lookup: PallasLookupRC> +impl, Lookup: PallasLookupRangeCheck> BaseFitsInScalarInstructions for EccChip where >::Base: diff --git a/halo2_gadgets/src/ecc/chip/mul.rs b/halo2_gadgets/src/ecc/chip/mul.rs index 9cf8391dc5..2714718a7a 100644 --- a/halo2_gadgets/src/ecc/chip/mul.rs +++ b/halo2_gadgets/src/ecc/chip/mul.rs @@ -1,6 +1,6 @@ use super::{add, EccPoint, NonIdentityEccPoint, ScalarVar, T_Q}; use crate::utilities::{ - lookup_range_check::{PallasLookupRC, PallasLookupRCConfig}, + lookup_range_check::{PallasLookupRangeCheck, PallasLookupRangeCheckConfig}, {bool_check, ternary}, }; use std::{ @@ -46,7 +46,7 @@ const INCOMPLETE_LO_LEN: usize = INCOMPLETE_LEN - INCOMPLETE_HI_LEN; const COMPLETE_RANGE: Range = INCOMPLETE_LEN..(INCOMPLETE_LEN + NUM_COMPLETE_BITS); #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { +pub struct Config { // Selector used to check switching logic on LSB q_mul_lsb: Selector, // Configuration used in complete addition @@ -61,7 +61,7 @@ pub struct Config { overflow_config: overflow::Config, } -impl Config { +impl Config { pub(super) fn configure( meta: &mut ConstraintSystem, add_config: add::Config, @@ -473,10 +473,10 @@ pub mod tests { tests::TestFixedBases, EccInstructions, NonIdentityPoint, Point, ScalarVar, }, - utilities::{lookup_range_check::PallasLookupRC, UtilitiesInstructions}, + utilities::{lookup_range_check::PallasLookupRangeCheck, UtilitiesInstructions}, }; - pub(crate) fn test_mul( + pub(crate) fn test_mul( chip: EccChip, mut layouter: impl Layouter, p: &NonIdentityPoint>, diff --git a/halo2_gadgets/src/ecc/chip/mul/overflow.rs b/halo2_gadgets/src/ecc/chip/mul/overflow.rs index 482594e62b..fb40781f7c 100644 --- a/halo2_gadgets/src/ecc/chip/mul/overflow.rs +++ b/halo2_gadgets/src/ecc/chip/mul/overflow.rs @@ -1,7 +1,7 @@ use super::{T_Q, Z}; use crate::{ sinsemilla::primitives as sinsemilla, - utilities::lookup_range_check::{PallasLookupRC, PallasLookupRCConfig}, + utilities::lookup_range_check::{PallasLookupRangeCheck, PallasLookupRangeCheckConfig}, }; use group::ff::PrimeField; @@ -16,7 +16,7 @@ use pasta_curves::pallas; use std::iter; #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { +pub struct Config { // Selector to check z_0 = alpha + t_q (mod p) q_mul_overflow: Selector, // 10-bit lookup table @@ -25,7 +25,7 @@ pub struct Config { advices: [Column; 3], } -impl Config { +impl Config { pub(super) fn configure( meta: &mut ConstraintSystem, lookup_config: Lookup, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs index e6060ec426..b39aa828e4 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs @@ -3,7 +3,7 @@ use super::H_BASE; use crate::utilities::{ bitrange_subset, bool_check, - lookup_range_check::{PallasLookupRC, PallasLookupRCConfig}, + lookup_range_check::{PallasLookupRangeCheck, PallasLookupRangeCheckConfig}, range_check, }; @@ -18,15 +18,17 @@ use pasta_curves::pallas; use std::convert::TryInto; #[derive(Clone, Debug, Eq, PartialEq)] -pub struct Config, Lookup: PallasLookupRC = PallasLookupRCConfig> -{ +pub struct Config< + Fixed: FixedPoints, + Lookup: PallasLookupRangeCheck = PallasLookupRangeCheckConfig, +> { q_mul_fixed_base_field: Selector, canon_advices: [Column; 3], lookup_config: Lookup, super_config: super::Config, } -impl, Lookup: PallasLookupRC> Config { +impl, Lookup: PallasLookupRangeCheck> Config { pub(crate) fn configure( meta: &mut ConstraintSystem, canon_advices: [Column; 3], @@ -389,7 +391,7 @@ pub mod tests { use pasta_curves::pallas; use rand::rngs::OsRng; - use crate::utilities::lookup_range_check::PallasLookupRC; + use crate::utilities::lookup_range_check::PallasLookupRangeCheck; use crate::{ ecc::{ chip::{EccChip, FixedPoint, H}, @@ -399,7 +401,7 @@ pub mod tests { utilities::UtilitiesInstructions, }; - pub(crate) fn test_mul_fixed_base_field( + pub(crate) fn test_mul_fixed_base_field( chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { @@ -412,7 +414,7 @@ pub mod tests { } #[allow(clippy::op_ref)] - fn test_single_base( + fn test_single_base( chip: EccChip, mut layouter: impl Layouter, base: FixedPointBaseField>, @@ -422,7 +424,7 @@ pub mod tests { let column = chip.config().advices[0]; - fn constrain_equal_non_id( + fn constrain_equal_non_id( chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs index 9ad7ce1686..393f065206 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs @@ -193,10 +193,10 @@ pub mod tests { tests::{FullWidth, TestFixedBases}, FixedPoint, NonIdentityPoint, Point, ScalarFixed, }, - utilities::lookup_range_check::PallasLookupRC, + utilities::lookup_range_check::PallasLookupRangeCheck, }; - pub(crate) fn test_mul_fixed( + pub(crate) fn test_mul_fixed( chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { @@ -212,13 +212,13 @@ pub mod tests { } #[allow(clippy::op_ref)] - fn test_single_base( + fn test_single_base( chip: EccChip, mut layouter: impl Layouter, base: FixedPoint>, base_val: pallas::Affine, ) -> Result<(), Error> { - fn constrain_equal_non_id( + fn constrain_equal_non_id( chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs index eb402d0f27..c2baaba5f8 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs @@ -260,13 +260,15 @@ pub mod tests { FixedPointShort, NonIdentityPoint, Point, ScalarFixedShort, }, utilities::{ - lookup_range_check::{LookupRangeCheck, PallasLookupRC, PallasLookupRCConfig}, + lookup_range_check::{ + LookupRangeCheck, PallasLookupRangeCheck, PallasLookupRangeCheckConfig, + }, UtilitiesInstructions, }, }; #[allow(clippy::op_ref)] - pub(crate) fn test_mul_fixed_short( + pub(crate) fn test_mul_fixed_short( chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { @@ -274,7 +276,7 @@ pub mod tests { let base_val = Short.generator(); let test_short = FixedPointShort::from_inner(chip.clone(), Short); - fn load_magnitude_sign( + fn load_magnitude_sign( chip: EccChip, mut layouter: impl Layouter, magnitude: pallas::Base, @@ -292,7 +294,7 @@ pub mod tests { Ok((magnitude, sign)) } - fn constrain_equal_non_id( + fn constrain_equal_non_id( chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, @@ -428,7 +430,7 @@ pub mod tests { } impl Circuit for MyCircuit { - type Config = EccConfig; + type Config = EccConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -464,8 +466,9 @@ pub mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); - let range_check = PallasLookupRCConfig::configure(meta, advices[9], lookup_table); - EccChip::::configure( + let range_check = + PallasLookupRangeCheckConfig::configure(meta, advices[9], lookup_table); + EccChip::::configure( meta, advices, lagrange_coeffs, diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 8b1be58365..d488933137 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -473,7 +473,7 @@ pub(crate) mod tests { }, sinsemilla::primitives::{self as sinsemilla, K}, tests::test_utils::test_against_stored_circuit, - utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRCConfig}, + utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRangeCheckConfig}, }; use group::{ff::Field, Curve}; @@ -519,18 +519,18 @@ pub(crate) mod tests { impl Circuit for MyCircuit { #[allow(clippy::type_complexity)] type Config = ( - EccConfig, + EccConfig, SinsemillaConfig< TestHashDomain, TestCommitDomain, TestFixedBases, - PallasLookupRCConfig, + PallasLookupRangeCheckConfig, >, SinsemillaConfig< TestHashDomain, TestCommitDomain, TestFixedBases, - PallasLookupRCConfig, + PallasLookupRangeCheckConfig, >, ); type FloorPlanner = SimpleFloorPlanner; @@ -577,9 +577,9 @@ pub(crate) mod tests { meta.lookup_table_column(), ); - let range_check = PallasLookupRCConfig::configure(meta, advices[9], table_idx); + let range_check = PallasLookupRangeCheckConfig::configure(meta, advices[9], table_idx); - let ecc_config = EccChip::::configure( + let ecc_config = EccChip::::configure( meta, advices, lagrange_coeffs, @@ -619,7 +619,7 @@ pub(crate) mod tests { TestHashDomain, TestCommitDomain, TestFixedBases, - PallasLookupRCConfig, + PallasLookupRangeCheckConfig, >::load(config.1.clone(), &mut layouter)?; // This MerkleCRH example is purely for illustrative purposes. diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs index af29f3319a..19f86a6b7d 100644 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ b/halo2_gadgets/src/sinsemilla/chip.rs @@ -9,7 +9,7 @@ use crate::{ chip::{DoubleAndAdd, NonIdentityEccPoint}, FixedPoints, }, - utilities::lookup_range_check::{PallasLookupRC, PallasLookupRCConfig}, + utilities::lookup_range_check::{PallasLookupRangeCheck, PallasLookupRangeCheckConfig}, }; use std::marker::PhantomData; @@ -30,12 +30,12 @@ mod hash_to_point; /// Configuration for the Sinsemilla hash chip #[derive(Eq, PartialEq, Clone, Debug)] -pub struct SinsemillaConfig +pub struct SinsemillaConfig where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookupRangeCheck, { /// Binary selector used in lookup argument and in the body of the Sinsemilla hash. q_sinsemilla1: Selector, @@ -68,7 +68,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookupRangeCheck, { /// Returns an array of all advice columns in this config, in arbitrary order. pub(super) fn advices(&self) -> [Column; 5] { @@ -98,12 +98,12 @@ where /// /// [Chip description](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html#plonk--halo-2-constraints). #[derive(Eq, PartialEq, Clone, Debug)] -pub struct SinsemillaChip +pub struct SinsemillaChip where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookupRangeCheck, { config: SinsemillaConfig, } @@ -113,7 +113,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookupRangeCheck, { type Config = SinsemillaConfig; type Loaded = (); @@ -132,7 +132,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookupRangeCheck, { /// Reconstructs this chip from the given config. pub fn construct(config: >::Config) -> Self { @@ -277,7 +277,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookupRangeCheck, { type CellValue = AssignedCell; diff --git a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs index 013995911c..96219016b2 100644 --- a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs +++ b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs @@ -8,7 +8,7 @@ use halo2_proofs::{ use super::{CommitDomains, FixedPoints, HashDomains}; use crate::{ sinsemilla::primitives::{self as sinsemilla, SINSEMILLA_S}, - utilities::lookup_range_check::PallasLookupRC, + utilities::lookup_range_check::PallasLookupRangeCheck, }; use pasta_curves::pallas; @@ -33,7 +33,7 @@ impl GeneratorTableConfig { Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookupRangeCheck, { let (table_idx, table_x, table_y) = ( config.generator_table.table_idx, diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 1470b33a5f..ab06b29d10 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -3,7 +3,7 @@ use super::{NonIdentityEccPoint, SinsemillaChip}; use crate::{ ecc::FixedPoints, sinsemilla::primitives::{self as sinsemilla, lebs2ip_k, INV_TWO_POW_K, SINSEMILLA_S}, - utilities::lookup_range_check::PallasLookupRC, + utilities::lookup_range_check::PallasLookupRangeCheck, }; use ff::Field; @@ -30,7 +30,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookupRangeCheck, { /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). #[allow(non_snake_case)] diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 1bb63d4f1a..bc08859c54 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -187,7 +187,7 @@ pub mod tests { tests::test_utils::test_against_stored_circuit, utilities::{ i2lebsp, - lookup_range_check::{LookupRangeCheck, PallasLookupRCConfig}, + lookup_range_check::{LookupRangeCheck, PallasLookupRangeCheckConfig}, UtilitiesInstructions, }, }; @@ -214,8 +214,18 @@ pub mod tests { impl Circuit for MyCircuit { type Config = ( - MerkleConfig, - MerkleConfig, + MerkleConfig< + TestHashDomain, + TestCommitDomain, + TestFixedBases, + PallasLookupRangeCheckConfig, + >, + MerkleConfig< + TestHashDomain, + TestCommitDomain, + TestFixedBases, + PallasLookupRangeCheckConfig, + >, ); type FloorPlanner = SimpleFloorPlanner; @@ -253,7 +263,7 @@ pub mod tests { meta.lookup_table_column(), ); - let range_check = PallasLookupRCConfig::configure(meta, advices[9], lookup.0); + let range_check = PallasLookupRangeCheckConfig::configure(meta, advices[9], lookup.0); let sinsemilla_config_1 = SinsemillaChip::configure( meta, @@ -288,7 +298,7 @@ pub mod tests { TestHashDomain, TestCommitDomain, TestFixedBases, - PallasLookupRCConfig, + PallasLookupRangeCheckConfig, >::load(config.0.sinsemilla_config.clone(), &mut layouter)?; // Construct Merkle chips which will be placed side-by-side in the circuit. diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs index ad19b24c4e..bc076f6c55 100644 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla/merkle/chip.rs @@ -12,7 +12,7 @@ use super::MerkleInstructions; use crate::{ sinsemilla::{primitives as sinsemilla, MessagePiece}, utilities::{ - lookup_range_check::{PallasLookupRC, PallasLookupRCConfig}, + lookup_range_check::{PallasLookupRangeCheck, PallasLookupRangeCheckConfig}, RangeConstrained, }, { @@ -31,12 +31,12 @@ use group::ff::PrimeField; /// Configuration for the `MerkleChip` implementation. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct MerkleConfig +pub struct MerkleConfig where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookupRangeCheck, { advices: [Column; 5], q_decompose: Selector, @@ -55,12 +55,12 @@ where /// This chip does **NOT** constrain `left⋆` and `right⋆` to be canonical encodings of /// `left` and `right`. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct MerkleChip +pub struct MerkleChip where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookupRangeCheck, { config: MerkleConfig, } @@ -70,7 +70,7 @@ where Hash: HashDomains, Fixed: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookupRangeCheck, { type Config = MerkleConfig; type Loaded = (); @@ -89,7 +89,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookupRangeCheck, { /// Configures the [`MerkleChip`]. pub fn configure( @@ -210,7 +210,7 @@ where Hash: HashDomains + Eq, Fixed: FixedPoints, Commit: CommitDomains + Eq, - Lookup: PallasLookupRC, + Lookup: PallasLookupRangeCheck, { #[allow(non_snake_case)] fn hash_layer( @@ -429,7 +429,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookupRangeCheck, { type Var = AssignedCell; } @@ -440,7 +440,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookupRangeCheck, { #[allow(clippy::type_complexity)] fn swap( @@ -462,7 +462,7 @@ where Hash: HashDomains, F: FixedPoints, Commit: CommitDomains, - Lookup: PallasLookupRC, + Lookup: PallasLookupRangeCheck, { type CellValue = as SinsemillaInstructions< pallas::Affine, diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 8203ea4b74..0334ccbab0 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -442,19 +442,19 @@ impl LookupRangeCheck for LookupRangeCh } } -/// `PallasLookupRC` a shorthand for `LookupRangeCheck` specialized with `pallas::Base` and +/// `PallasLookupRangeCheck` a shorthand for `LookupRangeCheck` specialized with `pallas::Base` and /// `sinsemilla::K` and used to improve readability. In addition, it extends /// the `LookupRangeCheck` with additional standard traits. -pub trait PallasLookupRC: +pub trait PallasLookupRangeCheck: LookupRangeCheck + Eq + PartialEq + Clone + Copy + Debug { } -/// `PallasLookupRCConfig` is a shorthand for `LookupRangeCheckConfig` specialized with +/// `PallasLookupRangeCheckConfig` is a shorthand for `LookupRangeCheckConfig` specialized with /// `pallas::Base` and `sinsemilla::K` and used to improve readability``` -pub type PallasLookupRCConfig = LookupRangeCheckConfig; +pub type PallasLookupRangeCheckConfig = LookupRangeCheckConfig; -impl PallasLookupRC for PallasLookupRCConfig {} +impl PallasLookupRangeCheck for PallasLookupRangeCheckConfig {} #[cfg(test)] mod tests { From b24153366405ce52c91612bd0410f76569a7747f Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Fri, 5 Jul 2024 14:00:58 +0200 Subject: [PATCH 88/99] Add Lookup generic argument in ecc tests --- halo2_gadgets/src/ecc.rs | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 067ef916c7..572952db69 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -579,6 +579,7 @@ impl> FixedPointShort { pub(crate) mod tests { use ff::PrimeField; use group::{prime::PrimeCurveAffine, Curve, Group}; + use std::marker::PhantomData; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, @@ -597,7 +598,7 @@ pub(crate) mod tests { }; use crate::{ tests::test_utils::test_against_stored_circuit, - utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRangeCheckConfig}, + utilities::lookup_range_check::{PallasLookupRangeCheck, PallasLookupRangeCheckConfig}, }; #[derive(Debug, Eq, PartialEq, Clone)] @@ -726,17 +727,21 @@ pub(crate) mod tests { type Base = BaseField; } - struct MyCircuit { + struct MyCircuit { test_errors: bool, + _lookup_marker: PhantomData, } #[allow(non_snake_case)] - impl Circuit for MyCircuit { - type Config = EccConfig; + impl Circuit for MyCircuit { + type Config = EccConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - MyCircuit { test_errors: false } + MyCircuit { + test_errors: false, + _lookup_marker: PhantomData, + } } fn configure(meta: &mut ConstraintSystem) -> Self::Config { @@ -767,9 +772,8 @@ pub(crate) mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); - let range_check = - PallasLookupRangeCheckConfig::configure(meta, advices[9], lookup_table); - EccChip::::configure( + let range_check = Lookup::configure(meta, advices[9], lookup_table); + EccChip::::configure( meta, advices, lagrange_coeffs, @@ -904,15 +908,21 @@ pub(crate) mod tests { #[test] fn ecc_chip() { - let k = 13; - let circuit = MyCircuit { test_errors: true }; + let k = 11; + let circuit: MyCircuit = MyCircuit { + test_errors: true, + _lookup_marker: PhantomData, + }; let prover = MockProver::run(k, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())) } #[test] - fn test_ecc_chip_against_stored_circuit() { - let circuit = MyCircuit { test_errors: false }; + fn test_against_stored_ecc_chip() { + let circuit: MyCircuit = MyCircuit { + test_errors: false, + _lookup_marker: PhantomData, + }; test_against_stored_circuit(circuit, "ecc_chip", 3872); } @@ -925,7 +935,10 @@ pub(crate) mod tests { root.fill(&WHITE).unwrap(); let root = root.titled("Ecc Chip Layout", ("sans-serif", 60)).unwrap(); - let circuit = MyCircuit { test_errors: false }; + let circuit: MyCircuit = MyCircuit { + test_errors: false, + _lookup_marker: PhantomData, + }; halo2_proofs::dev::CircuitLayout::default() .render(13, &circuit, &root) .unwrap(); From 4165304f08e89c0ae7bcb8fb7136903f099f5f1b Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Fri, 5 Jul 2024 14:10:42 +0200 Subject: [PATCH 89/99] Add Lookup generic argument in Sinsemilla tests --- .../src/ecc/chip/mul_fixed/base_field_elem.rs | 3 +- halo2_gadgets/src/sinsemilla.rs | 61 ++++++++++--------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs index b39aa828e4..0e0bc7ee4b 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs @@ -391,14 +391,13 @@ pub mod tests { use pasta_curves::pallas; use rand::rngs::OsRng; - use crate::utilities::lookup_range_check::PallasLookupRangeCheck; use crate::{ ecc::{ chip::{EccChip, FixedPoint, H}, tests::{BaseField, TestFixedBases}, FixedPointBaseField, NonIdentityPoint, Point, }, - utilities::UtilitiesInstructions, + utilities::{lookup_range_check::PallasLookupRangeCheck, UtilitiesInstructions}, }; pub(crate) fn test_mul_fixed_base_field( diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index d488933137..68392d147f 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -473,7 +473,7 @@ pub(crate) mod tests { }, sinsemilla::primitives::{self as sinsemilla, K}, tests::test_utils::test_against_stored_circuit, - utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRangeCheckConfig}, + utilities::lookup_range_check::{PallasLookupRangeCheck, PallasLookupRangeCheckConfig}, }; use group::{ff::Field, Curve}; @@ -481,6 +481,7 @@ pub(crate) mod tests { use pasta_curves::pallas; use std::convert::TryInto; + use std::marker::PhantomData; pub(crate) const PERSONALIZATION: &str = "MerkleCRH"; @@ -514,29 +515,25 @@ pub(crate) mod tests { } } - struct MyCircuit {} + struct MyCircuit { + _lookup_marker: PhantomData, + } + + type MyConfig = ( + EccConfig, + SinsemillaConfig, + SinsemillaConfig, + ); - impl Circuit for MyCircuit { + impl Circuit for MyCircuit { #[allow(clippy::type_complexity)] - type Config = ( - EccConfig, - SinsemillaConfig< - TestHashDomain, - TestCommitDomain, - TestFixedBases, - PallasLookupRangeCheckConfig, - >, - SinsemillaConfig< - TestHashDomain, - TestCommitDomain, - TestFixedBases, - PallasLookupRangeCheckConfig, - >, - ); + type Config = MyConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - MyCircuit {} + MyCircuit { + _lookup_marker: PhantomData, + } } #[allow(non_snake_case)] @@ -577,9 +574,9 @@ pub(crate) mod tests { meta.lookup_table_column(), ); - let range_check = PallasLookupRangeCheckConfig::configure(meta, advices[9], table_idx); + let range_check = Lookup::configure(meta, advices[9], table_idx); - let ecc_config = EccChip::::configure( + let ecc_config = EccChip::::configure( meta, advices, lagrange_coeffs, @@ -615,12 +612,10 @@ pub(crate) mod tests { let ecc_chip = EccChip::construct(config.0); // The two `SinsemillaChip`s share the same lookup table. - SinsemillaChip::< - TestHashDomain, - TestCommitDomain, - TestFixedBases, - PallasLookupRangeCheckConfig, - >::load(config.1.clone(), &mut layouter)?; + SinsemillaChip::::load( + config.1.clone(), + &mut layouter, + )?; // This MerkleCRH example is purely for illustrative purposes. // It is not an implementation of the Orchard protocol spec. @@ -747,14 +742,18 @@ pub(crate) mod tests { #[test] fn sinsemilla_chip() { let k = 11; - let circuit = MyCircuit {}; + let circuit: MyCircuit = MyCircuit { + _lookup_marker: PhantomData, + }; let prover = MockProver::run(k, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())) } #[test] fn test_sinsemilla_chip_against_stored_circuit() { - let circuit = MyCircuit {}; + let circuit: MyCircuit = MyCircuit { + _lookup_marker: PhantomData, + }; test_against_stored_circuit(circuit, "sinsemilla_chip", 4576); } @@ -768,7 +767,9 @@ pub(crate) mod tests { root.fill(&WHITE).unwrap(); let root = root.titled("SinsemillaHash", ("sans-serif", 60)).unwrap(); - let circuit = MyCircuit {}; + let circuit: MyCircuit = MyCircuit { + _lookup_marker: PhantomData, + }; halo2_proofs::dev::CircuitLayout::default() .render(11, &circuit, &root) .unwrap(); From c9e62f39c65b9e04af4942ec6eeb73eb0feb2f23 Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Fri, 5 Jul 2024 14:25:26 +0200 Subject: [PATCH 90/99] Refactor --- halo2_gadgets/src/ecc.rs | 2 +- halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs | 2 +- halo2_gadgets/src/utilities/lookup_range_check.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 572952db69..92bb976371 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -918,7 +918,7 @@ pub(crate) mod tests { } #[test] - fn test_against_stored_ecc_chip() { + fn test_ecc_chip_against_stored_circuit() { let circuit: MyCircuit = MyCircuit { test_errors: false, _lookup_marker: PhantomData, diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index ab06b29d10..b32b15c98f 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -17,7 +17,7 @@ use pasta_curves::{arithmetic::CurveAffine, pallas}; use std::ops::Deref; -/// Define an enum that can hold either a public or a private ECC Point +/// `EccPointQ` can hold either a public or a private ECC Point #[derive(Debug, Clone)] #[allow(dead_code)] pub enum EccPointQ<'a> { diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 0334ccbab0..f17b972bf6 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -58,7 +58,7 @@ impl RangeConstrained> { } } -/// Configuration that provides methods for a lookup range check. +/// Configuration that provides methods for a 10-bit lookup range check. #[derive(Eq, PartialEq, Debug, Clone, Copy)] pub struct LookupRangeCheckConfig { q_lookup: Selector, From 023551bfb13110a8cc77b53de08248cae74e848d Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Fri, 5 Jul 2024 14:26:47 +0200 Subject: [PATCH 91/99] Add Lookup generic argument in Lookup tests --- .../src/utilities/lookup_range_check.rs | 140 +++++++++--------- 1 file changed, 71 insertions(+), 69 deletions(-) diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index f17b972bf6..c1a3f481a8 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -471,23 +471,30 @@ mod tests { use crate::{ sinsemilla::primitives::K, tests::test_utils::test_against_stored_circuit, - utilities::lookup_range_check::{LookupRangeCheck, LookupRangeCheckConfig}, + utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRangeCheckConfig}, }; use std::{convert::TryInto, marker::PhantomData}; #[derive(Clone, Copy)] - struct MyLookupCircuit { + struct MyLookupCircuit> { num_words: usize, - _marker: PhantomData, + _field_marker: PhantomData, + _lookup_marker: PhantomData, } - impl Circuit for MyLookupCircuit { - type Config = LookupRangeCheckConfig; + impl + std::clone::Clone> Circuit + for MyLookupCircuit + { + type Config = Lookup; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - *self + MyLookupCircuit { + num_words: self.num_words, + _field_marker: PhantomData, + _lookup_marker: PhantomData, + } } fn configure(meta: &mut ConstraintSystem) -> Self::Config { @@ -496,7 +503,7 @@ mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); - LookupRangeCheckConfig::::configure(meta, running_sum, table_idx) + Lookup::configure(meta, running_sum, table_idx) } fn synthesize( @@ -562,10 +569,12 @@ mod tests { #[test] fn lookup_range_check() { - let circuit: MyLookupCircuit = MyLookupCircuit { - num_words: 6, - _marker: PhantomData, - }; + let circuit: MyLookupCircuit = + MyLookupCircuit { + num_words: 6, + _field_marker: PhantomData, + _lookup_marker: PhantomData, + }; let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); @@ -573,27 +582,33 @@ mod tests { #[test] fn test_lookup_range_check_against_stored_circuit() { - let circuit: MyLookupCircuit = MyLookupCircuit { - num_words: 6, - _marker: PhantomData, - }; + let circuit: MyLookupCircuit = + MyLookupCircuit { + num_words: 6, + _field_marker: PhantomData, + _lookup_marker: PhantomData, + }; test_against_stored_circuit(circuit, "lookup_range_check", 1888); } #[derive(Clone, Copy)] - struct MyShortRangeCheckCircuit { + struct MyShortRangeCheckCircuit> { element: Value, num_bits: usize, + _lookup_marker: PhantomData, } - impl Circuit for MyShortRangeCheckCircuit { - type Config = LookupRangeCheckConfig; + impl + std::clone::Clone> Circuit + for MyShortRangeCheckCircuit + { + type Config = Lookup; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { MyShortRangeCheckCircuit { element: Value::unknown(), num_bits: self.num_bits, + _lookup_marker: PhantomData, } } @@ -603,7 +618,7 @@ mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); - LookupRangeCheckConfig::::configure(meta, running_sum, table_idx) + Lookup::configure(meta, running_sum, table_idx) } fn synthesize( @@ -632,10 +647,12 @@ mod tests { circuit_name: &str, expected_proof_size: usize, ) { - let circuit: MyShortRangeCheckCircuit = MyShortRangeCheckCircuit { - element: Value::known(element), - num_bits, - }; + let circuit: MyShortRangeCheckCircuit = + MyShortRangeCheckCircuit { + element: Value::known(element), + num_bits, + _lookup_marker: PhantomData, + }; let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), *proof_result); @@ -684,45 +701,35 @@ mod tests { // Element larger than `num_bits` but within K bits let element = pallas::Base::from(1 << 6); let num_bits = 6; - test_short_range_check( - element, - num_bits, - &Err(vec![VerifyFailure::Lookup { - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 1, - }, - }]), - "not_saved", - proof_size, - ); + let error = Err(vec![VerifyFailure::Lookup { + lookup_index: 0, + location: FailureLocation::InRegion { + region: (1, "Range check 6 bits").into(), + offset: 1, + }, + }]); + test_short_range_check(element, num_bits, &error, "not_saved", proof_size); // Element larger than K bits let element = pallas::Base::from(1 << K); let num_bits = 6; - test_short_range_check( - element, - num_bits, - &Err(vec![ - VerifyFailure::Lookup { - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 0, - }, + let error = Err(vec![ + VerifyFailure::Lookup { + lookup_index: 0, + location: FailureLocation::InRegion { + region: (1, "Range check 6 bits").into(), + offset: 0, }, - VerifyFailure::Lookup { - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 1, - }, + }, + VerifyFailure::Lookup { + lookup_index: 0, + location: FailureLocation::InRegion { + region: (1, "Range check 6 bits").into(), + offset: 1, }, - ]), - "not_saved", - proof_size, - ); + }, + ]); + test_short_range_check(element, num_bits, &error, "not_saved", proof_size); // Element which is not within `num_bits`, but which has a shifted value within num_bits let num_bits = 6; @@ -733,18 +740,13 @@ mod tests { * pallas::Base::from(1 << (K as u64 - num_bits)) .invert() .unwrap(); - test_short_range_check( - element, - num_bits as usize, - &Err(vec![VerifyFailure::Lookup { - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 0, - }, - }]), - "not_saved", - proof_size, - ); + let error = Err(vec![VerifyFailure::Lookup { + lookup_index: 0, + location: FailureLocation::InRegion { + region: (1, "Range check 6 bits").into(), + offset: 0, + }, + }]); + test_short_range_check(element, num_bits as usize, &error, "not_saved", proof_size); } } From 20907a81fea38c9cc392f31cdfe173206fdfb50a Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Sun, 7 Jul 2024 16:54:14 +0200 Subject: [PATCH 92/99] Add Lookup generic argument into mul_fixed/short tests --- halo2_gadgets/src/ecc/chip/mul_fixed/short.rs | 503 +++++++++--------- 1 file changed, 258 insertions(+), 245 deletions(-) diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs index c2baaba5f8..ac5d57214f 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs @@ -248,21 +248,21 @@ pub mod tests { use group::{ff::PrimeField, Curve}; use halo2_proofs::{ arithmetic::CurveAffine, - circuit::{AssignedCell, Chip, Layouter, Value}, - plonk::{Any, Error}, + circuit::{AssignedCell, Chip, Layouter, SimpleFloorPlanner, Value}, + dev::{FailureLocation, MockProver, VerifyFailure}, + plonk::{Any, Circuit, ConstraintSystem, Error}, }; use pasta_curves::pallas; + use std::marker::PhantomData; use crate::{ ecc::{ - chip::{EccChip, FixedPoint, MagnitudeSign}, + chip::{EccChip, EccConfig, FixedPoint, MagnitudeSign}, tests::{Short, TestFixedBases}, FixedPointShort, NonIdentityPoint, Point, ScalarFixedShort, }, utilities::{ - lookup_range_check::{ - LookupRangeCheck, PallasLookupRangeCheck, PallasLookupRangeCheckConfig, - }, + lookup_range_check::{PallasLookupRangeCheck, PallasLookupRangeCheckConfig}, UtilitiesInstructions, }, }; @@ -405,267 +405,280 @@ pub mod tests { Ok(()) } - #[test] - fn invalid_magnitude_sign() { - use crate::{ - ecc::chip::{EccConfig, FixedPoint}, - utilities::UtilitiesInstructions, - }; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - dev::{FailureLocation, MockProver, VerifyFailure}, - plonk::{Circuit, ConstraintSystem, Error}, - }; - - #[derive(Default)] - struct MyCircuit { - magnitude: Value, - sign: Value, - // For test checking - magnitude_error: Value, - } + #[derive(Default)] + struct MyMagnitudeSignCircuit { + magnitude: Value, + sign: Value, + // For test checking + magnitude_error: Value, + _lookup_marker: PhantomData, + } - impl UtilitiesInstructions for MyCircuit { - type Var = AssignedCell; - } + impl UtilitiesInstructions + for MyMagnitudeSignCircuit + { + type Var = AssignedCell; + } - impl Circuit for MyCircuit { - type Config = EccConfig; - type FloorPlanner = SimpleFloorPlanner; + impl Circuit for MyMagnitudeSignCircuit { + type Config = EccConfig; + type FloorPlanner = SimpleFloorPlanner; - fn without_witnesses(&self) -> Self { - Self::default() + fn without_witnesses(&self) -> Self { + MyMagnitudeSignCircuit { + magnitude: Value::unknown(), + sign: Value::unknown(), + magnitude_error: Value::unknown(), + _lookup_marker: PhantomData, } + } - 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(), - ]; - let lookup_table = 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(), - ]; + 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(), + ]; + let lookup_table = 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(), + ]; - // Shared fixed column for loading constants - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - let range_check = - PallasLookupRangeCheckConfig::configure(meta, advices[9], lookup_table); - EccChip::::configure( - meta, - advices, - lagrange_coeffs, - range_check, - ) - } + // Shared fixed column for loading constants + let constants = meta.fixed_column(); + meta.enable_constant(constants); - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let column = config.advices[0]; - - let short_config = config.mul_fixed_short.clone(); - let magnitude_sign = { - let magnitude = self.load_private( - layouter.namespace(|| "load magnitude"), - column, - self.magnitude, - )?; - let sign = - self.load_private(layouter.namespace(|| "load sign"), column, self.sign)?; - ScalarFixedShort::new( - EccChip::construct(config), - layouter.namespace(|| "signed short scalar"), - (magnitude, sign), - )? - }; + let range_check = Lookup::configure(meta, advices[9], lookup_table); + EccChip::::configure( + meta, + advices, + lagrange_coeffs, + range_check, + ) + } - short_config.assign(layouter, &magnitude_sign.inner, &Short)?; + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let column = config.advices[0]; + + let short_config = config.mul_fixed_short.clone(); + let magnitude_sign = { + let magnitude = self.load_private( + layouter.namespace(|| "load magnitude"), + column, + self.magnitude, + )?; + let sign = + self.load_private(layouter.namespace(|| "load sign"), column, self.sign)?; + ScalarFixedShort::new( + EccChip::construct(config), + layouter.namespace(|| "signed short scalar"), + (magnitude, sign), + )? + }; - Ok(()) - } + short_config.assign(layouter, &magnitude_sign.inner, &Short)?; + + Ok(()) } + } - // Copied from halo2_proofs::dev::util - fn format_value(v: pallas::Base) -> String { - use ff::Field; - if v.is_zero_vartime() { - "0".into() - } else if v == pallas::Base::one() { - "1".into() - } else if v == -pallas::Base::one() { - "-1".into() - } else { - // Format value as hex. - let s = format!("{:?}", v); - // Remove leading zeroes. - let s = s.strip_prefix("0x").unwrap(); - let s = s.trim_start_matches('0'); - format!("0x{}", s) - } + // Copied from halo2_proofs::dev::util + fn format_value(v: pallas::Base) -> String { + use ff::Field; + if v.is_zero_vartime() { + "0".into() + } else if v == pallas::Base::one() { + "1".into() + } else if v == -pallas::Base::one() { + "-1".into() + } else { + // Format value as hex. + let s = format!("{:?}", v); + // Remove leading zeroes. + let s = s.strip_prefix("0x").unwrap(); + let s = s.trim_start_matches('0'); + format!("0x{}", s) } + } - // Magnitude larger than 64 bits should fail - { - let circuits = [ - // 2^64 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 64)), - sign: Value::known(pallas::Base::one()), - magnitude_error: Value::known(pallas::Base::from(1 << 1)), - }, - // -2^64 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 64)), - sign: Value::known(-pallas::Base::one()), - magnitude_error: Value::known(pallas::Base::from(1 << 1)), - }, - // 2^66 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 66)), - sign: Value::known(pallas::Base::one()), - magnitude_error: Value::known(pallas::Base::from(1 << 3)), - }, - // -2^66 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 66)), - sign: Value::known(-pallas::Base::one()), - magnitude_error: Value::known(pallas::Base::from(1 << 3)), - }, - // 2^254 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 127).square()), - sign: Value::known(pallas::Base::one()), - magnitude_error: Value::known( - pallas::Base::from_u128(1 << 95).square() * pallas::Base::from(2), - ), - }, - // -2^254 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 127).square()), - sign: Value::known(-pallas::Base::one()), - magnitude_error: Value::known( - pallas::Base::from_u128(1 << 95).square() * pallas::Base::from(2), - ), - }, - ]; + impl MyMagnitudeSignCircuit { + fn test_invalid_magnitude_sign() { + // Magnitude larger than 64 bits should fail + { + let circuits = [ + // 2^64 + 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 + 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 + 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 + 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 + MyMagnitudeSignCircuit:: { + magnitude: Value::known(pallas::Base::from_u128(1 << 127).square()), + sign: Value::known(pallas::Base::one()), + magnitude_error: Value::known( + pallas::Base::from_u128(1 << 95).square() * pallas::Base::from(2), + ), + _lookup_marker: PhantomData, + }, + // -2^254 + MyMagnitudeSignCircuit:: { + magnitude: Value::known(pallas::Base::from_u128(1 << 127).square()), + sign: Value::known(-pallas::Base::one()), + magnitude_error: Value::known( + pallas::Base::from_u128(1 << 95).square() * pallas::Base::from(2), + ), + _lookup_marker: PhantomData, + }, + ]; - for circuit in circuits.iter() { - let prover = MockProver::::run(11, circuit, vec![]).unwrap(); - circuit.magnitude_error.assert_if_known(|magnitude_error| { - assert_eq!( - prover.verify(), - Err(vec![ - VerifyFailure::ConstraintNotSatisfied { - constraint: ( - (17, "Short fixed-base mul gate").into(), - 0, - "last_window_check", - ) - .into(), - location: FailureLocation::InRegion { - region: (3, "Short fixed-base mul (most significant word)") + for circuit in circuits.iter() { + let prover = MockProver::::run(11, circuit, vec![]).unwrap(); + circuit.magnitude_error.assert_if_known(|magnitude_error| { + assert_eq!( + prover.verify(), + Err(vec![ + VerifyFailure::ConstraintNotSatisfied { + constraint: ( + (17, "Short fixed-base mul gate").into(), + 0, + "last_window_check", + ) .into(), - offset: 1, + location: FailureLocation::InRegion { + region: (3, "Short fixed-base mul (most significant word)") + .into(), + offset: 1, + }, + cell_values: vec![( + ((Any::Advice, 5).into(), 0).into(), + format_value(*magnitude_error), + )], }, - cell_values: vec![( - ((Any::Advice, 5).into(), 0).into(), - format_value(*magnitude_error), - )], - }, - VerifyFailure::Permutation { - column: (Any::Fixed, 9).into(), - location: FailureLocation::OutsideRegion { row: 0 }, - }, - VerifyFailure::Permutation { - column: (Any::Advice, 4).into(), - location: FailureLocation::InRegion { - region: (2, "Short fixed-base mul (incomplete addition)") - .into(), - offset: 22, + VerifyFailure::Permutation { + column: (Any::Fixed, 9).into(), + location: FailureLocation::OutsideRegion { row: 0 }, }, - }, - ]) - ); - true - }); + VerifyFailure::Permutation { + column: (Any::Advice, 4).into(), + location: FailureLocation::InRegion { + region: (2, "Short fixed-base mul (incomplete addition)") + .into(), + offset: 22, + }, + }, + ]) + ); + true + }); + } } - } - // Sign that is not +/- 1 should fail - { - let magnitude_u64 = rand::random::(); - let circuit = MyCircuit { - magnitude: Value::known(pallas::Base::from(magnitude_u64)), - sign: Value::known(pallas::Base::zero()), - magnitude_error: Value::unknown(), - }; + // Sign that is not +/- 1 should fail + { + let magnitude_u64 = rand::random::(); + let circuit: MyMagnitudeSignCircuit = MyMagnitudeSignCircuit { + magnitude: Value::known(pallas::Base::from(magnitude_u64)), + sign: Value::known(pallas::Base::zero()), + magnitude_error: Value::unknown(), + _lookup_marker: PhantomData, + }; - let negation_check_y = { - *(Short.generator() * pallas::Scalar::from(magnitude_u64)) - .to_affine() - .coordinates() - .unwrap() - .y() - }; + let negation_check_y = { + *(Short.generator() * pallas::Scalar::from(magnitude_u64)) + .to_affine() + .coordinates() + .unwrap() + .y() + }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![ - VerifyFailure::ConstraintNotSatisfied { - constraint: ((17, "Short fixed-base mul gate").into(), 1, "sign_check") - .into(), - location: FailureLocation::InRegion { - region: (3, "Short fixed-base mul (most significant word)").into(), - offset: 1, - }, - cell_values: vec![(((Any::Advice, 4).into(), 0).into(), "0".to_string())], - }, - VerifyFailure::ConstraintNotSatisfied { - constraint: ( - (17, "Short fixed-base mul gate").into(), - 3, - "negation_check" - ) - .into(), - location: FailureLocation::InRegion { - region: (3, "Short fixed-base mul (most significant word)").into(), - offset: 1, + let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); + assert_eq!( + prover.verify(), + Err(vec![ + VerifyFailure::ConstraintNotSatisfied { + constraint: ((17, "Short fixed-base mul gate").into(), 1, "sign_check") + .into(), + location: FailureLocation::InRegion { + region: (3, "Short fixed-base mul (most significant word)").into(), + offset: 1, + }, + cell_values: vec![( + ((Any::Advice, 4).into(), 0).into(), + "0".to_string() + )], }, - cell_values: vec![ - ( - ((Any::Advice, 1).into(), 0).into(), - format_value(negation_check_y), - ), - ( - ((Any::Advice, 3).into(), 0).into(), - format_value(negation_check_y), - ), - (((Any::Advice, 4).into(), 0).into(), "0".to_string()), - ], - } - ]) - ); + VerifyFailure::ConstraintNotSatisfied { + constraint: ( + (17, "Short fixed-base mul gate").into(), + 3, + "negation_check" + ) + .into(), + location: FailureLocation::InRegion { + region: (3, "Short fixed-base mul (most significant word)").into(), + offset: 1, + }, + cell_values: vec![ + ( + ((Any::Advice, 1).into(), 0).into(), + format_value(negation_check_y), + ), + ( + ((Any::Advice, 3).into(), 0).into(), + format_value(negation_check_y), + ), + (((Any::Advice, 4).into(), 0).into(), "0".to_string()), + ], + } + ]) + ); + } } } + + #[test] + fn invalid_magnitude_sign() { + MyMagnitudeSignCircuit::::test_invalid_magnitude_sign(); + } } From 632313c7e17f5c9a40f896b1a5f3a9d88848104b Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Sun, 7 Jul 2024 17:14:38 +0200 Subject: [PATCH 93/99] Add Lookup generic argument into Merkle tests --- halo2_gadgets/src/sinsemilla/merkle.rs | 64 +++++++++++++------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index bc08859c54..529d4b5e09 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -186,9 +186,7 @@ pub mod tests { }, tests::test_utils::test_against_stored_circuit, utilities::{ - i2lebsp, - lookup_range_check::{LookupRangeCheck, PallasLookupRangeCheckConfig}, - UtilitiesInstructions, + i2lebsp, lookup_range_check::PallasLookupRangeCheckConfig, UtilitiesInstructions, }, }; @@ -200,37 +198,37 @@ pub mod tests { plonk::{Circuit, ConstraintSystem, Error}, }; + use crate::utilities::lookup_range_check::PallasLookupRangeCheck; use rand::{rngs::OsRng, RngCore}; + use std::marker::PhantomData; use std::{convert::TryInto, iter}; const MERKLE_DEPTH: usize = 32; #[derive(Default)] - struct MyCircuit { + struct MyCircuit { leaf: Value, leaf_pos: Value, merkle_path: Value<[pallas::Base; MERKLE_DEPTH]>, + _lookup_marker: PhantomData, } - impl Circuit for MyCircuit { - type Config = ( - MerkleConfig< - TestHashDomain, - TestCommitDomain, - TestFixedBases, - PallasLookupRangeCheckConfig, - >, - MerkleConfig< - TestHashDomain, - TestCommitDomain, - TestFixedBases, - PallasLookupRangeCheckConfig, - >, - ); + type MyConfig = ( + MerkleConfig, + MerkleConfig, + ); + + impl Circuit for MyCircuit { + type Config = MyConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - Self::default() + MyCircuit { + leaf: Value::default(), + leaf_pos: Value::default(), + merkle_path: Value::default(), + _lookup_marker: PhantomData, + } } fn configure(meta: &mut ConstraintSystem) -> Self::Config { @@ -263,7 +261,7 @@ pub mod tests { meta.lookup_table_column(), ); - let range_check = PallasLookupRangeCheckConfig::configure(meta, advices[9], lookup.0); + let range_check = Lookup::configure(meta, advices[9], lookup.0); let sinsemilla_config_1 = SinsemillaChip::configure( meta, @@ -294,12 +292,10 @@ pub mod tests { mut layouter: impl Layouter, ) -> Result<(), Error> { // Load generator table (shared across both configs) - SinsemillaChip::< - TestHashDomain, - TestCommitDomain, - TestFixedBases, - PallasLookupRangeCheckConfig, - >::load(config.0.sinsemilla_config.clone(), &mut layouter)?; + SinsemillaChip::::load( + config.0.sinsemilla_config.clone(), + &mut layouter, + )?; // Construct Merkle chips which will be placed side-by-side in the circuit. let chip_1 = MerkleChip::construct(config.0.clone()); @@ -372,7 +368,7 @@ pub mod tests { } } - fn generate_circuit() -> MyCircuit { + fn generate_circuit() -> MyCircuit { let mut rng = OsRng; // Choose a random leaf and position @@ -389,12 +385,13 @@ pub mod tests { leaf: Value::known(leaf), leaf_pos: Value::known(pos), merkle_path: Value::known(path.try_into().unwrap()), + _lookup_marker: PhantomData, } } #[test] fn merkle_chip() { - let circuit = generate_circuit(); + let circuit: MyCircuit = generate_circuit(); let prover = MockProver::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())) @@ -402,7 +399,7 @@ pub mod tests { #[test] fn test_merkle_chip_against_stored_circuit() { - let circuit = generate_circuit(); + let circuit: MyCircuit = generate_circuit(); test_against_stored_circuit(circuit, "merkle_chip", 4160); } @@ -415,7 +412,12 @@ pub mod tests { root.fill(&WHITE).unwrap(); let root = root.titled("MerkleCRH Path", ("sans-serif", 60)).unwrap(); - let circuit = MyCircuit::default(); + let circuit: MyCircuit = MyCircuit { + leaf: Value::default(), + leaf_pos: Value::default(), + merkle_path: Value::default(), + _lookup_marker: PhantomData, + }; halo2_proofs::dev::CircuitLayout::default() .show_labels(false) .render(11, &circuit, &root) From 194162f34071bff98af62bbfd8d3ae508b6d0ea9 Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Sun, 7 Jul 2024 17:21:24 +0200 Subject: [PATCH 94/99] Refactor --- .../src/sinsemilla/chip/hash_to_point.rs | 148 +++++++++--------- halo2_gadgets/src/sinsemilla/merkle.rs | 8 +- 2 files changed, 78 insertions(+), 78 deletions(-) diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index b32b15c98f..5d08d170db 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -180,80 +180,6 @@ where Ok((x_a, y_a, zs_sum)) } - #[allow(unused_variables)] - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - fn check_hash_result( - &self, - Q: EccPointQ, - message: &>::Message, - x_a: X, - y_a: AssignedCell, pallas::Base>, - zs_sum: Vec>>, - ) -> Result< - ( - NonIdentityEccPoint, - Vec>>, - ), - Error, - > { - #[cfg(test)] - // Check equivalence to result from primitives::sinsemilla::hash_to_point - { - use crate::sinsemilla::primitives::{K, S_PERSONALIZATION}; - - use group::{prime::PrimeCurveAffine, Curve}; - use pasta_curves::arithmetic::CurveExt; - - let field_elems: Value> = message - .iter() - .map(|piece| piece.field_elem().map(|elem| (elem, piece.num_words()))) - .collect(); - - let value_Q = match Q { - EccPointQ::PublicPoint(p) => Value::known(p), - EccPointQ::PrivatePoint(p) => p.point(), - }; - - field_elems - .zip(x_a.value().zip(y_a.value())) - .zip(value_Q) - .assert_if_known(|((field_elems, (x_a, y_a)), value_Q)| { - // Get message as a bitstring. - let bitstring: Vec = field_elems - .iter() - .flat_map(|(elem, num_words)| { - elem.to_le_bits().into_iter().take(K * num_words) - }) - .collect(); - - let hasher_S = pallas::Point::hash_to_curve(S_PERSONALIZATION); - let S = |chunk: &[bool]| hasher_S(&lebs2ip_k(chunk).to_le_bytes()); - - // We can use complete addition here because it differs from - // incomplete addition with negligible probability. - let expected_point = bitstring - .chunks(K) - .fold(value_Q.to_curve(), |acc, chunk| (acc + S(chunk)) + acc); - let actual_point = - pallas::Affine::from_xy(x_a.evaluate(), y_a.evaluate()).unwrap(); - expected_point.to_affine() == actual_point - }); - } - - 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, - )) - } - #[allow(clippy::type_complexity)] /// Hashes a message piece containing `piece.length` number of `K`-bit words. /// @@ -459,6 +385,80 @@ where Ok((x_a, y_a, zs)) } + + #[allow(unused_variables)] + #[allow(non_snake_case)] + #[allow(clippy::type_complexity)] + fn check_hash_result( + &self, + Q: EccPointQ, + message: &>::Message, + x_a: X, + y_a: AssignedCell, pallas::Base>, + zs_sum: Vec>>, + ) -> Result< + ( + NonIdentityEccPoint, + Vec>>, + ), + Error, + > { + #[cfg(test)] + // Check equivalence to result from primitives::sinsemilla::hash_to_point + { + use crate::sinsemilla::primitives::{K, S_PERSONALIZATION}; + + use group::{prime::PrimeCurveAffine, Curve}; + use pasta_curves::arithmetic::CurveExt; + + let field_elems: Value> = message + .iter() + .map(|piece| piece.field_elem().map(|elem| (elem, piece.num_words()))) + .collect(); + + let value_Q = match Q { + EccPointQ::PublicPoint(p) => Value::known(p), + EccPointQ::PrivatePoint(p) => p.point(), + }; + + field_elems + .zip(x_a.value().zip(y_a.value())) + .zip(value_Q) + .assert_if_known(|((field_elems, (x_a, y_a)), value_Q)| { + // Get message as a bitstring. + let bitstring: Vec = field_elems + .iter() + .flat_map(|(elem, num_words)| { + elem.to_le_bits().into_iter().take(K * num_words) + }) + .collect(); + + let hasher_S = pallas::Point::hash_to_curve(S_PERSONALIZATION); + let S = |chunk: &[bool]| hasher_S(&lebs2ip_k(chunk).to_le_bytes()); + + // We can use complete addition here because it differs from + // incomplete addition with negligible probability. + let expected_point = bitstring + .chunks(K) + .fold(value_Q.to_curve(), |acc, chunk| (acc + S(chunk)) + acc); + let actual_point = + pallas::Affine::from_xy(x_a.evaluate(), y_a.evaluate()).unwrap(); + expected_point.to_affine() == actual_point + }); + } + + 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, + )) + } } /// The x-coordinate of the accumulator in a Sinsemilla hash instance. diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 529d4b5e09..4b56d18727 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -186,7 +186,9 @@ pub mod tests { }, tests::test_utils::test_against_stored_circuit, utilities::{ - i2lebsp, lookup_range_check::PallasLookupRangeCheckConfig, UtilitiesInstructions, + i2lebsp, + lookup_range_check::{PallasLookupRangeCheck, PallasLookupRangeCheckConfig}, + UtilitiesInstructions, }, }; @@ -198,10 +200,8 @@ pub mod tests { plonk::{Circuit, ConstraintSystem, Error}, }; - use crate::utilities::lookup_range_check::PallasLookupRangeCheck; use rand::{rngs::OsRng, RngCore}; - use std::marker::PhantomData; - use std::{convert::TryInto, iter}; + use std::{convert::TryInto, iter, marker::PhantomData}; const MERKLE_DEPTH: usize = 32; From f64d62fa2974554f9be6b81679cb4527c95842e5 Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Mon, 8 Jul 2024 17:56:24 +0200 Subject: [PATCH 95/99] Add generic Lookup argument in short_range_check tests --- .../src/utilities/lookup_range_check.rs | 47 +++++++++++++------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index c1a3f481a8..894bc87f87 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -471,7 +471,9 @@ mod tests { use crate::{ sinsemilla::primitives::K, tests::test_utils::test_against_stored_circuit, - utilities::lookup_range_check::{LookupRangeCheck, PallasLookupRangeCheckConfig}, + utilities::lookup_range_check::{ + LookupRangeCheck, PallasLookupRangeCheck, PallasLookupRangeCheckConfig, + }, }; use std::{convert::TryInto, marker::PhantomData}; @@ -640,19 +642,18 @@ mod tests { } } - fn test_short_range_check( + fn test_short_range_check( element: pallas::Base, num_bits: usize, proof_result: &Result<(), Vec>, circuit_name: &str, expected_proof_size: usize, ) { - let circuit: MyShortRangeCheckCircuit = - MyShortRangeCheckCircuit { - element: Value::known(element), - num_bits, - _lookup_marker: PhantomData, - }; + let circuit: MyShortRangeCheckCircuit = MyShortRangeCheckCircuit { + element: Value::known(element), + num_bits, + _lookup_marker: PhantomData, + }; let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), *proof_result); @@ -668,7 +669,7 @@ mod tests { // Edge case: zero bits (case 0) let element = pallas::Base::ZERO; let num_bits = 0; - test_short_range_check( + test_short_range_check::( element, num_bits, &Ok(()), @@ -679,7 +680,7 @@ mod tests { // Edge case: K bits (case 1) let element = pallas::Base::from((1 << K) - 1); let num_bits = K; - test_short_range_check( + test_short_range_check::( element, num_bits, &Ok(()), @@ -690,7 +691,7 @@ mod tests { // Element within `num_bits` (case 2) let element = pallas::Base::from((1 << 6) - 1); let num_bits = 6; - test_short_range_check( + test_short_range_check::( element, num_bits, &Ok(()), @@ -708,7 +709,13 @@ mod tests { offset: 1, }, }]); - test_short_range_check(element, num_bits, &error, "not_saved", proof_size); + test_short_range_check::( + element, + num_bits, + &error, + "not_saved", + proof_size, + ); // Element larger than K bits let element = pallas::Base::from(1 << K); @@ -729,7 +736,13 @@ mod tests { }, }, ]); - test_short_range_check(element, num_bits, &error, "not_saved", proof_size); + test_short_range_check::( + element, + num_bits, + &error, + "not_saved", + proof_size, + ); // Element which is not within `num_bits`, but which has a shifted value within num_bits let num_bits = 6; @@ -747,6 +760,12 @@ mod tests { offset: 0, }, }]); - test_short_range_check(element, num_bits as usize, &error, "not_saved", proof_size); + test_short_range_check::( + element, + num_bits as usize, + &error, + "not_saved", + proof_size, + ); } } From 1bb738a96c61f9bd5f332916a8adb63bc8e83458 Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Tue, 9 Jul 2024 14:16:25 +0200 Subject: [PATCH 96/99] Update EccPointQ enum --- halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 5d08d170db..d4e92bcf85 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -19,10 +19,10 @@ use std::ops::Deref; /// `EccPointQ` can hold either a public or a private ECC Point #[derive(Debug, Clone)] -#[allow(dead_code)] -pub enum EccPointQ<'a> { +pub enum EccPointQ { PublicPoint(pallas::Affine), - PrivatePoint(&'a NonIdentityEccPoint), + // We will use private point for ZSA + // PrivatePoint(&'a NonIdentityEccPoint), } impl SinsemillaChip From 3c03e465a2717d12688344695abab087e85aaa58 Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Tue, 9 Jul 2024 14:28:01 +0200 Subject: [PATCH 97/99] Update EccPointQ enum --- halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index d4e92bcf85..a11316808c 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -19,10 +19,11 @@ use std::ops::Deref; /// `EccPointQ` can hold either a public or a private ECC Point #[derive(Debug, Clone)] -pub enum EccPointQ { +pub enum EccPointQ<'a> { PublicPoint(pallas::Affine), + #[allow(dead_code)] // We will use private point for ZSA - // PrivatePoint(&'a NonIdentityEccPoint), + PrivatePoint(&'a NonIdentityEccPoint), } impl SinsemillaChip From 552df1a70e6ebe06445ea9cec496839fa1c08c7a Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Tue, 16 Jul 2024 14:52:25 +0200 Subject: [PATCH 98/99] Take into account Pablo's review --- halo2_gadgets/src/ecc.rs | 31 +++++----- halo2_gadgets/src/sinsemilla.rs | 24 ++++---- .../src/sinsemilla/chip/hash_to_point.rs | 1 - halo2_gadgets/src/sinsemilla/merkle.rs | 33 +++++++---- .../src/utilities/lookup_range_check.rs | 56 +++++++++---------- 5 files changed, 73 insertions(+), 72 deletions(-) diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 92bb976371..86ac8b3f68 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -732,16 +732,22 @@ pub(crate) mod tests { _lookup_marker: PhantomData, } + impl MyCircuit { + fn new(test_errors: bool) -> Self { + Self { + test_errors, + _lookup_marker: PhantomData, + } + } + } + #[allow(non_snake_case)] impl Circuit for MyCircuit { type Config = EccConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - MyCircuit { - test_errors: false, - _lookup_marker: PhantomData, - } + MyCircuit::new(false) } fn configure(meta: &mut ConstraintSystem) -> Self::Config { @@ -908,21 +914,15 @@ pub(crate) mod tests { #[test] fn ecc_chip() { - let k = 11; - let circuit: MyCircuit = MyCircuit { - test_errors: true, - _lookup_marker: PhantomData, - }; + let k = 13; + let circuit = MyCircuit::::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: MyCircuit = MyCircuit { - test_errors: false, - _lookup_marker: PhantomData, - }; + let circuit = MyCircuit::::new(false); test_against_stored_circuit(circuit, "ecc_chip", 3872); } @@ -935,10 +935,7 @@ pub(crate) mod tests { root.fill(&WHITE).unwrap(); let root = root.titled("Ecc Chip Layout", ("sans-serif", 60)).unwrap(); - let circuit: MyCircuit = MyCircuit { - test_errors: false, - _lookup_marker: PhantomData, - }; + let circuit = MyCircuit::::new(false); halo2_proofs::dev::CircuitLayout::default() .render(13, &circuit, &root) .unwrap(); diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 68392d147f..c576fda455 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -519,6 +519,14 @@ pub(crate) mod tests { _lookup_marker: PhantomData, } + impl MyCircuit { + fn new() -> Self { + MyCircuit { + _lookup_marker: PhantomData, + } + } + } + type MyConfig = ( EccConfig, SinsemillaConfig, @@ -531,9 +539,7 @@ pub(crate) mod tests { type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - MyCircuit { - _lookup_marker: PhantomData, - } + MyCircuit::new() } #[allow(non_snake_case)] @@ -742,18 +748,14 @@ pub(crate) mod tests { #[test] fn sinsemilla_chip() { let k = 11; - let circuit: MyCircuit = MyCircuit { - _lookup_marker: PhantomData, - }; + let circuit = MyCircuit::::new(); let prover = MockProver::run(k, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())) } #[test] fn test_sinsemilla_chip_against_stored_circuit() { - let circuit: MyCircuit = MyCircuit { - _lookup_marker: PhantomData, - }; + let circuit = MyCircuit::::new(); test_against_stored_circuit(circuit, "sinsemilla_chip", 4576); } @@ -767,9 +769,7 @@ pub(crate) mod tests { root.fill(&WHITE).unwrap(); let root = root.titled("SinsemillaHash", ("sans-serif", 60)).unwrap(); - let circuit: MyCircuit = MyCircuit { - _lookup_marker: PhantomData, - }; + let circuit = MyCircuit::::new(); halo2_proofs::dev::CircuitLayout::default() .render(11, &circuit, &root) .unwrap(); diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index a11316808c..f7a4ba2686 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -386,7 +386,6 @@ where Ok((x_a, y_a, zs)) } - #[allow(unused_variables)] #[allow(non_snake_case)] #[allow(clippy::type_complexity)] diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 4b56d18727..b047a7e86d 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -213,6 +213,21 @@ pub mod tests { _lookup_marker: PhantomData, } + impl MyCircuit { + fn new( + leaf: Value, + leaf_pos: Value, + merkle_path: Value<[pallas::Base; MERKLE_DEPTH]>, + ) -> Self { + Self { + leaf, + leaf_pos, + merkle_path, + _lookup_marker: PhantomData, + } + } + } + type MyConfig = ( MerkleConfig, MerkleConfig, @@ -223,12 +238,7 @@ pub mod tests { type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - MyCircuit { - leaf: Value::default(), - leaf_pos: Value::default(), - merkle_path: Value::default(), - _lookup_marker: PhantomData, - } + MyCircuit::new(Value::default(), Value::default(), Value::default()) } fn configure(meta: &mut ConstraintSystem) -> Self::Config { @@ -381,12 +391,11 @@ pub mod tests { .collect(); // The root is provided as a public input in the Orchard circuit. - MyCircuit { - leaf: Value::known(leaf), - leaf_pos: Value::known(pos), - merkle_path: Value::known(path.try_into().unwrap()), - _lookup_marker: PhantomData, - } + MyCircuit::new( + Value::known(leaf), + Value::known(pos), + Value::known(path.try_into().unwrap()), + ) } #[test] diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 894bc87f87..7e38b0737a 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -481,8 +481,16 @@ mod tests { #[derive(Clone, Copy)] struct MyLookupCircuit> { num_words: usize, - _field_marker: PhantomData, - _lookup_marker: PhantomData, + _marker: PhantomData<(F, Lookup)>, + } + + impl> MyLookupCircuit { + fn new(num_words: usize) -> Self { + MyLookupCircuit { + num_words, + _marker: PhantomData, + } + } } impl + std::clone::Clone> Circuit @@ -492,11 +500,7 @@ mod tests { type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - MyLookupCircuit { - num_words: self.num_words, - _field_marker: PhantomData, - _lookup_marker: PhantomData, - } + MyLookupCircuit::new(self.num_words) } fn configure(meta: &mut ConstraintSystem) -> Self::Config { @@ -571,25 +575,14 @@ mod tests { #[test] fn lookup_range_check() { - let circuit: MyLookupCircuit = - MyLookupCircuit { - num_words: 6, - _field_marker: PhantomData, - _lookup_marker: PhantomData, - }; - + let circuit = MyLookupCircuit::::new(6); let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); } #[test] fn test_lookup_range_check_against_stored_circuit() { - let circuit: MyLookupCircuit = - MyLookupCircuit { - num_words: 6, - _field_marker: PhantomData, - _lookup_marker: PhantomData, - }; + let circuit = MyLookupCircuit::::new(6); test_against_stored_circuit(circuit, "lookup_range_check", 1888); } @@ -600,6 +593,16 @@ mod tests { _lookup_marker: PhantomData, } + impl> MyShortRangeCheckCircuit { + fn new(element: Value, num_bits: usize) -> Self { + MyShortRangeCheckCircuit { + element, + num_bits, + _lookup_marker: PhantomData, + } + } + } + impl + std::clone::Clone> Circuit for MyShortRangeCheckCircuit { @@ -607,11 +610,7 @@ mod tests { type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - MyShortRangeCheckCircuit { - element: Value::unknown(), - num_bits: self.num_bits, - _lookup_marker: PhantomData, - } + MyShortRangeCheckCircuit::new(Value::unknown(), self.num_bits) } fn configure(meta: &mut ConstraintSystem) -> Self::Config { @@ -649,11 +648,8 @@ mod tests { circuit_name: &str, expected_proof_size: usize, ) { - let circuit: MyShortRangeCheckCircuit = MyShortRangeCheckCircuit { - element: Value::known(element), - num_bits, - _lookup_marker: PhantomData, - }; + let circuit = + MyShortRangeCheckCircuit::::new(Value::known(element), num_bits); let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), *proof_result); From 7ed444a72d456c8eda3b40df1ceee84454d43285 Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Thu, 8 Aug 2024 11:27:42 +0200 Subject: [PATCH 99/99] Remove unnecessary changes in CI --- .github/workflows/ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ed590bc01..ce5cafc981 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,10 +52,8 @@ jobs: with: beta-features: ${{ matrix.stage == 'beta' }} nightly-features: ${{ matrix.stage == 'nightly' }} - - name: Update apt - run: sudo apt-get update - name: Install cross-platform support dependencies - run: sudo apt-get install gcc-multilib + run: sudo apt install gcc-multilib - run: rustup target add i686-unknown-linux-gnu - name: Run tests run: >