diff --git a/verkletree/examples/test_commitment.rs b/verkletree/examples/test_commitment.rs new file mode 100644 index 0000000..e955020 --- /dev/null +++ b/verkletree/examples/test_commitment.rs @@ -0,0 +1,28 @@ +use verkletree::verkletree::*; +use zkmemory::commitment::commitment_scheme::CommitmentScheme; +extern crate alloc; +use ff::Field; +use halo2_proofs::halo2curves::bn256::Fr; +use rand::thread_rng; + +fn main() { + let rng = thread_rng(); + let elements: Vec = (0..16 * 16).map(|_| Fr::random(rng.clone())).collect(); + + let vk_commitment_scheme = VerkleTreeCommitmentScheme::setup(Some(2)); + + let indices: Vec = vec![2, 3, 3, 3]; + let leaf = elements[16 * 16 - 2]; + + let witness = VerkleTreeWitness { + leaf, + elements, + indices, + }; + + let root = vk_commitment_scheme.commit(witness.clone()); + + let opening = vk_commitment_scheme.open(witness.clone()); + + assert!(vk_commitment_scheme.verify(root, opening, witness)) +} diff --git a/verkletree/examples/test.rs b/verkletree/examples/test_verkle_tree.rs similarity index 70% rename from verkletree/examples/test.rs rename to verkletree/examples/test_verkle_tree.rs index 7d97c6e..1cc711e 100644 --- a/verkletree/examples/test.rs +++ b/verkletree/examples/test_verkle_tree.rs @@ -9,7 +9,13 @@ fn main() { let (circuit, root) = create_verkle_tree_proof(leaf, indices); let k = 10; + let mut prover = VerkleTreeProver::new(k, circuit, true); + let (params, vk) = prover.get_verifier_params(); + + let mut verifier = VerkleTreeVerifier::new(params, vk, true); + let proof = prover.create_proof(leaf, root); - assert!(prover.verify(proof, leaf, root)) + + assert!(verifier.verify(proof, leaf, root)) } diff --git a/verkletree/src/circuit.rs b/verkletree/src/circuit.rs index df5d743..52bf7dc 100644 --- a/verkletree/src/circuit.rs +++ b/verkletree/src/circuit.rs @@ -17,7 +17,7 @@ use halo2_proofs::{ }, plonk::{ create_proof, keygen_pk, keygen_vk, verify_proof, Advice, Circuit, Column, - ConstraintSystem, Error, Expression, Fixed, Instance, ProvingKey, Selector, + ConstraintSystem, Error, Expression, Fixed, Instance, ProvingKey, Selector, VerifyingKey, }, poly::{ commitment::{Blind, ParamsProver}, @@ -37,9 +37,10 @@ use poseidon::{ poseidon_constants::{MDS_FR, MDS_INV_FR, ROUND_CONSTANTS_FR}, poseidon_hash::Mtrx, }; +use rand::thread_rng; use rand_core::OsRng; -use zkmemory::commitment::kzg::create_kzg_proof; -use zkmemory::commitment::kzg::verify_kzg_proof; + +use zkmemory::commitment::kzg::{create_kzg_proof, verify_kzg_proof}; use zkmemory::constraints; pub(crate) const OMEGA_POWER: [Fr; 5] = [ @@ -49,7 +50,6 @@ pub(crate) const OMEGA_POWER: [Fr; 5] = [ Fr::from_raw([0x0157, 0, 0, 0]), Fr::from_raw([0x0961, 0, 0, 0]), ]; -use rand::thread_rng; #[derive(Clone, Copy)] /// Verkle tree config @@ -337,81 +337,10 @@ impl Spec for OrchardNullifier { } } -pub struct VerkleTreeProver, const W: usize, const R: usize, const A: usize> { - params: ParamsKZG, - pk: ProvingKey, - circuit: VerkleTreeCircuit, - expected: bool, -} - -impl, const W: usize, const R: usize, const A: usize> - VerkleTreeProver -{ - /// initialize the parameters for the prover - pub fn new(k: u32, circuit: VerkleTreeCircuit, expected: bool) -> Self { - let params = ParamsKZG::::setup(k, OsRng); - let vk = keygen_vk(¶ms, &circuit).expect("Cannot initialize verify key"); - let pk = keygen_pk(¶ms, vk.clone(), &circuit).expect("Cannot initialize proving key"); - - Self { - params, - pk, - circuit, - expected, - } - } - - /// Create proof for the permutation circuit - pub fn create_proof(&mut self, leaf: Fr, root: Fr) -> Vec { - let mut transcript = - Blake2bWrite::, G1Affine, Challenge255>::init(vec![]); - create_proof::< - KZGCommitmentScheme, - ProverSHPLONK<'_, Bn256>, - Challenge255, - OsRng, - Blake2bWrite, G1Affine, Challenge255>, - VerkleTreeCircuit, - >( - &self.params, - &self.pk, - &[self.circuit.clone()], - &[&[&[leaf, root]]], - OsRng, - &mut transcript, - ) - .expect("Fail to create proof."); - transcript.finalize() - } - - /// Verify the proof (by comparing the result with expected value) - pub fn verify(&mut self, proof: Vec, leaf: Fr, root: Fr) -> bool { - let strategy = SingleStrategy::new(&self.params); - let mut transcript = - Blake2bRead::<&[u8], G1Affine, Challenge255>::init(&proof[..]); - let result = verify_proof::< - KZGCommitmentScheme, - VerifierSHPLONK<'_, Bn256>, - Challenge255, - Blake2bRead<&[u8], G1Affine, Challenge255>, - SingleStrategy<'_, Bn256>, - >( - &self.params, - self.pk.get_vk(), - strategy, - &[&[&[leaf, root]]], - &mut transcript, - ); - match result { - Ok(()) => self.expected, - Err(_) => !self.expected, - } - } -} - /// A KZG struct for the purpose of testing the correctness of the Verkle tree circuit +#[derive(Clone, Debug)] pub struct KZGStruct { - kzg_params: ParamsKZG, + pub kzg_params: ParamsKZG, domain: EvaluationDomain, } @@ -510,6 +439,124 @@ pub fn create_verkle_tree_proof( (circuit, root) } +pub struct VerkleTreeVerifier { + params: ParamsKZG, + pub vk: VerifyingKey, + expected: bool, +} + +impl VerkleTreeVerifier { + /// initialize the verfier + pub fn new(params: ParamsKZG, vk: VerifyingKey, expected: bool) -> Self { + Self { + params, + vk, + expected, + } + } + + /// Verify the proof (by comparing the result with expected value) + pub fn verify(&mut self, proof: Vec, leaf: Fr, root: Fr) -> bool { + let strategy = SingleStrategy::new(&self.params); + let mut transcript = + Blake2bRead::<&[u8], G1Affine, Challenge255>::init(&proof[..]); + let result = verify_proof::< + KZGCommitmentScheme, + VerifierSHPLONK<'_, Bn256>, + Challenge255, + Blake2bRead<&[u8], G1Affine, Challenge255>, + SingleStrategy<'_, Bn256>, + >( + &self.params, + &self.vk, + strategy, + &[&[&[leaf, root]]], + &mut transcript, + ); + match result { + Ok(()) => self.expected, + Err(_) => !self.expected, + } + } +} + +pub struct VerkleTreeProver, const W: usize, const R: usize, const A: usize> { + params: ParamsKZG, + pk: ProvingKey, + circuit: VerkleTreeCircuit, + expected: bool, +} + +impl, const W: usize, const R: usize, const A: usize> + VerkleTreeProver +{ + /// initialize the prover + pub fn new(k: u32, circuit: VerkleTreeCircuit, expected: bool) -> Self { + let params = ParamsKZG::::setup(k, OsRng); + let vk = keygen_vk(¶ms, &circuit).expect("Cannot initialize verify key"); + let pk = keygen_pk(¶ms, vk.clone(), &circuit).expect("Cannot initialize proving key"); + + Self { + params, + pk, + circuit, + expected, + } + } + + // params to create VerkleTreeVerifier + pub fn get_verifier_params(&self) -> (ParamsKZG, VerifyingKey) { + (self.params.clone(), self.pk.get_vk().clone()) + } + + /// Create proof for the permutation circuit + pub fn create_proof(&mut self, leaf: Fr, root: Fr) -> Vec { + let mut transcript: Blake2bWrite, G1Affine, Challenge255> = + Blake2bWrite::, G1Affine, Challenge255>::init(vec![]); + create_proof::< + KZGCommitmentScheme, + ProverSHPLONK<'_, Bn256>, + Challenge255, + OsRng, + Blake2bWrite, G1Affine, Challenge255>, + VerkleTreeCircuit, + >( + &self.params, + &self.pk, + &[self.circuit.clone()], + &[&[&[leaf, root]]], + OsRng, + &mut transcript, + ) + .expect("Fail to create proof."); + transcript.finalize() + } + + /// Verify the proof (by comparing the result with expected value) + pub fn verify(&mut self, proof: Vec, leaf: Fr, root: Fr) -> bool { + let strategy = SingleStrategy::new(&self.params); + let mut transcript = + Blake2bRead::<&[u8], G1Affine, Challenge255>::init(&proof[..]); + let result = verify_proof::< + KZGCommitmentScheme, + VerifierSHPLONK<'_, Bn256>, + Challenge255, + Blake2bRead<&[u8], G1Affine, Challenge255>, + SingleStrategy<'_, Bn256>, + >( + &self.params, + self.pk.get_vk(), + strategy, + &[&[&[leaf, root]]], + &mut transcript, + ); + match result { + Ok(()) => self.expected, + Err(_) => !self.expected, + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/verkletree/src/lib.rs b/verkletree/src/lib.rs index ed2ff0f..6154418 100644 --- a/verkletree/src/lib.rs +++ b/verkletree/src/lib.rs @@ -1,2 +1,5 @@ /// Verkle Tree circuit pub mod circuit; + +/// Verkle Tree Commitment Scheme +pub mod verkletree; diff --git a/verkletree/src/verkletree.rs b/verkletree/src/verkletree.rs new file mode 100644 index 0000000..835d7e8 --- /dev/null +++ b/verkletree/src/verkletree.rs @@ -0,0 +1,283 @@ +extern crate alloc; +use crate::circuit::*; +use alloc::vec::Vec; +use core::marker::PhantomData; +use zkmemory::commitment::commitment_scheme::CommitmentScheme; + +use halo2_proofs::{ + halo2curves::bn256::{Bn256, Fr, G1Affine}, + plonk::VerifyingKey, + poly::{kzg::commitment::ParamsKZG, Coeff, Polynomial}, +}; + +pub(crate) 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)] +pub struct VerkleTreeWitness { + pub leaf: Fr, + pub elements: Vec, + pub indices: Vec, +} + +pub struct VerkleTreeCommitmentScheme { + pub kzg: KZGStruct, +} + +pub fn verkle_tree_commit(elements: Vec, kzg: KZGStruct) -> Fr { + let mut root = elements; + let mut evals = [Fr::from(0); 4]; + + let mut size = root.len(); + while size > 1 { + evals.copy_from_slice(&root[..4]); + root = root[4..].to_vec(); + + let commitment = kzg.commit(evals); + let temp = kzg.group_to_scalar::(commitment); + + root.push(temp); + size = root.len(); + } + + root[0] +} + +impl CommitmentScheme for VerkleTreeCommitmentScheme { + type Commitment = Fr; + type Opening = (ParamsKZG, VerifyingKey, Vec); + type PublicParams = ParamsKZG; + type Witness = VerkleTreeWitness; + + fn setup(_k: Option) -> Self { + match _k { + Some(k) => Self { + kzg: KZGStruct::new(k), + }, + _ => panic!("Invalid input parameter"), + } + } + + fn commit(&self, witness: Self::Witness) -> Self::Commitment { + verkle_tree_commit(witness.elements, self.kzg.clone()) + } + + fn open(&self, witness: Self::Witness) -> Self::Opening { + let indices = witness.indices; + let mut leaf_evaluations = witness.elements; + + let n = 4_usize.pow(indices.len() as u32); + assert_eq!( + leaf_evaluations.len(), + n, + "number of leaf must be 4^len(indices)" + ); + + let mut index = leaf_evaluations + .iter() + .position(|&x| x == witness.leaf) + .expect("Leaf not found in leaf_evaluations"); + + let kzg_instance = self.kzg.clone(); + + let mut evals = [Fr::from(0); 4]; + + let mut parent_evaluations: Vec> = Vec::with_capacity(indices.len()); + let mut parent_commitment_list: Vec> = Vec::with_capacity(indices.len()); + let mut tree_polynomials: Vec>> = + Vec::with_capacity(indices.len()); + + let commitment_indices_fr: Vec = indices.iter().map(|&x| Fr::from(x as u64)).collect(); + let evaluation_points: Vec = indices.iter().map(|&x| OMEGA_POWER[x]).collect(); + + let mut tree_size = 0; + let total_layers = indices.len(); + + // Process the leaves into layers of parent evaluations, commitments, and polynomials + while tree_size < total_layers { + let mut current_layer_evaluations: Vec = + Vec::with_capacity(leaf_evaluations.len() / 4); + let mut current_layer_commitments: Vec = + Vec::with_capacity(leaf_evaluations.len() / 4); + let mut current_layer_polynomials: Vec> = + Vec::with_capacity(leaf_evaluations.len() / 4); + + while !leaf_evaluations.is_empty() { + evals.copy_from_slice(&leaf_evaluations[..4]); // Copy first 4 elements + leaf_evaluations = leaf_evaluations.split_off(4); // Efficiently split the rest of the elements + + let commitment = kzg_instance.commit(evals); + let temp = kzg_instance.group_to_scalar::(commitment); + let poly = kzg_instance.poly_from_evals(evals); + + current_layer_polynomials.push(poly); + current_layer_evaluations.push(temp); + current_layer_commitments.push(commitment); + } + + // Update leaf_evaluations for the next layer before moving current_layer_evaluations + leaf_evaluations.clone_from(¤t_layer_evaluations); + + parent_evaluations.push(current_layer_evaluations); + parent_commitment_list.push(current_layer_commitments); + tree_polynomials.push(current_layer_polynomials); + + tree_size = parent_evaluations.len(); + } + + // Initialize commitment and path lists + let mut final_commitments: Vec = Vec::with_capacity(indices.len()); + let mut path_evaluations: Vec = Vec::with_capacity(indices.len()); + let mut polynomial_list: Vec> = Vec::with_capacity(indices.len()); + + index /= 4; + + // Iterate over parent elements, commitments, and polynomials to collect proof data + for ((commitments, evaluations), polynomials) in parent_commitment_list + .iter() + .zip(parent_evaluations.iter()) + .zip(tree_polynomials.iter()) + { + let commitment = commitments + .get(index) + .expect("Cannot get commitment's value"); + let evaluation = evaluations.get(index).expect("can not get node value's"); + let poly = polynomials + .get(index) + .expect("can not get polynomial's value"); + + final_commitments.push(*commitment); + path_evaluations.push(*evaluation); + polynomial_list.push(poly.clone()); + index /= 4 + } + + // Generate the proof + let verkle_proof = kzg_instance.create_proof( + evaluation_points, + polynomial_list, + final_commitments.clone(), + ); + + // Create the circuit + let circuit = VerkleTreeCircuit:: { + leaf: witness.leaf, + commitment: final_commitments.clone(), + proof: verkle_proof, + path_elements: path_evaluations.clone(), + indices: commitment_indices_fr, + params: kzg_instance.kzg_params, + _marker: PhantomData, + }; + + let verkle_root = *path_evaluations.last().unwrap(); + let k: u32 = 10; + + let mut prover = VerkleTreeProver::new(k, circuit, true); + let (params, vk) = prover.get_verifier_params(); + + let proof = prover.create_proof(witness.leaf, verkle_root); + (params, vk, proof) + } + + fn verify( + &self, + commitment: Self::Commitment, + opening: Self::Opening, + witness: Self::Witness, + ) -> bool { + let (params, vk, proof) = opening; + let mut verifier = VerkleTreeVerifier::new(params, vk, true); + verifier.verify(proof, witness.leaf, commitment) + } +} + +#[cfg(test)] +mod test { + use super::*; + + use ff::Field; + use rand::thread_rng; + + #[test] + fn test_valid_commitment_shemes() { + let rng = thread_rng(); + let elements: Vec = (0..16 * 4).map(|_| Fr::random(rng.clone())).collect(); + let vk_commitment_scheme = VerkleTreeCommitmentScheme::setup(Some(2)); + + let indices: Vec = vec![3, 3, 3]; + let leaf = elements[16 * 4 - 1]; + let witness = VerkleTreeWitness { + leaf, + elements, + indices, + }; + + let root = vk_commitment_scheme.commit(witness.clone()); + let opening = vk_commitment_scheme.open(witness.clone()); + assert!(vk_commitment_scheme.verify(root, opening, witness)) + } + + #[test] + fn test_wrong_leaf() { + let rng = thread_rng(); + let elements: Vec = (0..16 * 4).map(|_| Fr::random(rng.clone())).collect(); + let vk_commitment_scheme = VerkleTreeCommitmentScheme::setup(Some(2)); + + let indices: Vec = vec![3, 3, 3]; + let leaf = elements[0]; + let witness = VerkleTreeWitness { + leaf, + elements, + indices, + }; + + let root = vk_commitment_scheme.commit(witness.clone()); + let opening = vk_commitment_scheme.open(witness.clone()); + assert!(!vk_commitment_scheme.verify(root, opening, witness)) + } + + #[test] + fn test_wrong_root() { + let rng = thread_rng(); + let elements: Vec = (0..16 * 16).map(|_| Fr::random(rng.clone())).collect(); + let vk_commitment_scheme = VerkleTreeCommitmentScheme::setup(Some(2)); + + let indices: Vec = vec![3, 3, 3, 3]; + let leaf = elements[16 * 16 - 1]; + let witness = VerkleTreeWitness { + leaf, + elements, + indices, + }; + let root = Fr::random(rng.clone()); + + let opening = vk_commitment_scheme.open(witness.clone()); + assert!(!vk_commitment_scheme.verify(root, opening, witness)) + } + + #[test] + #[should_panic] + fn test_invalid_number_of_leaf() { + let rng = thread_rng(); + let elements: Vec = (0..16 * 16).map(|_| Fr::random(rng.clone())).collect(); + let vk_commitment_scheme = VerkleTreeCommitmentScheme::setup(Some(2)); + + let indices: Vec = vec![3, 3, 3]; + let leaf = elements[16 * 16 - 1]; + let witness = VerkleTreeWitness { + leaf, + elements, + indices, + }; + + let root = vk_commitment_scheme.commit(witness.clone()); + let opening = vk_commitment_scheme.open(witness.clone()); + assert!(!vk_commitment_scheme.verify(root, opening, witness)) + } +} diff --git a/zkmemory/src/commitment/verkle_tree.rs b/zkmemory/src/commitment/verkle_tree.rs index dea6331..ef3bb0a 100644 --- a/zkmemory/src/commitment/verkle_tree.rs +++ b/zkmemory/src/commitment/verkle_tree.rs @@ -71,6 +71,7 @@ impl VerkleTreeConfig { let selector = meta.fixed_column(); let selector_check = meta.selector(); let indices = meta.advice_column(); + for i in advice { meta.enable_equality(i); }