From 3373da37608bd5b2248b1a604717e1e78d7cc75c Mon Sep 17 00:00:00 2001 From: phamnhatminh1292001 <66765903+phamnhatminh1292001@users.noreply.github.com> Date: Thu, 2 May 2024 17:14:02 +0700 Subject: [PATCH 01/15] Add Verkle tree config Implement Verkle tree commitment scheme and Verkle tree verification circuit. --- zkmemory/src/commitment/verkle_tree.rs | 24 ++++++++++++++++++++++++ zkmemory/src/lib.rs | 8 ++++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/zkmemory/src/commitment/verkle_tree.rs b/zkmemory/src/commitment/verkle_tree.rs index 8b13789..261af8c 100644 --- a/zkmemory/src/commitment/verkle_tree.rs +++ b/zkmemory/src/commitment/verkle_tree.rs @@ -1 +1,25 @@ +//! Circuit for proving the correctness of the Verkle tree commitment. +extern crate alloc; +use core::marker::PhantomData; + +use crate::poseidon::poseidon_hash::{ConstantLength, Hash, Spec}; +use alloc::{vec, vec::Vec}; +use ff::{Field, PrimeField}; +use halo2_proofs::{ + circuit::{Layouter, Region, SimpleFloorPlanner, Value}, + plonk::{ + Advice, Circuit, Column, ConstraintSystem, Error, Expression, Fixed, Instance, Selector, + }, + poly::Rotation, +}; + +#[derive(Clone, Copy, Debug)] +/// Verkle tree config +pub struct VerkleTreeConfig { + advice: [Column; 2], + _marker: PhantomData, +} + +/// +pub(crate) struct VerkleTreeCircuit {} diff --git a/zkmemory/src/lib.rs b/zkmemory/src/lib.rs index 946aaa0..9fd0d7d 100644 --- a/zkmemory/src/lib.rs +++ b/zkmemory/src/lib.rs @@ -2,13 +2,13 @@ #![recursion_limit = "256"] #![cfg_attr(not(feature = "std"), no_std)] #![deny( - unused, - warnings, + // unused, + // warnings, future_incompatible, nonstandard_style, rust_2018_idioms, - missing_docs, - unused_imports + // missing_docs, + // unused_imports )] #![forbid(unsafe_code)] From 0799ad03b08846cf4f4d5ed4243b05a1f4e3479f Mon Sep 17 00:00:00 2001 From: phamnhatminh1292001 <66765903+phamnhatminh1292001@users.noreply.github.com> Date: Fri, 3 May 2024 17:41:30 +0700 Subject: [PATCH 02/15] Add helper functions for Verkle tree config --- zkmemory/src/commitment/merkle_tree.rs | 20 +++--- zkmemory/src/commitment/verkle_tree.rs | 99 +++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 11 deletions(-) diff --git a/zkmemory/src/commitment/merkle_tree.rs b/zkmemory/src/commitment/merkle_tree.rs index a58e98f..a7ec64e 100644 --- a/zkmemory/src/commitment/merkle_tree.rs +++ b/zkmemory/src/commitment/merkle_tree.rs @@ -90,7 +90,7 @@ impl MerkleTreeConfig { #[derive(Default)] /// Merkle tree circuit -pub(crate) struct MemoryTreeCircuit< +pub(crate) struct MerkleTreeCircuit< S: Spec, F: Field + PrimeField, const W: usize, @@ -105,7 +105,7 @@ pub(crate) struct MemoryTreeCircuit< _marker: PhantomData, } impl + Clone, F: Field + PrimeField, const W: usize, const R: usize> Circuit - for MemoryTreeCircuit + for MerkleTreeCircuit { type Config = MerkleTreeConfig; type FloorPlanner = SimpleFloorPlanner; @@ -175,7 +175,7 @@ impl + Clone, F: Field + PrimeField, const W: usize, const R: u } impl + Clone, F: Field + PrimeField, const W: usize, const R: usize> - MemoryTreeCircuit + MerkleTreeCircuit { // Assign the elements in the path into the witness table fn assign( @@ -246,7 +246,7 @@ impl + Clone, F: Field + PrimeField, const W: usize, const R: u #[cfg(test)] mod tests { extern crate alloc; - use super::MemoryTreeCircuit; + use super::MerkleTreeCircuit; use crate::poseidon::poseidon_hash::*; use alloc::vec; use core::marker::PhantomData; @@ -280,7 +280,7 @@ mod tests { let leaf_fp = Fp::from(leaf); let indices = indices.iter().map(|x| Fp::from(*x)).collect(); let elements = elements.iter().map(|x| Fp::from(*x)).collect(); - let circuit = MemoryTreeCircuit:: { + let circuit = MerkleTreeCircuit:: { leaf: leaf_fp, indices, elements, @@ -314,7 +314,7 @@ mod tests { let leaf_fp = Fp::from(leaf); let indices = indices.iter().map(|x| Fp::from(*x)).collect(); let elements = elements.iter().map(|x| Fp::from(*x)).collect(); - let circuit = MemoryTreeCircuit:: { + let circuit = MerkleTreeCircuit:: { leaf: leaf_fp, indices, elements, @@ -335,7 +335,7 @@ mod tests { let leaf_fp = Fp::from(leaf); let indices = indices.iter().map(|x| Fp::from(*x)).collect(); let elements = elements.iter().map(|x| Fp::from(*x)).collect(); - let circuit = MemoryTreeCircuit:: { + let circuit = MerkleTreeCircuit:: { leaf: leaf_fp, indices, elements, @@ -357,7 +357,7 @@ mod tests { let leaf_fp = Fp::from(leaf); let false_indices = false_indices.iter().map(|x| Fp::from(*x)).collect(); let elements = elements.iter().map(|x| Fp::from(*x)).collect(); - let circuit = MemoryTreeCircuit:: { + let circuit = MerkleTreeCircuit:: { leaf: leaf_fp, indices: false_indices, elements, @@ -378,7 +378,7 @@ mod tests { let leaf_fp = Fp::from(leaf); let indices = indices.iter().map(|x| Fp::from(*x)).collect(); let elements = elements.iter().map(|x| Fp::from(*x)).collect(); - let circuit = MemoryTreeCircuit:: { + let circuit = MerkleTreeCircuit:: { leaf: leaf_fp, indices, elements, @@ -399,7 +399,7 @@ mod tests { let leaf_fp = Fp::from(leaf); let indices = indices.iter().map(|x| Fp::from(*x)).collect(); let elements = elements.iter().map(|x| Fp::from(*x)).collect(); - let circuit = MemoryTreeCircuit:: { + let circuit = MerkleTreeCircuit:: { leaf: leaf_fp, indices, elements, diff --git a/zkmemory/src/commitment/verkle_tree.rs b/zkmemory/src/commitment/verkle_tree.rs index 261af8c..a8fd76c 100644 --- a/zkmemory/src/commitment/verkle_tree.rs +++ b/zkmemory/src/commitment/verkle_tree.rs @@ -18,8 +18,105 @@ use halo2_proofs::{ /// Verkle tree config pub struct VerkleTreeConfig { advice: [Column; 2], + pub instance: Column, + indices: Column, + selector: Column, + selector_zero: Selector, _marker: PhantomData, } +impl VerkleTreeConfig { + fn configure(meta: &mut ConstraintSystem, instance: Column) -> Self { + let advice = [0; 2].map(|_| meta.advice_column()); + let selector = meta.fixed_column(); + let selector_zero = meta.selector(); + let indices = meta.advice_column(); + for i in advice { + meta.enable_equality(i); + } + let one = Expression::Constant(F::ONE); + + // for i=0 indices[i] is equal to zero or one + // we handle i=0 seperately with selector_zero, since we are using + // a common selector for the other gates. + meta.create_gate("indices must be 0 or 1", |meta| { + let selector_zero = meta.query_selector(selector_zero); + let indices = meta.query_advice(indices, Rotation::cur()); + vec![selector_zero * indices.clone() * (one.clone() - indices)] + }); + + // for all i>=1 indices[i] is equal to zero or one + meta.create_gate("indices must be 0 or 1", |meta| { + let indices = meta.query_advice(indices, Rotation::cur()); + let selector = meta.query_fixed(selector, Rotation::cur()); + vec![selector * indices.clone() * (one.clone() - indices)] + }); + + VerkleTreeConfig { + advice, + instance, + indices, + selector, + selector_zero, + _marker: PhantomData, + } + } +} /// -pub(crate) struct VerkleTreeCircuit {} +#[derive(Default)] +pub(crate) struct VerkleTreeCircuit { + pub(crate) leaf: F, + pub(crate) non_leaf_elements: Vec, + pub(crate) indices: Vec, +} + +impl Circuit for VerkleTreeCircuit { + type Config = VerkleTreeConfig; + type FloorPlanner = SimpleFloorPlanner; + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let instance = meta.instance_column(); + meta.enable_equality(instance); + VerkleTreeConfig::::configure(meta, instance) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + assert_eq!(self.indices.len(), self.non_leaf_elements.len()); + let mut v = vec![self.leaf]; + + let leaf_cell = layouter.assign_region( + || "assign leaf", + |mut region| { + region.assign_advice( + || "assign leaf", + config.advice[0], + 0, + || Value::known(self.leaf), + ) + }, + )?; + + let root = layouter.assign_region( + || "assign root", + |mut region| { + region.assign_advice( + || "assign root", + config.advice[0], + 0, + || Value::known(v[self.indices.len()]), + ) + }, + )?; + + layouter.constrain_instance(leaf_cell.cell(), config.instance, 0)?; + layouter.constrain_instance(root.cell(), config.instance, 1)?; + Ok(()) + } +} From fbb79d5941776c5ff557beda48c7cc7723baf340 Mon Sep 17 00:00:00 2001 From: phamnhatminh1292001 <66765903+phamnhatminh1292001@users.noreply.github.com> Date: Mon, 6 May 2024 17:14:16 +0700 Subject: [PATCH 03/15] Add proving and verifying merkle tree proof methods --- zkmemory/src/commitment/verkle_tree.rs | 132 ++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 1 deletion(-) diff --git a/zkmemory/src/commitment/verkle_tree.rs b/zkmemory/src/commitment/verkle_tree.rs index a8fd76c..62e00fa 100644 --- a/zkmemory/src/commitment/verkle_tree.rs +++ b/zkmemory/src/commitment/verkle_tree.rs @@ -2,17 +2,21 @@ extern crate alloc; use core::marker::PhantomData; +extern crate std; +use std::println; -use crate::poseidon::poseidon_hash::{ConstantLength, Hash, Spec}; +use crate::poseidon::poseidon_hash::{ConstantLength, Hash, OrchardNullifier, Spec}; use alloc::{vec, vec::Vec}; use ff::{Field, PrimeField}; use halo2_proofs::{ + arithmetic::{eval_polynomial, lagrange_interpolate}, circuit::{Layouter, Region, SimpleFloorPlanner, Value}, plonk::{ Advice, Circuit, Column, ConstraintSystem, Error, Expression, Fixed, Instance, Selector, }, poly::Rotation, }; +use halo2curves::pasta::{pallas::Affine, Fp}; #[derive(Clone, Copy, Debug)] /// Verkle tree config @@ -120,3 +124,129 @@ impl Circuit for VerkleTreeCircuit { Ok(()) } } + +// verkle tree prove and verify function +fn hash_commit(commit: &C) -> Fp { + let preimage = commit.to_bytes(); + let preimage_fp = preimage.map(|x| Fp::from(x)); + Hash::, 3, 2>::init().hash(preimage_fp) +} + +fn vec_commit(v: &[Fp], bases: &[Affine]) -> C { + unimplemented!() +} + +struct NonLeafNode { + poly_coeffs: Vec, + commit: C, + commit_digest: Fp, +} + +struct VerkleTree { + leafs: Vec, + non_leaf_layers: Vec>>, + root: C, +} + +impl VerkleTree { + fn new(leafs: Vec, pedersen_bases: &[Affine]) -> Self { + let num_leafs = leafs.len(); + + assert!(A.is_power_of_two() && A != 1); + assert!(num_leafs.is_power_of_two() && num_leafs >= A); + assert_eq!(pedersen_bases.len(), A); + + let log2_arity = A.trailing_zeros() as usize; + let log2_leafs = num_leafs.trailing_zeros() as usize; + let height = log2_leafs / log2_arity; + + let interp_domain: Vec = (0..A as u64).map(Fp::from).collect(); + + let mut cur_layer = leafs.clone(); + let mut non_leaf_layers = Vec::>>::with_capacity(height); + + for _ in 0..height { + let next_layer: Vec> = cur_layer + .chunks(A) + .map(|sibs| { + let poly_coeffs = lagrange_interpolate(&interp_domain, sibs); + debug_assert_eq!(poly_coeffs.len(), A); + let commit = vec_commit(&poly_coeffs, pedersen_bases); + let commit_digest = hash_commit(&commit); + NonLeafNode { + poly_coeffs, + commit, + commit_digest, + } + }) + .collect(); + cur_layer = next_layer.iter().map(|node| node.commit_digest).collect(); + non_leaf_layers.push(next_layer); + } + + debug_assert_eq!(non_leaf_layers.last().unwrap().len(), 1); + let root = non_leaf_layers[height - 1][0].commit; + + VerkleTree { + leafs, + non_leaf_layers, + root, + } + } + + fn root(&self) -> &C { + &self.root + } + + fn prove(&self, mut challenge: usize) -> VerkleProof { + debug_assert!(challenge < self.leafs.len()); + let leaf = self.leafs[challenge]; + let polys = self + .non_leaf_layers + .iter() + .map(|layer| { + challenge /= A; + layer[challenge].poly_coeffs.to_vec() + }) + .collect::>>(); + VerkleProof { leaf, polys } + } +} + +#[derive(Debug)] +struct VerkleProof { + leaf: Fp, + polys: Vec>, +} + +impl VerkleProof { + fn verify(&self, mut challenge: usize, root: &C, pedersen_bases: &[Affine]) -> bool { + let arity_bit_len = A.trailing_zeros() as usize; + + // Check `poly_0(X)` evaluates to provided leaf. + let mut height = 0; + let mut x = Fp::from((challenge % A) as u64); + let mut y = eval_polynomial(&self.polys[0], x); + if y != self.leaf { + println!("error: poly_{}(x) != leaf", height); + return false; + } + let mut commit = vec_commit(&self.polys[0], pedersen_bases); + + // Check `poly_i(X)` evaluates to the previous polynomial's commitment digest. + for poly in &self.polys[1..] { + height += 1; + let commit_digest = hash_commit(&commit); + challenge >>= arity_bit_len; + x = Fp::from((challenge % A) as u64); + y = eval_polynomial(poly, x); + if y != commit_digest { + println!("error: poly_{}(x) != commit(poly_{})", height, height - 1); + return false; + } + commit = vec_commit(poly, pedersen_bases); + } + + commit == *root + } +} From 0f48b9ce0dc7c5e2df2b85254bcd26705dd56fd0 Mon Sep 17 00:00:00 2001 From: phamnhatminh1292001 <66765903+phamnhatminh1292001@users.noreply.github.com> Date: Thu, 9 May 2024 17:21:05 +0700 Subject: [PATCH 04/15] Reconfigure Verkle tree config and add Verkle tree commit function --- zkmemory/src/commitment/verkle_tree.rs | 250 ++++++++++--------------- 1 file changed, 101 insertions(+), 149 deletions(-) diff --git a/zkmemory/src/commitment/verkle_tree.rs b/zkmemory/src/commitment/verkle_tree.rs index 62e00fa..6a34cda 100644 --- a/zkmemory/src/commitment/verkle_tree.rs +++ b/zkmemory/src/commitment/verkle_tree.rs @@ -2,34 +2,53 @@ extern crate alloc; use core::marker::PhantomData; +use group::Curve; extern crate std; -use std::println; - -use crate::poseidon::poseidon_hash::{ConstantLength, Hash, OrchardNullifier, Spec}; +use crate::{ + constraints, + poseidon::poseidon_hash::{ConstantLength, Hash, OrchardNullifier, Spec}, +}; use alloc::{vec, vec::Vec}; -use ff::{Field, PrimeField}; +use constraints::gadgets::Table; +use ff::{Field, PrimeField, WithSmallOrderMulGroup}; use halo2_proofs::{ arithmetic::{eval_polynomial, lagrange_interpolate}, circuit::{Layouter, Region, SimpleFloorPlanner, Value}, + halo2curves::{pairing::Engine, CurveAffine}, plonk::{ Advice, Circuit, Column, ConstraintSystem, Error, Expression, Fixed, Instance, Selector, }, - poly::Rotation, + poly::{ + commitment::{Blind, CommitmentScheme, Params, ParamsProver, Prover}, + kzg::commitment::ParamsKZG, + EvaluationDomain, Rotation, + }, +}; +use halo2curves::pasta::{ + pallas::{Affine, Scalar}, + Fp, }; -use halo2curves::pasta::{pallas::Affine, Fp}; +use rand::thread_rng; +use rand_core::OsRng; +use std::println; #[derive(Clone, Copy, Debug)] /// Verkle tree config -pub struct VerkleTreeConfig { +pub struct VerkleTreeConfig { advice: [Column; 2], pub instance: Column, indices: Column, selector: Column, selector_zero: Selector, _marker: PhantomData, + table: Table, } -impl VerkleTreeConfig { - fn configure(meta: &mut ConstraintSystem, instance: Column) -> Self { +impl VerkleTreeConfig { + fn configure( + meta: &mut ConstraintSystem, + instance: Column, + table: Table, + ) -> Self { let advice = [0; 2].map(|_| meta.advice_column()); let selector = meta.fixed_column(); let selector_zero = meta.selector(); @@ -38,22 +57,15 @@ impl VerkleTreeConfig { meta.enable_equality(i); } - let one = Expression::Constant(F::ONE); - - // for i=0 indices[i] is equal to zero or one - // we handle i=0 seperately with selector_zero, since we are using - // a common selector for the other gates. - meta.create_gate("indices must be 0 or 1", |meta| { - let selector_zero = meta.query_selector(selector_zero); - let indices = meta.query_advice(indices, Rotation::cur()); - vec![selector_zero * indices.clone() * (one.clone() - indices)] + table.range_check(meta, "indices must be in 0..k", |meta| { + meta.query_advice(indices, Rotation::cur()) }); - // for all i>=1 indices[i] is equal to zero or one - meta.create_gate("indices must be 0 or 1", |meta| { - let indices = meta.query_advice(indices, Rotation::cur()); + meta.create_gate("previous commit is equal to current", |meta| { + let advice_cur = advice.map(|x| meta.query_advice(x, Rotation::cur())); + let advice_prev = advice.map(|x| meta.query_advice(x, Rotation::prev())); let selector = meta.query_fixed(selector, Rotation::cur()); - vec![selector * indices.clone() * (one.clone() - indices)] + vec![selector * (advice_prev[1].clone() - advice_cur[0].clone())] }); VerkleTreeConfig { @@ -63,28 +75,39 @@ impl VerkleTreeConfig { selector, selector_zero, _marker: PhantomData, + table, } } } /// #[derive(Default)] -pub(crate) struct VerkleTreeCircuit { +pub(crate) struct VerkleTreeCircuit +{ pub(crate) leaf: F, pub(crate) non_leaf_elements: Vec, pub(crate) indices: Vec, + _marker: PhantomData, } -impl Circuit for VerkleTreeCircuit { - type Config = VerkleTreeConfig; +impl Circuit + for VerkleTreeCircuit +{ + type Config = VerkleTreeConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - Self::default() + Self { + leaf: F::ZERO, + non_leaf_elements: vec![F::ZERO], + indices: vec![F::ZERO], + _marker: PhantomData, + } } fn configure(meta: &mut ConstraintSystem) -> Self::Config { let instance = meta.instance_column(); meta.enable_equality(instance); - VerkleTreeConfig::::configure(meta, instance) + let table = Table::::construct(meta); + VerkleTreeConfig::::configure(meta, instance, table) } fn synthesize( @@ -125,128 +148,57 @@ impl Circuit for VerkleTreeCircuit { } } -// verkle tree prove and verify function -fn hash_commit(commit: &C) -> Fp { - let preimage = commit.to_bytes(); - let preimage_fp = preimage.map(|x| Fp::from(x)); - Hash::, 3, 2>::init().hash(preimage_fp) -} - -fn vec_commit(v: &[Fp], bases: &[Affine]) -> C { - unimplemented!() -} - -struct NonLeafNode { - poly_coeffs: Vec, - commit: C, - commit_digest: Fp, -} - -struct VerkleTree { - leafs: Vec, - non_leaf_layers: Vec>>, - root: C, -} - -impl VerkleTree { - fn new(leafs: Vec, pedersen_bases: &[Affine]) -> Self { - let num_leafs = leafs.len(); - - assert!(A.is_power_of_two() && A != 1); - assert!(num_leafs.is_power_of_two() && num_leafs >= A); - assert_eq!(pedersen_bases.len(), A); - - let log2_arity = A.trailing_zeros() as usize; - let log2_leafs = num_leafs.trailing_zeros() as usize; - let height = log2_leafs / log2_arity; - - let interp_domain: Vec = (0..A as u64).map(Fp::from).collect(); - - let mut cur_layer = leafs.clone(); - let mut non_leaf_layers = Vec::>>::with_capacity(height); - - for _ in 0..height { - let next_layer: Vec> = cur_layer - .chunks(A) - .map(|sibs| { - let poly_coeffs = lagrange_interpolate(&interp_domain, sibs); - debug_assert_eq!(poly_coeffs.len(), A); - let commit = vec_commit(&poly_coeffs, pedersen_bases); - let commit_digest = hash_commit(&commit); - NonLeafNode { - poly_coeffs, - commit, - commit_digest, - } - }) - .collect(); - cur_layer = next_layer.iter().map(|node| node.commit_digest).collect(); - non_leaf_layers.push(next_layer); - } - - debug_assert_eq!(non_leaf_layers.last().unwrap().len(), 1); - let root = non_leaf_layers[height - 1][0].commit; - - VerkleTree { - leafs, - non_leaf_layers, - root, - } +impl< + 'params, + F: Field + PrimeField + WithSmallOrderMulGroup<3>, + Scheme: CommitmentScheme, + const A: usize, + > VerkleTreeCircuit +where + Scheme::Scalar: Field + PrimeField + WithSmallOrderMulGroup<3>, +{ + fn vec_commit< + S: Spec + Clone, + P: Prover<'params, Scheme>, + const W: usize, + const R: usize, + >( + child: [Scheme::Scalar; A], + omega_power: &[Scheme::Scalar], + params: &'params Scheme::ParamsProver, + k: u32, + ) -> F { + let rng = thread_rng(); + let domain = EvaluationDomain::new(1, k); + let poly = domain.coeff_from_vec(lagrange_interpolate(omega_power, &child)); + let blind = Blind::::new(&mut OsRng); + let commit: Scheme::Curve = params.commit(&poly, blind).to_affine(); + let coordinates = commit.coordinates().unwrap(); + let x = coordinates.x(); + let y = coordinates.y(); + // TODO: try to convert x,y from Scheme::Curve::Base into Scheme::Scalar type + Hash::, W, R>::init().hash([x, y]) } - - fn root(&self) -> &C { - &self.root - } - - fn prove(&self, mut challenge: usize) -> VerkleProof { - debug_assert!(challenge < self.leafs.len()); - let leaf = self.leafs[challenge]; - let polys = self - .non_leaf_layers - .iter() - .map(|layer| { - challenge /= A; - layer[challenge].poly_coeffs.to_vec() - }) - .collect::>>(); - VerkleProof { leaf, polys } - } -} - -#[derive(Debug)] -struct VerkleProof { - leaf: Fp, - polys: Vec>, -} - -impl VerkleProof { - fn verify(&self, mut challenge: usize, root: &C, pedersen_bases: &[Affine]) -> bool { - let arity_bit_len = A.trailing_zeros() as usize; - - // Check `poly_0(X)` evaluates to provided leaf. - let mut height = 0; - let mut x = Fp::from((challenge % A) as u64); - let mut y = eval_polynomial(&self.polys[0], x); - if y != self.leaf { - println!("error: poly_{}(x) != leaf", height); - return false; - } - let mut commit = vec_commit(&self.polys[0], pedersen_bases); - - // Check `poly_i(X)` evaluates to the previous polynomial's commitment digest. - for poly in &self.polys[1..] { - height += 1; - let commit_digest = hash_commit(&commit); - challenge >>= arity_bit_len; - x = Fp::from((challenge % A) as u64); - y = eval_polynomial(poly, x); - if y != commit_digest { - println!("error: poly_{}(x) != commit(poly_{})", height, height - 1); - return false; - } - commit = vec_commit(poly, pedersen_bases); - } - - commit == *root + fn assign( + &self, + value: F, + region: &mut Region<'_, F>, + config: VerkleTreeConfig, + offset: usize, + ) -> Result { + region.assign_advice( + || "value of the verious node", + config.advice[0], + offset, + || Value::known(value), + )?; + region.assign_fixed( + || "selector", + config.selector, + offset, + || Value::known(F::ONE), + )?; + config.selector_zero.enable(region, offset)?; + Ok((F::ZERO)) } } From e2495e2abb8fefda50265cb6a5925e5663d5b77e Mon Sep 17 00:00:00 2001 From: phamnhatminh1292001 <66765903+phamnhatminh1292001@users.noreply.github.com> Date: Fri, 10 May 2024 17:10:20 +0700 Subject: [PATCH 05/15] Fix errors in assign function --- zkmemory/src/commitment/verkle_tree.rs | 38 ++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/zkmemory/src/commitment/verkle_tree.rs b/zkmemory/src/commitment/verkle_tree.rs index 6a34cda..db9a339 100644 --- a/zkmemory/src/commitment/verkle_tree.rs +++ b/zkmemory/src/commitment/verkle_tree.rs @@ -130,6 +130,26 @@ impl Circuit }, )?; + layouter.assign_region( + || "Verkle proof", + |mut region| { + for i in 0..self.non_leaf_elements.len() { + if i == 0 { + self.assign(self.leaf, self.non_leaf_elements[i], &mut region, config, i)?; + } else { + self.assign( + self.non_leaf_elements[i - 1], + self.non_leaf_elements[i], + &mut region, + config, + i, + )?; + } + } + Ok(()) + }, + )?; + let root = layouter.assign_region( || "assign root", |mut region| { @@ -168,7 +188,6 @@ where params: &'params Scheme::ParamsProver, k: u32, ) -> F { - let rng = thread_rng(); let domain = EvaluationDomain::new(1, k); let poly = domain.coeff_from_vec(lagrange_interpolate(omega_power, &child)); let blind = Blind::::new(&mut OsRng); @@ -177,21 +196,30 @@ where let x = coordinates.x(); let y = coordinates.y(); // TODO: try to convert x,y from Scheme::Curve::Base into Scheme::Scalar type - Hash::, W, R>::init().hash([x, y]) + F::from(0) } fn assign( &self, - value: F, + cur_value: F, + next_value: F, region: &mut Region<'_, F>, config: VerkleTreeConfig, offset: usize, ) -> Result { region.assign_advice( - || "value of the verious node", + || "value of the current node", config.advice[0], offset, - || Value::known(value), + || Value::known(cur_value), )?; + + region.assign_advice( + || "value of the next node", + config.advice[1], + offset, + || Value::known(next_value), + )?; + region.assign_fixed( || "selector", config.selector, From 763cdf397dfcdef86b6c7b5179ea0f53a118dd1a Mon Sep 17 00:00:00 2001 From: phamnhatminh1292001 <66765903+phamnhatminh1292001@users.noreply.github.com> Date: Tue, 21 May 2024 17:13:39 +0700 Subject: [PATCH 06/15] Fix some bugs in verkle tree file --- zkmemory/src/commitment/verkle_tree.rs | 32 +++++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/zkmemory/src/commitment/verkle_tree.rs b/zkmemory/src/commitment/verkle_tree.rs index db9a339..21678d3 100644 --- a/zkmemory/src/commitment/verkle_tree.rs +++ b/zkmemory/src/commitment/verkle_tree.rs @@ -28,7 +28,6 @@ use halo2curves::pasta::{ pallas::{Affine, Scalar}, Fp, }; -use rand::thread_rng; use rand_core::OsRng; use std::println; @@ -41,7 +40,6 @@ pub struct VerkleTreeConfig { selector: Column, selector_zero: Selector, _marker: PhantomData, - table: Table, } impl VerkleTreeConfig { fn configure( @@ -75,7 +73,6 @@ impl VerkleTreeConfig { selector, selector_zero, _marker: PhantomData, - table, } } } @@ -89,8 +86,13 @@ pub(crate) struct VerkleTreeCircuit, } -impl Circuit - for VerkleTreeCircuit +impl< + F: Field + PrimeField + WithSmallOrderMulGroup<3>, + Scheme: CommitmentScheme, + const A: usize, + > Circuit for VerkleTreeCircuit +where + Scheme::Scalar: Field + PrimeField + WithSmallOrderMulGroup<3>, { type Config = VerkleTreeConfig; type FloorPlanner = SimpleFloorPlanner; @@ -135,11 +137,19 @@ impl Circuit |mut region| { for i in 0..self.non_leaf_elements.len() { if i == 0 { - self.assign(self.leaf, self.non_leaf_elements[i], &mut region, config, i)?; + self.assign( + self.leaf, + self.non_leaf_elements[i], + self.indices[i], + &mut region, + config, + i, + )?; } else { self.assign( self.non_leaf_elements[i - 1], self.non_leaf_elements[i], + self.indices[i], &mut region, config, i, @@ -198,10 +208,12 @@ where // TODO: try to convert x,y from Scheme::Curve::Base into Scheme::Scalar type F::from(0) } + fn assign( &self, cur_value: F, next_value: F, + index: F, region: &mut Region<'_, F>, config: VerkleTreeConfig, offset: usize, @@ -220,12 +232,20 @@ where || Value::known(next_value), )?; + region.assign_advice( + || "the index of the layer", + config.indices, + offset, + || Value::known(index), + )?; + region.assign_fixed( || "selector", config.selector, offset, || Value::known(F::ONE), )?; + config.selector_zero.enable(region, offset)?; Ok((F::ZERO)) } From 29cc86154c2aa065357c667b67453fef9b5938f9 Mon Sep 17 00:00:00 2001 From: phamnhatminh1292001 <66765903+phamnhatminh1292001@users.noreply.github.com> Date: Thu, 23 May 2024 17:05:04 +0700 Subject: [PATCH 07/15] Fix supported finite field from F to Fr --- zkmemory/src/commitment/verkle_tree.rs | 121 ++++++++++++------------- 1 file changed, 56 insertions(+), 65 deletions(-) diff --git a/zkmemory/src/commitment/verkle_tree.rs b/zkmemory/src/commitment/verkle_tree.rs index 21678d3..bd58c04 100644 --- a/zkmemory/src/commitment/verkle_tree.rs +++ b/zkmemory/src/commitment/verkle_tree.rs @@ -2,9 +2,11 @@ extern crate alloc; use core::marker::PhantomData; +use ethnum::U256; use group::Curve; extern crate std; use crate::{ + base::{Uint, B256}, constraints, poseidon::poseidon_hash::{ConstantLength, Hash, OrchardNullifier, Spec}, }; @@ -14,7 +16,8 @@ use ff::{Field, PrimeField, WithSmallOrderMulGroup}; use halo2_proofs::{ arithmetic::{eval_polynomial, lagrange_interpolate}, circuit::{Layouter, Region, SimpleFloorPlanner, Value}, - halo2curves::{pairing::Engine, CurveAffine}, + halo2curves::bn256::{Bn256, Fr, G1Affine}, + halo2curves::{bn256::G2Affine, pairing::Engine, CurveAffine}, plonk::{ Advice, Circuit, Column, ConstraintSystem, Error, Expression, Fixed, Instance, Selector, }, @@ -24,26 +27,22 @@ use halo2_proofs::{ EvaluationDomain, Rotation, }, }; -use halo2curves::pasta::{ - pallas::{Affine, Scalar}, - Fp, -}; +use halo2curves::pasta::pallas::{Affine, Scalar}; use rand_core::OsRng; use std::println; #[derive(Clone, Copy, Debug)] /// Verkle tree config -pub struct VerkleTreeConfig { +pub struct VerkleTreeConfig { advice: [Column; 2], pub instance: Column, indices: Column, selector: Column, selector_zero: Selector, - _marker: PhantomData, } -impl VerkleTreeConfig { +impl VerkleTreeConfig { fn configure( - meta: &mut ConstraintSystem, + meta: &mut ConstraintSystem, instance: Column, table: Table, ) -> Self { @@ -72,50 +71,43 @@ impl VerkleTreeConfig { indices, selector, selector_zero, - _marker: PhantomData, } } } /// #[derive(Default)] -pub(crate) struct VerkleTreeCircuit -{ - pub(crate) leaf: F, - pub(crate) non_leaf_elements: Vec, - pub(crate) indices: Vec, - _marker: PhantomData, +pub(crate) struct VerkleTreeCircuit { + pub(crate) leaf: Fr, + pub(crate) commitment: Vec, + pub(crate) proof: Vec, + pub(crate) non_leaf_elements: Vec, + pub(crate) indices: Vec, } -impl< - F: Field + PrimeField + WithSmallOrderMulGroup<3>, - Scheme: CommitmentScheme, - const A: usize, - > Circuit for VerkleTreeCircuit -where - Scheme::Scalar: Field + PrimeField + WithSmallOrderMulGroup<3>, -{ - type Config = VerkleTreeConfig; +impl Circuit for VerkleTreeCircuit { + type Config = VerkleTreeConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { Self { - leaf: F::ZERO, - non_leaf_elements: vec![F::ZERO], - indices: vec![F::ZERO], - _marker: PhantomData, + leaf: Fr::ZERO, + commitment: vec![G1Affine::generator()], + proof: vec![G1Affine::generator()], + non_leaf_elements: vec![Fr::ZERO], + indices: vec![Fr::ZERO], } } - fn configure(meta: &mut ConstraintSystem) -> Self::Config { + fn configure(meta: &mut ConstraintSystem) -> Self::Config { let instance = meta.instance_column(); meta.enable_equality(instance); let table = Table::::construct(meta); - VerkleTreeConfig::::configure(meta, instance, table) + VerkleTreeConfig::::configure(meta, instance, table) } fn synthesize( &self, config: Self::Config, - mut layouter: impl Layouter, + mut layouter: impl Layouter, ) -> Result<(), Error> { assert_eq!(self.indices.len(), self.non_leaf_elements.len()); let mut v = vec![self.leaf]; @@ -139,6 +131,8 @@ where if i == 0 { self.assign( self.leaf, + self.commitment[i], + self.proof[i], self.non_leaf_elements[i], self.indices[i], &mut region, @@ -148,6 +142,8 @@ where } else { self.assign( self.non_leaf_elements[i - 1], + self.commitment[i], + self.proof[i], self.non_leaf_elements[i], self.indices[i], &mut region, @@ -178,46 +174,37 @@ where } } -impl< - 'params, - F: Field + PrimeField + WithSmallOrderMulGroup<3>, - Scheme: CommitmentScheme, - const A: usize, - > VerkleTreeCircuit -where - Scheme::Scalar: Field + PrimeField + WithSmallOrderMulGroup<3>, -{ - fn vec_commit< - S: Spec + Clone, - P: Prover<'params, Scheme>, - const W: usize, - const R: usize, - >( - child: [Scheme::Scalar; A], - omega_power: &[Scheme::Scalar], - params: &'params Scheme::ParamsProver, +impl VerkleTreeCircuit { + fn vec_commit + Clone, const W: usize, const R: usize>( + child: [Fr; A], + omega_power: &[Fr], + params: ParamsKZG, k: u32, - ) -> F { + ) -> Fr { let domain = EvaluationDomain::new(1, k); let poly = domain.coeff_from_vec(lagrange_interpolate(omega_power, &child)); - let blind = Blind::::new(&mut OsRng); - let commit: Scheme::Curve = params.commit(&poly, blind).to_affine(); + let blind = Blind::::new(&mut OsRng); + let commit = params.commit(&poly, blind).to_affine(); let coordinates = commit.coordinates().unwrap(); - let x = coordinates.x(); - let y = coordinates.y(); - // TODO: try to convert x,y from Scheme::Curve::Base into Scheme::Scalar type - F::from(0) + let x: [u8; 32] = coordinates.x().to_bytes(); + let y = coordinates.y().to_bytes(); + let x_fr = Fr::from(B256::from(x)); + let y_fr = Fr::from(B256::from(y)); + let hash = Hash::, W, R>::init().hash([x_fr, y_fr]); + hash } fn assign( &self, - cur_value: F, - next_value: F, - index: F, - region: &mut Region<'_, F>, - config: VerkleTreeConfig, + cur_value: Fr, + commitment: G1Affine, + proof: G1Affine, + next_value: Fr, + index: Fr, + region: &mut Region<'_, Fr>, + config: VerkleTreeConfig, offset: usize, - ) -> Result { + ) -> Result { region.assign_advice( || "value of the current node", config.advice[0], @@ -243,10 +230,14 @@ where || "selector", config.selector, offset, - || Value::known(F::ONE), + || Value::known(Fr::ONE), )?; + let e1 = Bn256::pairing(&commitment, &G2Affine::generator()); + let e2 = Bn256::pairing(&proof, &G2Affine::generator()); + let e3 = Bn256::pairing(&G1Affine::generator(), &G2Affine::generator()); + config.selector_zero.enable(region, offset)?; - Ok((F::ZERO)) + Ok((Fr::ZERO)) } } From 83d8a3c914e04f21db03daeeb9d2c5371874401a Mon Sep 17 00:00:00 2001 From: phamnhatminh1292001 <66765903+phamnhatminh1292001@users.noreply.github.com> Date: Mon, 27 May 2024 16:54:10 +0700 Subject: [PATCH 08/15] Fix all bugs and add testcases --- zkmemory/src/commitment/verkle_tree.rs | 158 +++++++++++++++++++++---- 1 file changed, 132 insertions(+), 26 deletions(-) diff --git a/zkmemory/src/commitment/verkle_tree.rs b/zkmemory/src/commitment/verkle_tree.rs index bd58c04..b55e1d5 100644 --- a/zkmemory/src/commitment/verkle_tree.rs +++ b/zkmemory/src/commitment/verkle_tree.rs @@ -2,22 +2,25 @@ extern crate alloc; use core::marker::PhantomData; -use ethnum::U256; use group::Curve; extern crate std; use crate::{ - base::{Uint, B256}, + base::B256, constraints, - poseidon::poseidon_hash::{ConstantLength, Hash, OrchardNullifier, Spec}, + poseidon::poseidon_hash::{ConstantLength, Hash, Spec}, }; use alloc::{vec, vec::Vec}; use constraints::gadgets::Table; -use ff::{Field, PrimeField, WithSmallOrderMulGroup}; +use ff::{Field, PrimeField, PrimeFieldBits, WithSmallOrderMulGroup}; use halo2_proofs::{ - arithmetic::{eval_polynomial, lagrange_interpolate}, + arithmetic::lagrange_interpolate, circuit::{Layouter, Region, SimpleFloorPlanner, Value}, halo2curves::bn256::{Bn256, Fr, G1Affine}, - halo2curves::{bn256::G2Affine, pairing::Engine, CurveAffine}, + halo2curves::{ + bn256::{Fq12, G2Affine, Gt}, + pairing::Engine, + CurveAffine, + }, plonk::{ Advice, Circuit, Column, ConstraintSystem, Error, Expression, Fixed, Instance, Selector, }, @@ -35,6 +38,7 @@ use std::println; /// Verkle tree config pub struct VerkleTreeConfig { advice: [Column; 2], + check: Column, pub instance: Column, indices: Column, selector: Column, @@ -47,6 +51,7 @@ impl VerkleTreeConfig { table: Table, ) -> Self { let advice = [0; 2].map(|_| meta.advice_column()); + let check = meta.advice_column(); let selector = meta.fixed_column(); let selector_zero = meta.selector(); let indices = meta.advice_column(); @@ -65,8 +70,15 @@ impl VerkleTreeConfig { vec![selector * (advice_prev[1].clone() - advice_cur[0].clone())] }); + meta.create_gate("verification result should be valid", |meta| { + let check = meta.query_advice(check, Rotation::cur()); + let selector = meta.query_fixed(selector, Rotation::cur()); + vec![selector * (check - Expression::Constant(Fr::ONE))] + }); + VerkleTreeConfig { advice, + check, instance, indices, selector, @@ -75,16 +87,25 @@ impl VerkleTreeConfig { } } /// -#[derive(Default)] -pub(crate) struct VerkleTreeCircuit { + +pub(crate) struct VerkleTreeCircuit< + S: Spec, + const W: usize, + const R: usize, + const A: usize, +> { pub(crate) leaf: Fr, pub(crate) commitment: Vec, pub(crate) proof: Vec, pub(crate) non_leaf_elements: Vec, pub(crate) indices: Vec, + pub(crate) params: ParamsKZG, + _marker: PhantomData, } -impl Circuit for VerkleTreeCircuit { +impl, const W: usize, const R: usize, const A: usize> Circuit + for VerkleTreeCircuit +{ type Config = VerkleTreeConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -94,6 +115,8 @@ impl Circuit for VerkleTreeCircuit { proof: vec![G1Affine::generator()], non_leaf_elements: vec![Fr::ZERO], indices: vec![Fr::ZERO], + params: ParamsKZG::::new(1), + _marker: PhantomData, } } @@ -110,7 +133,6 @@ impl Circuit for VerkleTreeCircuit { mut layouter: impl Layouter, ) -> Result<(), Error> { assert_eq!(self.indices.len(), self.non_leaf_elements.len()); - let mut v = vec![self.leaf]; let leaf_cell = layouter.assign_region( || "assign leaf", @@ -133,7 +155,6 @@ impl Circuit for VerkleTreeCircuit { self.leaf, self.commitment[i], self.proof[i], - self.non_leaf_elements[i], self.indices[i], &mut region, config, @@ -144,7 +165,6 @@ impl Circuit for VerkleTreeCircuit { self.non_leaf_elements[i - 1], self.commitment[i], self.proof[i], - self.non_leaf_elements[i], self.indices[i], &mut region, config, @@ -163,7 +183,7 @@ impl Circuit for VerkleTreeCircuit { || "assign root", config.advice[0], 0, - || Value::known(v[self.indices.len()]), + || Value::known(self.non_leaf_elements[self.non_leaf_elements.len() - 1]), ) }, )?; @@ -174,19 +194,16 @@ impl Circuit for VerkleTreeCircuit { } } -impl VerkleTreeCircuit { - fn vec_commit + Clone, const W: usize, const R: usize>( - child: [Fr; A], - omega_power: &[Fr], - params: ParamsKZG, - k: u32, - ) -> Fr { +impl, const W: usize, const R: usize, const A: usize> + VerkleTreeCircuit +{ + fn vec_commit(child: [Fr; A], omega_power: &[Fr], k: u32, params: ParamsKZG) -> Fr { let domain = EvaluationDomain::new(1, k); let poly = domain.coeff_from_vec(lagrange_interpolate(omega_power, &child)); let blind = Blind::::new(&mut OsRng); let commit = params.commit(&poly, blind).to_affine(); let coordinates = commit.coordinates().unwrap(); - let x: [u8; 32] = coordinates.x().to_bytes(); + let x = coordinates.x().to_bytes(); let y = coordinates.y().to_bytes(); let x_fr = Fr::from(B256::from(x)); let y_fr = Fr::from(B256::from(y)); @@ -199,12 +216,11 @@ impl VerkleTreeCircuit { cur_value: Fr, commitment: G1Affine, proof: G1Affine, - next_value: Fr, index: Fr, region: &mut Region<'_, Fr>, config: VerkleTreeConfig, offset: usize, - ) -> Result { + ) -> Result<(), Error> { region.assign_advice( || "value of the current node", config.advice[0], @@ -212,6 +228,13 @@ impl VerkleTreeCircuit { || Value::known(cur_value), )?; + let coordinates = commitment.coordinates().unwrap(); + let x = coordinates.x().to_bytes(); + let y = coordinates.y().to_bytes(); + let x_fr = Fr::from(B256::from(x)); + let y_fr = Fr::from(B256::from(y)); + let next_value = Hash::, W, R>::init().hash([x_fr, y_fr]); + region.assign_advice( || "value of the next node", config.advice[1], @@ -234,10 +257,93 @@ impl VerkleTreeCircuit { )?; let e1 = Bn256::pairing(&commitment, &G2Affine::generator()); - let e2 = Bn256::pairing(&proof, &G2Affine::generator()); - let e3 = Bn256::pairing(&G1Affine::generator(), &G2Affine::generator()); + + let g2 = self.params.s_g2() - &self.mul_g2(index); + let g2 = halo2_proofs::halo2curves::bn256::G2Affine::from(g2); + let e2 = Bn256::pairing(&proof, &g2); + + let g3 = self.mul_g2(cur_value); + let e3 = Bn256::pairing(&G1Affine::generator(), &g3); + + let sub = e1 - e2 - e3; + let b = Fr::from(sub.eq(&Gt::identity())); + + region.assign_advice( + || "result of verification", + config.check, + offset, + || Value::known(b), + )?; config.selector_zero.enable(region, offset)?; - Ok((Fr::ZERO)) + Ok(()) + } + + fn mul_g2(&self, scalar: Fr) -> G2Affine { + let g2 = G2Affine::generator(); + let mut sum = G2Affine::generator(); + let bits = to_bin(scalar.to_bytes()); + for i in 1..bits.len() { + if bits[i] == 0 { + sum = (sum.clone() + sum.clone()).into(); + } else { + sum = (sum.clone() + sum.clone() + g2).into(); + } + } + sum + } +} + +fn to_bin(v: [u8; 32]) -> [u8; 256] { + let mut bin = [0; 256]; + for i in 0..32 { + let mut tmp = v[31 - i]; + for j in 0..8 { + bin[8 * (32 - i) - 1 - j] = tmp % 2; + tmp = tmp / 2; + } + } + bin +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::poseidon::poseidon_hash::*; + use alloc::vec; + use core::marker::PhantomData; + use rand::{thread_rng, Rng}; + use std::println; + #[test] + + fn test_1() { + let leaf = Fr::from(0u64); + let k = 10; + let non_leaf_elements = vec![ + Fr::from(0u64), + Fr::from(0u64), + Fr::from(0u64), + Fr::from(0u64), + ]; + let params = ParamsKZG::::new(3); + let commitment = vec![G1Affine::generator(); 4]; + let proof = vec![G1Affine::generator(); 4]; + let indices = vec![ + Fr::from(0u64), + Fr::from(0u64), + Fr::from(0u64), + Fr::from(0u64), + ]; + + let mut rng = thread_rng(); + let mut chunk = [0u8; 32]; + for e in chunk.iter_mut() { + *e = rng.gen_range(u8::MIN..u8::MAX); + } + chunk[31] = 0u8; + let fr = Fr::from_bytes(&chunk).expect("Unable to convert to Fr"); + let chunk_fr: [u8; 32] = fr.try_into().expect("Cannot convert from Fr to bytes"); + + assert_eq!(chunk_fr, chunk); } } From 8558228ea14b4f4393b3a5457ce95a1960e071cc Mon Sep 17 00:00:00 2001 From: phamnhatminh1292001 <66765903+phamnhatminh1292001@users.noreply.github.com> Date: Tue, 28 May 2024 17:03:06 +0700 Subject: [PATCH 09/15] Add testcases and refactor code --- zkmemory/src/commitment/kzg.rs | 291 ++-- zkmemory/src/commitment/verkle_tree.rs | 399 ++++-- zkmemory/src/poseidon/poseidon_constants.rs | 1411 ++++++++++++++++++- 3 files changed, 1831 insertions(+), 270 deletions(-) diff --git a/zkmemory/src/commitment/kzg.rs b/zkmemory/src/commitment/kzg.rs index d58b7dd..cfe0e58 100644 --- a/zkmemory/src/commitment/kzg.rs +++ b/zkmemory/src/commitment/kzg.rs @@ -135,131 +135,6 @@ where .coeff_from_vec(lagrange_interpolate(&OMEGA_POWER, &evals)) } - // Create the list of proof for KZG openings - // More specifially, this function, given a list of points x_1,x_2,...,x_n - // and polynomials p_1(x),p_2(x),...,p_n(x), - // create a witness for the value p_1(x_1), p_2(x_2),...,p_n(x_n). - // Used as a misc function to create the proof of the trace record - fn create_kzg_proof< - 'params, - Scheme: CommitmentScheme, - P: Prover<'params, Scheme>, - E: EncodedChallenge, - TW: TranscriptWriterBuffer, Scheme::Curve, E>, - >( - &self, - params: &'params Scheme::ParamsProver, - // a list of point x_1,x_2,...x_n - points_list: Vec, - // a list of polynomials p_1(x), p_2(x),...,p_n(x) - polynomial_list: Vec>, - // the list of commitment of p_1(x),p_2(x),...,p_n(x) - commitment_list: Vec, - ) -> Vec - where - Scheme::Scalar: WithSmallOrderMulGroup<3>, - { - assert_eq!( - (points_list.len(), polynomial_list.len()), - (points_list.len(), commitment_list.len()) - ); - - let mut transcript = TW::init(Vec::new()); - let blind = Blind::new(&mut OsRng); - - // Add the commitment the polynomial p_i(x) to transcript - for commitment in &commitment_list { - // Add the commitment of the polynomial p_i(x) to transcript - transcript - .write_point(*commitment) - .expect("Unable to write point") - } - - let mut queries: Vec::Curve>> = Vec::new(); - for (i, point) in points_list.iter().enumerate() { - // Evaluate the values p_i(x_i) for i=1,2,...,n and add to the transcript - transcript - .write_scalar(eval_polynomial(&polynomial_list[i], *point)) - .expect("Unable to write scalar to transcript"); - - // This query is used to list all the values p_1(x_1), p_2(x_2),...,p_n(x_n) - // in the query list of SHPLONK prover - queries.push(ProverQuery::new(*point, &polynomial_list[i], blind)); - } - - // Create the proof - P::new(params) - .create_proof(&mut OsRng, &mut transcript, queries) - .expect("Unable to create proof"); - transcript.finalize() - } - - // Verify KZG openings - // This function, given the list of points x_1,x_2,...,x_n, - // a list of openings p_1(x_1),p_2(x_2),...,p_n(x_n) - // and a list of commitment c_1,c_2,..c_n - // then returns True or False to determine the correctness of the opening. - // Used as a misc function to help verifying the trace record - fn verify_kzg_proof< - 'a, - 'params, - Scheme: CommitmentScheme, - Vr: Verifier<'params, Scheme>, - E: EncodedChallenge, - Tr: TranscriptReadBuffer<&'a [u8], Scheme::Curve, E>, - Strategy: VerificationStrategy<'params, Scheme, Vr, Output = Strategy>, - >( - &self, - params: &'params Scheme::ParamsVerifier, - // A list of points x_1,x_2,...x_n - points_list: Vec, - // The evaluation of p_1(x_1),p_2(x_2),...,p_n(x_n) - eval: Vec, - // The commitments of the polynomials p_1(x),p_2(x),...,p_n(x) - commitments: Vec, - // The proof of opening - proof: &'a [u8], - ) -> bool { - let verifier = Vr::new(params); - let mut transcript = Tr::init(proof); - let mut check = true; - let mut eval_list = Vec::new(); - let mut queries = Vec::new(); - - let commitment_list: Vec<::Curve> = points_list - .iter() - .map(|_| transcript.read_point().expect("Unable to read point")) - .collect(); - - for (i, point) in points_list.iter().enumerate() { - // Check if commitment list input matches the commitment list from the Prover's proof - check = check && (commitments[i] == commitment_list[i]); - - // Read the eval list from transcript - eval_list.push(transcript.read_scalar().expect("Unable to read scalar")); - - // Check if eval list input matches the eval list from the Prover's proof - check = check && (eval[i] == eval_list[i]); - - queries.push(VerifierQuery::new_commitment( - &commitment_list[i], - *point, - eval[i], - )); - } - - // Apply the verify function from SHPLONK to return the result - check - && Strategy::new(params) - .process(|msm_accumulator| { - verifier - .verify_proof(&mut transcript, queries, msm_accumulator) - .map_err(|_| Error::Opening) - }) - .expect("Unable to verify proof") - .finalize() - } - /// Open all fields from the trace record /// The function, given input a trace record and its commitment, /// outputs a proof of correct opening @@ -282,15 +157,17 @@ where // Create the proof // I use the anonymous lifetime parameter '_ here, since currently // I do not know how to add a specific life time parameter in the script. - self.create_kzg_proof::< - KZGCommitmentScheme, - ProverSHPLONK<'_,Bn256>, - Challenge255, - Blake2bWrite, G1Affine, Challenge255>>( - &self.kzg_params, - OMEGA_POWER[0..5].to_vec(), - polynomial_list, - commitment_list) + create_kzg_proof::< + KZGCommitmentScheme, + ProverSHPLONK<'_, Bn256>, + Challenge255, + Blake2bWrite, G1Affine, Challenge255>, + >( + &self.kzg_params, + OMEGA_POWER[0..5].to_vec(), + polynomial_list, + commitment_list, + ) } /// Verify the correctness of the trace record. @@ -310,17 +187,143 @@ where // for the polynomial p(x) converted from the trace let eval = Vec::from(self.trace_to_field(trace)); // Finally, verify the correctness of the trace record - self.verify_kzg_proof::< - KZGCommitmentScheme, - VerifierSHPLONK<'_,Bn256>, - Challenge255, - Blake2bRead<&'_[u8], G1Affine, Challenge255>, - AccumulatorStrategy<'_,Bn256>, - >(&self.kzg_params, OMEGA_POWER[0..5].to_vec(), - eval, - commitment_list, - proof.as_slice()) + verify_kzg_proof::< + KZGCommitmentScheme, + VerifierSHPLONK<'_, Bn256>, + Challenge255, + Blake2bRead<&'_ [u8], G1Affine, Challenge255>, + AccumulatorStrategy<'_, Bn256>, + >( + &self.kzg_params, + OMEGA_POWER[0..5].to_vec(), + eval, + commitment_list, + proof.as_slice(), + ) + } +} + +/// Create the list of proof for KZG openings +/// More specifially, this function, given a list of points x_1,x_2,...,x_n +/// and polynomials p_1(x),p_2(x),...,p_n(x), +/// create a witness for the value p_1(x_1), p_2(x_2),...,p_n(x_n). +/// Used as a misc function to create the proof of the trace record +pub fn create_kzg_proof< + 'params, + Scheme: CommitmentScheme, + P: Prover<'params, Scheme>, + E: EncodedChallenge, + TW: TranscriptWriterBuffer, Scheme::Curve, E>, +>( + params: &'params Scheme::ParamsProver, + // a list of point x_1,x_2,...x_n + points_list: Vec, + // a list of polynomials p_1(x), p_2(x),...,p_n(x) + polynomial_list: Vec>, + // the list of commitment of p_1(x),p_2(x),...,p_n(x) + commitment_list: Vec, +) -> Vec +where + Scheme::Scalar: WithSmallOrderMulGroup<3>, +{ + assert_eq!( + (points_list.len(), polynomial_list.len()), + (points_list.len(), commitment_list.len()) + ); + + let mut transcript = TW::init(Vec::new()); + let blind = Blind::new(&mut OsRng); + + // Add the commitment the polynomial p_i(x) to transcript + for commitment in &commitment_list { + // Add the commitment of the polynomial p_i(x) to transcript + transcript + .write_point(*commitment) + .expect("Unable to write point") } + + let mut queries: Vec::Curve>> = Vec::new(); + for (i, point) in points_list.iter().enumerate() { + // Evaluate the values p_i(x_i) for i=1,2,...,n and add to the transcript + transcript + .write_scalar(eval_polynomial(&polynomial_list[i], *point)) + .expect("Unable to write scalar to transcript"); + + // This query is used to list all the values p_1(x_1), p_2(x_2),...,p_n(x_n) + // in the query list of SHPLONK prover + queries.push(ProverQuery::new(*point, &polynomial_list[i], blind)); + } + + // Create the proof + P::new(params) + .create_proof(&mut OsRng, &mut transcript, queries) + .expect("Unable to create proof"); + transcript.finalize() +} + +/// Verify KZG openings +/// This function, given the list of points x_1,x_2,...,x_n, +/// a list of openings p_1(x_1),p_2(x_2),...,p_n(x_n) +/// and a list of commitment c_1,c_2,..c_n +/// then returns True or False to determine the correctness of the opening. +/// Used as a misc function to help verifying the trace record +pub fn verify_kzg_proof< + 'a, + 'params, + Scheme: CommitmentScheme, + Vr: Verifier<'params, Scheme>, + E: EncodedChallenge, + Tr: TranscriptReadBuffer<&'a [u8], Scheme::Curve, E>, + Strategy: VerificationStrategy<'params, Scheme, Vr, Output = Strategy>, +>( + params: &'params Scheme::ParamsVerifier, + // A list of points x_1,x_2,...x_n + points_list: Vec, + // The evaluation of p_1(x_1),p_2(x_2),...,p_n(x_n) + eval: Vec, + // The commitments of the polynomials p_1(x),p_2(x),...,p_n(x) + commitments: Vec, + // The proof of opening + proof: &'a [u8], +) -> bool { + let verifier = Vr::new(params); + let mut transcript = Tr::init(proof); + let mut check = true; + let mut eval_list = Vec::new(); + let mut queries = Vec::new(); + + let commitment_list: Vec<::Curve> = points_list + .iter() + .map(|_| transcript.read_point().expect("Unable to read point")) + .collect(); + + for (i, point) in points_list.iter().enumerate() { + // Check if commitment list input matches the commitment list from the Prover's proof + check = check && (commitments[i] == commitment_list[i]); + + // Read the eval list from transcript + eval_list.push(transcript.read_scalar().expect("Unable to read scalar")); + + // Check if eval list input matches the eval list from the Prover's proof + check = check && (eval[i] == eval_list[i]); + + queries.push(VerifierQuery::new_commitment( + &commitment_list[i], + *point, + eval[i], + )); + } + + // Apply the verify function from SHPLONK to return the result + check + && Strategy::new(params) + .process(|msm_accumulator| { + verifier + .verify_proof(&mut transcript, queries, msm_accumulator) + .map_err(|_| Error::Opening) + }) + .expect("Unable to verify proof") + .finalize() } #[cfg(test)] diff --git a/zkmemory/src/commitment/verkle_tree.rs b/zkmemory/src/commitment/verkle_tree.rs index b55e1d5..09e2933 100644 --- a/zkmemory/src/commitment/verkle_tree.rs +++ b/zkmemory/src/commitment/verkle_tree.rs @@ -2,37 +2,34 @@ extern crate alloc; use core::marker::PhantomData; -use group::Curve; extern crate std; use crate::{ - base::B256, constraints, poseidon::poseidon_hash::{ConstantLength, Hash, Spec}, }; use alloc::{vec, vec::Vec}; use constraints::gadgets::Table; -use ff::{Field, PrimeField, PrimeFieldBits, WithSmallOrderMulGroup}; +use ff::Field; use halo2_proofs::{ - arithmetic::lagrange_interpolate, circuit::{Layouter, Region, SimpleFloorPlanner, Value}, halo2curves::bn256::{Bn256, Fr, G1Affine}, - halo2curves::{ - bn256::{Fq12, G2Affine, Gt}, - pairing::Engine, - CurveAffine, - }, + halo2curves::CurveAffineExt, plonk::{ Advice, Circuit, Column, ConstraintSystem, Error, Expression, Fixed, Instance, Selector, }, poly::{ - commitment::{Blind, CommitmentScheme, Params, ParamsProver, Prover}, - kzg::commitment::ParamsKZG, - EvaluationDomain, Rotation, + commitment::ParamsProver, + kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG}, + multiopen::VerifierSHPLONK, + strategy::AccumulatorStrategy, + }, + Rotation, }, + transcript::{Blake2bRead, Challenge255}, }; -use halo2curves::pasta::pallas::{Affine, Scalar}; -use rand_core::OsRng; -use std::println; + +use super::kzg::verify_kzg_proof; #[derive(Clone, Copy, Debug)] /// Verkle tree config @@ -42,7 +39,8 @@ pub struct VerkleTreeConfig { pub instance: Column, indices: Column, selector: Column, - selector_zero: Selector, + selector_check: Selector, + table: Table, } impl VerkleTreeConfig { fn configure( @@ -53,7 +51,7 @@ impl VerkleTreeConfig { let advice = [0; 2].map(|_| meta.advice_column()); let check = meta.advice_column(); let selector = meta.fixed_column(); - let selector_zero = meta.selector(); + let selector_check = meta.selector(); let indices = meta.advice_column(); for i in advice { meta.enable_equality(i); @@ -72,8 +70,8 @@ impl VerkleTreeConfig { meta.create_gate("verification result should be valid", |meta| { let check = meta.query_advice(check, Rotation::cur()); - let selector = meta.query_fixed(selector, Rotation::cur()); - vec![selector * (check - Expression::Constant(Fr::ONE))] + let selector_check = meta.query_selector(selector_check); + vec![selector_check * (check - Expression::Constant(Fr::ONE))] }); VerkleTreeConfig { @@ -82,7 +80,8 @@ impl VerkleTreeConfig { instance, indices, selector, - selector_zero, + selector_check, + table, } } } @@ -96,7 +95,7 @@ pub(crate) struct VerkleTreeCircuit< > { pub(crate) leaf: Fr, pub(crate) commitment: Vec, - pub(crate) proof: Vec, + pub(crate) proof: Vec, pub(crate) non_leaf_elements: Vec, pub(crate) indices: Vec, pub(crate) params: ParamsKZG, @@ -112,7 +111,7 @@ impl, const W: usize, const R: usize, const A: usize> Circuit< Self { leaf: Fr::ZERO, commitment: vec![G1Affine::generator()], - proof: vec![G1Affine::generator()], + proof: vec![0], non_leaf_elements: vec![Fr::ZERO], indices: vec![Fr::ZERO], params: ParamsKZG::::new(1), @@ -154,7 +153,6 @@ impl, const W: usize, const R: usize, const A: usize> Circuit< self.assign( self.leaf, self.commitment[i], - self.proof[i], self.indices[i], &mut region, config, @@ -164,7 +162,6 @@ impl, const W: usize, const R: usize, const A: usize> Circuit< self.assign( self.non_leaf_elements[i - 1], self.commitment[i], - self.proof[i], self.indices[i], &mut region, config, @@ -172,10 +169,45 @@ impl, const W: usize, const R: usize, const A: usize> Circuit< )?; } } + config.table.load(&mut region)?; Ok(()) }, )?; + let mut poly_list = vec![]; + poly_list.push(self.leaf); + for i in 0..self.non_leaf_elements.len() - 1 { + poly_list.push(self.non_leaf_elements[i]); + } + + let b = verify_kzg_proof::< + KZGCommitmentScheme, + VerifierSHPLONK<'_, Bn256>, + Challenge255, + Blake2bRead<&'_ [u8], G1Affine, Challenge255>, + AccumulatorStrategy<'_, Bn256>, + >( + &self.params, + self.indices.clone(), + poly_list, + self.commitment.clone(), + self.proof.as_slice(), + ); + let b = Fr::from(b); + + layouter.assign_region( + || "assign check result", + |mut region| { + config.selector_check.enable(&mut region, 0)?; + region.assign_advice( + || "assign check result", + config.check, + 0, + || Value::known(b), + ) + }, + )?; + let root = layouter.assign_region( || "assign root", |mut region| { @@ -197,25 +229,10 @@ impl, const W: usize, const R: usize, const A: usize> Circuit< impl, const W: usize, const R: usize, const A: usize> VerkleTreeCircuit { - fn vec_commit(child: [Fr; A], omega_power: &[Fr], k: u32, params: ParamsKZG) -> Fr { - let domain = EvaluationDomain::new(1, k); - let poly = domain.coeff_from_vec(lagrange_interpolate(omega_power, &child)); - let blind = Blind::::new(&mut OsRng); - let commit = params.commit(&poly, blind).to_affine(); - let coordinates = commit.coordinates().unwrap(); - let x = coordinates.x().to_bytes(); - let y = coordinates.y().to_bytes(); - let x_fr = Fr::from(B256::from(x)); - let y_fr = Fr::from(B256::from(y)); - let hash = Hash::, W, R>::init().hash([x_fr, y_fr]); - hash - } - fn assign( &self, cur_value: Fr, commitment: G1Affine, - proof: G1Affine, index: Fr, region: &mut Region<'_, Fr>, config: VerkleTreeConfig, @@ -227,12 +244,9 @@ impl, const W: usize, const R: usize, const A: usize> offset, || Value::known(cur_value), )?; - - let coordinates = commitment.coordinates().unwrap(); - let x = coordinates.x().to_bytes(); - let y = coordinates.y().to_bytes(); - let x_fr = Fr::from(B256::from(x)); - let y_fr = Fr::from(B256::from(y)); + let (x, y) = commitment.into_coordinates(); + let x_fr = Fr::from_bytes(&x.to_bytes()).unwrap(); + let y_fr = Fr::from_bytes(&y.to_bytes()).unwrap(); let next_value = Hash::, W, R>::init().hash([x_fr, y_fr]); region.assign_advice( @@ -249,101 +263,236 @@ impl, const W: usize, const R: usize, const A: usize> || Value::known(index), )?; - region.assign_fixed( - || "selector", - config.selector, - offset, - || Value::known(Fr::ONE), - )?; + if offset != 0 { + region.assign_fixed( + || "selector", + config.selector, + offset, + || Value::known(Fr::ONE), + )?; + } - let e1 = Bn256::pairing(&commitment, &G2Affine::generator()); + Ok(()) + } +} - let g2 = self.params.s_g2() - &self.mul_g2(index); - let g2 = halo2_proofs::halo2curves::bn256::G2Affine::from(g2); - let e2 = Bn256::pairing(&proof, &g2); +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + commitment::kzg::create_kzg_proof, + poseidon::{ + poseidon_constants::{MDS_FR, MDS_INV_FR, ROUND_CONSTANTS_FR}, + poseidon_hash::*, + }, + }; + use alloc::vec; + use core::marker::PhantomData; + use group::Curve; + use halo2_proofs::{ + arithmetic::lagrange_interpolate, + dev::MockProver, + halo2curves::CurveAffineExt, + poly::{ + commitment::Blind, kzg::multiopen::ProverSHPLONK, Coeff, EvaluationDomain, Polynomial, + }, + transcript::Blake2bWrite, + }; + use rand_core::OsRng; + /// + pub struct KZGTest { + kzg_params: ParamsKZG, + domain: EvaluationDomain, + } - let g3 = self.mul_g2(cur_value); - let e3 = Bn256::pairing(&G1Affine::generator(), &g3); + impl KZGTest { + /// Initialize KZG parameters + pub fn new(k: u32) -> Self { + Self { + kzg_params: ParamsKZG::::new(k), + domain: EvaluationDomain::new(1, k), + } + } - let sub = e1 - e2 - e3; - let b = Fr::from(sub.eq(&Gt::identity())); + pub fn poly_from_evals(&self, evals: [Fr; 4]) -> Polynomial { + // Use Lagrange interpolation + self.domain.coeff_from_vec(lagrange_interpolate( + &[Fr::from(0), Fr::from(1), Fr::from(2), Fr::from(3)], + &evals, + )) + } - region.assign_advice( - || "result of verification", - config.check, - offset, - || Value::known(b), - )?; + pub fn commit(&self, evals: [Fr; 4]) -> G1Affine { + self.kzg_params + .commit(&self.poly_from_evals(evals), Blind(Fr::random(OsRng))) + .to_affine() + } - config.selector_zero.enable(region, offset)?; - Ok(()) - } + pub fn create_proof( + &self, + point: Vec, + polynomial: Vec>, + commitment: Vec, + ) -> Vec { + create_kzg_proof::< + KZGCommitmentScheme, + ProverSHPLONK<'_, Bn256>, + Challenge255, + Blake2bWrite, G1Affine, Challenge255>, + >(&self.kzg_params, point, polynomial, commitment) + } - fn mul_g2(&self, scalar: Fr) -> G2Affine { - let g2 = G2Affine::generator(); - let mut sum = G2Affine::generator(); - let bits = to_bin(scalar.to_bytes()); - for i in 1..bits.len() { - if bits[i] == 0 { - sum = (sum.clone() + sum.clone()).into(); - } else { - sum = (sum.clone() + sum.clone() + g2).into(); - } + pub fn group_to_scalar, const W: usize, const R: usize>( + &self, + g: G1Affine, + ) -> Fr { + let (x, y) = g.into_coordinates(); + let x_fr = Fr::from_bytes(&x.to_bytes()).unwrap(); + let y_fr = Fr::from_bytes(&y.to_bytes()).unwrap(); + Hash::, W, R>::init().hash([x_fr, y_fr]) } - sum } -} -fn to_bin(v: [u8; 32]) -> [u8; 256] { - let mut bin = [0; 256]; - for i in 0..32 { - let mut tmp = v[31 - i]; - for j in 0..8 { - bin[8 * (32 - i) - 1 - j] = tmp % 2; - tmp = tmp / 2; + #[derive(Clone, Debug)] + pub struct OrchardNullifier; + + impl Spec for OrchardNullifier { + fn full_rounds() -> usize { + 8 + } + + fn partial_rounds() -> usize { + 56 + } + + fn sbox(val: Fr) -> Fr { + val.pow_vartime([5]) + } + + fn constants() -> (Vec<[Fr; 3]>, Mtrx, Mtrx) { + (ROUND_CONSTANTS_FR[..].to_vec(), MDS_FR, MDS_INV_FR) } } - bin -} -#[cfg(test)] -mod tests { - use super::*; - use crate::poseidon::poseidon_hash::*; - use alloc::vec; - use core::marker::PhantomData; - use rand::{thread_rng, Rng}; - use std::println; #[test] - fn test_1() { - let leaf = Fr::from(0u64); - let k = 10; - let non_leaf_elements = vec![ - Fr::from(0u64), - Fr::from(0u64), - Fr::from(0u64), - Fr::from(0u64), - ]; - let params = ParamsKZG::::new(3); - let commitment = vec![G1Affine::generator(); 4]; - let proof = vec![G1Affine::generator(); 4]; - let indices = vec![ - Fr::from(0u64), - Fr::from(0u64), - Fr::from(0u64), - Fr::from(0u64), - ]; - - let mut rng = thread_rng(); - let mut chunk = [0u8; 32]; - for e in chunk.iter_mut() { - *e = rng.gen_range(u8::MIN..u8::MAX); - } - chunk[31] = 0u8; - let fr = Fr::from_bytes(&chunk).expect("Unable to convert to Fr"); - let chunk_fr: [u8; 32] = fr.try_into().expect("Cannot convert from Fr to bytes"); + fn test_valid_verkle_tree() { + let kzg = KZGTest::new(2); + let leaf = Fr::from(1); + let indices = vec![Fr::from(1)]; + let evals = [Fr::from(3), leaf, Fr::from(7), Fr::from(15)]; + let poly0 = vec![kzg.poly_from_evals(evals)]; + let commit = kzg.commit(evals); + let root = kzg.group_to_scalar::(commit); + let non_leaf_elements = vec![root]; + let commitment = vec![commit]; + let proof = kzg.create_proof(vec![Fr::from(1)], poly0, commitment.clone()); + + let circuit = VerkleTreeCircuit:: { + leaf, + commitment, + proof, + non_leaf_elements, + indices, + params: kzg.kzg_params, + _marker: PhantomData, + }; + + let prover = + MockProver::run(10, &circuit, vec![vec![leaf, root]]).expect("Cannot run the circuit"); + assert_eq!(prover.verify(), Ok(())); + } + + #[test] + fn wrong_verkle_root() { + let kzg = KZGTest::new(2); + let leaf = Fr::from(1); + let indices = vec![Fr::from(0)]; + let evals = [leaf, Fr::from(0), Fr::from(0), Fr::from(0)]; + let poly0 = vec![kzg.poly_from_evals(evals)]; + let commit = kzg.commit(evals); + let root = kzg.group_to_scalar::(commit); + let non_leaf_elements = vec![Fr::from(0)]; + let commitment = vec![commit]; + let proof = kzg.create_proof(vec![Fr::from(0)], poly0, commitment.clone()); + + let circuit = VerkleTreeCircuit:: { + leaf, + commitment, + proof, + non_leaf_elements, + indices, + params: kzg.kzg_params, + _marker: PhantomData, + }; + + let prover = + MockProver::run(10, &circuit, vec![vec![leaf, root]]).expect("Cannot run the circuit"); + assert_ne!(prover.verify(), Ok(())); + } + + #[test] + fn wrong_opening_index() { + let kzg = KZGTest::new(2); + let leaf = Fr::from(1); + let indices = vec![Fr::from(0)]; + let evals = [leaf, Fr::from(0), Fr::from(0), Fr::from(0)]; + let poly0 = vec![kzg.poly_from_evals(evals)]; + let commit = kzg.commit(evals); + let root = kzg.group_to_scalar::(commit); + let non_leaf_elements = vec![root]; + let commitment = vec![commit]; + let proof = kzg.create_proof(vec![Fr::from(1)], poly0, commitment.clone()); + + let circuit = VerkleTreeCircuit:: { + leaf, + commitment, + proof, + non_leaf_elements, + indices, + params: kzg.kzg_params, + _marker: PhantomData, + }; + + let prover = + MockProver::run(10, &circuit, vec![vec![leaf, root]]).expect("Cannot run the circuit"); + assert_ne!(prover.verify(), Ok(())); + } + + #[test] + fn valid_verkle_tree_2() { + let kzg = KZGTest::new(2); + let leaf = Fr::from(1); + let indices = vec![Fr::from(0), Fr::from(1)]; + let evals = [leaf, Fr::from(1), Fr::from(3), Fr::from(5)]; + let poly0 = kzg.poly_from_evals(evals); + let commit_0 = kzg.commit(evals); + let non_leaf_0 = kzg.group_to_scalar::(commit_0); + let evals_1 = [Fr::from(0), non_leaf_0, Fr::from(3), Fr::from(5)]; + let poly1 = kzg.poly_from_evals(evals_1); + let commit_1 = kzg.commit(evals_1); + let root = kzg.group_to_scalar::(commit_1); + + let non_leaf_elements = vec![non_leaf_0, root]; + let commitment = vec![commit_0, commit_1]; + let proof = kzg.create_proof( + vec![Fr::from(0), Fr::from(1)], + vec![poly0, poly1], + commitment.clone(), + ); + + let circuit = VerkleTreeCircuit:: { + leaf, + commitment, + proof, + non_leaf_elements, + indices, + params: kzg.kzg_params, + _marker: PhantomData, + }; - assert_eq!(chunk_fr, chunk); + let prover = + MockProver::run(10, &circuit, vec![vec![leaf, root]]).expect("Cannot run the circuit"); + assert_eq!(prover.verify(), Ok(())); } } diff --git a/zkmemory/src/poseidon/poseidon_constants.rs b/zkmemory/src/poseidon/poseidon_constants.rs index 6d40cd2..8c176b6 100644 --- a/zkmemory/src/poseidon/poseidon_constants.rs +++ b/zkmemory/src/poseidon/poseidon_constants.rs @@ -1,6 +1,6 @@ //! This file consists of specific hash parameters. -use halo2curves::pasta::pallas::Base; +use halo2_proofs::halo2curves::{bn256::Fr, pasta::pallas::Base}; pub(crate) const MDS: [[Base; 3]; 3] = [ [ @@ -1410,3 +1410,1412 @@ pub(crate) const ROUND_CONSTANTS: [[Base; 3]; 64] = [ ]), ], ]; + +pub(crate) const MDS_FR: [[Fr; 3]; 3] = [ + [ + Fr::from_raw([ + 0x323f_2486_d7e1_1b63, + 0x97d7_a0ab_2385_0b56, + 0xb3d5_9fbd_c8c9_ead4, + 0x0ab5_e5b8_74a6_8de7, + ]), + Fr::from_raw([ + 0x8eca_5596_e996_ab5e, + 0x240d_4a7c_bf73_5736, + 0x293f_0f0d_886c_7954, + 0x3191_6628_e58a_5abb, + ]), + Fr::from_raw([ + 0x19d1_cf25_d8e8_345d, + 0xa0a3_b71a_5fb1_5735, + 0xd803_952b_bb36_4fdf, + 0x07c0_45d5_f5e9_e5a6, + ]), + ], + [ + Fr::from_raw([ + 0xd049_cdc8_d085_167c, + 0x3a0a_4640_48bd_770a, + 0xf8e2_4f66_822c_2d9f, + 0x2331_6263_0ebf_9ed7, + ]), + Fr::from_raw([ + 0x4022_7011_3e04_7a2e, + 0x78f8_365c_85bb_ab07, + 0xb366_6454_8d60_957d, + 0x25ca_e259_9892_a8b0, + ]), + Fr::from_raw([ + 0xf84d_806f_685f_747a, + 0x9aad_3d82_62ef_d83f, + 0x7493_8717_989a_1957, + 0x22f5_b5e1_e608_1c97, + ]), + ], + [ + Fr::from_raw([ + 0xfee7_a994_4f84_dbe4, + 0x2168_0eab_c56b_c15d, + 0xf333_aa91_c383_3464, + 0x2e29_dd59_c64b_1037, + ]), + Fr::from_raw([ + 0xc771_effa_4326_3664, + 0xcbea_f48b_3a06_24c3, + 0x92d1_5e7d_ceef_1665, + 0x1d1a_ab4e_c1cd_6788, + ]), + Fr::from_raw([ + 0x1563_9415_f6e8_5ef1, + 0x7587_2c39_b59a_31f6, + 0x51e0_cbea_d655_16b9, + 0x3bf7_6308_6a18_9364, + ]), + ], +]; + +pub(crate) const MDS_INV_FR: [[Fr; 3]; 3] = [ + [ + Fr::from_raw([ + 0xc6de_463c_d140_4e6b, + 0x4543_705f_35e9_8ab5, + 0xcc59_ffd0_0de8_6443, + 0x2cc0_57f3_fa14_687a, + ]), + Fr::from_raw([ + 0x1718_4041_7cab_7576, + 0xfadb_f8ae_7ae2_4796, + 0x5fd7_2b55_df20_8385, + 0x32e7_c439_f2f9_67e5, + ]), + Fr::from_raw([ + 0x9426_45bd_7d44_64e0, + 0x1403_db6f_5030_2040, + 0xf461_778a_bf6c_91fa, + 0x2eae_5df8_c311_5969, + ]), + ], + [ + Fr::from_raw([ + 0xa1ca_1516_a4a1_a6a0, + 0x13f0_74fd_e9a1_8b29, + 0xdb18_b4ae_fe68_d26d, + 0x07bf_3684_8106_7199, + ]), + Fr::from_raw([ + 0xe824_25bc_1b23_a059, + 0xbb1d_6504_0c85_c1bf, + 0x018a_918b_9dac_5dad, + 0x2aec_6906_c63f_3cf1, + ]), + Fr::from_raw([ + 0xe054_1adf_238e_0781, + 0x76b2_a713_9db7_1b36, + 0x1215_944a_64a2_46b2, + 0x0952_e024_3aec_2af0, + ]), + ], + [ + Fr::from_raw([ + 0x2a41_8d8d_73a7_c908, + 0xaef9_112e_952f_dbb5, + 0x723a_63a0_c09d_ab26, + 0x2fcb_ba6f_9159_a219, + ]), + Fr::from_raw([ + 0x76ef_ab42_d4fb_a90b, + 0xc5e4_960d_7424_cd37, + 0xb4dd_d4b4_d645_2256, + 0x1ec7_3725_74f3_851b, + ]), + Fr::from_raw([ + 0xadc8_933c_6f3c_72ee, + 0x87a7_435d_30f8_be81, + 0x3c26_fa4b_7d25_b1e4, + 0x0d0c_2efd_6472_f12a, + ]), + ], +]; + +pub(crate) const ROUND_CONSTANTS_FR: [[Fr; 3]; 64] = [ + [ + Fr::from_raw([ + 0x5753_8c25_9642_6303, + 0x4e71_162f_3100_3b70, + 0x353f_628f_76d1_10f3, + 0x360d_7470_611e_473d, + ]), + Fr::from_raw([ + 0xbdb7_4213_bf63_188b, + 0x4908_ac2f_12eb_e06f, + 0x5dc3_c6c5_febf_aa31, + 0x2bab_94d7_ae22_2d13, + ]), + Fr::from_raw([ + 0x0939_d927_53cc_5dc8, + 0xef77_e7d7_3676_6c5d, + 0x2bf0_3e1a_29aa_871f, + 0x150c_93fe_f652_fb1c, + ]), + ], + [ + Fr::from_raw([ + 0x1425_9dce_5377_82b2, + 0x03cc_0a60_141e_894e, + 0x955d_55db_56dc_57c1, + 0x3270_661e_6892_8b3a, + ]), + Fr::from_raw([ + 0xce9f_b9ff_c345_afb3, + 0xb407_c370_f2b5_a1cc, + 0xa0b7_afe4_e205_7299, + 0x073f_116f_0412_2e25, + ]), + Fr::from_raw([ + 0x8eba_d76f_c715_54d8, + 0x55c9_cd20_61ae_93ca, + 0x7aff_d09c_1f53_f5fd, + 0x2a32_ec5c_4ee5_b183, + ]), + ], + [ + Fr::from_raw([ + 0x2d8c_cbe2_92ef_eead, + 0x634d_24fc_6e25_59f2, + 0x651e_2cfc_7406_28ca, + 0x2703_26ee_039d_f19e, + ]), + Fr::from_raw([ + 0xa068_fc37_c182_e274, + 0x8af8_95bc_e012_f182, + 0xdc10_0fe7_fcfa_5491, + 0x27c6_642a_c633_bc66, + ]), + Fr::from_raw([ + 0x9ca1_8682_e26d_7ff9, + 0x710e_1fb6_ab97_6a45, + 0xd27f_5739_6989_129d, + 0x1bdf_d8b0_1401_c70a, + ]), + ], + [ + Fr::from_raw([ + 0xc832_d824_261a_35ea, + 0xf4f6_fb3f_9054_d373, + 0x14b9_d6a9_c84d_d678, + 0x162a_14c6_2f9a_89b8, + ]), + Fr::from_raw([ + 0xf798_2466_7b5b_6bec, + 0xac0a_1fc7_1e2c_f0c0, + 0x2af6_f79e_3127_feea, + 0x2d19_3e0f_76de_586b, + ]), + Fr::from_raw([ + 0x5d0b_f58d_c8a4_aa94, + 0x4fef_f829_8499_0ff8, + 0x8169_6ef1_104e_674f, + 0x044c_a3cc_4a85_d73b, + ]), + ], + [ + Fr::from_raw([ + 0x6198_785f_0cd6_b9af, + 0xb8d9_e2d4_f314_f46f, + 0x1d04_5341_6d3e_235c, + 0x1cba_f2b3_71da_c6a8, + ]), + Fr::from_raw([ + 0x343e_0761_0f3f_ede5, + 0x293c_4ab0_38fd_bbdc, + 0x0e6c_49d0_61b6_b5f4, + 0x1d5b_2777_692c_205b, + ]), + Fr::from_raw([ + 0xf60e_971b_8d73_b04f, + 0x06a9_adb0_c1e6_f962, + 0xaa30_535b_dd74_9a7e, + 0x2e9b_dbba_3dd3_4bff, + ]), + ], + [ + Fr::from_raw([ + 0x035a_1366_1f22_418b, + 0xde40_fbe2_6d04_7b05, + 0x8bd5_bae3_6969_299f, + 0x2de1_1886_b180_11ca, + ]), + Fr::from_raw([ + 0xbc99_8884_ba96_a721, + 0x2ab9_395c_449b_e947, + 0x0d5b_4a3f_1841_dcd8, + 0x2e07_de17_80b8_a70d, + ]), + Fr::from_raw([ + 0x825e_4c2b_b749_25ca, + 0x2504_40a9_9d6b_8af3, + 0xbbdb_63db_d52d_ad16, + 0x0f69_f185_4d20_ca0c, + ]), + ], + [ + Fr::from_raw([ + 0x816c_0594_22dc_705e, + 0x6ce5_1135_07f9_6de9, + 0x0d13_5dc6_39fb_09a4, + 0x2eb1_b254_17fe_1767, + ]), + Fr::from_raw([ + 0xb8b1_bdf4_953b_d82c, + 0xff36_c661_d26c_c42d, + 0x8c24_cb44_c3fa_b48a, + 0x115c_d0a0_643c_fb98, + ]), + Fr::from_raw([ + 0xde80_1612_311d_04cd, + 0xbb57_ddf1_4e0f_958a, + 0x066d_7378_b999_868b, + 0x26ca_293f_7b2c_462d, + ]), + ], + [ + Fr::from_raw([ + 0xf520_9d14_b248_20ca, + 0x0f16_0bf9_f71e_967f, + 0x2a83_0aa1_6241_2cd9, + 0x17bf_1b93_c4c7_e01a, + ]), + Fr::from_raw([ + 0x05c8_6f2e_7dc2_93c5, + 0xe03c_0354_bd8c_fd38, + 0xa24f_8456_369c_85df, + 0x35b4_1a7a_c4f3_c571, + ]), + Fr::from_raw([ + 0x72ac_156a_f435_d09e, + 0x64e1_4d3b_eb2d_ddde, + 0x4359_2799_4849_bea9, + 0x3b14_8008_0523_c439, + ]), + ], + [ + Fr::from_raw([ + 0x2716_18d8_74b1_4c6d, + 0x08e2_8644_2a2d_3eb2, + 0x4950_856d_c907_d575, + 0x2cc6_8100_31dc_1b0d, + ]), + Fr::from_raw([ + 0x91f3_18c0_9f0c_b566, + 0x9e51_7aa9_3b78_341d, + 0x0596_18e2_afd2_ef99, + 0x25bd_bbed_a1bd_e8c1, + ]), + Fr::from_raw([ + 0xc631_3487_073f_7f7b, + 0x2a5e_d0a2_7b61_926c, + 0xb95f_33c2_5dde_8ac0, + 0x392a_4a87_58e0_6ee8, + ]), + ], + [ + Fr::from_raw([ + 0xe7bb_cef0_2eb5_866c, + 0x5e6a_6fd1_5db8_9365, + 0x9aa6_111f_4de0_0948, + 0x272a_5587_8a08_442b, + ]), + Fr::from_raw([ + 0x9b92_5b3c_5b21_e0e2, + 0xa6eb_ba01_1694_dd12, + 0xefa1_3c4e_60e2_6239, + 0x2d5b_308b_0cf0_2cdf, + ]), + Fr::from_raw([ + 0xef38_c57c_3116_73ac, + 0x44df_f42f_18b4_6c56, + 0xdd5d_293d_72e2_e5f2, + 0x1654_9fc6_af2f_3b72, + ]), + ], + [ + Fr::from_raw([ + 0x9b71_26d9_b468_60df, + 0x7639_8265_3442_0311, + 0xfa69_c3a2_ad52_f76d, + 0x1b10_bb7a_82af_ce39, + ]), + Fr::from_raw([ + 0x90d2_7f6a_00b7_dfc8, + 0xd1b3_6968_ba04_05c0, + 0xc79c_2df7_dc98_a3be, + 0x0f1e_7505_ebd9_1d2f, + ]), + Fr::from_raw([ + 0xff45_7756_b819_bb20, + 0x797f_d6e3_f18e_b1ca, + 0x537a_7497_a3b4_3f46, + 0x2f31_3faf_0d3f_6187, + ]), + ], + [ + Fr::from_raw([ + 0xf0bc_3e73_2ecb_26f6, + 0x5cad_11eb_f0f7_ceb8, + 0xfa3c_a61c_0ed1_5bc5, + 0x3a5c_bb6d_e450_b481, + ]), + Fr::from_raw([ + 0x8655_27cb_ca91_5982, + 0x51ba_a6e2_0f89_2b62, + 0xd920_86e2_53b4_39d6, + 0x3dab_54bc_9bef_688d, + ]), + Fr::from_raw([ + 0x3680_45ac_f2b7_1ae3, + 0x4c24_b33b_410f_efd4, + 0xe280_d316_7012_3f74, + 0x06db_fb42_b979_884d, + ]), + ], + [ + Fr::from_raw([ + 0xa7fc_32d2_2f18_b9d3, + 0xb8d2_de72_e3d2_c9ec, + 0xc6f0_39ea_1973_a63e, + 0x068d_6b46_08aa_e810, + ]), + Fr::from_raw([ + 0x2b5d_fcc5_5725_55df, + 0xb868_a7d7_e1f1_f69a, + 0x0ee2_58c9_b8fd_fccd, + 0x366e_bfaf_a3ad_381c, + ]), + Fr::from_raw([ + 0xe6bc_229e_95bc_76b1, + 0x7ef6_6d89_d044_d022, + 0x04db_3024_f41d_3f56, + 0x3967_8f65_512f_1ee4, + ]), + ], + [ + Fr::from_raw([ + 0xe534_c88f_e53d_85fe, + 0xcf82_c25f_99dc_01a4, + 0xd58b_7750_a3bc_2fe1, + 0x2166_8f01_6a80_63c0, + ]), + Fr::from_raw([ + 0x4bef_429b_c533_1608, + 0xe34d_ea56_439f_e195, + 0x1bc7_4936_3e98_a768, + 0x39d0_0994_a8a5_046a, + ]), + Fr::from_raw([ + 0x770c_956f_60d8_81b3, + 0xb163_d416_05d3_9f99, + 0x6b20_3bbe_12fb_3425, + 0x1f9d_bdc3_f843_1263, + ]), + ], + [ + Fr::from_raw([ + 0x9794_a9f7_c336_eab2, + 0xbe0b_c829_fe5e_66c6, + 0xe5f1_7b9e_0ee0_cab6, + 0x0277_45a9_cddf_ad95, + ]), + Fr::from_raw([ + 0x5202_5657_abd8_aee0, + 0x2fa4_3fe2_0a45_c78d, + 0x788d_695c_61e9_3212, + 0x1cec_0803_c504_b635, + ]), + Fr::from_raw([ + 0xd387_2a95_59a0_3a73, + 0xed50_82c8_dbf3_1365, + 0x7207_7448_ef87_cc6e, + 0x1235_23d7_5e9f_abc1, + ]), + ], + [ + Fr::from_raw([ + 0x0017_79e3_a1d3_57f4, + 0x27fe_ba35_975e_e7e5, + 0xf419_b848_e5d6_94bf, + 0x1723_d145_2c9c_f02d, + ]), + Fr::from_raw([ + 0x9dab_1ee4_dcf9_6622, + 0x21c3_f776_f572_836d, + 0xfcc0_573d_7e61_3694, + 0x1739_d180_a160_10bd, + ]), + Fr::from_raw([ + 0x7029_0452_042d_048d, + 0xfafa_96fb_eb0a_b893, + 0xacce_3239_1794_b627, + 0x2d4e_6354_da9c_c554, + ]), + ], + [ + Fr::from_raw([ + 0x670b_cf6f_8b48_5dcd, + 0x8f3b_d43f_9926_0621, + 0x4a86_9553_c9d0_07f8, + 0x153e_e614_2e53_5e33, + ]), + Fr::from_raw([ + 0xd258_d2e2_b778_2172, + 0x968a_d442_4af8_3700, + 0x635e_f7e7_a430_b486, + 0x0c45_bfd3_a69a_aa65, + ]), + Fr::from_raw([ + 0x0e56_33d2_51f7_3307, + 0x6897_ac0a_8ffa_5ff1, + 0xf2d5_6aec_8314_4600, + 0x0adf_d53b_256a_6957, + ]), + ], + [ + Fr::from_raw([ + 0xac9d_36a8_b751_6d63, + 0x3f87_b28f_1c1b_e4bd, + 0x8cd1_726b_7cba_b8ee, + 0x315d_2ac8_ebdb_ac3c, + ]), + Fr::from_raw([ + 0x299c_e44e_a423_d8e1, + 0xc9bb_60d1_f695_9879, + 0xcfae_c23d_2b16_883f, + 0x1b84_7271_2d02_eef4, + ]), + Fr::from_raw([ + 0xc4a5_4041_98ad_f70c, + 0x367d_2c54_e369_28c9, + 0xbd0b_70fa_2255_eb6f, + 0x3c1c_d07e_fda6_ff24, + ]), + ], + [ + Fr::from_raw([ + 0xbbe5_23ae_f9ab_107a, + 0x4a16_073f_738f_7e0c, + 0x687f_4e51_b2e1_dcd3, + 0x1360_52d2_6bb3_d373, + ]), + Fr::from_raw([ + 0x676c_36c2_4ef9_67dd, + 0x7b3c_fbb8_7303_2681, + 0xc1bd_d859_a123_2a1d, + 0x16c9_6bee_f6a0_a848, + ]), + Fr::from_raw([ + 0x067e_ec7f_2d63_40c4, + 0x0123_87ba_b4f1_662d, + 0x2ab7_fed8_f499_a9fb, + 0x284b_38c5_7ff6_5c26, + ]), + ], + [ + Fr::from_raw([ + 0xaf1d_ff20_4c92_2f86, + 0xfc06_772c_1c04_11a6, + 0x39e2_4219_8897_d17c, + 0x0c59_93d1_75e8_1f66, + ]), + Fr::from_raw([ + 0xbbf5_3f67_b1f8_7b15, + 0xf248_87ad_48e1_7759, + 0xfcda_655d_1ba9_c8f9, + 0x03bf_7a3f_7bd0_43da, + ]), + Fr::from_raw([ + 0x9b5c_d09e_36d8_be62, + 0x4c8f_9cbe_69f0_e827, + 0xb0cf_9995_67f0_0e73, + 0x3188_fe4e_e9f9_fafb, + ]), + ], + [ + Fr::from_raw([ + 0xafea_99a2_ec6c_595a, + 0x3af5_bf77_c1c4_2652, + 0x5a39_768c_480d_61e1, + 0x171f_528c_cf65_8437, + ]), + Fr::from_raw([ + 0x5a05_63b9_b8e9_f1d5, + 0x812c_3286_ee70_0067, + 0x196e_4185_9b35_ef88, + 0x12f4_175c_4ab4_5afc, + ]), + Fr::from_raw([ + 0x0e74_d4d3_6911_8b79, + 0x7e23_e1aa_be96_cfab, + 0x8f8f_dcf8_00a9_ac69, + 0x3a50_9e15_5cb7_ebfd, + ]), + ], + [ + Fr::from_raw([ + 0x9871_2c65_678c_fd30, + 0x984b_c8f2_e4c1_b69e, + 0x1a89_920e_2504_c3b3, + 0x10f2_a685_df4a_27c8, + ]), + Fr::from_raw([ + 0xe8a1_6728_cc9d_4918, + 0x5457_3c93_33c5_6321, + 0x1d8d_93d5_4ab9_1a0e, + 0x09e5_f497_90c8_a0e2, + ]), + Fr::from_raw([ + 0x609a_7403_47cf_5fea, + 0x42d1_7ed6_ee0f_ab7e, + 0x2bf3_5705_d9f8_4a34, + 0x352d_69be_d80e_e3e5, + ]), + ], + [ + Fr::from_raw([ + 0x3a75_8af6_fa84_e0e8, + 0xc634_debd_281b_76a6, + 0x4915_62fa_f2b1_90d3, + 0x058e_e73b_a9f3_f293, + ]), + Fr::from_raw([ + 0x621a_1325_10a4_3904, + 0x092c_b921_19bc_76be, + 0xcd0f_1fc5_5b1a_3250, + 0x232f_99cc_911e_ddd9, + ]), + Fr::from_raw([ + 0xc3b9_7c1e_301b_c213, + 0xf9ef_d52c_a6bc_2961, + 0x86c2_2c6c_5d48_69f0, + 0x201b_eed7_b8f3_ab81, + ]), + ], + [ + Fr::from_raw([ + 0xbf6b_3431_ba94_e9bc, + 0x2938_8842_744a_1210, + 0xa1c9_291d_5860_2f51, + 0x1376_dce6_5800_30c6, + ]), + Fr::from_raw([ + 0x6454_843c_5486_d7b3, + 0x072b_a8b0_2d92_e722, + 0x2b33_56c3_8238_f761, + 0x1793_199e_6fd6_ba34, + ]), + Fr::from_raw([ + 0x06a3_f1d3_b433_311b, + 0x3c66_160d_c62a_acac, + 0x9fee_9c20_c87a_67df, + 0x22de_7a74_88dc_c735, + ]), + ], + [ + Fr::from_raw([ + 0x30d6_e3fd_516b_47a8, + 0xdbe0_b77f_ae77_e1d0, + 0xdf8f_f37f_e2d8_edf8, + 0x3514_d5e9_066b_b160, + ]), + Fr::from_raw([ + 0x1937_7427_137a_81c7, + 0xff45_3d6f_900f_144a, + 0xf919_a00d_abbf_5fa5, + 0x30cd_3006_931a_d636, + ]), + Fr::from_raw([ + 0x5b6a_7422_0692_b506, + 0x8f9e_4b2c_ae2e_bb51, + 0x41f8_1a5c_f613_c8df, + 0x253d_1a5c_5293_4127, + ]), + ], + [ + Fr::from_raw([ + 0x73f6_66cb_86a4_8e8e, + 0x851b_3a59_c990_fafc, + 0xa35e_9613_e7f5_fe92, + 0x035b_461c_02d7_9d19, + ]), + Fr::from_raw([ + 0x7cfb_f86a_3aa0_4780, + 0x92b1_283c_2d5f_ccde, + 0x5bc0_0eed_d56b_93e0, + 0x23a9_9280_79d1_75bd, + ]), + Fr::from_raw([ + 0xf1e4_ccd7_3fa0_0a82, + 0xb5e2_ea34_36ee_f957, + 0xf159_4a07_63c6_11ab, + 0x13a7_785a_e134_ea92, + ]), + ], + [ + Fr::from_raw([ + 0xbbf0_4f52_52de_4279, + 0x3889_c578_6344_6d88, + 0x4962_ae3c_0da1_7e31, + 0x39fc_e308_b7d4_3c57, + ]), + Fr::from_raw([ + 0x3b57_e344_89b5_3fad, + 0xbef0_0a08_c6ed_38d2, + 0xc0fd_f016_62f6_0d22, + 0x1aae_1883_3f8e_1d3a, + ]), + Fr::from_raw([ + 0x5551_3e03_3398_513f, + 0x27c1_b3fd_8f85_d8a8, + 0x8b2e_80c0_64fd_83ed, + 0x1a76_1ce8_2400_af01, + ]), + ], + [ + Fr::from_raw([ + 0x5244_ca74_9b73_e481, + 0xdcf6_af28_30a5_0287, + 0x16dd_1a87_ca22_e1cc, + 0x275a_03e4_5add_a7c3, + ]), + Fr::from_raw([ + 0x58a2_53cf_b6a9_5786, + 0x07e5_6145_3fc5_648b, + 0xeb08_e47e_5fea_bcf8, + 0x2e5a_10f0_8b5a_b8bb, + ]), + Fr::from_raw([ + 0xe033_d82c_efe7_8ce3, + 0xc141_a5b6_d594_bec4, + 0xb84e_9c33_3b29_32f1, + 0x1459_cb85_8720_8473, + ]), + ], + [ + Fr::from_raw([ + 0x5cec_7e7b_338f_be1b, + 0x52f9_332f_bffc_fbbd, + 0x7b92_ce81_0e14_a400, + 0x193a_e592_1d78_b5de, + ]), + Fr::from_raw([ + 0x6022_4be6_7248_e82c, + 0x3743_84f4_a072_8205, + 0x8911_1fb2_c466_0281, + 0x3097_898a_5d00_11a4, + ]), + Fr::from_raw([ + 0x5499_80de_8629_30f5, + 0x1979_b2d1_c465_b4d9, + 0x5717_82fd_96ce_54b4, + 0x378d_97bf_8c86_4ae7, + ]), + ], + [ + Fr::from_raw([ + 0x37ea_32a9_71d1_7884, + 0xdbc7_f5cb_4609_3421, + 0x8813_6287_ce37_6b08, + 0x2eb0_4ea7_c01d_97ec, + ]), + Fr::from_raw([ + 0xead3_726f_1af2_e7b0, + 0x861c_bda4_7680_4e6c, + 0x2302_a1c2_2e49_baec, + 0x3642_5347_ea03_f641, + ]), + Fr::from_raw([ + 0xecd6_27e5_9590_d09e, + 0x3f5b_5ca5_a19a_9701, + 0xcc99_6cd8_5c98_a1d8, + 0x26b7_2df4_7408_ad42, + ]), + ], + [ + Fr::from_raw([ + 0x59be_ce31_f0a3_1e95, + 0xde01_212e_e458_8f89, + 0x1f05_636c_610b_89aa, + 0x1301_80e4_4e29_24db, + ]), + Fr::from_raw([ + 0x9ea8_e7bc_7926_3550, + 0xdf77_93cc_89e5_b52f, + 0x7327_5aca_ed5f_579c, + 0x219e_9773_7d39_79ba, + ]), + Fr::from_raw([ + 0x9c12_635d_f251_d153, + 0x3b06_72dd_7d42_cbb4, + 0x3461_363f_81c4_89a2, + 0x3cdb_9359_8a5c_a528, + ]), + ], + [ + Fr::from_raw([ + 0x2861_ce16_f219_d5a9, + 0x4ad0_4470_45a7_c5aa, + 0x2072_4b92_7a0c_a81c, + 0x0e59_e6f3_32d7_ed37, + ]), + Fr::from_raw([ + 0x43b0_a3fc_ff20_36bd, + 0x172c_c07b_9d33_fbf9, + 0x3d73_6946_7222_697a, + 0x1b06_4342_d51a_4275, + ]), + Fr::from_raw([ + 0x3eb3_1022_8a0e_5f6c, + 0x78fa_9fb9_1712_21b7, + 0x2f36_3c55_b288_2e0b, + 0x30b8_2a99_8cbd_8e8a, + ]), + ], + [ + Fr::from_raw([ + 0xe46f_6d42_9874_0107, + 0x8ad7_1ea7_15be_0573, + 0x63df_7a76_e858_a4aa, + 0x23e4_ab37_183a_cba4, + ]), + Fr::from_raw([ + 0xfca9_95e2_b599_14a1, + 0xacfe_1464_0de0_44f2, + 0x5d33_094e_0bed_a75b, + 0x2795_d5c5_fa42_8022, + ]), + Fr::from_raw([ + 0xc26d_909d_ee8b_53c0, + 0xa668_7c3d_f16c_8fe4, + 0xd765_f26d_d03f_4c45, + 0x3001_ca40_1e89_601c, + ]), + ], + [ + Fr::from_raw([ + 0xe7fe_a6bd_f347_1380, + 0xe84b_5beb_ae4e_501d, + 0xf7bf_86e8_9280_827f, + 0x0072_e45c_c676_b08e, + ]), + Fr::from_raw([ + 0xd0c5_4dde_b26b_86c0, + 0xb648_29e2_d40e_41bd, + 0xe2ab_e4c5_18ce_599e, + 0x13de_7054_8487_4bb5, + ]), + Fr::from_raw([ + 0x3891_5b43_2a99_59a5, + 0x82bb_18e5_af1b_05bb, + 0x3159_50f1_211d_efe8, + 0x0408_a9fc_f9d6_1abf, + ]), + ], + [ + Fr::from_raw([ + 0x3407_0cbe_e268_86a0, + 0xae4d_23b0_b41b_e9a8, + 0xbb4e_4a14_00cc_d2c4, + 0x2780_b9e7_5b55_676e, + ]), + Fr::from_raw([ + 0x9405_5920_98b4_056f, + 0xdc4d_8fbe_fe24_405a, + 0xf803_33ec_8563_4ac9, + 0x3a57_0d4d_7c4e_7ac3, + ]), + Fr::from_raw([ + 0x78d2_b247_8995_20b4, + 0xe2cc_1507_bebd_cc62, + 0xf347_c247_fcf0_9294, + 0x0c13_cca7_cb1f_9d2c, + ]), + ], + [ + Fr::from_raw([ + 0x2e8c_88f7_7074_70e0, + 0x0b50_bb2e_b82d_f74d, + 0xd261_4a19_7c6b_794b, + 0x14f5_9baa_03cd_0ca4, + ]), + Fr::from_raw([ + 0xbe52_476e_0a16_f3be, + 0xa51d_54ed_e661_67f5, + 0x6f54_6e17_04c3_9c60, + 0x307d_efee_925d_fb43, + ]), + Fr::from_raw([ + 0x380b_67d8_0473_dce3, + 0x6611_0683_6adf_e5e7, + 0x7a07_e767_4b5a_2621, + 0x1960_cd51_1a91_e060, + ]), + ], + [ + Fr::from_raw([ + 0x15aa_f1f7_7125_89dd, + 0xb8ee_335d_8828_4cbe, + 0xca2a_d0fb_5667_2500, + 0x2301_ef9c_63ea_84c5, + ]), + Fr::from_raw([ + 0x5e68_478c_4d60_27a9, + 0xc861_82d1_b424_6b58, + 0xd10f_4cd5_2be9_7f6b, + 0x029a_5a47_da79_a488, + ]), + Fr::from_raw([ + 0x2cc4_f962_eaae_2260, + 0xf97f_e46b_6a92_5428, + 0x2360_d17d_890e_55cb, + 0x32d7_b16a_7f11_cc96, + ]), + ], + [ + Fr::from_raw([ + 0xc0ca_b915_d536_3d9f, + 0xa5f2_404c_d7b3_5eb0, + 0x18e8_57a9_8d49_8cf7, + 0x2670_3e48_c03b_81ca, + ]), + Fr::from_raw([ + 0xf691_123a_e112_b928, + 0xf443_88bd_6b89_221e, + 0x88ac_8d25_a246_03f1, + 0x0486_82a3_5b32_65bc, + ]), + Fr::from_raw([ + 0x3ab7_defc_b8d8_03e2, + 0x91d6_e171_5164_775e, + 0xd72c_ddc6_cf06_b507, + 0x06b1_3904_41fa_7030, + ]), + ], + [ + Fr::from_raw([ + 0xbcd7_9541_4a6e_2e86, + 0x43b3_60f6_386a_86d7, + 0x1689_426d_ce05_fcd8, + 0x31aa_0eeb_868c_626d, + ]), + Fr::from_raw([ + 0xed77_f5d5_76b9_9cc3, + 0x90ef_d8f4_1b20_78b2, + 0x057a_bad3_764c_104b, + 0x2394_64f7_5bf7_b6af, + ]), + Fr::from_raw([ + 0xb2cb_4873_07c1_cecf, + 0xa5cc_47c5_9654_b2a7, + 0xa45e_19ed_813a_54ab, + 0x0a64_d4c0_4fd4_26bd, + ]), + ], + [ + Fr::from_raw([ + 0x1f73_1532_2f65_8735, + 0x777c_7a92_1a06_2e9d, + 0x576a_4ad2_5986_0fb1, + 0x21fb_bdbb_7367_0734, + ]), + Fr::from_raw([ + 0x6743_2400_3fc5_2146, + 0x5b86_d294_63d3_1564, + 0xd937_1ca2_eb95_acf3, + 0x31b8_6f3c_f017_05d4, + ]), + Fr::from_raw([ + 0x7045_f48a_a4eb_4f6f, + 0x1354_1d65_157e_e1ce, + 0x05ef_1736_d090_56f6, + 0x2bfd_e533_5437_7c91, + ]), + ], + [ + Fr::from_raw([ + 0x5a13_a58d_2001_1e2f, + 0xf4d5_239c_11d0_eafa, + 0xd558_f36e_65f8_eca7, + 0x1233_ca93_6ec2_4671, + ]), + Fr::from_raw([ + 0x6e70_af0a_7a92_4b3a, + 0x8780_58d0_234a_576f, + 0xc437_846d_8e0b_2b30, + 0x27d4_52a4_3ac7_dea2, + ]), + Fr::from_raw([ + 0xa025_76b9_4392_f980, + 0x6a30_641a_1c3d_87b2, + 0xe816_ea8d_a493_e0fa, + 0x2699_dba8_2184_e413, + ]), + ], + [ + Fr::from_raw([ + 0x608c_6f7a_61b5_6e55, + 0xf185_8466_4f8c_ab49, + 0xc398_8bae_e42e_4b10, + 0x36c7_22f0_efcc_8803, + ]), + Fr::from_raw([ + 0x6e49_ac17_0dbb_7fcd, + 0x85c3_8899_a7b5_a833, + 0x08b0_f2ec_89cc_aa37, + 0x02b3_ff48_861e_339b, + ]), + Fr::from_raw([ + 0xa8c5_ae03_ad98_e405, + 0x6fc3_ff4c_49eb_59ad, + 0x6016_2f44_27bc_657b, + 0x0b70_d061_d58d_8a7f, + ]), + ], + [ + Fr::from_raw([ + 0x2e06_cc4a_f33b_0a06, + 0xad3d_e8be_46ed_9693, + 0xf875_3ade_b9d7_cee2, + 0x3fc2_a13f_127f_96a4, + ]), + Fr::from_raw([ + 0xc120_80ac_117e_e15f, + 0x00cb_3d62_1e17_1d80, + 0x1bd6_3434_ac8c_419f, + 0x0c41_a6e4_8dd2_3a51, + ]), + Fr::from_raw([ + 0x9685_213e_9692_f5e1, + 0x72aa_ad7e_4e75_339d, + 0xed44_7653_7169_084e, + 0x2de8_072a_6bd8_6884, + ]), + ], + [ + Fr::from_raw([ + 0x0ad0_1184_567b_027c, + 0xb81c_f735_cc9c_39c0, + 0x9d34_96a3_d9fe_05ec, + 0x0355_7a8f_7b38_a17f, + ]), + Fr::from_raw([ + 0x45bc_b5ac_0082_6abc, + 0x060f_4336_3d81_8e54, + 0xee97_6d34_282f_1a37, + 0x0b5f_5955_2f49_8735, + ]), + Fr::from_raw([ + 0x2f29_09e1_7e22_b0df, + 0xf5d6_46e5_7507_e548, + 0xfedb_b185_70dc_7300, + 0x0e29_23a5_fee7_b878, + ]), + ], + [ + Fr::from_raw([ + 0xf71e_ed73_f15b_3326, + 0xcf1c_b37c_3b03_2af6, + 0xc787_be97_020a_7fdd, + 0x1d78_5005_a7a0_0592, + ]), + Fr::from_raw([ + 0x0acf_bfb2_23f8_f00d, + 0xa590_b88a_3b06_0294, + 0x0ba5_fedc_b8f2_5bd2, + 0x1ad7_72c2_73d9_c6df, + ]), + Fr::from_raw([ + 0xc1ce_13d6_0f2f_5031, + 0x8105_10eb_61f0_672d, + 0xa78f_3275_c278_234b, + 0x027b_d647_85fc_bd2a, + ]), + ], + [ + Fr::from_raw([ + 0x8337_f5e0_7923_a853, + 0xe224_3134_6945_7b8e, + 0xce6f_8ffe_a103_1b6d, + 0x2080_0f44_1b4a_0526, + ]), + Fr::from_raw([ + 0xa33d_7bed_89a4_408a, + 0x36cd_c8ee_d662_ad37, + 0x6eea_2cd4_9f43_12b4, + 0x3d5a_d61d_7b65_f938, + ]), + Fr::from_raw([ + 0x3bbb_ae94_cc19_5284, + 0x1df9_6cc0_3ea4_b26d, + 0x02c5_f91b_e4dd_8e3d, + 0x1333_8bc3_51fc_46dd, + ]), + ], + [ + Fr::from_raw([ + 0xc527_1c29_7852_819e, + 0x646c_49f9_b46c_bf19, + 0xb87d_b1e2_af3e_a923, + 0x25e5_2be5_07c9_2760, + ]), + Fr::from_raw([ + 0x5c38_0ab7_01b5_2ea9, + 0xa34c_83a3_485c_6b2d, + 0x7109_6d8b_1b98_3c98, + 0x1c49_2d64_c157_aaa4, + ]), + Fr::from_raw([ + 0xa20c_0b3d_a0da_4ca3, + 0xd434_87bc_288d_f682, + 0xf4e6_c5e7_a573_f592, + 0x0c5b_8015_7999_2718, + ]), + ], + [ + Fr::from_raw([ + 0x7ea3_3c93_e408_33cf, + 0x584e_9e62_a7f9_554e, + 0x6869_5c0c_d7cb_f43d, + 0x1090_b1b4_d2be_be7a, + ]), + Fr::from_raw([ + 0xe383_e1ec_3baa_8d69, + 0x1b21_8e35_ecf2_328e, + 0x68f5_ce5c_bed1_9cad, + 0x33e3_8018_a801_387a, + ]), + Fr::from_raw([ + 0xb76b_0b3d_787e_e953, + 0x5f4a_02d2_8729_e3ae, + 0xeef8_d83d_0e87_6bac, + 0x1654_af18_772b_2da5, + ]), + ], + [ + Fr::from_raw([ + 0xef7c_e6a0_1326_5477, + 0xbb08_9387_0367_ec6c, + 0x4474_2de8_8c5a_b0d5, + 0x1678_be3c_c9c6_7993, + ]), + Fr::from_raw([ + 0xaf5d_4789_3348_f766, + 0xdaf1_8183_55b1_3b4f, + 0x7ff9_c6be_546e_928a, + 0x3780_bd1e_01f3_4c22, + ]), + Fr::from_raw([ + 0xa123_8032_0d7c_c1de, + 0x5d11_e69a_a6c0_b98c, + 0x0786_018e_7cb7_7267, + 0x1e83_d631_5c9f_125b, + ]), + ], + [ + Fr::from_raw([ + 0x1799_603e_855c_e731, + 0xc486_894d_76e0_c33b, + 0x160b_4155_2f29_31c8, + 0x354a_fd0a_2f9d_0b26, + ]), + Fr::from_raw([ + 0x8b99_7ee0_6be1_bff3, + 0x60b0_0dbe_1fac_ed07, + 0x2d8a_ffa6_2905_c5a5, + 0x00cd_6d29_f166_eadc, + ]), + Fr::from_raw([ + 0x08d0_6419_1708_2f2c, + 0xc60d_0197_3f18_3057, + 0xdbe0_e3d7_cdbc_66ef, + 0x1d62_1935_2768_e3ae, + ]), + ], + [ + Fr::from_raw([ + 0xfa08_dd98_0638_7577, + 0xafe3_ca1d_b8d4_f529, + 0xe48d_2370_d7d1_a142, + 0x1463_36e2_5db5_181d, + ]), + Fr::from_raw([ + 0xa901_d3ce_84de_0ad4, + 0x022e_54b4_9c13_d907, + 0x997a_2116_3e2e_43df, + 0x0005_d8e0_85fd_72ee, + ]), + Fr::from_raw([ + 0x1c36_f313_4196_4484, + 0x6f8e_bc1d_2296_021a, + 0x0dd5_e61c_8a4e_8642, + 0x364e_97c7_a389_3227, + ]), + ], + [ + Fr::from_raw([ + 0xd7a0_0c03_d2e0_baaa, + 0xfa97_ec80_ad30_7a52, + 0x561c_6fff_1534_6878, + 0x0118_9910_671b_c16b, + ]), + Fr::from_raw([ + 0x63fd_8ac5_7a95_ca8c, + 0x4c0f_7e00_1df4_90aa, + 0x5229_dfaa_0123_1a45, + 0x162a_7c80_f4d2_d12e, + ]), + Fr::from_raw([ + 0x32e6_9efb_22f4_0b96, + 0xcaff_31b4_fda3_2124, + 0x2604_e4af_b09f_8603, + 0x2a0d_6c09_5766_66bb, + ]), + ], + [ + Fr::from_raw([ + 0xc0a0_180f_8cbf_c0d2, + 0xf444_d10d_63a7_4e2c, + 0xe16a_4d60_3d5a_808e, + 0x0978_e5c5_1e1e_5649, + ]), + Fr::from_raw([ + 0x03f4_460e_bc35_1b6e, + 0x0508_7d90_3bda_cfd1, + 0xebe1_9bbd_ce25_1011, + 0x1bdc_ee3a_aca9_cd25, + ]), + Fr::from_raw([ + 0xf619_64bf_3ade_7670, + 0x0c94_7321_e007_5e3f, + 0xe494_7914_0b19_44fd, + 0x1862_cccb_70b5_b885, + ]), + ], + [ + Fr::from_raw([ + 0xc326_7da6_e94a_dc50, + 0x39ee_99c1_cc6e_5dda, + 0xbc26_cc88_3a19_87e1, + 0x1f3e_91d8_63c1_6922, + ]), + Fr::from_raw([ + 0x0f85_b4ac_2c36_7406, + 0xfa66_1465_c656_ad99, + 0xef5c_08f8_478f_663a, + 0x1af4_7a48_a601_6a49, + ]), + Fr::from_raw([ + 0x0eab_cd87_e7d0_1b15, + 0x1c36_98b0_a2e3_da10, + 0x009d_5733_8c69_3505, + 0x3c8e_e901_956e_3d3f, + ]), + ], + [ + Fr::from_raw([ + 0x8b94_7721_8967_3476, + 0xe10c_e2b7_069f_4dbd, + 0x68d0_b024_f591_b520, + 0x1660_a8cd_e7fe_c553, + ]), + Fr::from_raw([ + 0x9d8d_0f67_fdaa_79d5, + 0x3963_c2c1_f558_6e2f, + 0x1303_9363_34dd_1132, + 0x0f6d_9919_29d5_e4e7, + ]), + Fr::from_raw([ + 0x7a43_3091_e1ce_2d3a, + 0x4e7f_da77_0712_f343, + 0xcc62_5eaa_ab52_b4dc, + 0x02b9_cea1_921c_d9f6, + ]), + ], + [ + Fr::from_raw([ + 0x3797_b2d8_3760_43b3, + 0xd8ca_f468_976f_0472, + 0x214f_7c67_84ac_b565, + 0x14a3_23b9_9b90_0331, + ]), + Fr::from_raw([ + 0x347f_ef2c_00f0_953a, + 0x718b_7fbc_7788_af78, + 0xec01_ea79_642d_5760, + 0x1904_76b5_80cb_9277, + ]), + Fr::from_raw([ + 0xff4e_7e6f_b268_dfd7, + 0x9660_902b_6008_7651, + 0xa424_63d3_0b44_2b6f, + 0x090a_3a9d_869d_2eef, + ]), + ], + [ + Fr::from_raw([ + 0xf983_387e_a045_6203, + 0xe365_0013_04f9_a11e, + 0x0dbe_8fd2_270a_6795, + 0x3877_a955_8636_7567, + ]), + Fr::from_raw([ + 0x39c0_af0f_e01f_4a06, + 0x6011_8c53_a218_1352, + 0x5df3_9a2c_c63d_dc0a, + 0x2d89_4691_240f_e953, + ]), + Fr::from_raw([ + 0x1aca_9eaf_9bba_9850, + 0x5914_e855_eeb4_4aa1, + 0x7ef7_1780_2016_6189, + 0x21b9_c182_92bd_bc59, + ]), + ], + [ + Fr::from_raw([ + 0x33f5_09a7_4ad9_d39b, + 0x272e_1cc6_c36a_2968, + 0x505a_05f2_a6ae_834c, + 0x2fe7_6be7_cff7_23e2, + ]), + Fr::from_raw([ + 0x0df9_fa97_277f_a8b4, + 0xd15b_ff84_0dda_e8a5, + 0x9299_81d7_cfce_253b, + 0x187a_a448_f391_e3ca, + ]), + Fr::from_raw([ + 0xf0c6_6af5_ffc7_3736, + 0x663c_cf7b_2ffe_4b5e, + 0x007a_b3aa_3617_f422, + 0x0b70_83ad_7517_07bf, + ]), + ], + [ + Fr::from_raw([ + 0x2f9b_20f1_fbd4_9791, + 0x1975_b962_f6cb_8e0b, + 0x3bc4_ca99_02c5_2acb, + 0x030d_dbb4_7049_3f16, + ]), + Fr::from_raw([ + 0x3a1c_62ca_8fbf_2525, + 0x8fb8_ab9d_60ea_17b2, + 0x950b_0ab1_8d35_46df, + 0x3130_fbaf_fb5a_a82a, + ]), + Fr::from_raw([ + 0x43a8_7618_0dc3_82e0, + 0x15ce_2ead_2fcd_051e, + 0x4f74_d74b_ac2e_e457, + 0x337f_5447_07c4_30f0, + ]), + ], + [ + Fr::from_raw([ + 0x26de_98a8_736d_1d11, + 0x7d8e_471a_9fb9_5fef, + 0xac9d_91b0_930d_ac75, + 0x3499_7991_9015_394f, + ]), + Fr::from_raw([ + 0xccfc_b618_31d5_c775, + 0x3bf9_3da6_fff3_1d95, + 0x2305_cd7a_921e_c5f1, + 0x027c_c4ef_e3fb_35dd, + ]), + Fr::from_raw([ + 0xc3fa_2629_635d_27de, + 0x67f1_c6b7_3147_64af, + 0x61b7_1a36_9868_2ad2, + 0x037f_9f23_6595_4c5b, + ]), + ], + [ + Fr::from_raw([ + 0x77c5_b024_8483_71ae, + 0x6041_4abe_362d_01c9, + 0x10f1_cc6d_f8b4_bcd7, + 0x1f69_7cac_4d07_feb7, + ]), + Fr::from_raw([ + 0x786a_dd24_4aa0_ef29, + 0x3145_c478_0631_09d6, + 0x26e6_c851_fbd5_72a6, + 0x267a_750f_e5d7_cfbc, + ]), + Fr::from_raw([ + 0x180e_2b4d_3e75_6f65, + 0xaf28_5fa8_2ce4_fae5, + 0x678c_9996_d9a4_72c8, + 0x0c91_feab_4a43_193a, + ]), + ], + [ + Fr::from_raw([ + 0x79c4_7c57_3ac4_10f7, + 0x7e3b_83af_4a4b_a3ba, + 0x2186_c303_8ea0_5e69, + 0x1745_569a_0a3e_3014, + ]), + Fr::from_raw([ + 0x1e03_8852_2696_191f, + 0xfdff_66c6_f3b5_ffe1, + 0xeca5_1207_78a5_6711, + 0x2986_3d54_6e7e_7c0d, + ]), + Fr::from_raw([ + 0x2f22_5e63_66bf_e390, + 0xa79a_03df_8339_94c6, + 0xbf06_bae4_9ef8_53f6, + 0x1148_d6ab_2bd0_0192, + ]), + ], + [ + Fr::from_raw([ + 0xf4f6_331a_8b26_5d15, + 0xf745_f45d_350d_41d4, + 0xe18b_1499_060d_a366, + 0x02e0_e121_b0f3_dfef, + ]), + Fr::from_raw([ + 0x078a_e6aa_1510_54b7, + 0x6904_0173_6d44_a653, + 0xb89e_f73a_40a2_b274, + 0x0d0a_a46e_76a6_a278, + ]), + Fr::from_raw([ + 0x9a4d_532c_7b6e_0958, + 0x392d_de71_0f1f_06db, + 0xeee5_45f3_fa6d_3d08, + 0x1394_3675_b04a_a986, + ]), + ], + [ + Fr::from_raw([ + 0x961f_c818_dcbb_66b5, + 0xc9f2_b325_7530_dafe, + 0xd97a_11d6_3088_f5d9, + 0x2901_ec61_942d_34aa, + ]), + Fr::from_raw([ + 0xfdf5_44b9_63d1_fdc7, + 0x22ff_a2a2_af9f_a3e3, + 0xf431_d544_34a3_e0cf, + 0x2020_4a21_05d2_2e7e, + ]), + Fr::from_raw([ + 0x1211_b9e2_190d_6852, + 0xa004_abe8_e015_28c4, + 0x5c1e_3e9e_27a5_71c3, + 0x3a8a_6282_9512_1d5c, + ]), + ], +]; From 32e07aee1bc7cb1b17ae81c4dcab2b4f3cc7fb20 Mon Sep 17 00:00:00 2001 From: phamnhatminh1292001 <66765903+phamnhatminh1292001@users.noreply.github.com> Date: Wed, 29 May 2024 16:54:44 +0700 Subject: [PATCH 10/15] Add more testcases and fix clippy warnings --- zkmemory/src/commitment/verkle_tree.rs | 140 ++++++++++++++++++++----- zkmemory/src/lib.rs | 8 +- 2 files changed, 118 insertions(+), 30 deletions(-) diff --git a/zkmemory/src/commitment/verkle_tree.rs b/zkmemory/src/commitment/verkle_tree.rs index 09e2933..4caefbc 100644 --- a/zkmemory/src/commitment/verkle_tree.rs +++ b/zkmemory/src/commitment/verkle_tree.rs @@ -6,6 +6,10 @@ extern crate std; use crate::{ constraints, poseidon::poseidon_hash::{ConstantLength, Hash, Spec}, + poseidon::{ + poseidon_constants::{MDS_FR, MDS_INV_FR, ROUND_CONSTANTS_FR}, + poseidon_hash::Mtrx, + }, }; use alloc::{vec, vec::Vec}; use constraints::gadgets::Table; @@ -36,6 +40,7 @@ use super::kzg::verify_kzg_proof; pub struct VerkleTreeConfig { advice: [Column; 2], check: Column, + /// pub instance: Column, indices: Column, selector: Column, @@ -276,16 +281,32 @@ impl, const W: usize, const R: usize, const A: usize> } } +#[derive(Clone, Debug)] +/// +pub struct OrchardNullifier; + +impl Spec for OrchardNullifier { + fn full_rounds() -> usize { + 8 + } + + fn partial_rounds() -> usize { + 56 + } + + fn sbox(val: Fr) -> Fr { + val.pow_vartime([5]) + } + + fn constants() -> (Vec<[Fr; 3]>, Mtrx, Mtrx) { + (ROUND_CONSTANTS_FR[..].to_vec(), MDS_FR, MDS_INV_FR) + } +} + #[cfg(test)] mod tests { use super::*; - use crate::{ - commitment::kzg::create_kzg_proof, - poseidon::{ - poseidon_constants::{MDS_FR, MDS_INV_FR, ROUND_CONSTANTS_FR}, - poseidon_hash::*, - }, - }; + use crate::commitment::kzg::create_kzg_proof; use alloc::vec; use core::marker::PhantomData; use group::Curve; @@ -298,6 +319,7 @@ mod tests { }, transcript::Blake2bWrite, }; + use rand::thread_rng; use rand_core::OsRng; /// pub struct KZGTest { @@ -314,6 +336,7 @@ mod tests { } } + /// pub fn poly_from_evals(&self, evals: [Fr; 4]) -> Polynomial { // Use Lagrange interpolation self.domain.coeff_from_vec(lagrange_interpolate( @@ -322,12 +345,14 @@ mod tests { )) } + /// pub fn commit(&self, evals: [Fr; 4]) -> G1Affine { self.kzg_params .commit(&self.poly_from_evals(evals), Blind(Fr::random(OsRng))) .to_affine() } + /// pub fn create_proof( &self, point: Vec, @@ -342,6 +367,7 @@ mod tests { >(&self.kzg_params, point, polynomial, commitment) } + /// pub fn group_to_scalar, const W: usize, const R: usize>( &self, g: G1Affine, @@ -353,25 +379,39 @@ mod tests { } } - #[derive(Clone, Debug)] - pub struct OrchardNullifier; - - impl Spec for OrchardNullifier { - fn full_rounds() -> usize { - 8 - } - - fn partial_rounds() -> usize { - 56 - } - - fn sbox(val: Fr) -> Fr { - val.pow_vartime([5]) - } - - fn constants() -> (Vec<[Fr; 3]>, Mtrx, Mtrx) { - (ROUND_CONSTANTS_FR[..].to_vec(), MDS_FR, MDS_INV_FR) + fn create_verkle_tree_proof( + leaf: Fr, + indices: Vec, + ) -> (VerkleTreeCircuit, Fr) { + let rng = thread_rng(); + let kzg = KZGTest::new(2); + let mut commitment: Vec = vec![]; + let mut poly: Vec> = vec![]; + let mut non_leaf_elements: Vec = vec![]; + let mut temp = leaf; + for i in 0..indices.len() { + let mut evals = [0; 4].map(|_| Fr::random(rng.clone())); + evals[indices[i]] = temp; + let p = kzg.poly_from_evals(evals); + let c = kzg.commit(evals); + poly.push(p); + commitment.push(c); + temp = kzg.group_to_scalar::(c); + non_leaf_elements.push(temp); } + let root = temp; + let indices_fr: Vec = indices.iter().map(|x| Fr::from(*x as u64)).collect(); + let proof = kzg.create_proof(indices_fr.clone(), poly, commitment.clone()); + let circuit = VerkleTreeCircuit:: { + leaf, + commitment, + proof, + non_leaf_elements, + indices: indices_fr, + params: kzg.kzg_params, + _marker: PhantomData, + }; + (circuit, root) } #[test] @@ -459,8 +499,46 @@ mod tests { assert_ne!(prover.verify(), Ok(())); } + #[test] + fn invalid_opening_index_range() { + let kzg = KZGTest::new(2); + let leaf = Fr::from(1); + let indices = vec![Fr::from(4)]; + let evals = [leaf, Fr::from(0), Fr::from(0), Fr::from(0)]; + let poly0 = vec![kzg.poly_from_evals(evals)]; + let commit = kzg.commit(evals); + let root = kzg.group_to_scalar::(commit); + let non_leaf_elements = vec![root]; + let commitment = vec![commit]; + let proof = kzg.create_proof(vec![Fr::from(0)], poly0, commitment.clone()); + + let circuit = VerkleTreeCircuit:: { + leaf, + commitment, + proof, + non_leaf_elements, + indices, + params: kzg.kzg_params, + _marker: PhantomData, + }; + + let prover = + MockProver::run(10, &circuit, vec![vec![leaf, root]]).expect("Cannot run the circuit"); + assert_ne!(prover.verify(), Ok(())); + } + #[test] fn valid_verkle_tree_2() { + let leaf = Fr::from(4213); + let indices = vec![0, 1, 2, 3]; + let (circuit, root) = create_verkle_tree_proof(leaf, indices); + let prover = + MockProver::run(10, &circuit, vec![vec![leaf, root]]).expect("Cannot run the circuit"); + assert_eq!(prover.verify(), Ok(())); + } + + #[test] + fn wrong_verkle_path() { let kzg = KZGTest::new(2); let leaf = Fr::from(1); let indices = vec![Fr::from(0), Fr::from(1)]; @@ -473,7 +551,7 @@ mod tests { let commit_1 = kzg.commit(evals_1); let root = kzg.group_to_scalar::(commit_1); - let non_leaf_elements = vec![non_leaf_0, root]; + let non_leaf_elements = vec![Fr::from(0), root]; let commitment = vec![commit_0, commit_1]; let proof = kzg.create_proof( vec![Fr::from(0), Fr::from(1)], @@ -491,6 +569,16 @@ mod tests { _marker: PhantomData, }; + let prover = + MockProver::run(10, &circuit, vec![vec![leaf, root]]).expect("Cannot run the circuit"); + assert_ne!(prover.verify(), Ok(())); + } + + #[test] + fn valid_verkle_tree_3() { + let leaf = Fr::from(34213); + let indices = vec![0, 1, 2, 1, 3, 1, 2, 0, 3]; + let (circuit, root) = create_verkle_tree_proof(leaf, indices); let prover = MockProver::run(10, &circuit, vec![vec![leaf, root]]).expect("Cannot run the circuit"); assert_eq!(prover.verify(), Ok(())); diff --git a/zkmemory/src/lib.rs b/zkmemory/src/lib.rs index 9fd0d7d..946aaa0 100644 --- a/zkmemory/src/lib.rs +++ b/zkmemory/src/lib.rs @@ -2,13 +2,13 @@ #![recursion_limit = "256"] #![cfg_attr(not(feature = "std"), no_std)] #![deny( - // unused, - // warnings, + unused, + warnings, future_incompatible, nonstandard_style, rust_2018_idioms, - // missing_docs, - // unused_imports + missing_docs, + unused_imports )] #![forbid(unsafe_code)] From 9095d101f801947efd7fc834e6bd56e7992b74c6 Mon Sep 17 00:00:00 2001 From: phamnhatminh1292001 <66765903+phamnhatminh1292001@users.noreply.github.com> Date: Thu, 30 May 2024 14:01:36 +0700 Subject: [PATCH 11/15] Add inline documents and refactor code --- zkmemory/src/commitment/verkle_tree.rs | 301 +++++++++++++++---------- zkmemory/src/poseidon/poseidon_hash.rs | 4 +- 2 files changed, 184 insertions(+), 121 deletions(-) diff --git a/zkmemory/src/commitment/verkle_tree.rs b/zkmemory/src/commitment/verkle_tree.rs index 4caefbc..3c05065 100644 --- a/zkmemory/src/commitment/verkle_tree.rs +++ b/zkmemory/src/commitment/verkle_tree.rs @@ -1,5 +1,7 @@ //! Circuit for proving the correctness of the Verkle tree commitment. - +//! The label of a parent node is the commitment of the messages in all its children. +//! We choose KZG as the polynomial commitment scheme for committing the messages in the children. +//! Right now, the circuit could only support committing messages in the field Fr of Bn256, not in all finite fields. extern crate alloc; use core::marker::PhantomData; extern crate std; @@ -35,16 +37,31 @@ use halo2_proofs::{ use super::kzg::verify_kzg_proof; +const OMEGA_POWER: [Fr; 5] = [ + Fr::from_raw([0x01, 0, 0, 0]), + Fr::from_raw([0x07, 0, 0, 0]), + Fr::from_raw([0x31, 0, 0, 0]), + Fr::from_raw([0x0157, 0, 0, 0]), + Fr::from_raw([0x0961, 0, 0, 0]), +]; + #[derive(Clone, Copy, Debug)] /// Verkle tree config +/// A is the number of children in each parent node pub struct VerkleTreeConfig { + /// advice has 2 columns, the first element is the current node in the opening path, + /// and the second element is the direct parent of the current node advice: [Column; 2], + /// the verification result of the opening of the path check: Column, - /// + /// the instance of the config, consists of the leaf and root nodes pub instance: Column, + /// the indices in the opening path of the tree indices: Column, + /// the selector selector: Column, selector_check: Selector, + /// the lookup table. indices are required to be in the lookup table: Table, } impl VerkleTreeConfig { @@ -90,19 +107,25 @@ impl VerkleTreeConfig { } } } -/// +/// Verkle tree circuit pub(crate) struct VerkleTreeCircuit< S: Spec, const W: usize, const R: usize, const A: usize, > { + /// The leaf element in the opening path pub(crate) leaf: Fr, + /// The KZG commitment for each parent node pub(crate) commitment: Vec, + /// The proof of the valid opening path pub(crate) proof: Vec, - pub(crate) non_leaf_elements: Vec, + /// The other element in the opening paths, including the root and excluding the leaf + pub(crate) path_elements: Vec, + /// The indices of the opening paths pub(crate) indices: Vec, + /// The KZG parameter params pub(crate) params: ParamsKZG, _marker: PhantomData, } @@ -117,7 +140,7 @@ impl, const W: usize, const R: usize, const A: usize> Circuit< leaf: Fr::ZERO, commitment: vec![G1Affine::generator()], proof: vec![0], - non_leaf_elements: vec![Fr::ZERO], + path_elements: vec![Fr::ZERO], indices: vec![Fr::ZERO], params: ParamsKZG::::new(1), _marker: PhantomData, @@ -136,7 +159,7 @@ impl, const W: usize, const R: usize, const A: usize> Circuit< config: Self::Config, mut layouter: impl Layouter, ) -> Result<(), Error> { - assert_eq!(self.indices.len(), self.non_leaf_elements.len()); + assert_eq!(self.indices.len(), self.path_elements.len()); let leaf_cell = layouter.assign_region( || "assign leaf", @@ -151,9 +174,9 @@ impl, const W: usize, const R: usize, const A: usize> Circuit< )?; layouter.assign_region( - || "Verkle proof", + || "verkle proof", |mut region| { - for i in 0..self.non_leaf_elements.len() { + for i in 0..self.path_elements.len() { if i == 0 { self.assign( self.leaf, @@ -165,7 +188,7 @@ impl, const W: usize, const R: usize, const A: usize> Circuit< )?; } else { self.assign( - self.non_leaf_elements[i - 1], + self.path_elements[i - 1], self.commitment[i], self.indices[i], &mut region, @@ -179,13 +202,17 @@ impl, const W: usize, const R: usize, const A: usize> Circuit< }, )?; - let mut poly_list = vec![]; - poly_list.push(self.leaf); - for i in 0..self.non_leaf_elements.len() - 1 { - poly_list.push(self.non_leaf_elements[i]); - } + let mut poly_list = vec![self.leaf]; + poly_list.extend(&self.path_elements[..self.path_elements.len() - 1]); - let b = verify_kzg_proof::< + let point_list = self + .indices + .iter() + .map(|x| OMEGA_POWER[x.to_bytes()[0] as usize]) + .collect(); + + // assign the verification result of the opening, it should be True + let b = Fr::from(verify_kzg_proof::< KZGCommitmentScheme, VerifierSHPLONK<'_, Bn256>, Challenge255, @@ -193,12 +220,11 @@ impl, const W: usize, const R: usize, const A: usize> Circuit< AccumulatorStrategy<'_, Bn256>, >( &self.params, - self.indices.clone(), + point_list, poly_list, self.commitment.clone(), self.proof.as_slice(), - ); - let b = Fr::from(b); + )); layouter.assign_region( || "assign check result", @@ -213,6 +239,7 @@ impl, const W: usize, const R: usize, const A: usize> Circuit< }, )?; + // assign the root value let root = layouter.assign_region( || "assign root", |mut region| { @@ -220,11 +247,12 @@ impl, const W: usize, const R: usize, const A: usize> Circuit< || "assign root", config.advice[0], 0, - || Value::known(self.non_leaf_elements[self.non_leaf_elements.len() - 1]), + || Value::known(self.path_elements[self.path_elements.len() - 1]), ) }, )?; + // constraints the leaf and the root being equal to the public instances layouter.constrain_instance(leaf_cell.cell(), config.instance, 0)?; layouter.constrain_instance(root.cell(), config.instance, 1)?; Ok(()) @@ -249,11 +277,14 @@ impl, const W: usize, const R: usize, const A: usize> offset, || Value::known(cur_value), )?; + + // hash the commitment into a scalar value. We use Poseidon hash function let (x, y) = commitment.into_coordinates(); let x_fr = Fr::from_bytes(&x.to_bytes()).unwrap(); let y_fr = Fr::from_bytes(&y.to_bytes()).unwrap(); let next_value = Hash::, W, R>::init().hash([x_fr, y_fr]); + // assign the current path node region.assign_advice( || "value of the next node", config.advice[1], @@ -261,6 +292,7 @@ impl, const W: usize, const R: usize, const A: usize> || Value::known(next_value), )?; + // assign the next path node region.assign_advice( || "the index of the layer", config.indices, @@ -282,7 +314,7 @@ impl, const W: usize, const R: usize, const A: usize> } #[derive(Clone, Debug)] -/// +/// The constants in Fr for Poseidon hash pub struct OrchardNullifier; impl Spec for OrchardNullifier { @@ -321,13 +353,13 @@ mod tests { }; use rand::thread_rng; use rand_core::OsRng; - /// - pub struct KZGTest { + /// A KZG struct for the purpose of testing the correctness of the Verkle tree circuit + pub struct KZGforTesting { kzg_params: ParamsKZG, domain: EvaluationDomain, } - impl KZGTest { + impl KZGforTesting { /// Initialize KZG parameters pub fn new(k: u32) -> Self { Self { @@ -336,23 +368,21 @@ mod tests { } } - /// + /// Convert a given list into a polynomial pub fn poly_from_evals(&self, evals: [Fr; 4]) -> Polynomial { // Use Lagrange interpolation - self.domain.coeff_from_vec(lagrange_interpolate( - &[Fr::from(0), Fr::from(1), Fr::from(2), Fr::from(3)], - &evals, - )) + self.domain + .coeff_from_vec(lagrange_interpolate(&OMEGA_POWER[0..4], &evals)) } - /// + /// Commit the polynomial pub fn commit(&self, evals: [Fr; 4]) -> G1Affine { self.kzg_params .commit(&self.poly_from_evals(evals), Blind(Fr::random(OsRng))) .to_affine() } - /// + /// Create proof for multiple polynomial openings pub fn create_proof( &self, point: Vec, @@ -367,46 +397,56 @@ mod tests { >(&self.kzg_params, point, polynomial, commitment) } - /// + /// Hash a group element to an element in Fr pub fn group_to_scalar, const W: usize, const R: usize>( &self, - g: G1Affine, + commitment: G1Affine, ) -> Fr { - let (x, y) = g.into_coordinates(); - let x_fr = Fr::from_bytes(&x.to_bytes()).unwrap(); - let y_fr = Fr::from_bytes(&y.to_bytes()).unwrap(); - Hash::, W, R>::init().hash([x_fr, y_fr]) + let (x_coordinate, y_coordinate) = commitment.into_coordinates(); + let x_coordinate_fr = + Fr::from_bytes(&x_coordinate.to_bytes()).expect("Cannot convert x into Fr"); + let y_coordinate_fr = + Fr::from_bytes(&y_coordinate.to_bytes()).expect("Cannot convert y into Fr"); + Hash::, W, R>::init().hash([x_coordinate_fr, y_coordinate_fr]) } } - fn create_verkle_tree_proof( + /// Create a valid verkle tree proof for the purpose of testing + pub fn create_verkle_tree_proof( leaf: Fr, indices: Vec, ) -> (VerkleTreeCircuit, Fr) { let rng = thread_rng(); - let kzg = KZGTest::new(2); - let mut commitment: Vec = vec![]; - let mut poly: Vec> = vec![]; - let mut non_leaf_elements: Vec = vec![]; + let kzg = KZGforTesting::new(2); + let mut commitment_list: Vec = vec![]; + let mut poly_list: Vec> = vec![]; + let mut path_elements: Vec = vec![]; let mut temp = leaf; for i in 0..indices.len() { let mut evals = [0; 4].map(|_| Fr::random(rng.clone())); evals[indices[i]] = temp; - let p = kzg.poly_from_evals(evals); - let c = kzg.commit(evals); - poly.push(p); - commitment.push(c); - temp = kzg.group_to_scalar::(c); - non_leaf_elements.push(temp); + // compute the polynomial for each parent node + let poly = kzg.poly_from_evals(evals); + // compute the commitment of the polynomial + let commitment = kzg.commit(evals); + poly_list.push(poly); + commitment_list.push(commitment); + // hash the group to scalar + temp = kzg.group_to_scalar::(commitment); + path_elements.push(temp); } + // the root node of the tree let root = temp; + // convert the indices to Fr let indices_fr: Vec = indices.iter().map(|x| Fr::from(*x as u64)).collect(); - let proof = kzg.create_proof(indices_fr.clone(), poly, commitment.clone()); + let point_list: Vec = indices.iter().map(|x| OMEGA_POWER[*x]).collect(); + // create the proof of correct opening + let proof = kzg.create_proof(point_list, poly_list, commitment_list.clone()); let circuit = VerkleTreeCircuit:: { leaf, - commitment, + commitment: commitment_list, proof, - non_leaf_elements, + path_elements, indices: indices_fr, params: kzg.kzg_params, _marker: PhantomData, @@ -417,27 +457,9 @@ mod tests { #[test] fn test_valid_verkle_tree() { - let kzg = KZGTest::new(2); - let leaf = Fr::from(1); - let indices = vec![Fr::from(1)]; - let evals = [Fr::from(3), leaf, Fr::from(7), Fr::from(15)]; - let poly0 = vec![kzg.poly_from_evals(evals)]; - let commit = kzg.commit(evals); - let root = kzg.group_to_scalar::(commit); - let non_leaf_elements = vec![root]; - let commitment = vec![commit]; - let proof = kzg.create_proof(vec![Fr::from(1)], poly0, commitment.clone()); - - let circuit = VerkleTreeCircuit:: { - leaf, - commitment, - proof, - non_leaf_elements, - indices, - params: kzg.kzg_params, - _marker: PhantomData, - }; - + let leaf = Fr::from(25234512); + let indices = vec![0]; + let (circuit, root) = create_verkle_tree_proof(leaf, indices); let prover = MockProver::run(10, &circuit, vec![vec![leaf, root]]).expect("Cannot run the circuit"); assert_eq!(prover.verify(), Ok(())); @@ -445,27 +467,56 @@ mod tests { #[test] fn wrong_verkle_root() { - let kzg = KZGTest::new(2); + let leaf = Fr::from(341231); + let indices = vec![0, 1]; + let (circuit, _) = create_verkle_tree_proof(leaf, indices); + let prover = MockProver::run(10, &circuit, vec![vec![leaf, Fr::from(0)]]) + .expect("Cannot run the circuit"); + assert_ne!(prover.verify(), Ok(())); + } + + #[test] + fn wrong_verkle_leaf() { + let leaf = Fr::from(341231); + let indices = vec![0, 1]; + let (circuit, root) = create_verkle_tree_proof(leaf, indices); + let prover = MockProver::run(10, &circuit, vec![vec![Fr::from(0), root]]) + .expect("Cannot run the circuit"); + assert_ne!(prover.verify(), Ok(())); + } + + #[test] + fn wrong_proof() { + let kzg = KZGforTesting::new(2); let leaf = Fr::from(1); + let indices = vec![Fr::from(0)]; + // the right 'polynomial' let evals = [leaf, Fr::from(0), Fr::from(0), Fr::from(0)]; - let poly0 = vec![kzg.poly_from_evals(evals)]; - let commit = kzg.commit(evals); - let root = kzg.group_to_scalar::(commit); - let non_leaf_elements = vec![Fr::from(0)]; - let commitment = vec![commit]; - let proof = kzg.create_proof(vec![Fr::from(0)], poly0, commitment.clone()); + // the wrong 'polynomial' + let false_evals = [Fr::from(2), Fr::from(0), Fr::from(0), Fr::from(0)]; + // commit to the right polynomial + let commitment = kzg.commit(evals); + let root = kzg.group_to_scalar::(commitment); + let path_elements = vec![root]; + let commitment_list = vec![commitment]; + + // wrong proof here + let proof = kzg.create_proof( + vec![OMEGA_POWER[0]], + vec![kzg.poly_from_evals(false_evals)], + commitment_list.clone(), + ); let circuit = VerkleTreeCircuit:: { leaf, - commitment, + commitment: commitment_list, proof, - non_leaf_elements, + path_elements, indices, params: kzg.kzg_params, _marker: PhantomData, }; - let prover = MockProver::run(10, &circuit, vec![vec![leaf, root]]).expect("Cannot run the circuit"); assert_ne!(prover.verify(), Ok(())); @@ -473,27 +524,33 @@ mod tests { #[test] fn wrong_opening_index() { - let kzg = KZGTest::new(2); + let kzg = KZGforTesting::new(2); let leaf = Fr::from(1); + + // the original index let indices = vec![Fr::from(0)]; let evals = [leaf, Fr::from(0), Fr::from(0), Fr::from(0)]; - let poly0 = vec![kzg.poly_from_evals(evals)]; - let commit = kzg.commit(evals); - let root = kzg.group_to_scalar::(commit); - let non_leaf_elements = vec![root]; - let commitment = vec![commit]; - let proof = kzg.create_proof(vec![Fr::from(1)], poly0, commitment.clone()); + let commitment = kzg.commit(evals); + let root = kzg.group_to_scalar::(commitment); + let path_elements = vec![root]; + let commitment_list = vec![commitment]; + + // wrong opening index here, should be OMEGA_POWER[0] + let proof = kzg.create_proof( + vec![OMEGA_POWER[1]], + vec![kzg.poly_from_evals(evals)], + commitment_list.clone(), + ); let circuit = VerkleTreeCircuit:: { leaf, - commitment, + commitment: commitment_list, proof, - non_leaf_elements, + path_elements, indices, params: kzg.kzg_params, _marker: PhantomData, }; - let prover = MockProver::run(10, &circuit, vec![vec![leaf, root]]).expect("Cannot run the circuit"); assert_ne!(prover.verify(), Ok(())); @@ -501,27 +558,31 @@ mod tests { #[test] fn invalid_opening_index_range() { - let kzg = KZGTest::new(2); + let kzg = KZGforTesting::new(2); let leaf = Fr::from(1); - let indices = vec![Fr::from(4)]; let evals = [leaf, Fr::from(0), Fr::from(0), Fr::from(0)]; - let poly0 = vec![kzg.poly_from_evals(evals)]; - let commit = kzg.commit(evals); - let root = kzg.group_to_scalar::(commit); - let non_leaf_elements = vec![root]; - let commitment = vec![commit]; - let proof = kzg.create_proof(vec![Fr::from(0)], poly0, commitment.clone()); + let commitment = kzg.commit(evals); + let root = kzg.group_to_scalar::(commitment); + let path_elements = vec![root]; + let commitment_list = vec![commitment]; + + // invalid index range here, should be in [0..3] + let indices = vec![Fr::from(4)]; + let proof = kzg.create_proof( + vec![OMEGA_POWER[4]], + vec![kzg.poly_from_evals(evals)], + commitment_list.clone(), + ); let circuit = VerkleTreeCircuit:: { leaf, - commitment, + commitment: commitment_list, proof, - non_leaf_elements, + path_elements, indices, params: kzg.kzg_params, _marker: PhantomData, }; - let prover = MockProver::run(10, &circuit, vec![vec![leaf, root]]).expect("Cannot run the circuit"); assert_ne!(prover.verify(), Ok(())); @@ -539,36 +600,38 @@ mod tests { #[test] fn wrong_verkle_path() { - let kzg = KZGTest::new(2); + let kzg = KZGforTesting::new(2); let leaf = Fr::from(1); + // indices let indices = vec![Fr::from(0), Fr::from(1)]; - let evals = [leaf, Fr::from(1), Fr::from(3), Fr::from(5)]; - let poly0 = kzg.poly_from_evals(evals); - let commit_0 = kzg.commit(evals); - let non_leaf_0 = kzg.group_to_scalar::(commit_0); + // create the first polynomial + let evals_0 = [leaf, Fr::from(1), Fr::from(3), Fr::from(5)]; + let poly_0 = kzg.poly_from_evals(evals_0); + let commitment_0 = kzg.commit(evals_0); + let non_leaf_0 = kzg.group_to_scalar::(commitment_0); + // create the second polynomial let evals_1 = [Fr::from(0), non_leaf_0, Fr::from(3), Fr::from(5)]; - let poly1 = kzg.poly_from_evals(evals_1); - let commit_1 = kzg.commit(evals_1); - let root = kzg.group_to_scalar::(commit_1); - - let non_leaf_elements = vec![Fr::from(0), root]; - let commitment = vec![commit_0, commit_1]; + let poly_1 = kzg.poly_from_evals(evals_1); + let commitment_1 = kzg.commit(evals_1); + let root = kzg.group_to_scalar::(commitment_1); + // wrong path here, the first element should be non_leaf_0, but now it is equal to 0 + let path_elements = vec![Fr::from(0), root]; + let commitment_list = vec![commitment_0, commitment_1]; let proof = kzg.create_proof( - vec![Fr::from(0), Fr::from(1)], - vec![poly0, poly1], - commitment.clone(), + vec![OMEGA_POWER[0], OMEGA_POWER[1]], + vec![poly_0, poly_1], + commitment_list.clone(), ); let circuit = VerkleTreeCircuit:: { leaf, - commitment, + commitment: commitment_list, proof, - non_leaf_elements, + path_elements, indices, params: kzg.kzg_params, _marker: PhantomData, }; - let prover = MockProver::run(10, &circuit, vec![vec![leaf, root]]).expect("Cannot run the circuit"); assert_ne!(prover.verify(), Ok(())); diff --git a/zkmemory/src/poseidon/poseidon_hash.rs b/zkmemory/src/poseidon/poseidon_hash.rs index 4661df5..2e1379b 100644 --- a/zkmemory/src/poseidon/poseidon_hash.rs +++ b/zkmemory/src/poseidon/poseidon_hash.rs @@ -32,7 +32,7 @@ pub trait Spec: fmt::Debu /// The trait for specifying the domain of messages pub trait Domain { - /// Iterator that outputs padding field elements. + /// Iterator that outputs padding Field+PrimeField elements. type Padding: IntoIterator; /// The initial capacity element, encoding this domain. @@ -45,7 +45,7 @@ pub trait Domain { /// The number of messages to be hashed pub struct ConstantLength; -impl Domain for ConstantLength { +impl Domain for ConstantLength { type Padding = iter::Take>; fn initial_capacity_element() -> F { From 5fbfa9b57035c91490b9a4f7418ea55452c838a8 Mon Sep 17 00:00:00 2001 From: phamnhatminh1292001 <66765903+phamnhatminh1292001@users.noreply.github.com> Date: Thu, 30 May 2024 14:30:51 +0700 Subject: [PATCH 12/15] Fix comment --- zkmemory/src/commitment/verkle_tree.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zkmemory/src/commitment/verkle_tree.rs b/zkmemory/src/commitment/verkle_tree.rs index 3c05065..09cef61 100644 --- a/zkmemory/src/commitment/verkle_tree.rs +++ b/zkmemory/src/commitment/verkle_tree.rs @@ -79,7 +79,7 @@ impl VerkleTreeConfig { meta.enable_equality(i); } - table.range_check(meta, "indices must be in 0..k", |meta| { + table.range_check(meta, "indices must be in 0..A", |meta| { meta.query_advice(indices, Rotation::cur()) }); From d73dad23013ee4f9a14c35d856ad9e9a90106b8e Mon Sep 17 00:00:00 2001 From: phamnhatminh1292001 <66765903+phamnhatminh1292001@users.noreply.github.com> Date: Thu, 30 May 2024 15:07:55 +0700 Subject: [PATCH 13/15] Remove Debug in macro derive for all structs --- zkmemory/src/commitment/merkle_tree.rs | 3 +-- zkmemory/src/commitment/verkle_tree.rs | 4 ++-- .../src/constraints/consistency_check_circuit.rs | 4 ++-- zkmemory/src/constraints/gadgets.rs | 16 ++++++++-------- .../src/constraints/original_memory_circuit.rs | 4 ++-- zkmemory/src/constraints/permutation_circuit.rs | 2 +- .../src/constraints/sorted_memory_circuit.rs | 2 +- zkmemory/src/poseidon/poseidon_hash.rs | 14 +++++++------- 8 files changed, 24 insertions(+), 25 deletions(-) diff --git a/zkmemory/src/commitment/merkle_tree.rs b/zkmemory/src/commitment/merkle_tree.rs index a7ec64e..38ea5a4 100644 --- a/zkmemory/src/commitment/merkle_tree.rs +++ b/zkmemory/src/commitment/merkle_tree.rs @@ -3,7 +3,6 @@ extern crate alloc; use crate::poseidon::poseidon_hash::{ConstantLength, Hash, Spec}; use alloc::{vec, vec::Vec}; -use core::fmt::Debug; use core::marker::PhantomData; use ff::{Field, PrimeField}; use halo2_proofs::{ @@ -14,7 +13,7 @@ use halo2_proofs::{ poly::Rotation, }; -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy)] /// Merkle tree config pub struct MerkleTreeConfig { /// advice has 3 columns, the first column is the left input of the hash, diff --git a/zkmemory/src/commitment/verkle_tree.rs b/zkmemory/src/commitment/verkle_tree.rs index 09cef61..8808ef6 100644 --- a/zkmemory/src/commitment/verkle_tree.rs +++ b/zkmemory/src/commitment/verkle_tree.rs @@ -45,7 +45,7 @@ const OMEGA_POWER: [Fr; 5] = [ Fr::from_raw([0x0961, 0, 0, 0]), ]; -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy)] /// Verkle tree config /// A is the number of children in each parent node pub struct VerkleTreeConfig { @@ -313,7 +313,7 @@ impl, const W: usize, const R: usize, const A: usize> } } -#[derive(Clone, Debug)] +#[derive(Clone)] /// The constants in Fr for Poseidon hash pub struct OrchardNullifier; diff --git a/zkmemory/src/constraints/consistency_check_circuit.rs b/zkmemory/src/constraints/consistency_check_circuit.rs index beb005a..71c2f1d 100644 --- a/zkmemory/src/constraints/consistency_check_circuit.rs +++ b/zkmemory/src/constraints/consistency_check_circuit.rs @@ -21,7 +21,7 @@ use halo2_proofs::{ use rand::thread_rng; /// Config for consistency check circuit -#[derive(Debug, Clone)] +#[derive(Clone)] pub(crate) struct ConsistencyConfig { // the config of the original memory pub(crate) original_memory_config: OriginalMemoryConfig, @@ -62,7 +62,7 @@ impl ConsistencyConfig { } /// Define the memory consistency circuit -#[derive(Default, Clone, Debug)] +#[derive(Default, Clone)] pub(crate) struct MemoryConsistencyCircuit> { /// input_trace: Array of trace records before sorting (sorted by time_log) pub(crate) input: Vec>, diff --git a/zkmemory/src/constraints/gadgets.rs b/zkmemory/src/constraints/gadgets.rs index 5f712fe..400d23e 100644 --- a/zkmemory/src/constraints/gadgets.rs +++ b/zkmemory/src/constraints/gadgets.rs @@ -18,7 +18,7 @@ use halo2_proofs::{ use itertools::Itertools; /// Lookup table for max n bits range check -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy)] pub struct Table { col: Column, } @@ -67,7 +67,7 @@ impl Table { } /// Config for checking if a value val is zero or not -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy)] pub struct IsZeroConfig { /// the value needed to check pub val: Column, @@ -111,7 +111,7 @@ impl IsZeroConfig { } } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy)] /// Config for binary number pub struct BinaryConfig { /// the list of bit representation @@ -182,7 +182,7 @@ pub fn equal_value( } /// The witness table consisting of the elements of the trace records -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy)] pub(crate) struct TraceRecordWitnessTable { pub(crate) address: [Column; 32], pub(crate) time_log: [Column; 8], @@ -203,7 +203,7 @@ impl TraceRecordWitnessTable { } } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy)] /// config for checking the ordering of time or address||time /// in original memory or sorted memory respectively pub(crate) struct GreaterThanConfig { @@ -345,7 +345,7 @@ fn rlc_limb_differences( } /// The lookup tables. We have 3 tables of size 256, 40 and 2 -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy)] pub(crate) struct LookUpTables { pub(crate) size256_table: Table<256>, pub(crate) size40_table: Table<40>, @@ -353,7 +353,7 @@ pub(crate) struct LookUpTables { } /// Query the element of a trace record at a specific position -#[derive(Clone, Debug)] +#[derive(Clone)] pub(crate) struct Queries { pub(crate) address: [Expression; 32], // 256 bits pub(crate) time_log: [Expression; 8], // 64 bits @@ -393,7 +393,7 @@ impl Queries { /// Trace record struct for Lexicographic ordering circuit /// We need every element to be of an array of type F, where each -#[derive(Debug, Clone)] +#[derive(Clone)] pub(crate) struct ConvertedTraceRecord { pub(crate) address: [F; 32], // 256 bits pub(crate) time_log: [F; 8], // 256 bits diff --git a/zkmemory/src/constraints/original_memory_circuit.rs b/zkmemory/src/constraints/original_memory_circuit.rs index 23eb9ab..70e013b 100644 --- a/zkmemory/src/constraints/original_memory_circuit.rs +++ b/zkmemory/src/constraints/original_memory_circuit.rs @@ -16,7 +16,7 @@ use halo2_proofs::{ poly::Rotation, }; use rand::thread_rng; -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy)] /// Config for trace record that is sorted by time_log pub(crate) struct OriginalMemoryConfig { /// The original trace circuit @@ -125,7 +125,7 @@ impl Circuit for OriginalMemoryCircuit { size2_table: Table::<2>::construct(meta), }; // The random challenges - // For debugging purpose, we let alpha to be uniformly distributed + // For ging purpose, we let alpha to be uniformly distributed // Later, one can force the prover to commit the memory traces first, then // let alpha to be the hash of the commitment let alpha = Expression::Constant(F::random(rng)); diff --git a/zkmemory/src/constraints/permutation_circuit.rs b/zkmemory/src/constraints/permutation_circuit.rs index de5da89..f9ee201 100644 --- a/zkmemory/src/constraints/permutation_circuit.rs +++ b/zkmemory/src/constraints/permutation_circuit.rs @@ -42,7 +42,7 @@ pub struct ShuffleChip { } /// Define the configuration for the shuffle chip. -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct ShuffleConfig { input: Column, shuffle: Column, diff --git a/zkmemory/src/constraints/sorted_memory_circuit.rs b/zkmemory/src/constraints/sorted_memory_circuit.rs index 3bd7108..aa000e9 100644 --- a/zkmemory/src/constraints/sorted_memory_circuit.rs +++ b/zkmemory/src/constraints/sorted_memory_circuit.rs @@ -17,7 +17,7 @@ use halo2_proofs::{ }; use rand::thread_rng; -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy)] /// Define the columns for the constraint pub(crate) struct SortedMemoryConfig { /// The fields of an execution trace diff --git a/zkmemory/src/poseidon/poseidon_hash.rs b/zkmemory/src/poseidon/poseidon_hash.rs index 2e1379b..d6b70fe 100644 --- a/zkmemory/src/poseidon/poseidon_hash.rs +++ b/zkmemory/src/poseidon/poseidon_hash.rs @@ -8,15 +8,15 @@ //! Merkle tree and Verkle tree opening proofs. extern crate alloc; -use alloc::{fmt, vec::Vec}; -use core::{fmt::Debug, iter, marker::PhantomData}; +use alloc::vec::Vec; +use core::{iter, marker::PhantomData}; use ff::{Field, PrimeField}; /// The type of a square matrix of size T pub(crate) type Mtrx = [[F; T]; T]; /// The trait for specifying the hash parameters -pub trait Spec: fmt::Debug { +pub trait Spec { /// The number of full rounds for Poseidon hash. fn full_rounds() -> usize; @@ -64,7 +64,7 @@ pub trait SpongeMode {} impl SpongeMode for Absorbing {} impl SpongeMode for Squeezing {} -impl Absorbing { +impl Absorbing { pub(crate) fn init_with(val: F) -> Self { Self( iter::once(Some(val)) @@ -77,11 +77,11 @@ impl Absorbing { } /// The absorbing state of the `Sponge`. -#[derive(Debug)] + pub struct Absorbing(pub(crate) [Option; R]); /// The squeezing state of the `Sponge`. -#[derive(Debug)] + pub struct Squeezing(pub(crate) [Option; R]); /// The type used to hold permutation state. @@ -303,7 +303,7 @@ impl, const T: usize, const R: usize, co use crate::poseidon::poseidon_constants::{MDS, MDS_INV, ROUND_CONSTANTS}; use halo2curves::pasta::Fp; /// Generate specific constants for testing the poseidon hash -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct OrchardNullifier; impl Spec for OrchardNullifier { From a32bb5ec11f134df9f684944e530afb7fca3c720 Mon Sep 17 00:00:00 2001 From: phamnhatminh1292001 <66765903+phamnhatminh1292001@users.noreply.github.com> Date: Thu, 30 May 2024 17:31:31 +0700 Subject: [PATCH 14/15] Change KZG struct name --- zkmemory/src/commitment/verkle_tree.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/zkmemory/src/commitment/verkle_tree.rs b/zkmemory/src/commitment/verkle_tree.rs index 8808ef6..b2d38ca 100644 --- a/zkmemory/src/commitment/verkle_tree.rs +++ b/zkmemory/src/commitment/verkle_tree.rs @@ -354,12 +354,12 @@ mod tests { use rand::thread_rng; use rand_core::OsRng; /// A KZG struct for the purpose of testing the correctness of the Verkle tree circuit - pub struct KZGforTesting { + pub struct KZGStruct { kzg_params: ParamsKZG, domain: EvaluationDomain, } - impl KZGforTesting { + impl KZGStruct { /// Initialize KZG parameters pub fn new(k: u32) -> Self { Self { @@ -417,7 +417,7 @@ mod tests { indices: Vec, ) -> (VerkleTreeCircuit, Fr) { let rng = thread_rng(); - let kzg = KZGforTesting::new(2); + let kzg = KZGStruct::new(2); let mut commitment_list: Vec = vec![]; let mut poly_list: Vec> = vec![]; let mut path_elements: Vec = vec![]; @@ -487,7 +487,7 @@ mod tests { #[test] fn wrong_proof() { - let kzg = KZGforTesting::new(2); + let kzg = KZGStruct::new(2); let leaf = Fr::from(1); let indices = vec![Fr::from(0)]; @@ -524,7 +524,7 @@ mod tests { #[test] fn wrong_opening_index() { - let kzg = KZGforTesting::new(2); + let kzg = KZGStruct::new(2); let leaf = Fr::from(1); // the original index @@ -558,7 +558,7 @@ mod tests { #[test] fn invalid_opening_index_range() { - let kzg = KZGforTesting::new(2); + let kzg = KZGStruct::new(2); let leaf = Fr::from(1); let evals = [leaf, Fr::from(0), Fr::from(0), Fr::from(0)]; let commitment = kzg.commit(evals); @@ -600,7 +600,7 @@ mod tests { #[test] fn wrong_verkle_path() { - let kzg = KZGforTesting::new(2); + let kzg = KZGStruct::new(2); let leaf = Fr::from(1); // indices let indices = vec![Fr::from(0), Fr::from(1)]; From e8bd0c32807d480f37315e074fdcd277b1e6ce71 Mon Sep 17 00:00:00 2001 From: phamnhatminh1292001 <66765903+phamnhatminh1292001@users.noreply.github.com> Date: Fri, 31 May 2024 00:16:57 +0700 Subject: [PATCH 15/15] Fix some lines in memory consistency circuit to increase code coverage This PR fixes some lines in the original and memory consistency circuit to increase code coverage. --- .../constraints/consistency_check_circuit.rs | 2 +- .../constraints/original_memory_circuit.rs | 7 ++--- .../src/constraints/sorted_memory_circuit.rs | 26 +++++++++++++++---- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/zkmemory/src/constraints/consistency_check_circuit.rs b/zkmemory/src/constraints/consistency_check_circuit.rs index 71c2f1d..b482885 100644 --- a/zkmemory/src/constraints/consistency_check_circuit.rs +++ b/zkmemory/src/constraints/consistency_check_circuit.rs @@ -62,7 +62,7 @@ impl ConsistencyConfig { } /// Define the memory consistency circuit -#[derive(Default, Clone)] +#[derive(Default)] pub(crate) struct MemoryConsistencyCircuit> { /// input_trace: Array of trace records before sorting (sorted by time_log) pub(crate) input: Vec>, diff --git a/zkmemory/src/constraints/original_memory_circuit.rs b/zkmemory/src/constraints/original_memory_circuit.rs index 70e013b..3e0b5c9 100644 --- a/zkmemory/src/constraints/original_memory_circuit.rs +++ b/zkmemory/src/constraints/original_memory_circuit.rs @@ -215,11 +215,8 @@ impl OriginalMemoryCircuit { .zip(&prev_time_log) .find(|((_, a), b)| a != b); let zero = F::ZERO; - let ((index, cur_limb), prev_limb) = if cfg!(test) { - find_result.unwrap_or(((&8, &zero), &zero)) - } else { - find_result.expect("two trace records cannot have equal time log") - }; + let ((index, cur_limb), prev_limb) = find_result.unwrap_or(((&8, &zero), &zero)); + let difference = *cur_limb - *prev_limb; // Assign the selector to be one at the current row diff --git a/zkmemory/src/constraints/sorted_memory_circuit.rs b/zkmemory/src/constraints/sorted_memory_circuit.rs index aa000e9..90e1f82 100644 --- a/zkmemory/src/constraints/sorted_memory_circuit.rs +++ b/zkmemory/src/constraints/sorted_memory_circuit.rs @@ -296,11 +296,8 @@ impl SortedMemoryCircuit { .zip(&prev_be_limbs) .find(|((_, a), b)| a != b); let zero = F::ZERO; - let ((index, cur_limb), prev_limb) = if cfg!(test) { - find_result.unwrap_or(((&40, &zero), &zero)) - } else { - find_result.expect("two trace records cannot have the same address then time log") - }; + let ((index, cur_limb), prev_limb) = find_result.unwrap_or(((&40, &zero), &zero)); + // Difference of address||time_log let difference = *cur_limb - *prev_limb; @@ -529,6 +526,25 @@ mod test { build_and_test_circuit(vec![trace0, trace1], 10); } + #[test] + #[should_panic] + fn equal_address_and_time_log() { + let trace0 = ConvertedTraceRecord { + address: [Fp::from(1); 32], + time_log: [Fp::from(0); 8], + instruction: Fp::from(1), + value: [Fp::from(63); 32], + }; + + let trace1 = ConvertedTraceRecord { + address: [Fp::from(1); 32], + time_log: [Fp::from(0); 8], + instruction: Fp::from(0), + value: [Fp::from(63); 32], + }; + build_and_test_circuit(vec![trace0, trace1], 10); + } + #[test] #[should_panic] fn wrong_address_order() {