From 1445c203726053ef7da8841c2e8ed4afadd3b18b Mon Sep 17 00:00:00 2001 From: EkamSinghPandher Date: Thu, 1 Aug 2024 11:53:15 +0800 Subject: [PATCH 01/17] feature:add-merkle-proof-circuit --- crates/zk-por-core/src/account.rs | 25 +++ crates/zk-por-core/src/circuit_utils.rs | 171 ++++++++++++++++++ crates/zk-por-core/src/lib.rs | 2 + .../src/merkle_proof_prover/merkle_proof.rs | 19 ++ .../merkle_proof_circuits.rs | 60 ++++++ .../src/merkle_proof_prover/mod.rs | 3 + .../src/merkle_proof_prover/prover.rs | 73 ++++++++ .../circuits/account_circuit.rs | 17 +- .../circuits/circuit_utils.rs | 85 --------- .../circuits/merkle_sum_circuit.rs | 17 +- .../src/merkle_sum_prover/circuits/mod.rs | 1 - .../src/merkle_sum_prover/prover.rs | 14 +- 12 files changed, 378 insertions(+), 109 deletions(-) create mode 100644 crates/zk-por-core/src/circuit_utils.rs create mode 100644 crates/zk-por-core/src/merkle_proof_prover/merkle_proof.rs create mode 100644 crates/zk-por-core/src/merkle_proof_prover/merkle_proof_circuits.rs create mode 100644 crates/zk-por-core/src/merkle_proof_prover/mod.rs create mode 100644 crates/zk-por-core/src/merkle_proof_prover/prover.rs delete mode 100644 crates/zk-por-core/src/merkle_sum_prover/circuits/circuit_utils.rs diff --git a/crates/zk-por-core/src/account.rs b/crates/zk-por-core/src/account.rs index 94c882b..700fbd1 100644 --- a/crates/zk-por-core/src/account.rs +++ b/crates/zk-por-core/src/account.rs @@ -1,3 +1,9 @@ +use plonky2::{ + hash::{hash_types::HashOut, poseidon::PoseidonHash}, + plonk::config::Hasher, +}; +use plonky2_field::types::Field; + use crate::types::F; /// A struct representing a users account. It represents their equity and debt as a Vector of goldilocks field elements. @@ -7,3 +13,22 @@ pub struct Account { pub equity: Vec, pub debt: Vec, } + +impl Account { + /// Gets the account hash for a given account. + pub fn get_hash(self) -> HashOut { + let mut sum_equity = F::ZERO; + let mut sum_debt = F::ZERO; + + self.equity.iter().for_each(|x| { + sum_equity = sum_equity + *x; + }); + self.debt.iter().for_each(|x| { + sum_debt = sum_debt + *x; + }); + + let hash = PoseidonHash::hash_no_pad(vec![sum_equity, sum_debt].as_slice()); + + hash + } +} diff --git a/crates/zk-por-core/src/circuit_utils.rs b/crates/zk-por-core/src/circuit_utils.rs new file mode 100644 index 0000000..4ef1407 --- /dev/null +++ b/crates/zk-por-core/src/circuit_utils.rs @@ -0,0 +1,171 @@ +use log::Level; +use plonky2::{ + hash::{ + hash_types::{HashOutTarget, RichField}, + poseidon::PoseidonHash, + }, + iop::{ + target::{BoolTarget, Target}, + witness::PartialWitness, + }, + plonk::{ + circuit_builder::CircuitBuilder, circuit_data::CircuitData, config::GenericConfig, + prover::prove, + }, + util::timing::TimingTree, +}; +use plonky2_field::extension::Extendable; +use std::panic; + +use crate::{ + circuit_config::STANDARD_CONFIG, + types::{C, MAX_POSITIVE_AMOUNT_LOG}, +}; + +/// Test runner for ease of testing +pub fn run_circuit_test(test: T) -> () +where + T: FnOnce(&mut CircuitBuilder, &mut PartialWitness) -> () + panic::UnwindSafe, + F: RichField + Extendable, + C: GenericConfig, +{ + let mut builder = CircuitBuilder::::new(STANDARD_CONFIG); + let mut pw: PartialWitness = PartialWitness::::new(); + test(&mut builder, &mut pw); + builder.print_gate_counts(0); + let mut timing = TimingTree::new("prove", Level::Debug); + let data = builder.build::(); + let CircuitData { prover_only, common, verifier_only: _ } = &data; + let proof = prove(&prover_only, &common, pw, &mut timing).expect("Prove fail"); + timing.print(); + data.verify(proof).expect("Verify fail") +} + +/// Computes `if b { h0 } else { h1 }`. +pub fn select_hash, const D: usize>( + builder: &mut CircuitBuilder, + b: BoolTarget, + h0: HashOutTarget, + h1: HashOutTarget, +) -> HashOutTarget { + HashOutTarget { + elements: core::array::from_fn(|i| builder.select(b, h0.elements[i], h1.elements[i])), + } +} + +/// Assert 0 <= x <= MAX_POSITIVE_AMOUNT +/// MAX_POSITIVE_AMOUNT = (1 << MAX_POSITIVE_AMOUNT_LOG) - 1 +pub fn assert_non_negative_unsigned, const D: usize>( + builder: &mut CircuitBuilder, + x: Target, +) { + builder.range_check(x, MAX_POSITIVE_AMOUNT_LOG); +} + +/// Get Hash target by doing a poseidon hash on my input vector. +pub fn get_hash_from_input_targets_circuit, const D: usize>( + builder: &mut CircuitBuilder, + inputs: Vec, +) -> HashOutTarget { + builder.hash_n_to_hash_no_pad::(inputs) +} + +/// Hash 2 hashout targets by splitting it into its individual component elements +pub fn hash_2_subhashes_circuit, const D: usize>( + builder: &mut CircuitBuilder, + hash_1: &HashOutTarget, + hash_2: &HashOutTarget, +) -> HashOutTarget { + let inputs = vec![hash_1.elements.to_vec(), hash_2.elements.to_vec()].concat(); + get_hash_from_input_targets_circuit(builder, inputs) +} + +#[cfg(test)] +pub mod test { + use crate::types::F; + use plonky2::{hash::hash_types::HashOut, iop::witness::WitnessWrite}; + use plonky2_field::types::{Field, Field64}; + + use super::{ + assert_non_negative_unsigned, get_hash_from_input_targets_circuit, + hash_2_subhashes_circuit, run_circuit_test, + }; + + #[test] + fn test_assert_non_negative_unsigned() { + run_circuit_test(|builder, _pw| { + let x = builder.constant(F::from_canonical_u16(0)); + assert_non_negative_unsigned(builder, x); + }); + } + + #[test] + #[should_panic] + fn test_assert_non_negative_unsigned_panic() { + run_circuit_test(|builder, _pw| { + let x = builder.constant(F::from_canonical_i64(-1)); + assert_non_negative_unsigned(builder, x); + }); + } + + #[test] + fn test_get_hash_from_input_targets_circuit() { + run_circuit_test(|builder, pw| { + let target_1 = builder.add_virtual_target(); + let target_2 = builder.add_virtual_target(); + let hash_target = builder.add_virtual_hash(); + let calculated_hash_target = + get_hash_from_input_targets_circuit(builder, vec![target_1, target_2]); + builder.connect_hashes(hash_target, calculated_hash_target); + + let value_1 = F::ZERO; + let value_2 = F::ZERO; + + let hash = HashOut::from_vec(vec![ + F::from_canonical_u64(4330397376401421145), + F::from_canonical_u64(14124799381142128323), + F::from_canonical_u64(8742572140681234676), + F::from_canonical_u64(14345658006221440202), + ]); + + pw.set_target(target_1, value_1); + pw.set_target(target_2, value_2); + pw.set_hash_target(hash_target, hash); + }); + } + + #[test] + fn test_hash_2_subhashes_circuit() { + run_circuit_test(|builder, pw| { + let hash_target_1 = builder.add_virtual_hash(); + let hash_target_2 = builder.add_virtual_hash(); + let hash_target_3 = builder.add_virtual_hash(); + let calculated_hash_target = + hash_2_subhashes_circuit(builder, &hash_target_1, &hash_target_2); + builder.connect_hashes(hash_target_3, calculated_hash_target); + + let hash_1 = HashOut::from_vec(vec![ + F::from_canonical_u64(4330397376401421145), + F::from_canonical_u64(14124799381142128323), + F::from_canonical_u64(8742572140681234676), + F::from_canonical_u64(14345658006221440202), + ]); + let hash_2 = HashOut::from_vec(vec![ + F::from_canonical_u64(4330397376401421145), + F::from_canonical_u64(14124799381142128323), + F::from_canonical_u64(8742572140681234676), + F::from_canonical_u64(14345658006221440202), + ]); + + let hash_3 = HashOut::from_vec(vec![ + F::from_canonical_u64(13121882728673923020), + F::from_canonical_u64(10197653806804742863), + F::from_canonical_u64(16037207047953124082), + F::from_canonical_u64(2420399206709257475), + ]); + pw.set_hash_target(hash_target_1, hash_1); + pw.set_hash_target(hash_target_2, hash_2); + pw.set_hash_target(hash_target_3, hash_3); + }); + } +} diff --git a/crates/zk-por-core/src/lib.rs b/crates/zk-por-core/src/lib.rs index 34dce8b..7069838 100644 --- a/crates/zk-por-core/src/lib.rs +++ b/crates/zk-por-core/src/lib.rs @@ -1,6 +1,8 @@ pub mod account; pub mod circuit_config; +pub mod circuit_utils; pub mod error; +pub mod merkle_proof_prover; pub mod merkle_sum_prover; pub mod parser; pub mod types; diff --git a/crates/zk-por-core/src/merkle_proof_prover/merkle_proof.rs b/crates/zk-por-core/src/merkle_proof_prover/merkle_proof.rs new file mode 100644 index 0000000..e8e7486 --- /dev/null +++ b/crates/zk-por-core/src/merkle_proof_prover/merkle_proof.rs @@ -0,0 +1,19 @@ +use plonky2::hash::hash_types::HashOut; + +use crate::{account::Account, types::F}; + +/// Proving Inputs required for a merkle proof. These inputs are used to prove the merkle tree proof of inclusion for a single +/// user. +pub struct MerkleProofProvingInputs { + pub siblings: Vec>, + pub root: HashOut, + pub index: F, + pub account: Account, +} + +impl MerkleProofProvingInputs { + /// Gets the leaf hash of an account + pub fn get_account_hash(self) -> HashOut { + self.account.get_hash() + } +} diff --git a/crates/zk-por-core/src/merkle_proof_prover/merkle_proof_circuits.rs b/crates/zk-por-core/src/merkle_proof_prover/merkle_proof_circuits.rs new file mode 100644 index 0000000..f659c21 --- /dev/null +++ b/crates/zk-por-core/src/merkle_proof_prover/merkle_proof_circuits.rs @@ -0,0 +1,60 @@ +use plonky2::{ + hash::hash_types::HashOutTarget, iop::target::Target, plonk::circuit_builder::CircuitBuilder, +}; + +use crate::{ + circuit_utils::{hash_2_subhashes_circuit, select_hash}, + merkle_sum_prover::circuits::account_circuit::{AccountSumTargets, AccountTargets}, + types::{D, F}, +}; + +pub struct MerkleProofTargets { + pub merkle_root_target: HashOutTarget, + pub account_hash: HashOutTarget, + pub index_target: Target, + pub siblings: Vec, + pub merkle_tree_depth: usize, +} + +impl MerkleProofTargets { + pub fn new_from_account_targets( + builder: &mut CircuitBuilder, + account_targets: &AccountTargets, + merkle_proof_len: usize, + ) -> MerkleProofTargets { + let merkle_root_target = builder.add_virtual_hash(); + let account_sum_targets = AccountSumTargets::from_account_target(&account_targets, builder); + let account_hash = account_sum_targets.get_account_hash_targets(builder); + let index_target = builder.add_virtual_target(); + let siblings: Vec = + (0..merkle_proof_len).enumerate().map(|_| builder.add_virtual_hash()).collect(); + MerkleProofTargets { + merkle_root_target, + account_hash, + index_target, + siblings, + merkle_tree_depth: merkle_proof_len, + } + } + + /// Given the siblings in a merkle tree and my root hash, verify the merkle proof of inclusion of the supplied leaf hash. + /// Since the order of the hash depends on my siblings position, we use the index bits of the index target to determine the order of the + /// hash inputs. + pub fn verify_merkle_proof_circuit(self, builder: &mut CircuitBuilder) { + // Get the index bits up to the merkle tree depth number of bits from Little endian representation + let index_bits = builder.split_le(self.index_target, self.merkle_tree_depth); + + let mut leaf_hash = self.account_hash; + + for i in 0..self.siblings.len() { + let sibling = self.siblings.get(i).unwrap(); + + // Order is based on the index bits at the ith index + let first_hash = select_hash(builder, index_bits[i], *sibling, leaf_hash); + let second_hash = select_hash(builder, index_bits[i], leaf_hash, *sibling); + leaf_hash = hash_2_subhashes_circuit(builder, &first_hash, &second_hash); + } + + builder.connect_hashes(leaf_hash, self.merkle_root_target); + } +} diff --git a/crates/zk-por-core/src/merkle_proof_prover/mod.rs b/crates/zk-por-core/src/merkle_proof_prover/mod.rs new file mode 100644 index 0000000..b3fe42a --- /dev/null +++ b/crates/zk-por-core/src/merkle_proof_prover/mod.rs @@ -0,0 +1,3 @@ +pub mod merkle_proof; +pub mod merkle_proof_circuits; +pub mod prover; diff --git a/crates/zk-por-core/src/merkle_proof_prover/prover.rs b/crates/zk-por-core/src/merkle_proof_prover/prover.rs new file mode 100644 index 0000000..9b48eba --- /dev/null +++ b/crates/zk-por-core/src/merkle_proof_prover/prover.rs @@ -0,0 +1,73 @@ +use log::Level; +use plonky2::{iop::witness::PartialWitness, plonk::{circuit_builder::CircuitBuilder, circuit_data::CircuitData, proof::ProofWithPublicInputs, prover::prove}, util::timing::TimingTree}; + +use crate::{ + circuit_config::STANDARD_CONFIG, merkle_sum_prover::circuits::account_circuit::AccountTargets, types::{C, D, F} +}; + +use super::{merkle_proof::MerkleProofProvingInputs, merkle_proof_circuits::MerkleProofTargets}; + +use tracing::error; + +pub struct MerkleProofProver { + pub merkle_proof: MerkleProofProvingInputs, +} + +impl MerkleProofProver { + pub fn build_and_set_merkle_proof_circuit( + &self, + builder: &mut CircuitBuilder, + pw: &mut PartialWitness, + ) { + let merkle_proof_len = self.merkle_proof.siblings.len(); + + let account_targets = AccountTargets::new_from_account(&self.merkle_proof.account, builder); + + let merkle_proof_targets = MerkleProofTargets::new_from_account_targets( + builder, + &account_targets, + merkle_proof_len, + ); + + merkle_proof_targets.verify_merkle_proof_circuit(builder); + + account_targets.set_account_targets(&self.merkle_proof.account, pw); + } + + pub fn get_proof(&self) -> ProofWithPublicInputs { + let mut builder = CircuitBuilder::::new(STANDARD_CONFIG); + let mut pw = PartialWitness::::new(); + + self.build_and_set_merkle_proof_circuit(&mut builder, &mut pw); + + builder.print_gate_counts(0); + + let mut timing = TimingTree::new("prove", Level::Debug); + let data = builder.build::(); + + let CircuitData { prover_only, common, verifier_only: _ } = &data; + + println!("Started Proving"); + + let proof_res = prove(&prover_only, &common, pw.clone(), &mut timing); + + match proof_res { + Ok(proof) => { + println!("Finished Proving"); + + let proof_verification_res = data.verify(proof.clone()); + match proof_verification_res { + Ok(_) => proof, + Err(e) => { + error!("Proof verification failed: {:?}", e); + panic!("Proof verification failed!"); + } + } + } + Err(e) => { + error!("Proof generation failed: {:?}", e); + panic!("Proof generation failed!"); + } + } + } +} diff --git a/crates/zk-por-core/src/merkle_sum_prover/circuits/account_circuit.rs b/crates/zk-por-core/src/merkle_sum_prover/circuits/account_circuit.rs index 79eb261..929e907 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/circuits/account_circuit.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/circuits/account_circuit.rs @@ -1,4 +1,5 @@ use plonky2::{ + hash::{hash_types::HashOutTarget, poseidon::PoseidonHash}, iop::{ target::Target, witness::{PartialWitness, WitnessWrite}, @@ -8,11 +9,10 @@ use plonky2::{ use crate::{ account::Account, + circuit_utils::assert_non_negative_unsigned, types::{D, F}, }; -use super::circuit_utils::assert_non_negative_unsigned; - #[derive(Debug, Clone)] /// Targets representing a users account, where their equity and debt are split into individual tokens. pub struct AccountTargets { @@ -64,14 +64,19 @@ impl AccountSumTargets { AccountSumTargets { sum_equity, sum_debt } } + + /// Get account hash targets + pub fn get_account_hash_targets(&self, builder: &mut CircuitBuilder) -> HashOutTarget { + let hash_inputs = vec![self.sum_equity, self.sum_debt]; + + let hash = builder.hash_n_to_hash_no_pad::(hash_inputs); + hash + } } #[cfg(test)] pub mod test { - use crate::{ - merkle_sum_prover::circuits::circuit_utils::run_circuit_test, - parser::read_json_into_accounts_vec, - }; + use crate::{circuit_utils::run_circuit_test, parser::read_json_into_accounts_vec}; use super::{AccountSumTargets, AccountTargets}; diff --git a/crates/zk-por-core/src/merkle_sum_prover/circuits/circuit_utils.rs b/crates/zk-por-core/src/merkle_sum_prover/circuits/circuit_utils.rs deleted file mode 100644 index 7139a23..0000000 --- a/crates/zk-por-core/src/merkle_sum_prover/circuits/circuit_utils.rs +++ /dev/null @@ -1,85 +0,0 @@ -use log::Level; -use plonky2::{ - hash::hash_types::{HashOutTarget, RichField}, - iop::{ - target::{BoolTarget, Target}, - witness::PartialWitness, - }, - plonk::{ - circuit_builder::CircuitBuilder, circuit_data::CircuitData, config::GenericConfig, - prover::prove, - }, - util::timing::TimingTree, -}; -use plonky2_field::extension::Extendable; -use std::panic; - -use crate::{ - circuit_config::STANDARD_CONFIG, - types::{C, MAX_POSITIVE_AMOUNT_LOG}, -}; - -/// Test runner for ease of testing -pub fn run_circuit_test(test: T) -> () -where - T: FnOnce(&mut CircuitBuilder, &mut PartialWitness) -> () + panic::UnwindSafe, - F: RichField + Extendable, - C: GenericConfig, -{ - let mut builder = CircuitBuilder::::new(STANDARD_CONFIG); - let mut pw: PartialWitness = PartialWitness::::new(); - test(&mut builder, &mut pw); - builder.print_gate_counts(0); - let mut timing = TimingTree::new("prove", Level::Debug); - let data = builder.build::(); - let CircuitData { prover_only, common, verifier_only: _ } = &data; - let proof = prove(&prover_only, &common, pw, &mut timing).expect("Prove fail"); - timing.print(); - data.verify(proof).expect("Verify fail") -} - -/// Computes `if b { h0 } else { h1 }`. -pub fn select_hash, const D: usize>( - builder: &mut CircuitBuilder, - b: BoolTarget, - h0: HashOutTarget, - h1: HashOutTarget, -) -> HashOutTarget { - HashOutTarget { - elements: core::array::from_fn(|i| builder.select(b, h0.elements[i], h1.elements[i])), - } -} - -/// Assert 0 <= x <= MAX_POSITIVE_AMOUNT -/// MAX_POSITIVE_AMOUNT = (1 << MAX_POSITIVE_AMOUNT_LOG) - 1 -pub fn assert_non_negative_unsigned, const D: usize>( - builder: &mut CircuitBuilder, - x: Target, -) { - builder.range_check(x, MAX_POSITIVE_AMOUNT_LOG); -} - -#[cfg(test)] -pub mod test { - use crate::types::F; - use plonky2_field::types::{Field, Field64}; - - use super::{assert_non_negative_unsigned, run_circuit_test}; - - #[test] - fn test_assert_non_negative_unsigned() { - run_circuit_test(|builder, _pw| { - let x = builder.constant(F::from_canonical_u16(0)); - assert_non_negative_unsigned(builder, x); - }); - } - - #[test] - #[should_panic] - fn test_assert_non_negative_unsigned_panic() { - run_circuit_test(|builder, _pw| { - let x = builder.constant(F::from_canonical_i64(-1)); - assert_non_negative_unsigned(builder, x); - }); - } -} diff --git a/crates/zk-por-core/src/merkle_sum_prover/circuits/merkle_sum_circuit.rs b/crates/zk-por-core/src/merkle_sum_prover/circuits/merkle_sum_circuit.rs index a2ee47c..c09a9bd 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/circuits/merkle_sum_circuit.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/circuits/merkle_sum_circuit.rs @@ -4,9 +4,12 @@ use plonky2::{ plonk::circuit_builder::CircuitBuilder, }; -use crate::types::{D, F}; +use crate::{ + circuit_utils::assert_non_negative_unsigned, + types::{D, F}, +}; -use super::{account_circuit::AccountSumTargets, circuit_utils::assert_non_negative_unsigned}; +use super::account_circuit::AccountSumTargets; /// A node in the merkle sum tree, contains the total amount of equity (in usd) and the total amount of debt (in usd) and the hash. /// @@ -53,9 +56,7 @@ impl MerkleSumNodeTarget { builder: &mut CircuitBuilder, account_targets: &AccountSumTargets, ) -> MerkleSumNodeTarget { - let hash_inputs = vec![account_targets.sum_equity, account_targets.sum_debt]; - - let hash = builder.hash_n_to_hash_no_pad::(hash_inputs); + let hash = account_targets.get_account_hash_targets(builder); MerkleSumNodeTarget { sum_equity: account_targets.sum_equity, sum_debt: account_targets.sum_debt, @@ -122,10 +123,8 @@ pub fn build_merkle_sum_tree_from_account_targets( #[cfg(test)] pub mod test { use crate::{ - merkle_sum_prover::circuits::{ - account_circuit::{AccountSumTargets, AccountTargets}, - circuit_utils::run_circuit_test, - }, + circuit_utils::run_circuit_test, + merkle_sum_prover::circuits::account_circuit::{AccountSumTargets, AccountTargets}, parser::read_json_into_accounts_vec, }; diff --git a/crates/zk-por-core/src/merkle_sum_prover/circuits/mod.rs b/crates/zk-por-core/src/merkle_sum_prover/circuits/mod.rs index f84e13b..1a973f1 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/circuits/mod.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/circuits/mod.rs @@ -1,3 +1,2 @@ pub mod account_circuit; -pub mod circuit_utils; pub mod merkle_sum_circuit; diff --git a/crates/zk-por-core/src/merkle_sum_prover/prover.rs b/crates/zk-por-core/src/merkle_sum_prover/prover.rs index 92ac544..b01fcd2 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/prover.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/prover.rs @@ -16,7 +16,7 @@ use plonky2::{ }, util::timing::TimingTree, }; -use plonky2_field::goldilocks_field::GoldilocksField; + use tracing::error; /// A merkle sum tree prover with a batch id representing its index in the recursive proof tree and a Vec of accounts representing accounts in this batch. @@ -36,12 +36,9 @@ impl MerkleSumTreeProver { let mut account_targets: Vec = Vec::new(); for i in 0..self.accounts.len() { - let equity_targets = - builder.add_virtual_targets(self.accounts.get(i).unwrap().equity.len()); - let debt_targets = - builder.add_virtual_targets(self.accounts.get(i).unwrap().debt.len()); - let account_target = AccountTargets { equity: equity_targets, debt: debt_targets }; - + // Build account targets + let account_target = AccountTargets::new_from_account(self.accounts.get(i).unwrap(), builder); + // Set account targets account_target.set_account_targets(self.accounts.get(i).unwrap(), pw); account_targets.push(account_target); } @@ -51,6 +48,7 @@ impl MerkleSumTreeProver { .map(|x| AccountSumTargets::from_account_target(x, builder)) .collect(); + // build merkle sum tree let _merkle_tree_targets = build_merkle_sum_tree_from_account_targets(builder, &mut account_sum_targets); } @@ -58,7 +56,7 @@ impl MerkleSumTreeProver { /// Get the merkle sum tree proof of this batch of accounts. pub fn get_proof(&self) -> ProofWithPublicInputs { let mut builder = CircuitBuilder::::new(STANDARD_CONFIG); - let mut pw = PartialWitness::::new(); + let mut pw = PartialWitness::::new(); self.build_and_set_merkle_tree_targets(&mut builder, &mut pw); From b07b04e8aed4713df1f054badd92b00e8d827a25 Mon Sep 17 00:00:00 2001 From: EkamSinghPandher Date: Thu, 1 Aug 2024 11:53:40 +0800 Subject: [PATCH 02/17] feature:add-merkle-proof-circuit-prover --- .../zk-por-core/src/merkle_proof_prover/prover.rs | 13 +++++++++++-- crates/zk-por-core/src/merkle_sum_prover/prover.rs | 3 ++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/crates/zk-por-core/src/merkle_proof_prover/prover.rs b/crates/zk-por-core/src/merkle_proof_prover/prover.rs index 9b48eba..a775a30 100644 --- a/crates/zk-por-core/src/merkle_proof_prover/prover.rs +++ b/crates/zk-por-core/src/merkle_proof_prover/prover.rs @@ -1,8 +1,17 @@ use log::Level; -use plonky2::{iop::witness::PartialWitness, plonk::{circuit_builder::CircuitBuilder, circuit_data::CircuitData, proof::ProofWithPublicInputs, prover::prove}, util::timing::TimingTree}; +use plonky2::{ + iop::witness::PartialWitness, + plonk::{ + circuit_builder::CircuitBuilder, circuit_data::CircuitData, proof::ProofWithPublicInputs, + prover::prove, + }, + util::timing::TimingTree, +}; use crate::{ - circuit_config::STANDARD_CONFIG, merkle_sum_prover::circuits::account_circuit::AccountTargets, types::{C, D, F} + circuit_config::STANDARD_CONFIG, + merkle_sum_prover::circuits::account_circuit::AccountTargets, + types::{C, D, F}, }; use super::{merkle_proof::MerkleProofProvingInputs, merkle_proof_circuits::MerkleProofTargets}; diff --git a/crates/zk-por-core/src/merkle_sum_prover/prover.rs b/crates/zk-por-core/src/merkle_sum_prover/prover.rs index b01fcd2..450cf58 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/prover.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/prover.rs @@ -37,7 +37,8 @@ impl MerkleSumTreeProver { for i in 0..self.accounts.len() { // Build account targets - let account_target = AccountTargets::new_from_account(self.accounts.get(i).unwrap(), builder); + let account_target = + AccountTargets::new_from_account(self.accounts.get(i).unwrap(), builder); // Set account targets account_target.set_account_targets(self.accounts.get(i).unwrap(), pw); account_targets.push(account_target); From 2c3315b7a085a91ee6c4173d7b939a8323e3638a Mon Sep 17 00:00:00 2001 From: EkamSinghPandher Date: Thu, 1 Aug 2024 14:55:28 +0800 Subject: [PATCH 03/17] feature:add-merkle-proof-logic-and-circuit-tests --- crates/zk-por-core/src/account.rs | 2 +- .../src/merkle_proof_prover/merkle_proof.rs | 17 +- .../merkle_proof_circuits.rs | 25 ++- .../src/merkle_proof_prover/prover.rs | 42 ++++ .../src/merkle_sum_prover/merkle_sum_tree.rs | 182 ++++++++++++++++++ .../zk-por-core/src/merkle_sum_prover/mod.rs | 2 + .../src/merkle_sum_prover/prover.rs | 48 ++--- .../src/merkle_sum_prover/utils.rs | 21 ++ 8 files changed, 298 insertions(+), 41 deletions(-) create mode 100644 crates/zk-por-core/src/merkle_sum_prover/merkle_sum_tree.rs create mode 100644 crates/zk-por-core/src/merkle_sum_prover/utils.rs diff --git a/crates/zk-por-core/src/account.rs b/crates/zk-por-core/src/account.rs index 700fbd1..b7655f0 100644 --- a/crates/zk-por-core/src/account.rs +++ b/crates/zk-por-core/src/account.rs @@ -16,7 +16,7 @@ pub struct Account { impl Account { /// Gets the account hash for a given account. - pub fn get_hash(self) -> HashOut { + pub fn get_hash(&self) -> HashOut { let mut sum_equity = F::ZERO; let mut sum_debt = F::ZERO; diff --git a/crates/zk-por-core/src/merkle_proof_prover/merkle_proof.rs b/crates/zk-por-core/src/merkle_proof_prover/merkle_proof.rs index e8e7486..1800654 100644 --- a/crates/zk-por-core/src/merkle_proof_prover/merkle_proof.rs +++ b/crates/zk-por-core/src/merkle_proof_prover/merkle_proof.rs @@ -1,6 +1,8 @@ use plonky2::hash::hash_types::HashOut; -use crate::{account::Account, types::F}; +use crate::{account::Account, merkle_sum_prover::merkle_sum_tree::MerkleSumTree, types::F}; + +use plonky2_field::types::Field; /// Proving Inputs required for a merkle proof. These inputs are used to prove the merkle tree proof of inclusion for a single /// user. @@ -16,4 +18,17 @@ impl MerkleProofProvingInputs { pub fn get_account_hash(self) -> HashOut { self.account.get_hash() } + + pub fn new_from_merkle_tree( + index: usize, + account: &Account, + tree: &MerkleSumTree, + ) -> MerkleProofProvingInputs { + MerkleProofProvingInputs { + siblings: tree.get_siblings_hashes(index), + root: tree.get_root().hash, + index: F::from_canonical_u64(index as u64), + account: account.clone(), + } + } } diff --git a/crates/zk-por-core/src/merkle_proof_prover/merkle_proof_circuits.rs b/crates/zk-por-core/src/merkle_proof_prover/merkle_proof_circuits.rs index f659c21..27e7061 100644 --- a/crates/zk-por-core/src/merkle_proof_prover/merkle_proof_circuits.rs +++ b/crates/zk-por-core/src/merkle_proof_prover/merkle_proof_circuits.rs @@ -1,5 +1,10 @@ use plonky2::{ - hash::hash_types::HashOutTarget, iop::target::Target, plonk::circuit_builder::CircuitBuilder, + hash::hash_types::HashOutTarget, + iop::{ + target::Target, + witness::{PartialWitness, WitnessWrite}, + }, + plonk::circuit_builder::CircuitBuilder, }; use crate::{ @@ -8,6 +13,8 @@ use crate::{ types::{D, F}, }; +use super::merkle_proof::MerkleProofProvingInputs; + pub struct MerkleProofTargets { pub merkle_root_target: HashOutTarget, pub account_hash: HashOutTarget, @@ -40,7 +47,7 @@ impl MerkleProofTargets { /// Given the siblings in a merkle tree and my root hash, verify the merkle proof of inclusion of the supplied leaf hash. /// Since the order of the hash depends on my siblings position, we use the index bits of the index target to determine the order of the /// hash inputs. - pub fn verify_merkle_proof_circuit(self, builder: &mut CircuitBuilder) { + pub fn verify_merkle_proof_circuit(&self, builder: &mut CircuitBuilder) { // Get the index bits up to the merkle tree depth number of bits from Little endian representation let index_bits = builder.split_le(self.index_target, self.merkle_tree_depth); @@ -57,4 +64,18 @@ impl MerkleProofTargets { builder.connect_hashes(leaf_hash, self.merkle_root_target); } + + pub fn set_merkle_proof_targets( + &self, + merkle_proof_pis: &MerkleProofProvingInputs, + pw: &mut PartialWitness, + ) { + self.siblings.iter().enumerate().for_each(|x| { + let hash_pi = merkle_proof_pis.siblings.get(x.0).unwrap(); + pw.set_hash_target(*x.1, *hash_pi); + }); + + pw.set_target(self.index_target, merkle_proof_pis.index); + pw.set_hash_target(self.merkle_root_target, merkle_proof_pis.root); + } } diff --git a/crates/zk-por-core/src/merkle_proof_prover/prover.rs b/crates/zk-por-core/src/merkle_proof_prover/prover.rs index a775a30..4314337 100644 --- a/crates/zk-por-core/src/merkle_proof_prover/prover.rs +++ b/crates/zk-por-core/src/merkle_proof_prover/prover.rs @@ -23,6 +23,7 @@ pub struct MerkleProofProver { } impl MerkleProofProver { + /// Build the circuit for a merkle proof of inclusion of a given account at a specific index. pub fn build_and_set_merkle_proof_circuit( &self, builder: &mut CircuitBuilder, @@ -39,10 +40,12 @@ impl MerkleProofProver { ); merkle_proof_targets.verify_merkle_proof_circuit(builder); + merkle_proof_targets.set_merkle_proof_targets(&self.merkle_proof, pw); account_targets.set_account_targets(&self.merkle_proof.account, pw); } + /// Get the Proof with PI's of a merkle proof of inclusion of a users account at a given index. pub fn get_proof(&self) -> ProofWithPublicInputs { let mut builder = CircuitBuilder::::new(STANDARD_CONFIG); let mut pw = PartialWitness::::new(); @@ -80,3 +83,42 @@ impl MerkleProofProver { } } } + +#[cfg(test)] +pub mod test { + use crate::{ + circuit_utils::run_circuit_test, + merkle_proof_prover::{merkle_proof::MerkleProofProvingInputs, prover::MerkleProofProver}, + merkle_sum_prover::merkle_sum_tree::MerkleSumTree, + parser::read_json_into_accounts_vec, + }; + + #[test] + pub fn test_build_and_set_merkle_targets() { + run_circuit_test(|builder, pw| { + let path = "../../test-data/batch0.json"; + let accounts = read_json_into_accounts_vec(path); + let account = accounts.get(0).unwrap(); + let merkle_tree = MerkleSumTree::new_tree_from_accounts(&accounts); + let merkle_proof_pis = + MerkleProofProvingInputs::new_from_merkle_tree(0, account, &merkle_tree); + let prover = MerkleProofProver { merkle_proof: merkle_proof_pis }; + + prover.build_and_set_merkle_proof_circuit(builder, pw); + }); + } + + #[test] + pub fn test_get_proof() { + let path = "../../test-data/batch0.json"; + let accounts = read_json_into_accounts_vec(path); + let account = accounts.get(0).unwrap(); + let merkle_tree = MerkleSumTree::new_tree_from_accounts(&accounts); + let merkle_proof_pis = + MerkleProofProvingInputs::new_from_merkle_tree(0, account, &merkle_tree); + + let prover = MerkleProofProver { merkle_proof: merkle_proof_pis }; + + let _proof = prover.get_proof(); + } +} diff --git a/crates/zk-por-core/src/merkle_sum_prover/merkle_sum_tree.rs b/crates/zk-por-core/src/merkle_sum_prover/merkle_sum_tree.rs new file mode 100644 index 0000000..b223074 --- /dev/null +++ b/crates/zk-por-core/src/merkle_sum_prover/merkle_sum_tree.rs @@ -0,0 +1,182 @@ +use plonky2::{hash::hash_types::HashOut, util::log2_strict}; + +use crate::{ + account::Account, + types::{D, F}, +}; + +use super::utils::hash_2_subhashes; +use plonky2_field::types::Field; + +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct MerkleSumNode { + pub sum_equity: F, + pub sum_debt: F, + pub hash: HashOut, +} + +impl MerkleSumNode { + /// Get a new merkle sum node given a account. + pub fn new_from_account(account: &Account) -> MerkleSumNode { + let mut sum_equity = F::ZERO; + account.equity.iter().for_each(|x| { + sum_equity = sum_equity + *x; + }); + + let mut sum_debt = F::ZERO; + account.debt.iter().for_each(|x| { + sum_debt = sum_debt + *x; + }); + + let hash = account.get_hash(); + MerkleSumNode { hash, sum_equity, sum_debt } + } + + /// Get a new MerkleSumNode given its 2 child nodes. + pub fn new_from_children_nodes(node1: &MerkleSumNode, node2: &MerkleSumNode) -> MerkleSumNode { + let hash = hash_2_subhashes::(&node1.hash, &node2.hash); + let sum_equity = node1.sum_equity + node2.sum_equity; + let sum_debt = node2.sum_debt + node2.sum_debt; + MerkleSumNode { hash, sum_equity, sum_debt } + } +} + +/// Struct representing a merkle sum tree, it is represented as a vector of Merkle Sum Nodes. +pub struct MerkleSumTree { + pub merkle_sum_tree: Vec, + pub tree_depth: usize, +} + +impl MerkleSumTree { + /// Create a new merkle sum tree from a set of accounts, note that this set must be a power of 2. + /// In the future we can try to pad with empty accounts. + pub fn new_tree_from_accounts(accounts: &Vec) -> MerkleSumTree { + let mut merkle_sum_tree: Vec = Vec::new(); + let num_leaves = accounts.len(); + + for i in 0..num_leaves * 2 - 1 { + if i < num_leaves { + let account = accounts.get(i).unwrap(); + merkle_sum_tree.push(MerkleSumNode::new_from_account(account)); + } else { + let left_child_index = 2 * (i - num_leaves); + let right_child_index = 2 * (i - num_leaves) + 1; + let left_child = merkle_sum_tree.get(left_child_index).unwrap(); + let right_child = merkle_sum_tree.get(right_child_index).unwrap(); + let node = MerkleSumNode::new_from_children_nodes(left_child, right_child); + merkle_sum_tree.push(node); + } + } + + MerkleSumTree { merkle_sum_tree, tree_depth: log2_strict(accounts.len()) } + } + + pub fn get_root(&self) -> MerkleSumNode { + *self.merkle_sum_tree.last().unwrap() + } + + pub fn get_from_index(&self, index: usize) -> Option<&MerkleSumNode> { + return self.merkle_sum_tree.get(index); + } + + /// Get the siblings for the merkle proof of inclusion given a leaf index as Merkle Sum Nodes. + /// We get the parent index of a leaf using the formula: parent = index / 2 + num_leaves + pub fn get_siblings(&self, mut index: usize) -> Vec { + let mut siblings = Vec::new(); + let num_leaves = 1 << self.tree_depth; + while index < self.merkle_sum_tree.len() - 1 { + if index % 2 == 1 { + let sibling_index = index - 1; + let sibling = self.merkle_sum_tree.get(sibling_index).unwrap(); + siblings.push(*sibling); + } else { + let sibling_index = index + 1; + let sibling = self.merkle_sum_tree.get(sibling_index).unwrap(); + siblings.push(*sibling); + } + + let parent = index / 2 + num_leaves; + index = parent; + } + return siblings; + } + + /// Get siblings as just the hashes of the merkle sum tree + pub fn get_siblings_hashes(&self, index: usize) -> Vec> { + let siblings = self.get_siblings(index); + siblings.iter().map(|x| x.hash).collect() + } +} + +#[cfg(test)] +pub mod test { + use crate::{parser::read_json_into_accounts_vec, types::F}; + use plonky2_field::types::Field; + + use super::{MerkleSumNode, MerkleSumTree}; + + #[test] + pub fn test_new_from_account() { + let path = "../../test-data/batch0.json"; + let accounts = read_json_into_accounts_vec(path); + + let account = accounts.get(0).unwrap(); + let node = MerkleSumNode::new_from_account(account); + assert_eq!(node.sum_equity, F::from_canonical_u64(133876586)); + assert_eq!(node.sum_debt, F::from_canonical_u64(0)); + } + + #[test] + pub fn test_new_from_children_nodes() { + let path = "../../test-data/batch0.json"; + let accounts = read_json_into_accounts_vec(path); + + let account1 = accounts.get(0).unwrap(); + let node1 = MerkleSumNode::new_from_account(account1); + let account2 = accounts.get(1).unwrap(); + let node2 = MerkleSumNode::new_from_account(account2); + let node3 = MerkleSumNode::new_from_children_nodes(&node1, &node2); + assert_eq!( + node3.sum_equity, + F::from_canonical_u64(138512215) + F::from_canonical_u64(133876586) + ); + assert_eq!(node3.sum_debt, F::from_canonical_u64(0)); + } + + #[test] + pub fn test_new_tree_from_accounts() { + let path = "../../test-data/batch0.json"; + let accounts = read_json_into_accounts_vec(path); + let mut sum_equity = F::ZERO; + + for i in 0..accounts.len() { + let account = accounts.get(i).unwrap(); + account.equity.iter().for_each(|x| { + sum_equity = sum_equity + *x; + }); + } + + let tree = MerkleSumTree::new_tree_from_accounts(&accounts); + + let root = tree.get_root(); + assert_eq!(root.sum_equity, sum_equity); + assert_eq!(root.sum_debt, F::ZERO); + } + + #[test] + fn test_get_siblings() { + let path = "../../test-data/batch0.json"; + let accounts = read_json_into_accounts_vec(path); + + let merkle_sum_tree = MerkleSumTree::new_tree_from_accounts(&accounts); + + let mut siblings_calculated: Vec = Vec::new(); + siblings_calculated.push(*merkle_sum_tree.get_from_index(0).unwrap()); + siblings_calculated.push(*merkle_sum_tree.get_from_index(17).unwrap()); + siblings_calculated.push(*merkle_sum_tree.get_from_index(25).unwrap()); + siblings_calculated.push(*merkle_sum_tree.get_from_index(29).unwrap()); + + let siblings = merkle_sum_tree.get_siblings(1); + assert_eq!(siblings, siblings_calculated); + } +} diff --git a/crates/zk-por-core/src/merkle_sum_prover/mod.rs b/crates/zk-por-core/src/merkle_sum_prover/mod.rs index 0d9141b..db3cc19 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/mod.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/mod.rs @@ -1,2 +1,4 @@ pub mod circuits; +pub mod merkle_sum_tree; pub mod prover; +pub mod utils; diff --git a/crates/zk-por-core/src/merkle_sum_prover/prover.rs b/crates/zk-por-core/src/merkle_sum_prover/prover.rs index 450cf58..72e3755 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/prover.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/prover.rs @@ -95,48 +95,22 @@ impl MerkleSumTreeProver { #[cfg(test)] pub mod test { - use log::Level; - use plonky2::{ - iop::witness::PartialWitness, - plonk::{circuit_builder::CircuitBuilder, circuit_data::CircuitData, prover::prove}, - util::timing::TimingTree, - }; - use plonky2_field::goldilocks_field::GoldilocksField; - - use crate::{ - circuit_config::STANDARD_CONFIG, - parser::read_json_into_accounts_vec, - types::{C, D, F}, - }; + use crate::{circuit_utils::run_circuit_test, parser::read_json_into_accounts_vec}; use super::MerkleSumTreeProver; #[test] pub fn test_build_and_set_merkle_targets() { - let mut builder = CircuitBuilder::::new(STANDARD_CONFIG); - let mut pw = PartialWitness::::new(); - - let path = "../../test-data/batch0.json"; - let accounts = read_json_into_accounts_vec(path); - let prover = MerkleSumTreeProver { - // batch_id: 0, - accounts, - }; - - prover.build_and_set_merkle_tree_targets(&mut builder, &mut pw); - - let data = builder.build::(); - - let CircuitData { prover_only, common, verifier_only: _ } = &data; - - println!("Started Proving"); - let mut timing = TimingTree::new("prove", Level::Debug); - let proof_res = prove(&prover_only, &common, pw.clone(), &mut timing); - let proof = proof_res.expect("Proof failed"); - - println!("Verifying Proof"); - // Verify proof - let _proof_verification_res = data.verify(proof.clone()).unwrap(); + run_circuit_test(|builder, pw| { + let path = "../../test-data/batch0.json"; + let accounts = read_json_into_accounts_vec(path); + let prover = MerkleSumTreeProver { + // batch_id: 0, + accounts, + }; + + prover.build_and_set_merkle_tree_targets(builder, pw); + }); } #[test] diff --git a/crates/zk-por-core/src/merkle_sum_prover/utils.rs b/crates/zk-por-core/src/merkle_sum_prover/utils.rs new file mode 100644 index 0000000..cf18797 --- /dev/null +++ b/crates/zk-por-core/src/merkle_sum_prover/utils.rs @@ -0,0 +1,21 @@ +use plonky2::{ + hash::{ + hash_types::{HashOut, RichField}, + poseidon::PoseidonHash, + }, + plonk::config::Hasher, +}; +use plonky2_field::extension::Extendable; + +pub fn hash_2_subhashes, const D: usize>( + hash_1: &HashOut, + hash_2: &HashOut, +) -> HashOut { + let inputs = vec![hash_1.elements.to_vec(), hash_2.elements.to_vec()].concat(); + hash_inputs(inputs) +} + +pub fn hash_inputs(inputs: Vec) -> HashOut { + let hash = PoseidonHash::hash_no_pad(inputs.as_slice()); + return hash; +} From 3540cc55f265000572ef6ba6de1dc7f8e962a5a9 Mon Sep 17 00:00:00 2001 From: EkamSinghPandher Date: Thu, 1 Aug 2024 16:26:27 +0800 Subject: [PATCH 04/17] chore:review-changes --- crates/zk-por-core/src/account.rs | 12 ++-- crates/zk-por-core/src/circuit_config.rs | 2 +- crates/zk-por-core/src/circuit_utils.rs | 10 +-- .../src/merkle_sum_prover/merkle_sum_tree.rs | 11 ++-- crates/zk-por-core/src/recursive/prove.rs | 64 +++++++++++++++++++ 5 files changed, 80 insertions(+), 19 deletions(-) create mode 100644 crates/zk-por-core/src/recursive/prove.rs diff --git a/crates/zk-por-core/src/account.rs b/crates/zk-por-core/src/account.rs index b7655f0..bf0b734 100644 --- a/crates/zk-por-core/src/account.rs +++ b/crates/zk-por-core/src/account.rs @@ -17,14 +17,12 @@ pub struct Account { impl Account { /// Gets the account hash for a given account. pub fn get_hash(&self) -> HashOut { - let mut sum_equity = F::ZERO; - let mut sum_debt = F::ZERO; - - self.equity.iter().for_each(|x| { - sum_equity = sum_equity + *x; + let sum_equity = self.equity.iter().fold(F::ZERO, |acc, x| { + acc + *x }); - self.debt.iter().for_each(|x| { - sum_debt = sum_debt + *x; + + let sum_debt = self.debt.iter().fold(F::ZERO, |acc, x| { + acc + *x }); let hash = PoseidonHash::hash_no_pad(vec![sum_equity, sum_debt].as_slice()); diff --git a/crates/zk-por-core/src/circuit_config.rs b/crates/zk-por-core/src/circuit_config.rs index 2f4959e..c3a494f 100644 --- a/crates/zk-por-core/src/circuit_config.rs +++ b/crates/zk-por-core/src/circuit_config.rs @@ -10,7 +10,7 @@ pub const STANDARD_CONFIG: CircuitConfig = CircuitConfig { use_base_arithmetic_gate: true, security_bits: 100, num_challenges: 2, - zero_knowledge: true, + zero_knowledge: false, max_quotient_degree_factor: 8, fri_config: FriConfig { rate_bits: 3, diff --git a/crates/zk-por-core/src/circuit_utils.rs b/crates/zk-por-core/src/circuit_utils.rs index 4ef1407..b8c9451 100644 --- a/crates/zk-por-core/src/circuit_utils.rs +++ b/crates/zk-por-core/src/circuit_utils.rs @@ -19,7 +19,7 @@ use std::panic; use crate::{ circuit_config::STANDARD_CONFIG, - types::{C, MAX_POSITIVE_AMOUNT_LOG}, + types::{C, D, F, MAX_POSITIVE_AMOUNT_LOG}, }; /// Test runner for ease of testing @@ -42,7 +42,7 @@ where } /// Computes `if b { h0 } else { h1 }`. -pub fn select_hash, const D: usize>( +pub fn select_hash( builder: &mut CircuitBuilder, b: BoolTarget, h0: HashOutTarget, @@ -55,7 +55,7 @@ pub fn select_hash, const D: usize>( /// Assert 0 <= x <= MAX_POSITIVE_AMOUNT /// MAX_POSITIVE_AMOUNT = (1 << MAX_POSITIVE_AMOUNT_LOG) - 1 -pub fn assert_non_negative_unsigned, const D: usize>( +pub fn assert_non_negative_unsigned( builder: &mut CircuitBuilder, x: Target, ) { @@ -63,7 +63,7 @@ pub fn assert_non_negative_unsigned, const D: usize } /// Get Hash target by doing a poseidon hash on my input vector. -pub fn get_hash_from_input_targets_circuit, const D: usize>( +pub fn get_hash_from_input_targets_circuit( builder: &mut CircuitBuilder, inputs: Vec, ) -> HashOutTarget { @@ -71,7 +71,7 @@ pub fn get_hash_from_input_targets_circuit, const D } /// Hash 2 hashout targets by splitting it into its individual component elements -pub fn hash_2_subhashes_circuit, const D: usize>( +pub fn hash_2_subhashes_circuit( builder: &mut CircuitBuilder, hash_1: &HashOutTarget, hash_2: &HashOutTarget, diff --git a/crates/zk-por-core/src/merkle_sum_prover/merkle_sum_tree.rs b/crates/zk-por-core/src/merkle_sum_prover/merkle_sum_tree.rs index b223074..5b7f842 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/merkle_sum_tree.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/merkle_sum_tree.rs @@ -18,14 +18,13 @@ pub struct MerkleSumNode { impl MerkleSumNode { /// Get a new merkle sum node given a account. pub fn new_from_account(account: &Account) -> MerkleSumNode { - let mut sum_equity = F::ZERO; - account.equity.iter().for_each(|x| { - sum_equity = sum_equity + *x; + + let sum_equity = account.equity.iter().fold(F::ZERO, |acc, x| { + acc + *x }); - let mut sum_debt = F::ZERO; - account.debt.iter().for_each(|x| { - sum_debt = sum_debt + *x; + let sum_debt = account.debt.iter().fold(F::ZERO, |acc, x| { + acc + *x }); let hash = account.get_hash(); diff --git a/crates/zk-por-core/src/recursive/prove.rs b/crates/zk-por-core/src/recursive/prove.rs new file mode 100644 index 0000000..ad2fb67 --- /dev/null +++ b/crates/zk-por-core/src/recursive/prove.rs @@ -0,0 +1,64 @@ +use plonky2::{ + iop::witness::{PartialWitness, WitnessWrite}, + plonk::{ + circuit_data::{CircuitData, CommonCircuitData, VerifierOnlyCircuitData}, + config::{AlgebraicHasher, GenericConfig}, + proof::ProofWithPublicInputs, + prover::prove, + }, + util::timing::TimingTree, +}; + +use crate::types::{D, F}; +use anyhow::Result; + +use super::circuit::RecursiveTargets; + +pub type ProofTuple = + (ProofWithPublicInputs, VerifierOnlyCircuitData, CommonCircuitData); + +pub fn prove_n_subproofs< + C: GenericConfig, + InnerC: GenericConfig, + const N: usize, +>( + sub_proofs: Vec>, + inner_circuit_vd: &VerifierOnlyCircuitData, + recursive_circuit: &CircuitData, + recursive_targets: RecursiveTargets, +) -> Result> +where + InnerC::Hasher: AlgebraicHasher, + // [(); C::Hasher::HASH_SIZE]:, // TODO: figure out how to make this work +{ + if sub_proofs.len() != N { + return Err(anyhow::anyhow!(format!( + "number of proofs [{}] is not consistent with N [{}]", + sub_proofs.len(), + N + ))); + } + + let mut pw = PartialWitness::new(); + pw.set_verifier_data_target(&recursive_targets.verifier_circuit_target, inner_circuit_vd); + + (0..N).for_each(|i| { + pw.set_proof_with_pis_target( + &recursive_targets.proof_with_pub_input_targets[i], + &sub_proofs[i], + ); + }); + + let mut timing = TimingTree::new("prove_N_subproofs", log::Level::Debug); + let start = std::time::Instant::now(); + log::debug!("before prove"); + let proof = prove(&recursive_circuit.prover_only, &recursive_circuit.common, pw, &mut timing)?; + log::debug!("time for {:?} proofs, {:?}", N, start.elapsed().as_millis()); + + #[cfg(debug_assertions)] + { + recursive_circuit.verify(proof.clone())?; + } + + Ok(proof) +} From fa4680d7ac342c3e1ee5f03f58ef5b97630be6fb Mon Sep 17 00:00:00 2001 From: EkamSinghPandher Date: Thu, 1 Aug 2024 16:37:14 +0800 Subject: [PATCH 05/17] refactor:remove-proving-circuits --- crates/zk-por-core/src/lib.rs | 2 +- .../src/merkle_proof_prover/merkle_proof.rs | 34 ----- .../merkle_proof_circuits.rs | 81 ------------ .../src/merkle_proof_prover/mod.rs | 3 - .../src/merkle_proof_prover/prover.rs | 124 ------------------ .../zk-por-core/src/merkle_sum_prover/mod.rs | 1 - .../merkle_sum_tree.rs | 4 +- 7 files changed, 2 insertions(+), 247 deletions(-) delete mode 100644 crates/zk-por-core/src/merkle_proof_prover/merkle_proof.rs delete mode 100644 crates/zk-por-core/src/merkle_proof_prover/merkle_proof_circuits.rs delete mode 100644 crates/zk-por-core/src/merkle_proof_prover/mod.rs delete mode 100644 crates/zk-por-core/src/merkle_proof_prover/prover.rs rename crates/zk-por-core/src/{merkle_sum_prover => }/merkle_sum_tree.rs (98%) diff --git a/crates/zk-por-core/src/lib.rs b/crates/zk-por-core/src/lib.rs index 7069838..36a96c9 100644 --- a/crates/zk-por-core/src/lib.rs +++ b/crates/zk-por-core/src/lib.rs @@ -2,7 +2,7 @@ pub mod account; pub mod circuit_config; pub mod circuit_utils; pub mod error; -pub mod merkle_proof_prover; pub mod merkle_sum_prover; pub mod parser; pub mod types; +pub mod merkle_sum_tree; diff --git a/crates/zk-por-core/src/merkle_proof_prover/merkle_proof.rs b/crates/zk-por-core/src/merkle_proof_prover/merkle_proof.rs deleted file mode 100644 index 1800654..0000000 --- a/crates/zk-por-core/src/merkle_proof_prover/merkle_proof.rs +++ /dev/null @@ -1,34 +0,0 @@ -use plonky2::hash::hash_types::HashOut; - -use crate::{account::Account, merkle_sum_prover::merkle_sum_tree::MerkleSumTree, types::F}; - -use plonky2_field::types::Field; - -/// Proving Inputs required for a merkle proof. These inputs are used to prove the merkle tree proof of inclusion for a single -/// user. -pub struct MerkleProofProvingInputs { - pub siblings: Vec>, - pub root: HashOut, - pub index: F, - pub account: Account, -} - -impl MerkleProofProvingInputs { - /// Gets the leaf hash of an account - pub fn get_account_hash(self) -> HashOut { - self.account.get_hash() - } - - pub fn new_from_merkle_tree( - index: usize, - account: &Account, - tree: &MerkleSumTree, - ) -> MerkleProofProvingInputs { - MerkleProofProvingInputs { - siblings: tree.get_siblings_hashes(index), - root: tree.get_root().hash, - index: F::from_canonical_u64(index as u64), - account: account.clone(), - } - } -} diff --git a/crates/zk-por-core/src/merkle_proof_prover/merkle_proof_circuits.rs b/crates/zk-por-core/src/merkle_proof_prover/merkle_proof_circuits.rs deleted file mode 100644 index 27e7061..0000000 --- a/crates/zk-por-core/src/merkle_proof_prover/merkle_proof_circuits.rs +++ /dev/null @@ -1,81 +0,0 @@ -use plonky2::{ - hash::hash_types::HashOutTarget, - iop::{ - target::Target, - witness::{PartialWitness, WitnessWrite}, - }, - plonk::circuit_builder::CircuitBuilder, -}; - -use crate::{ - circuit_utils::{hash_2_subhashes_circuit, select_hash}, - merkle_sum_prover::circuits::account_circuit::{AccountSumTargets, AccountTargets}, - types::{D, F}, -}; - -use super::merkle_proof::MerkleProofProvingInputs; - -pub struct MerkleProofTargets { - pub merkle_root_target: HashOutTarget, - pub account_hash: HashOutTarget, - pub index_target: Target, - pub siblings: Vec, - pub merkle_tree_depth: usize, -} - -impl MerkleProofTargets { - pub fn new_from_account_targets( - builder: &mut CircuitBuilder, - account_targets: &AccountTargets, - merkle_proof_len: usize, - ) -> MerkleProofTargets { - let merkle_root_target = builder.add_virtual_hash(); - let account_sum_targets = AccountSumTargets::from_account_target(&account_targets, builder); - let account_hash = account_sum_targets.get_account_hash_targets(builder); - let index_target = builder.add_virtual_target(); - let siblings: Vec = - (0..merkle_proof_len).enumerate().map(|_| builder.add_virtual_hash()).collect(); - MerkleProofTargets { - merkle_root_target, - account_hash, - index_target, - siblings, - merkle_tree_depth: merkle_proof_len, - } - } - - /// Given the siblings in a merkle tree and my root hash, verify the merkle proof of inclusion of the supplied leaf hash. - /// Since the order of the hash depends on my siblings position, we use the index bits of the index target to determine the order of the - /// hash inputs. - pub fn verify_merkle_proof_circuit(&self, builder: &mut CircuitBuilder) { - // Get the index bits up to the merkle tree depth number of bits from Little endian representation - let index_bits = builder.split_le(self.index_target, self.merkle_tree_depth); - - let mut leaf_hash = self.account_hash; - - for i in 0..self.siblings.len() { - let sibling = self.siblings.get(i).unwrap(); - - // Order is based on the index bits at the ith index - let first_hash = select_hash(builder, index_bits[i], *sibling, leaf_hash); - let second_hash = select_hash(builder, index_bits[i], leaf_hash, *sibling); - leaf_hash = hash_2_subhashes_circuit(builder, &first_hash, &second_hash); - } - - builder.connect_hashes(leaf_hash, self.merkle_root_target); - } - - pub fn set_merkle_proof_targets( - &self, - merkle_proof_pis: &MerkleProofProvingInputs, - pw: &mut PartialWitness, - ) { - self.siblings.iter().enumerate().for_each(|x| { - let hash_pi = merkle_proof_pis.siblings.get(x.0).unwrap(); - pw.set_hash_target(*x.1, *hash_pi); - }); - - pw.set_target(self.index_target, merkle_proof_pis.index); - pw.set_hash_target(self.merkle_root_target, merkle_proof_pis.root); - } -} diff --git a/crates/zk-por-core/src/merkle_proof_prover/mod.rs b/crates/zk-por-core/src/merkle_proof_prover/mod.rs deleted file mode 100644 index b3fe42a..0000000 --- a/crates/zk-por-core/src/merkle_proof_prover/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod merkle_proof; -pub mod merkle_proof_circuits; -pub mod prover; diff --git a/crates/zk-por-core/src/merkle_proof_prover/prover.rs b/crates/zk-por-core/src/merkle_proof_prover/prover.rs deleted file mode 100644 index 4314337..0000000 --- a/crates/zk-por-core/src/merkle_proof_prover/prover.rs +++ /dev/null @@ -1,124 +0,0 @@ -use log::Level; -use plonky2::{ - iop::witness::PartialWitness, - plonk::{ - circuit_builder::CircuitBuilder, circuit_data::CircuitData, proof::ProofWithPublicInputs, - prover::prove, - }, - util::timing::TimingTree, -}; - -use crate::{ - circuit_config::STANDARD_CONFIG, - merkle_sum_prover::circuits::account_circuit::AccountTargets, - types::{C, D, F}, -}; - -use super::{merkle_proof::MerkleProofProvingInputs, merkle_proof_circuits::MerkleProofTargets}; - -use tracing::error; - -pub struct MerkleProofProver { - pub merkle_proof: MerkleProofProvingInputs, -} - -impl MerkleProofProver { - /// Build the circuit for a merkle proof of inclusion of a given account at a specific index. - pub fn build_and_set_merkle_proof_circuit( - &self, - builder: &mut CircuitBuilder, - pw: &mut PartialWitness, - ) { - let merkle_proof_len = self.merkle_proof.siblings.len(); - - let account_targets = AccountTargets::new_from_account(&self.merkle_proof.account, builder); - - let merkle_proof_targets = MerkleProofTargets::new_from_account_targets( - builder, - &account_targets, - merkle_proof_len, - ); - - merkle_proof_targets.verify_merkle_proof_circuit(builder); - merkle_proof_targets.set_merkle_proof_targets(&self.merkle_proof, pw); - - account_targets.set_account_targets(&self.merkle_proof.account, pw); - } - - /// Get the Proof with PI's of a merkle proof of inclusion of a users account at a given index. - pub fn get_proof(&self) -> ProofWithPublicInputs { - let mut builder = CircuitBuilder::::new(STANDARD_CONFIG); - let mut pw = PartialWitness::::new(); - - self.build_and_set_merkle_proof_circuit(&mut builder, &mut pw); - - builder.print_gate_counts(0); - - let mut timing = TimingTree::new("prove", Level::Debug); - let data = builder.build::(); - - let CircuitData { prover_only, common, verifier_only: _ } = &data; - - println!("Started Proving"); - - let proof_res = prove(&prover_only, &common, pw.clone(), &mut timing); - - match proof_res { - Ok(proof) => { - println!("Finished Proving"); - - let proof_verification_res = data.verify(proof.clone()); - match proof_verification_res { - Ok(_) => proof, - Err(e) => { - error!("Proof verification failed: {:?}", e); - panic!("Proof verification failed!"); - } - } - } - Err(e) => { - error!("Proof generation failed: {:?}", e); - panic!("Proof generation failed!"); - } - } - } -} - -#[cfg(test)] -pub mod test { - use crate::{ - circuit_utils::run_circuit_test, - merkle_proof_prover::{merkle_proof::MerkleProofProvingInputs, prover::MerkleProofProver}, - merkle_sum_prover::merkle_sum_tree::MerkleSumTree, - parser::read_json_into_accounts_vec, - }; - - #[test] - pub fn test_build_and_set_merkle_targets() { - run_circuit_test(|builder, pw| { - let path = "../../test-data/batch0.json"; - let accounts = read_json_into_accounts_vec(path); - let account = accounts.get(0).unwrap(); - let merkle_tree = MerkleSumTree::new_tree_from_accounts(&accounts); - let merkle_proof_pis = - MerkleProofProvingInputs::new_from_merkle_tree(0, account, &merkle_tree); - let prover = MerkleProofProver { merkle_proof: merkle_proof_pis }; - - prover.build_and_set_merkle_proof_circuit(builder, pw); - }); - } - - #[test] - pub fn test_get_proof() { - let path = "../../test-data/batch0.json"; - let accounts = read_json_into_accounts_vec(path); - let account = accounts.get(0).unwrap(); - let merkle_tree = MerkleSumTree::new_tree_from_accounts(&accounts); - let merkle_proof_pis = - MerkleProofProvingInputs::new_from_merkle_tree(0, account, &merkle_tree); - - let prover = MerkleProofProver { merkle_proof: merkle_proof_pis }; - - let _proof = prover.get_proof(); - } -} diff --git a/crates/zk-por-core/src/merkle_sum_prover/mod.rs b/crates/zk-por-core/src/merkle_sum_prover/mod.rs index db3cc19..e8d02b7 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/mod.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/mod.rs @@ -1,4 +1,3 @@ pub mod circuits; -pub mod merkle_sum_tree; pub mod prover; pub mod utils; diff --git a/crates/zk-por-core/src/merkle_sum_prover/merkle_sum_tree.rs b/crates/zk-por-core/src/merkle_sum_tree.rs similarity index 98% rename from crates/zk-por-core/src/merkle_sum_prover/merkle_sum_tree.rs rename to crates/zk-por-core/src/merkle_sum_tree.rs index 5b7f842..745ec3a 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/merkle_sum_tree.rs +++ b/crates/zk-por-core/src/merkle_sum_tree.rs @@ -1,11 +1,9 @@ use plonky2::{hash::hash_types::HashOut, util::log2_strict}; use crate::{ - account::Account, - types::{D, F}, + account::Account, merkle_sum_prover::utils::hash_2_subhashes, types::{D, F} }; -use super::utils::hash_2_subhashes; use plonky2_field::types::Field; #[derive(Debug, Clone, Copy, PartialEq)] From ce15ebe06d66817e413e1aa8313af4233c6f97c6 Mon Sep 17 00:00:00 2001 From: EkamSinghPandher Date: Thu, 1 Aug 2024 16:44:21 +0800 Subject: [PATCH 06/17] chore:fmt --- crates/zk-por-core/src/account.rs | 8 ++------ crates/zk-por-core/src/circuit_utils.rs | 5 +---- crates/zk-por-core/src/lib.rs | 2 +- crates/zk-por-core/src/merkle_sum_tree.rs | 15 ++++++--------- 4 files changed, 10 insertions(+), 20 deletions(-) diff --git a/crates/zk-por-core/src/account.rs b/crates/zk-por-core/src/account.rs index bf0b734..9cdad93 100644 --- a/crates/zk-por-core/src/account.rs +++ b/crates/zk-por-core/src/account.rs @@ -17,13 +17,9 @@ pub struct Account { impl Account { /// Gets the account hash for a given account. pub fn get_hash(&self) -> HashOut { - let sum_equity = self.equity.iter().fold(F::ZERO, |acc, x| { - acc + *x - }); + let sum_equity = self.equity.iter().fold(F::ZERO, |acc, x| acc + *x); - let sum_debt = self.debt.iter().fold(F::ZERO, |acc, x| { - acc + *x - }); + let sum_debt = self.debt.iter().fold(F::ZERO, |acc, x| acc + *x); let hash = PoseidonHash::hash_no_pad(vec![sum_equity, sum_debt].as_slice()); diff --git a/crates/zk-por-core/src/circuit_utils.rs b/crates/zk-por-core/src/circuit_utils.rs index b8c9451..efe96cf 100644 --- a/crates/zk-por-core/src/circuit_utils.rs +++ b/crates/zk-por-core/src/circuit_utils.rs @@ -55,10 +55,7 @@ pub fn select_hash( /// Assert 0 <= x <= MAX_POSITIVE_AMOUNT /// MAX_POSITIVE_AMOUNT = (1 << MAX_POSITIVE_AMOUNT_LOG) - 1 -pub fn assert_non_negative_unsigned( - builder: &mut CircuitBuilder, - x: Target, -) { +pub fn assert_non_negative_unsigned(builder: &mut CircuitBuilder, x: Target) { builder.range_check(x, MAX_POSITIVE_AMOUNT_LOG); } diff --git a/crates/zk-por-core/src/lib.rs b/crates/zk-por-core/src/lib.rs index 36a96c9..dc654ce 100644 --- a/crates/zk-por-core/src/lib.rs +++ b/crates/zk-por-core/src/lib.rs @@ -3,6 +3,6 @@ pub mod circuit_config; pub mod circuit_utils; pub mod error; pub mod merkle_sum_prover; +pub mod merkle_sum_tree; pub mod parser; pub mod types; -pub mod merkle_sum_tree; diff --git a/crates/zk-por-core/src/merkle_sum_tree.rs b/crates/zk-por-core/src/merkle_sum_tree.rs index 745ec3a..40faa92 100644 --- a/crates/zk-por-core/src/merkle_sum_tree.rs +++ b/crates/zk-por-core/src/merkle_sum_tree.rs @@ -1,7 +1,9 @@ use plonky2::{hash::hash_types::HashOut, util::log2_strict}; use crate::{ - account::Account, merkle_sum_prover::utils::hash_2_subhashes, types::{D, F} + account::Account, + merkle_sum_prover::utils::hash_2_subhashes, + types::{D, F}, }; use plonky2_field::types::Field; @@ -16,14 +18,9 @@ pub struct MerkleSumNode { impl MerkleSumNode { /// Get a new merkle sum node given a account. pub fn new_from_account(account: &Account) -> MerkleSumNode { - - let sum_equity = account.equity.iter().fold(F::ZERO, |acc, x| { - acc + *x - }); - - let sum_debt = account.debt.iter().fold(F::ZERO, |acc, x| { - acc + *x - }); + let sum_equity = account.equity.iter().fold(F::ZERO, |acc, x| acc + *x); + + let sum_debt = account.debt.iter().fold(F::ZERO, |acc, x| acc + *x); let hash = account.get_hash(); MerkleSumNode { hash, sum_equity, sum_debt } From 96acebfb30ec5b1649b78c5fb210a9824db51c9d Mon Sep 17 00:00:00 2001 From: EkamSinghPandher Date: Thu, 1 Aug 2024 16:59:19 +0800 Subject: [PATCH 07/17] chore:remove-unused-functions --- crates/zk-por-core/src/circuit_utils.rs | 108 +----------------------- 1 file changed, 4 insertions(+), 104 deletions(-) diff --git a/crates/zk-por-core/src/circuit_utils.rs b/crates/zk-por-core/src/circuit_utils.rs index efe96cf..d2aa4b5 100644 --- a/crates/zk-por-core/src/circuit_utils.rs +++ b/crates/zk-por-core/src/circuit_utils.rs @@ -1,13 +1,7 @@ use log::Level; use plonky2::{ - hash::{ - hash_types::{HashOutTarget, RichField}, - poseidon::PoseidonHash, - }, - iop::{ - target::{BoolTarget, Target}, - witness::PartialWitness, - }, + hash::hash_types::RichField, + iop::{target::Target, witness::PartialWitness}, plonk::{ circuit_builder::CircuitBuilder, circuit_data::CircuitData, config::GenericConfig, prover::prove, @@ -41,52 +35,19 @@ where data.verify(proof).expect("Verify fail") } -/// Computes `if b { h0 } else { h1 }`. -pub fn select_hash( - builder: &mut CircuitBuilder, - b: BoolTarget, - h0: HashOutTarget, - h1: HashOutTarget, -) -> HashOutTarget { - HashOutTarget { - elements: core::array::from_fn(|i| builder.select(b, h0.elements[i], h1.elements[i])), - } -} - /// Assert 0 <= x <= MAX_POSITIVE_AMOUNT /// MAX_POSITIVE_AMOUNT = (1 << MAX_POSITIVE_AMOUNT_LOG) - 1 pub fn assert_non_negative_unsigned(builder: &mut CircuitBuilder, x: Target) { builder.range_check(x, MAX_POSITIVE_AMOUNT_LOG); } -/// Get Hash target by doing a poseidon hash on my input vector. -pub fn get_hash_from_input_targets_circuit( - builder: &mut CircuitBuilder, - inputs: Vec, -) -> HashOutTarget { - builder.hash_n_to_hash_no_pad::(inputs) -} - -/// Hash 2 hashout targets by splitting it into its individual component elements -pub fn hash_2_subhashes_circuit( - builder: &mut CircuitBuilder, - hash_1: &HashOutTarget, - hash_2: &HashOutTarget, -) -> HashOutTarget { - let inputs = vec![hash_1.elements.to_vec(), hash_2.elements.to_vec()].concat(); - get_hash_from_input_targets_circuit(builder, inputs) -} - #[cfg(test)] pub mod test { use crate::types::F; - use plonky2::{hash::hash_types::HashOut, iop::witness::WitnessWrite}; + use plonky2_field::types::{Field, Field64}; - use super::{ - assert_non_negative_unsigned, get_hash_from_input_targets_circuit, - hash_2_subhashes_circuit, run_circuit_test, - }; + use super::{assert_non_negative_unsigned, run_circuit_test}; #[test] fn test_assert_non_negative_unsigned() { @@ -104,65 +65,4 @@ pub mod test { assert_non_negative_unsigned(builder, x); }); } - - #[test] - fn test_get_hash_from_input_targets_circuit() { - run_circuit_test(|builder, pw| { - let target_1 = builder.add_virtual_target(); - let target_2 = builder.add_virtual_target(); - let hash_target = builder.add_virtual_hash(); - let calculated_hash_target = - get_hash_from_input_targets_circuit(builder, vec![target_1, target_2]); - builder.connect_hashes(hash_target, calculated_hash_target); - - let value_1 = F::ZERO; - let value_2 = F::ZERO; - - let hash = HashOut::from_vec(vec![ - F::from_canonical_u64(4330397376401421145), - F::from_canonical_u64(14124799381142128323), - F::from_canonical_u64(8742572140681234676), - F::from_canonical_u64(14345658006221440202), - ]); - - pw.set_target(target_1, value_1); - pw.set_target(target_2, value_2); - pw.set_hash_target(hash_target, hash); - }); - } - - #[test] - fn test_hash_2_subhashes_circuit() { - run_circuit_test(|builder, pw| { - let hash_target_1 = builder.add_virtual_hash(); - let hash_target_2 = builder.add_virtual_hash(); - let hash_target_3 = builder.add_virtual_hash(); - let calculated_hash_target = - hash_2_subhashes_circuit(builder, &hash_target_1, &hash_target_2); - builder.connect_hashes(hash_target_3, calculated_hash_target); - - let hash_1 = HashOut::from_vec(vec![ - F::from_canonical_u64(4330397376401421145), - F::from_canonical_u64(14124799381142128323), - F::from_canonical_u64(8742572140681234676), - F::from_canonical_u64(14345658006221440202), - ]); - let hash_2 = HashOut::from_vec(vec![ - F::from_canonical_u64(4330397376401421145), - F::from_canonical_u64(14124799381142128323), - F::from_canonical_u64(8742572140681234676), - F::from_canonical_u64(14345658006221440202), - ]); - - let hash_3 = HashOut::from_vec(vec![ - F::from_canonical_u64(13121882728673923020), - F::from_canonical_u64(10197653806804742863), - F::from_canonical_u64(16037207047953124082), - F::from_canonical_u64(2420399206709257475), - ]); - pw.set_hash_target(hash_target_1, hash_1); - pw.set_hash_target(hash_target_2, hash_2); - pw.set_hash_target(hash_target_3, hash_3); - }); - } } From 3eaadd717890d97d3f1801c55f7d06c93a02a284 Mon Sep 17 00:00:00 2001 From: EkamSinghPandher Date: Thu, 1 Aug 2024 19:03:38 +0800 Subject: [PATCH 08/17] feature:add-scheme-for-userid-hashing --- crates/zk-por-core/src/account.rs | 21 +++++++++++++++++-- .../circuits/account_circuit.rs | 10 ++++++--- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/crates/zk-por-core/src/account.rs b/crates/zk-por-core/src/account.rs index 9cdad93..ff56b18 100644 --- a/crates/zk-por-core/src/account.rs +++ b/crates/zk-por-core/src/account.rs @@ -9,7 +9,7 @@ use crate::types::F; /// A struct representing a users account. It represents their equity and debt as a Vector of goldilocks field elements. #[derive(Debug, Clone)] pub struct Account { - pub id: String, + pub id: String, // 256 bit hex string pub equity: Vec, pub debt: Vec, } @@ -21,8 +21,25 @@ impl Account { let sum_debt = self.debt.iter().fold(F::ZERO, |acc, x| acc + *x); - let hash = PoseidonHash::hash_no_pad(vec![sum_equity, sum_debt].as_slice()); + let id = self.get_user_id_in_field(); + + let hash = PoseidonHash::hash_no_pad(vec![id, vec![sum_equity, sum_debt]].concat().as_slice()); hash } + + /// Gets a user id as a vec of 5 GF elements. + pub fn get_user_id_in_field(&self)-> Vec{ + assert!(self.id.len() == 64); + let segments = vec![ + self.id[0..14].to_string(), // First 56 bits (14 hex chars) + self.id[14..28].to_string(), // Second 56 bits + self.id[28..42].to_string(), // Third 56 bits + self.id[42..56].to_string(), // Fourth 56 bits + self.id[56..64].to_string(), // Remaining 32 bits (8 hex chars, fits in 56 bits) + ]; + + segments.iter() + .map(|seg| F::from_canonical_u64(u64::from_str_radix(seg, 16).unwrap())).collect::>() + } } diff --git a/crates/zk-por-core/src/merkle_sum_prover/circuits/account_circuit.rs b/crates/zk-por-core/src/merkle_sum_prover/circuits/account_circuit.rs index 929e907..ca053bf 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/circuits/account_circuit.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/circuits/account_circuit.rs @@ -16,6 +16,7 @@ use crate::{ #[derive(Debug, Clone)] /// Targets representing a users account, where their equity and debt are split into individual tokens. pub struct AccountTargets { + pub id: Vec, pub equity: Vec, pub debt: Vec, } @@ -25,10 +26,11 @@ impl AccountTargets { account: &Account, builder: &mut CircuitBuilder, ) -> AccountTargets { + let id = builder.add_virtual_targets(5); // id is 5 targets let equity = builder.add_virtual_targets(account.equity.len()); let debt = builder.add_virtual_targets(account.debt.len()); - AccountTargets { equity, debt } + AccountTargets { id, equity, debt } } pub fn set_account_targets(&self, account_info: &Account, pw: &mut PartialWitness) { @@ -37,12 +39,14 @@ impl AccountTargets { pw.set_target_arr(self.equity.as_slice(), account_info.equity.as_slice()); pw.set_target_arr(self.debt.as_slice(), account_info.debt.as_slice()); + pw.set_target_arr(self.id.as_slice(), &account_info.get_user_id_in_field().as_slice()); } } #[derive(Debug, Clone)] /// Targets representing a users account, where their equity and liabilities are summed into 2 summed values. pub struct AccountSumTargets { + pub id: Vec, pub sum_equity: Target, pub sum_debt: Target, } @@ -62,12 +66,12 @@ impl AccountSumTargets { // Ensure the equity is greater than the debt. This works as long as we constrict our equity to 62 bits. assert_non_negative_unsigned(builder, diff_between_equity_debt); - AccountSumTargets { sum_equity, sum_debt } + AccountSumTargets { id: account.id.clone(), sum_equity, sum_debt } } /// Get account hash targets pub fn get_account_hash_targets(&self, builder: &mut CircuitBuilder) -> HashOutTarget { - let hash_inputs = vec![self.sum_equity, self.sum_debt]; + let hash_inputs = vec![self.id.clone(), vec![self.sum_equity, self.sum_debt]].concat(); let hash = builder.hash_n_to_hash_no_pad::(hash_inputs); hash From c8b5edb3a80e35d294bb72d209ef674e3d4bc2df Mon Sep 17 00:00:00 2001 From: EkamSinghPandher Date: Thu, 1 Aug 2024 19:04:35 +0800 Subject: [PATCH 09/17] chore:fmt --- crates/zk-por-core/src/account.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/crates/zk-por-core/src/account.rs b/crates/zk-por-core/src/account.rs index ff56b18..0aaf1b0 100644 --- a/crates/zk-por-core/src/account.rs +++ b/crates/zk-por-core/src/account.rs @@ -23,13 +23,14 @@ impl Account { let id = self.get_user_id_in_field(); - let hash = PoseidonHash::hash_no_pad(vec![id, vec![sum_equity, sum_debt]].concat().as_slice()); + let hash = + PoseidonHash::hash_no_pad(vec![id, vec![sum_equity, sum_debt]].concat().as_slice()); hash } - /// Gets a user id as a vec of 5 GF elements. - pub fn get_user_id_in_field(&self)-> Vec{ + /// Gets a user id as a vec of 5 GF elements. + pub fn get_user_id_in_field(&self) -> Vec { assert!(self.id.len() == 64); let segments = vec![ self.id[0..14].to_string(), // First 56 bits (14 hex chars) @@ -38,8 +39,10 @@ impl Account { self.id[42..56].to_string(), // Fourth 56 bits self.id[56..64].to_string(), // Remaining 32 bits (8 hex chars, fits in 56 bits) ]; - - segments.iter() - .map(|seg| F::from_canonical_u64(u64::from_str_radix(seg, 16).unwrap())).collect::>() + + segments + .iter() + .map(|seg| F::from_canonical_u64(u64::from_str_radix(seg, 16).unwrap())) + .collect::>() } } From d95ff4eff8a49e0f5692ea438d73eed4a08afa72 Mon Sep 17 00:00:00 2001 From: EkamSinghPandher Date: Fri, 2 Aug 2024 11:12:23 +0800 Subject: [PATCH 10/17] chore:basic-refactoring --- .../circuits/merkle_sum_circuit.rs | 62 ++++++++++--------- .../src/merkle_sum_prover/prover.rs | 9 ++- 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/crates/zk-por-core/src/merkle_sum_prover/circuits/merkle_sum_circuit.rs b/crates/zk-por-core/src/merkle_sum_prover/circuits/merkle_sum_circuit.rs index c09a9bd..658b7ad 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/circuits/merkle_sum_circuit.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/circuits/merkle_sum_circuit.rs @@ -82,42 +82,46 @@ impl MerkleSumTreeTarget { builder.register_public_input(root.sum_debt); builder.register_public_inputs(&root.hash.elements); } -} -/// Builds a merkle sum tree of a given size (based on the number of leaves). It will build the merkle sum tree on top of the leaves vector -/// in order to do the task in place. There is no return value as the input leaves vector is mutated. -pub fn build_merkle_sum_tree( - builder: &mut CircuitBuilder, - leaves: &mut Vec, -) { - let num_leaves = leaves.len(); - - for i in num_leaves..(num_leaves * 2 - 1) { - let left_child_index = 2 * (i - num_leaves); - let right_child_index = 2 * (i - num_leaves) + 1; - let left_child = leaves.get(left_child_index).unwrap(); - let right_child = leaves.get(right_child_index).unwrap(); - leaves.push(MerkleSumNodeTarget::get_child_from_parents(builder, left_child, right_child)); + /// Builds a merkle sum tree of a given size (based on the number of leaves). It will build the merkle sum tree on top of the leaves vector + /// in order to do the task in place. There is no return value as the input leaves vector is mutated. + pub fn build_merkle_sum_tree( + builder: &mut CircuitBuilder, + leaves: &mut Vec, + ) { + let num_leaves = leaves.len(); + + for i in num_leaves..(num_leaves * 2 - 1) { + let left_child_index = 2 * (i - num_leaves); + let right_child_index = 2 * (i - num_leaves) + 1; + let left_child = leaves.get(left_child_index).unwrap(); + let right_child = leaves.get(right_child_index).unwrap(); + leaves.push(MerkleSumNodeTarget::get_child_from_parents( + builder, + left_child, + right_child, + )); + } } -} -/// Given a list of account targets, build the corresponding merkle sum tree. -pub fn build_merkle_sum_tree_from_account_targets( - builder: &mut CircuitBuilder, - accounts: &mut Vec, -) -> MerkleSumTreeTarget { - let mut leaves: Vec = accounts - .iter() - .map(|x| MerkleSumNodeTarget::get_node_from_account_targets(builder, x)) - .collect(); + /// Given a list of account targets, build the corresponding merkle sum tree. + pub fn build_new_from_account_targets( + builder: &mut CircuitBuilder, + accounts: &mut Vec, + ) -> MerkleSumTreeTarget { + let mut leaves: Vec = accounts + .iter() + .map(|x| MerkleSumNodeTarget::get_node_from_account_targets(builder, x)) + .collect(); - build_merkle_sum_tree(builder, &mut leaves); + MerkleSumTreeTarget::build_merkle_sum_tree(builder, &mut leaves); - let tree = MerkleSumTreeTarget { sum_tree: leaves }; + let tree = MerkleSumTreeTarget { sum_tree: leaves }; - tree.register_public_inputs(builder); + tree.register_public_inputs(builder); - return tree; + return tree; + } } #[cfg(test)] diff --git a/crates/zk-por-core/src/merkle_sum_prover/prover.rs b/crates/zk-por-core/src/merkle_sum_prover/prover.rs index 72e3755..a768648 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/prover.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/prover.rs @@ -1,10 +1,7 @@ use crate::{ account::Account, circuit_config::STANDARD_CONFIG, - merkle_sum_prover::circuits::{ - account_circuit::{AccountSumTargets, AccountTargets}, - merkle_sum_circuit::build_merkle_sum_tree_from_account_targets, - }, + merkle_sum_prover::circuits::account_circuit::{AccountSumTargets, AccountTargets}, types::{C, D, F}, }; use log::Level; @@ -19,6 +16,8 @@ use plonky2::{ use tracing::error; +use super::circuits::merkle_sum_circuit::MerkleSumTreeTarget; + /// A merkle sum tree prover with a batch id representing its index in the recursive proof tree and a Vec of accounts representing accounts in this batch. #[derive(Clone, Debug)] pub struct MerkleSumTreeProver { @@ -51,7 +50,7 @@ impl MerkleSumTreeProver { // build merkle sum tree let _merkle_tree_targets = - build_merkle_sum_tree_from_account_targets(builder, &mut account_sum_targets); + MerkleSumTreeTarget::build_new_from_account_targets(builder, &mut account_sum_targets); } /// Get the merkle sum tree proof of this batch of accounts. From 36dcefcf1fb218dd7b2037992afc36e617a5fff4 Mon Sep 17 00:00:00 2001 From: EkamSinghPandher Date: Fri, 2 Aug 2024 17:32:27 +0800 Subject: [PATCH 11/17] chore:refactor-into-prover --- crates/zk-por-core/benches/batch_circuit.rs | 102 ++++++++-------- .../zk-por-core/benches/recursive_circuit.rs | 110 +++++++++--------- crates/zk-por-core/src/account.rs | 5 +- .../src/merkle_sum_prover/prover.rs | 51 ++++---- crates/zk-por-core/src/recursive/prover.rs | 74 +++++++++--- .../src/recursive/recursive_circuit.rs | 5 +- crates/zk-por-core/tests/recursive_circuit.rs | 65 +++++------ 7 files changed, 230 insertions(+), 182 deletions(-) diff --git a/crates/zk-por-core/benches/batch_circuit.rs b/crates/zk-por-core/benches/batch_circuit.rs index a4b8d90..71ca282 100644 --- a/crates/zk-por-core/benches/batch_circuit.rs +++ b/crates/zk-por-core/benches/batch_circuit.rs @@ -1,51 +1,51 @@ -#![feature(test)] - -use zk_por_core::{ - account::gen_accounts_with_random_data, - merkle_sum_prover::{ - circuits::merkle_sum_circuit::build_merkle_sum_tree_circuit, prover::MerkleSumTreeProver, - }, -}; - -extern crate test; -use test::Bencher; - -fn bench(b: &mut Bencher, batch_size: usize) { - let num_assets = 4; - let (circuit_data, account_targets) = build_merkle_sum_tree_circuit(batch_size, num_assets); - let accounts = gen_accounts_with_random_data(batch_size, num_assets).0; - b.iter(|| { - let prover = MerkleSumTreeProver { accounts: accounts.clone() }; - _ = prover.prove_with_circuit(&circuit_data, account_targets.clone()); - }); -} - -#[bench] -pub fn bench_batch_size_equal_2(b: &mut Bencher) { - bench(b, 2); -} - -#[bench] -pub fn bench_batch_size_equal_16(b: &mut Bencher) { - bench(b, 16); -} - -#[bench] -pub fn bench_batch_size_equal_256(b: &mut Bencher) { - bench(b, 256); -} - -#[bench] -pub fn bench_batch_size_equal_1024(b: &mut Bencher) { - bench(b, 1024); -} - -#[bench] -pub fn bench_batch_size_equal_2048(b: &mut Bencher) { - bench(b, 2048); -} - -#[bench] -pub fn bench_batch_size_equal_4096(b: &mut Bencher) { - bench(b, 4096); -} +// #![feature(test)] + +// use zk_por_core::{ +// account::gen_accounts_with_random_data, +// merkle_sum_prover::{ +// circuits::merkle_sum_circuit::build_merkle_sum_tree_circuit, prover::MerkleSumTreeProver, +// }, +// }; + +// extern crate test; +// use test::Bencher; + +// fn bench(b: &mut Bencher, batch_size: usize) { +// let num_assets = 4; +// let (circuit_data, account_targets) = build_merkle_sum_tree_circuit(batch_size, num_assets); +// let accounts = gen_accounts_with_random_data(batch_size, num_assets).0; +// b.iter(|| { +// let prover = MerkleSumTreeProver { accounts: accounts.clone() }; +// _ = prover.prove_with_circuit(&circuit_data, account_targets.clone()); +// }); +// } + +// #[bench] +// pub fn bench_batch_size_equal_2(b: &mut Bencher) { +// bench(b, 2); +// } + +// #[bench] +// pub fn bench_batch_size_equal_16(b: &mut Bencher) { +// bench(b, 16); +// } + +// #[bench] +// pub fn bench_batch_size_equal_256(b: &mut Bencher) { +// bench(b, 256); +// } + +// #[bench] +// pub fn bench_batch_size_equal_1024(b: &mut Bencher) { +// bench(b, 1024); +// } + +// #[bench] +// pub fn bench_batch_size_equal_2048(b: &mut Bencher) { +// bench(b, 2048); +// } + +// #[bench] +// pub fn bench_batch_size_equal_4096(b: &mut Bencher) { +// bench(b, 4096); +// } diff --git a/crates/zk-por-core/benches/recursive_circuit.rs b/crates/zk-por-core/benches/recursive_circuit.rs index 730f579..e8dfc7b 100644 --- a/crates/zk-por-core/benches/recursive_circuit.rs +++ b/crates/zk-por-core/benches/recursive_circuit.rs @@ -1,67 +1,67 @@ -#![feature(test)] +// #![feature(test)] -use zk_por_core::merkle_sum_prover::{ - circuits::merkle_sum_circuit::build_merkle_sum_tree_circuit, prover::MerkleSumTreeProver, -}; +// use zk_por_core::merkle_sum_prover::{ +// circuits::merkle_sum_circuit::build_merkle_sum_tree_circuit, prover::MerkleSumTreeProver, +// }; -use zk_por_core::{ - account::gen_accounts_with_random_data, - recursive::{circuit::build_recursive_n_circuit, prove::prove_n_subproofs}, - types::C, -}; +// use zk_por_core::{ +// account::gen_accounts_with_random_data, +// recursive::{recursive_circuit::build_recursive_n_circuit, prover::prove_n_subproofs}, +// types::C, +// }; -extern crate test; -use test::Bencher; +// extern crate test; +// use test::Bencher; -fn bench(b: &mut Bencher, batch_size: usize) { - let asset_num = 4; - let (merkle_sum_circuit, account_targets) = - build_merkle_sum_tree_circuit(batch_size, asset_num); +// fn bench(b: &mut Bencher, batch_size: usize) { +// let asset_num = 4; +// let (merkle_sum_circuit, account_targets) = +// build_merkle_sum_tree_circuit(batch_size, asset_num); - let accounts = gen_accounts_with_random_data(batch_size, asset_num).0; - let prover = MerkleSumTreeProver { accounts }; +// let accounts = gen_accounts_with_random_data(batch_size, asset_num).0; +// let prover = MerkleSumTreeProver { accounts }; - let merkle_sum_proof = prover.prove_with_circuit(&merkle_sum_circuit, account_targets).unwrap(); +// let merkle_sum_proof = prover.prove_with_circuit(&merkle_sum_circuit, account_targets).unwrap(); - let (recursive_circuit, recursive_account_targets) = build_recursive_n_circuit::( - &merkle_sum_circuit.common, - &merkle_sum_circuit.verifier_only, - ); - let mut subproofs = Vec::new(); - (0..SUBPROOF_NUM).for_each(|_| { - subproofs.push(merkle_sum_proof.clone()); - }); +// let (recursive_circuit, recursive_account_targets) = build_recursive_n_circuit::( +// &merkle_sum_circuit.common, +// &merkle_sum_circuit.verifier_only, +// ); +// let mut subproofs = Vec::new(); +// (0..SUBPROOF_NUM).for_each(|_| { +// subproofs.push(merkle_sum_proof.clone()); +// }); - b.iter(|| { - _ = prove_n_subproofs( - subproofs.clone(), - &merkle_sum_circuit.verifier_only, - &recursive_circuit, - recursive_account_targets.clone(), - ); - }); -} -#[bench] -pub fn bench_subproof_num_4_batch_size_1024(b: &mut Bencher) { - bench::<4>(b, 1024); -} +// b.iter(|| { +// _ = prove_n_subproofs( +// subproofs.clone(), +// &merkle_sum_circuit.verifier_only, +// &recursive_circuit, +// recursive_account_targets.clone(), +// ); +// }); +// } +// #[bench] +// pub fn bench_subproof_num_4_batch_size_1024(b: &mut Bencher) { +// bench::<4>(b, 1024); +// } -#[bench] -pub fn bench_subproof_num_8_batch_size_1024(b: &mut Bencher) { - bench::<8>(b, 1024); -} +// #[bench] +// pub fn bench_subproof_num_8_batch_size_1024(b: &mut Bencher) { +// bench::<8>(b, 1024); +// } -#[bench] -pub fn bench_subproof_num_16_batch_size_1024(b: &mut Bencher) { - bench::<16>(b, 1024); -} +// #[bench] +// pub fn bench_subproof_num_16_batch_size_1024(b: &mut Bencher) { +// bench::<16>(b, 1024); +// } -#[bench] -pub fn bench_subproof_num_32_batch_size_1024(b: &mut Bencher) { - bench::<32>(b, 1024); -} +// #[bench] +// pub fn bench_subproof_num_32_batch_size_1024(b: &mut Bencher) { +// bench::<32>(b, 1024); +// } -#[bench] -pub fn bench_subproof_num_64_batch_size_1024(b: &mut Bencher) { - bench::<64>(b, 1024); -} +// #[bench] +// pub fn bench_subproof_num_64_batch_size_1024(b: &mut Bencher) { +// bench::<64>(b, 1024); +// } diff --git a/crates/zk-por-core/src/account.rs b/crates/zk-por-core/src/account.rs index 467f8fc..ae526a3 100644 --- a/crates/zk-por-core/src/account.rs +++ b/crates/zk-por-core/src/account.rs @@ -61,7 +61,10 @@ pub fn gen_accounts_with_random_data(num_accounts: usize, num_assets: usize) -> equities.push(F::from_canonical_u32(equity)); debts.push(F::from_canonical_u32(debt)); } - let account_id = rng.gen_range(0..i32::MAX).to_string(); + + let mut bytes = [0u8; 32]; // 32 bytes * 2 hex chars per byte = 64 hex chars + rng.fill(&mut bytes); + let account_id = bytes.iter().map(|byte| format!("{:02x}", byte)).collect::(); accounts.push(Account { id: account_id, equity: equities, debt: debts }); } accounts diff --git a/crates/zk-por-core/src/merkle_sum_prover/prover.rs b/crates/zk-por-core/src/merkle_sum_prover/prover.rs index 837193c..f8d49d6 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/prover.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/prover.rs @@ -1,7 +1,6 @@ use crate::{ account::Account, circuit_config::STANDARD_CONFIG, - error::ProofError, merkle_sum_prover::circuits::account_circuit::{AccountSumTargets, AccountTargets}, types::{C, D, F}, }; @@ -92,32 +91,42 @@ impl MerkleSumTreeProver { } } - pub fn prove_with_circuit( - &self, - circuit_data: &CircuitData, - account_targets: Vec, - ) -> Result, ProofError> { - if account_targets.len() != self.accounts.len() { - return Err(ProofError::InvalidParameter( - "Account targets length does not match accounts length".to_string(), - )); - } + /// Get the merkle sum tree proof of this batch of accounts. + pub fn get_proof_with_cd(&self) -> (ProofWithPublicInputs, CircuitData) { + let mut builder = CircuitBuilder::::new(STANDARD_CONFIG); + let mut pw = PartialWitness::::new(); - let mut pw = PartialWitness::new(); + self.build_and_set_merkle_tree_targets(&mut builder, &mut pw); - let CircuitData { prover_only, common, verifier_only: _ } = circuit_data; + builder.print_gate_counts(0); - for i in 0..self.accounts.len() { - account_targets[i].set_account_targets(self.accounts.get(i).unwrap(), &mut pw); - } + let mut timing = TimingTree::new("prove", Level::Debug); + let data = builder.build::(); + + let CircuitData { prover_only, common, verifier_only: _ } = &data; - let mut timing = TimingTree::new("prove_merkle_sum_tree", Level::Debug); - let proof = - prove(&prover_only, &common, pw, &mut timing).map_err(|_| ProofError::InvalidProof)?; + println!("Started Proving"); - circuit_data.verify(proof.clone()).unwrap(); + let proof_res = prove(&prover_only, &common, pw.clone(), &mut timing); - Ok(proof) + match proof_res { + Ok(proof) => { + println!("Finished Proving"); + + let proof_verification_res = data.verify(proof.clone()); + match proof_verification_res { + Ok(_) => (proof, data), + Err(e) => { + error!("Proof verification failed: {:?}", e); + panic!("Proof verification failed!"); + } + } + } + Err(e) => { + error!("Proof generation failed: {:?}", e); + panic!("Proof generation failed!"); + } + } } } diff --git a/crates/zk-por-core/src/recursive/prover.rs b/crates/zk-por-core/src/recursive/prover.rs index 8f2b74a..cc79de8 100644 --- a/crates/zk-por-core/src/recursive/prover.rs +++ b/crates/zk-por-core/src/recursive/prover.rs @@ -1,3 +1,4 @@ +use log::Level; use plonky2::{ iop::witness::{PartialWitness, WitnessWrite}, plonk::{ @@ -9,37 +10,84 @@ use plonky2::{ }, util::timing::TimingTree, }; +use tracing::error; -use crate::types::{D, F}; +use crate::{ + circuit_config::STANDARD_CONFIG, + types::{D, F}, +}; use anyhow::Result; use super::recursive_circuit::{build_new_recursive_n_circuit_targets, RecursiveTargets}; -pub struct RecursiveProver< - C: GenericConfig, - const N: usize, -> { - pub batch_id: usize, +pub struct RecursiveProver, const N: usize> { + // pub batch_id: usize, pub sub_proofs: [ProofWithPublicInputs; N], pub merkle_sum_circuit: CircuitData, } -impl, const N: usize> - RecursiveProver -{ +impl, const N: usize> RecursiveProver { pub fn build_and_set_recursive_targets( &self, builder: &mut CircuitBuilder, pw: &mut PartialWitness, - ) where >::Hasher: AlgebraicHasher{ - + ) where + >::Hasher: AlgebraicHasher, + { let recursive_targets: RecursiveTargets = build_new_recursive_n_circuit_targets( &self.merkle_sum_circuit.common, &self.merkle_sum_circuit.verifier_only, - builder + builder, ); - recursive_targets.set_targets(pw, self.sub_proofs.to_vec(), &self.merkle_sum_circuit.verifier_only) + recursive_targets.set_targets( + pw, + self.sub_proofs.to_vec(), + &self.merkle_sum_circuit.verifier_only, + ) + } + + pub fn get_proof(&self) -> ProofWithPublicInputs + where + >::Hasher: AlgebraicHasher, + { + let mut builder = CircuitBuilder::::new(STANDARD_CONFIG); + let mut pw = PartialWitness::::new(); + + self.build_and_set_recursive_targets(&mut builder, &mut pw); + + builder.print_gate_counts(0); + + let mut timing = TimingTree::new("prove", Level::Debug); + let data = builder.build::(); + + let CircuitData { prover_only, common, verifier_only: _ } = &data; + + log::debug!("before prove"); + let start = std::time::Instant::now(); + + let proof_res = prove(&prover_only, &common, pw.clone(), &mut timing); + + log::debug!("time for {:?} proofs, {:?}", N, start.elapsed().as_millis()); + + match proof_res { + Ok(proof) => { + println!("Finished Proving"); + + let proof_verification_res = data.verify(proof.clone()); + match proof_verification_res { + Ok(_) => proof, + Err(e) => { + error!("Proof verification failed: {:?}", e); + panic!("Proof verification failed!"); + } + } + } + Err(e) => { + error!("Proof generation failed: {:?}", e); + panic!("Proof generation failed!"); + } + } } } diff --git a/crates/zk-por-core/src/recursive/recursive_circuit.rs b/crates/zk-por-core/src/recursive/recursive_circuit.rs index bc869da..7ced5e0 100644 --- a/crates/zk-por-core/src/recursive/recursive_circuit.rs +++ b/crates/zk-por-core/src/recursive/recursive_circuit.rs @@ -69,10 +69,7 @@ impl RecursiveTargets { /// build recursive circuit that proves N subproofs and geneate parent merkle sum node targets /// This circuit hardcode the constraint that the verifier_circuit_target.circuit_digest must be equal to that inner_verifier_circuit_data.circuit_digest; -pub fn build_new_recursive_n_circuit_targets< - C: GenericConfig, - const N: usize, ->( +pub fn build_new_recursive_n_circuit_targets, const N: usize>( inner_common_circuit_data: &CommonCircuitData, inner_verifier_circuit_data: &VerifierOnlyCircuitData, builder: &mut CircuitBuilder, diff --git a/crates/zk-por-core/tests/recursive_circuit.rs b/crates/zk-por-core/tests/recursive_circuit.rs index 7064874..d731e77 100644 --- a/crates/zk-por-core/tests/recursive_circuit.rs +++ b/crates/zk-por-core/tests/recursive_circuit.rs @@ -1,4 +1,6 @@ -use zk_por_core::recursive::{prover::prove_n_subproofs}; +use plonky2::plonk::proof::ProofWithPublicInputs; +use zk_por_core::recursive::prover::RecursiveProver; +use zk_por_core::types::D; use zk_por_core::merkle_sum_prover::prover::MerkleSumTreeProver; @@ -14,51 +16,40 @@ fn test() { let asset_num = 2; const RECURSIVE_FACTOR: usize = 8; - let start = std::time::Instant::now(); - let (merkle_sum_circuit, account_targets) = - build_merkle_sum_tree_circuit(batch_size, asset_num); - println!("build merkle sum tree circuit in : {:?}", start.elapsed()); + let accounts = gen_accounts_with_random_data(batch_size, asset_num); - let (accounts, equity_sum, debt_sum) = gen_accounts_with_random_data(batch_size, asset_num); - let prover = MerkleSumTreeProver { accounts }; + let equity_sum = accounts.iter().fold(F::ZERO, |acc, x|{ + acc + x.equity.iter().fold(F::ZERO, |acc_2, y|{ + acc_2 + *y + }) + }); + + let debt_sum = accounts.iter().fold(F::ZERO, |acc, x|{ + acc + x.debt.iter().fold(F::ZERO, |acc_2, y|{ + acc_2 + *y + }) + }); - let start = std::time::Instant::now(); - let merkle_sum_proof = prover.prove_with_circuit(&merkle_sum_circuit, account_targets).unwrap(); - println!("prove merkle sum tree in : {:?}", start.elapsed()); + let prover = MerkleSumTreeProver { accounts }; - let start = std::time::Instant::now(); - let (recursive_circuit, recursive_account_targets) = - build_recursive_n_circuit::( - &merkle_sum_circuit.common, - &merkle_sum_circuit.verifier_only, - ); - println!("build recursive circuit in : {:?}", start.elapsed()); + let (merkle_sum_proof, cd) = prover.get_proof_with_cd(); + + let sub_proofs:[ProofWithPublicInputs; RECURSIVE_FACTOR] = std::array::from_fn(|_| merkle_sum_proof.clone()); - let mut subproofs = Vec::new(); - (0..RECURSIVE_FACTOR).for_each(|_| { - subproofs.push(merkle_sum_proof.clone()); - }); - let start = std::time::Instant::now(); - let recursive_proof_result = prove_n_subproofs( - subproofs, - &merkle_sum_circuit.verifier_only, - &recursive_circuit, - recursive_account_targets, - ); - println!("prove recursive subproofs in : {:?}", start.elapsed()); + let recursive_prover = RecursiveProver{ + sub_proofs, + merkle_sum_circuit: cd + }; - assert!(recursive_proof_result.is_ok()); - let recursive_proof = recursive_proof_result.unwrap(); + let recursive_proof_result = recursive_prover.get_proof(); // print public inputs in recursive proof assert_eq!( - F::from_canonical_u32(equity_sum * (RECURSIVE_FACTOR as u32)), - recursive_proof.public_inputs[0] + equity_sum * F::from_canonical_u32(RECURSIVE_FACTOR as u32), + recursive_proof_result.public_inputs[0] ); assert_eq!( - F::from_canonical_u32(debt_sum * (RECURSIVE_FACTOR as u32)), - recursive_proof.public_inputs[1] + debt_sum * F::from_canonical_u32(RECURSIVE_FACTOR as u32), + recursive_proof_result.public_inputs[1] ); - - assert!(recursive_circuit.verify(recursive_proof).is_ok()); } From 79c925bc378b8e7b52520e2e2996ae01ffdb7723 Mon Sep 17 00:00:00 2001 From: EkamSinghPandher Date: Fri, 2 Aug 2024 17:43:25 +0800 Subject: [PATCH 12/17] refactor:refactor-and-wrap-recursive-in-prover --- crates/zk-por-core/src/lib.rs | 2 +- .../src/merkle_sum_prover/circuits/account_circuit.rs | 4 +++- crates/zk-por-core/src/{recursive => recursive_prover}/mod.rs | 0 .../zk-por-core/src/{recursive => recursive_prover}/prover.rs | 0 .../src/{recursive => recursive_prover}/recursive_circuit.rs | 0 crates/zk-por-core/tests/recursive_circuit.rs | 2 +- 6 files changed, 5 insertions(+), 3 deletions(-) rename crates/zk-por-core/src/{recursive => recursive_prover}/mod.rs (100%) rename crates/zk-por-core/src/{recursive => recursive_prover}/prover.rs (100%) rename crates/zk-por-core/src/{recursive => recursive_prover}/recursive_circuit.rs (100%) diff --git a/crates/zk-por-core/src/lib.rs b/crates/zk-por-core/src/lib.rs index b87a68f..2f0bc1c 100644 --- a/crates/zk-por-core/src/lib.rs +++ b/crates/zk-por-core/src/lib.rs @@ -7,5 +7,5 @@ pub mod error; pub mod merkle_sum_prover; pub mod merkle_sum_tree; pub mod parser; -pub mod recursive; +pub mod recursive_prover; pub mod types; diff --git a/crates/zk-por-core/src/merkle_sum_prover/circuits/account_circuit.rs b/crates/zk-por-core/src/merkle_sum_prover/circuits/account_circuit.rs index 9f713af..96e5f34 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/circuits/account_circuit.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/circuits/account_circuit.rs @@ -26,7 +26,7 @@ impl AccountTargets { account: &Account, builder: &mut CircuitBuilder, ) -> AccountTargets { - let id = [builder.add_virtual_target(); 5]; + let id: [Target; 5] = std::array::from_fn(|_| builder.add_virtual_target()); let equity = builder.add_virtual_targets(account.equity.len()); let debt = builder.add_virtual_targets(account.debt.len()); @@ -37,6 +37,8 @@ impl AccountTargets { assert_eq!(self.equity.len(), account_info.equity.len()); assert_eq!(self.debt.len(), account_info.debt.len()); + println!("{:?}", account_info.get_user_id_in_field()); + pw.set_target_arr(self.equity.as_slice(), account_info.equity.as_slice()); pw.set_target_arr(self.debt.as_slice(), account_info.debt.as_slice()); pw.set_target_arr(self.id.as_slice(), &account_info.get_user_id_in_field().as_slice()); diff --git a/crates/zk-por-core/src/recursive/mod.rs b/crates/zk-por-core/src/recursive_prover/mod.rs similarity index 100% rename from crates/zk-por-core/src/recursive/mod.rs rename to crates/zk-por-core/src/recursive_prover/mod.rs diff --git a/crates/zk-por-core/src/recursive/prover.rs b/crates/zk-por-core/src/recursive_prover/prover.rs similarity index 100% rename from crates/zk-por-core/src/recursive/prover.rs rename to crates/zk-por-core/src/recursive_prover/prover.rs diff --git a/crates/zk-por-core/src/recursive/recursive_circuit.rs b/crates/zk-por-core/src/recursive_prover/recursive_circuit.rs similarity index 100% rename from crates/zk-por-core/src/recursive/recursive_circuit.rs rename to crates/zk-por-core/src/recursive_prover/recursive_circuit.rs diff --git a/crates/zk-por-core/tests/recursive_circuit.rs b/crates/zk-por-core/tests/recursive_circuit.rs index d731e77..31acd5c 100644 --- a/crates/zk-por-core/tests/recursive_circuit.rs +++ b/crates/zk-por-core/tests/recursive_circuit.rs @@ -1,5 +1,5 @@ use plonky2::plonk::proof::ProofWithPublicInputs; -use zk_por_core::recursive::prover::RecursiveProver; +use zk_por_core::recursive_prover::prover::RecursiveProver; use zk_por_core::types::D; use zk_por_core::merkle_sum_prover::prover::MerkleSumTreeProver; From 749a6e98a391dc44f183f72ae8858070d56b0852 Mon Sep 17 00:00:00 2001 From: EkamSinghPandher Date: Fri, 2 Aug 2024 17:46:51 +0800 Subject: [PATCH 13/17] chore:fmt --- .../src/merkle_sum_prover/prover.rs | 4 +-- crates/zk-por-core/tests/recursive_circuit.rs | 29 +++++++------------ 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/crates/zk-por-core/src/merkle_sum_prover/prover.rs b/crates/zk-por-core/src/merkle_sum_prover/prover.rs index f8d49d6..faee336 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/prover.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/prover.rs @@ -91,8 +91,8 @@ impl MerkleSumTreeProver { } } - /// Get the merkle sum tree proof of this batch of accounts. - pub fn get_proof_with_cd(&self) -> (ProofWithPublicInputs, CircuitData) { + /// Get the merkle sum tree proof of this batch of accounts. + pub fn get_proof_with_cd(&self) -> (ProofWithPublicInputs, CircuitData) { let mut builder = CircuitBuilder::::new(STANDARD_CONFIG); let mut pw = PartialWitness::::new(); diff --git a/crates/zk-por-core/tests/recursive_circuit.rs b/crates/zk-por-core/tests/recursive_circuit.rs index 31acd5c..073a7f8 100644 --- a/crates/zk-por-core/tests/recursive_circuit.rs +++ b/crates/zk-por-core/tests/recursive_circuit.rs @@ -1,6 +1,5 @@ use plonky2::plonk::proof::ProofWithPublicInputs; -use zk_por_core::recursive_prover::prover::RecursiveProver; -use zk_por_core::types::D; +use zk_por_core::{recursive_prover::prover::RecursiveProver, types::D}; use zk_por_core::merkle_sum_prover::prover::MerkleSumTreeProver; @@ -18,28 +17,22 @@ fn test() { let accounts = gen_accounts_with_random_data(batch_size, asset_num); - let equity_sum = accounts.iter().fold(F::ZERO, |acc, x|{ - acc + x.equity.iter().fold(F::ZERO, |acc_2, y|{ - acc_2 + *y - }) - }); + let equity_sum = accounts + .iter() + .fold(F::ZERO, |acc, x| acc + x.equity.iter().fold(F::ZERO, |acc_2, y| acc_2 + *y)); - let debt_sum = accounts.iter().fold(F::ZERO, |acc, x|{ - acc + x.debt.iter().fold(F::ZERO, |acc_2, y|{ - acc_2 + *y - }) - }); + let debt_sum = accounts + .iter() + .fold(F::ZERO, |acc, x| acc + x.debt.iter().fold(F::ZERO, |acc_2, y| acc_2 + *y)); let prover = MerkleSumTreeProver { accounts }; let (merkle_sum_proof, cd) = prover.get_proof_with_cd(); - - let sub_proofs:[ProofWithPublicInputs; RECURSIVE_FACTOR] = std::array::from_fn(|_| merkle_sum_proof.clone()); - let recursive_prover = RecursiveProver{ - sub_proofs, - merkle_sum_circuit: cd - }; + let sub_proofs: [ProofWithPublicInputs; RECURSIVE_FACTOR] = + std::array::from_fn(|_| merkle_sum_proof.clone()); + + let recursive_prover = RecursiveProver { sub_proofs, merkle_sum_circuit: cd }; let recursive_proof_result = recursive_prover.get_proof(); From 6e8eb0fd432e0d3ddc37d26f8cd79fcc8efa8eb0 Mon Sep 17 00:00:00 2001 From: EkamSinghPandher Date: Fri, 2 Aug 2024 18:10:45 +0800 Subject: [PATCH 14/17] chore:update bench --- crates/zk-por-core/benches/batch_circuit.rs | 96 +++++++------- .../zk-por-core/benches/recursive_circuit.rs | 121 ++++++++---------- crates/zk-por-core/src/bin/batch_proof.rs | 57 --------- crates/zk-por-core/src/bin/bench_batch.rs | 20 --- crates/zk-por-core/src/bin/bench_recursion.rs | 44 ------- crates/zk-por-core/src/core/mod.rs | 1 - crates/zk-por-core/src/core/parser.rs | 96 -------------- crates/zk-por-core/src/lib.rs | 1 - .../src/merkle_sum_prover/prover.rs | 22 ++++ 9 files changed, 121 insertions(+), 337 deletions(-) delete mode 100644 crates/zk-por-core/src/bin/batch_proof.rs delete mode 100644 crates/zk-por-core/src/bin/bench_batch.rs delete mode 100644 crates/zk-por-core/src/bin/bench_recursion.rs delete mode 100644 crates/zk-por-core/src/core/mod.rs delete mode 100644 crates/zk-por-core/src/core/parser.rs diff --git a/crates/zk-por-core/benches/batch_circuit.rs b/crates/zk-por-core/benches/batch_circuit.rs index 71ca282..adb5f50 100644 --- a/crates/zk-por-core/benches/batch_circuit.rs +++ b/crates/zk-por-core/benches/batch_circuit.rs @@ -1,51 +1,45 @@ -// #![feature(test)] - -// use zk_por_core::{ -// account::gen_accounts_with_random_data, -// merkle_sum_prover::{ -// circuits::merkle_sum_circuit::build_merkle_sum_tree_circuit, prover::MerkleSumTreeProver, -// }, -// }; - -// extern crate test; -// use test::Bencher; - -// fn bench(b: &mut Bencher, batch_size: usize) { -// let num_assets = 4; -// let (circuit_data, account_targets) = build_merkle_sum_tree_circuit(batch_size, num_assets); -// let accounts = gen_accounts_with_random_data(batch_size, num_assets).0; -// b.iter(|| { -// let prover = MerkleSumTreeProver { accounts: accounts.clone() }; -// _ = prover.prove_with_circuit(&circuit_data, account_targets.clone()); -// }); -// } - -// #[bench] -// pub fn bench_batch_size_equal_2(b: &mut Bencher) { -// bench(b, 2); -// } - -// #[bench] -// pub fn bench_batch_size_equal_16(b: &mut Bencher) { -// bench(b, 16); -// } - -// #[bench] -// pub fn bench_batch_size_equal_256(b: &mut Bencher) { -// bench(b, 256); -// } - -// #[bench] -// pub fn bench_batch_size_equal_1024(b: &mut Bencher) { -// bench(b, 1024); -// } - -// #[bench] -// pub fn bench_batch_size_equal_2048(b: &mut Bencher) { -// bench(b, 2048); -// } - -// #[bench] -// pub fn bench_batch_size_equal_4096(b: &mut Bencher) { -// bench(b, 4096); -// } +#![feature(test)] + +use zk_por_core::{ + account::gen_accounts_with_random_data, merkle_sum_prover::prover::MerkleSumTreeProver, +}; + +extern crate test; +use test::Bencher; + +fn bench(b: &mut Bencher, batch_size: usize) { + let num_assets = 50; + let accounts = gen_accounts_with_random_data(batch_size, num_assets); + let prover = MerkleSumTreeProver { accounts }; + b.iter(|| _ = prover.get_proof()); +} + +#[bench] +pub fn bench_batch_size_equal_2(b: &mut Bencher) { + bench(b, 2); +} + +#[bench] +pub fn bench_batch_size_equal_16(b: &mut Bencher) { + bench(b, 16); +} + +#[bench] +pub fn bench_batch_size_equal_256(b: &mut Bencher) { + bench(b, 256); +} + +#[bench] +pub fn bench_batch_size_equal_1024(b: &mut Bencher) { + bench(b, 1024); +} + +#[bench] +pub fn bench_batch_size_equal_2048(b: &mut Bencher) { + bench(b, 2048); +} + +#[bench] +pub fn bench_batch_size_equal_4096(b: &mut Bencher) { + bench(b, 4096); +} diff --git a/crates/zk-por-core/benches/recursive_circuit.rs b/crates/zk-por-core/benches/recursive_circuit.rs index e8dfc7b..dbcafba 100644 --- a/crates/zk-por-core/benches/recursive_circuit.rs +++ b/crates/zk-por-core/benches/recursive_circuit.rs @@ -1,67 +1,54 @@ -// #![feature(test)] - -// use zk_por_core::merkle_sum_prover::{ -// circuits::merkle_sum_circuit::build_merkle_sum_tree_circuit, prover::MerkleSumTreeProver, -// }; - -// use zk_por_core::{ -// account::gen_accounts_with_random_data, -// recursive::{recursive_circuit::build_recursive_n_circuit, prover::prove_n_subproofs}, -// types::C, -// }; - -// extern crate test; -// use test::Bencher; - -// fn bench(b: &mut Bencher, batch_size: usize) { -// let asset_num = 4; -// let (merkle_sum_circuit, account_targets) = -// build_merkle_sum_tree_circuit(batch_size, asset_num); - -// let accounts = gen_accounts_with_random_data(batch_size, asset_num).0; -// let prover = MerkleSumTreeProver { accounts }; - -// let merkle_sum_proof = prover.prove_with_circuit(&merkle_sum_circuit, account_targets).unwrap(); - -// let (recursive_circuit, recursive_account_targets) = build_recursive_n_circuit::( -// &merkle_sum_circuit.common, -// &merkle_sum_circuit.verifier_only, -// ); -// let mut subproofs = Vec::new(); -// (0..SUBPROOF_NUM).for_each(|_| { -// subproofs.push(merkle_sum_proof.clone()); -// }); - -// b.iter(|| { -// _ = prove_n_subproofs( -// subproofs.clone(), -// &merkle_sum_circuit.verifier_only, -// &recursive_circuit, -// recursive_account_targets.clone(), -// ); -// }); -// } -// #[bench] -// pub fn bench_subproof_num_4_batch_size_1024(b: &mut Bencher) { -// bench::<4>(b, 1024); -// } - -// #[bench] -// pub fn bench_subproof_num_8_batch_size_1024(b: &mut Bencher) { -// bench::<8>(b, 1024); -// } - -// #[bench] -// pub fn bench_subproof_num_16_batch_size_1024(b: &mut Bencher) { -// bench::<16>(b, 1024); -// } - -// #[bench] -// pub fn bench_subproof_num_32_batch_size_1024(b: &mut Bencher) { -// bench::<32>(b, 1024); -// } - -// #[bench] -// pub fn bench_subproof_num_64_batch_size_1024(b: &mut Bencher) { -// bench::<64>(b, 1024); -// } +#![feature(test)] + +use plonky2::plonk::proof::ProofWithPublicInputs; +use zk_por_core::merkle_sum_prover::prover::MerkleSumTreeProver; + +use zk_por_core::{ + account::gen_accounts_with_random_data, + recursive_prover::prover::RecursiveProver, + types::{C, D, F}, +}; + +extern crate test; +use test::Bencher; + +fn bench(b: &mut Bencher, batch_size: usize) { + let asset_num = 50; + let accounts = gen_accounts_with_random_data(batch_size, asset_num); + let prover = MerkleSumTreeProver { accounts }; + + let (merkle_sum_proof, merkle_sum_cd) = prover.get_proof_with_cd(); + + let sub_proofs: [ProofWithPublicInputs; SUBPROOF_NUM] = + std::array::from_fn(|_| merkle_sum_proof.clone()); + + let recursive_prover = RecursiveProver { sub_proofs, merkle_sum_circuit: merkle_sum_cd }; + + b.iter(|| { + recursive_prover.get_proof(); + }); +} +#[bench] +pub fn bench_subproof_num_4_batch_size_1024(b: &mut Bencher) { + bench::<4>(b, 1024); +} + +#[bench] +pub fn bench_subproof_num_8_batch_size_1024(b: &mut Bencher) { + bench::<8>(b, 1024); +} + +#[bench] +pub fn bench_subproof_num_16_batch_size_1024(b: &mut Bencher) { + bench::<16>(b, 1024); +} + +#[bench] +pub fn bench_subproof_num_32_batch_size_1024(b: &mut Bencher) { + bench::<32>(b, 1024); +} + +#[bench] +pub fn bench_subproof_num_64_batch_size_1024(b: &mut Bencher) { + bench::<64>(b, 1024); +} diff --git a/crates/zk-por-core/src/bin/batch_proof.rs b/crates/zk-por-core/src/bin/batch_proof.rs deleted file mode 100644 index f60fbbd..0000000 --- a/crates/zk-por-core/src/bin/batch_proof.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::str::FromStr; - -use plonky2::{ - iop::witness::PartialWitness, - plonk::{circuit_builder::CircuitBuilder, circuit_data::CircuitData, prover::prove}, - util::timing::TimingTree, -}; -use plonky2_field::goldilocks_field::GoldilocksField; - -use tracing::Level; -use zk_por_core::{ - circuit_config::STANDARD_CONFIG, - config::ProverConfig, - merkle_sum_prover::prover::MerkleSumTreeProver, - parser::read_json_into_accounts_vec, - types::{C, D, F}, -}; -use zk_por_tracing::{init_tracing, TraceConfig}; - -fn main() { - let cfg = ProverConfig::try_new().unwrap(); - - let trace_cfg = TraceConfig { - prefix: cfg.log.file_name_prefix, - dir: cfg.log.dir, - level: Level::from_str(&cfg.log.level).unwrap(), - console: cfg.log.console, - flame: cfg.log.flame, - }; - let guard = init_tracing(trace_cfg); - - let mut builder = CircuitBuilder::::new(STANDARD_CONFIG); - let mut pw = PartialWitness::::new(); - - let path = "../../test-data/batch0.json"; - let accounts = read_json_into_accounts_vec(path); - let prover = MerkleSumTreeProver { - // batch_id: 0, - accounts, - }; - - prover.build_and_set_merkle_tree_targets(&mut builder, &mut pw); - - let data = builder.build::(); - - let CircuitData { prover_only, common, verifier_only: _ } = &data; - - println!("Started Proving"); - let mut timing = TimingTree::new("prove", log::Level::Debug); - let proof_res = prove(&prover_only, &common, pw.clone(), &mut timing); - let proof = proof_res.expect("Proof failed"); - - println!("Verifying Proof"); - // Verify proof - let _proof_verification_res = data.verify(proof.clone()).unwrap(); - drop(guard); -} diff --git a/crates/zk-por-core/src/bin/bench_batch.rs b/crates/zk-por-core/src/bin/bench_batch.rs deleted file mode 100644 index e39cd67..0000000 --- a/crates/zk-por-core/src/bin/bench_batch.rs +++ /dev/null @@ -1,20 +0,0 @@ -use zk_por_core::{ - account::gen_accounts_with_random_data, - merkle_sum_prover::{ - circuits::merkle_sum_circuit::build_merkle_sum_tree_circuit, prover::MerkleSumTreeProver, - }, -}; - -fn main() { - let num_accounts = 1024; // configure this for bench. - - let num_assets = 5; - let (circuit_data, account_targets) = build_merkle_sum_tree_circuit(num_accounts, num_assets); - - let (accounts, _, _) = gen_accounts_with_random_data(num_accounts, num_assets); - let start = std::time::Instant::now(); - let prover = MerkleSumTreeProver { accounts }; - _ = prover.prove_with_circuit(&circuit_data, account_targets); - - println!("prove {} accounts in batch in : {:?}", num_accounts, start.elapsed()); -} diff --git a/crates/zk-por-core/src/bin/bench_recursion.rs b/crates/zk-por-core/src/bin/bench_recursion.rs deleted file mode 100644 index 842f89d..0000000 --- a/crates/zk-por-core/src/bin/bench_recursion.rs +++ /dev/null @@ -1,44 +0,0 @@ -use zk_por_core::merkle_sum_prover::{ - circuits::merkle_sum_circuit::build_merkle_sum_tree_circuit, prover::MerkleSumTreeProver, -}; - -use zk_por_core::{ - account::gen_accounts_with_random_data, - recursive::{circuit::build_recursive_n_circuit, prove::prove_n_subproofs}, - types::C, -}; - -fn main() { - const SUBPROOF_NUM: usize = 128; // configure this for bench. - - let batch_size = 1024; - let asset_num = 4; - let (merkle_sum_circuit, account_targets) = - build_merkle_sum_tree_circuit(batch_size, asset_num); - println!("build merkle sum tree circuit"); - - let accounts = gen_accounts_with_random_data(batch_size, asset_num).0; - let prover = MerkleSumTreeProver { accounts }; - - let merkle_sum_proof = prover.prove_with_circuit(&merkle_sum_circuit, account_targets).unwrap(); - println!("prove merkle sum tree"); - - let (recursive_circuit, recursive_account_targets) = build_recursive_n_circuit::( - &merkle_sum_circuit.common, - &merkle_sum_circuit.verifier_only, - ); - println!("build recursive circuit"); - - let mut subproofs = Vec::new(); - (0..SUBPROOF_NUM).for_each(|_| { - subproofs.push(merkle_sum_proof.clone()); - }); - let start = std::time::Instant::now(); - _ = prove_n_subproofs( - subproofs.clone(), - &merkle_sum_circuit.verifier_only, - &recursive_circuit, - recursive_account_targets.clone(), - ); - println!("prove recursive {} subproofs in : {:?}", SUBPROOF_NUM, start.elapsed()); -} diff --git a/crates/zk-por-core/src/core/mod.rs b/crates/zk-por-core/src/core/mod.rs deleted file mode 100644 index 67c567f..0000000 --- a/crates/zk-por-core/src/core/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod parser; diff --git a/crates/zk-por-core/src/core/parser.rs b/crates/zk-por-core/src/core/parser.rs deleted file mode 100644 index 49496db..0000000 --- a/crates/zk-por-core/src/core/parser.rs +++ /dev/null @@ -1,96 +0,0 @@ -use std::{collections::BTreeMap, fs::File, io::BufReader}; - -use plonky2_field::types::Field; -use serde_json::Value; - -use crate::types::F; - -use crate::account::Account; - -/// Read a json file and return the vec of associated accounts. -pub fn read_json_into_accounts_vec(path: &str) -> Vec { - let parsed_data = read_json_file_into_map(path); - let accounts_data = parse_exchange_state(&parsed_data); - accounts_data -} - -/// Reads a json file into a json string. -fn read_json_file_into_map(path: &str) -> Vec> { - let file = File::open(path).expect("Cannot read file"); - let reader = BufReader::new(file); - - // Deserialize the binary data to a struct - serde_json::from_reader(reader).expect("Unable to parse Json Data") -} - -/// Parses the exchanges state at some snapshot and returns. -fn parse_exchange_state(parsed_data: &Vec>) -> Vec { - let mut accounts_data: Vec = Vec::new(); - for obj in parsed_data { - let mut account_id = ""; - let mut inner_vec: Vec = Vec::new(); - for (key, value) in obj.iter() { - if key != "id" { - if let Some(number_str) = value.as_str() { - if let Ok(number) = number_str.parse::() { - inner_vec.push(F::from_canonical_u64(number)); - } - } - } else { - account_id = value.as_str().unwrap(); - } - } - accounts_data.push(Account { id: account_id.into(), equity: inner_vec, debt: Vec::new() }); - } - accounts_data -} - -#[cfg(test)] -mod test { - use crate::core::parser::read_json_into_accounts_vec; - - use super::{parse_exchange_state, read_json_file_into_map}; - - #[test] - pub fn test_read_json_file_into_map() { - let path = "../../test-data/batch0.json"; - let maps = read_json_file_into_map(path); - - let id_0 = "320b5ea99e653bc2b593db4130d10a4efd3a0b4cc2e1a6672b678d71dfbd33ad"; - let parsed_id_0 = maps.get(0).unwrap().get("id").unwrap(); - assert_eq!(id_0, parsed_id_0); - - let id_1 = "47db1d296a7c146eab653591583a9a4873c626d8de47ae11393edd153e40f1ed"; - let parsed_id_1 = maps.get(1).unwrap().get("id").unwrap(); - assert_eq!(id_1, parsed_id_1); - } - - #[test] - pub fn test_parse_exchange_state() { - let path = "../../test-data/batch0.json"; - let maps = read_json_file_into_map(path); - let accounts = parse_exchange_state(&maps); - - let id_0 = "320b5ea99e653bc2b593db4130d10a4efd3a0b4cc2e1a6672b678d71dfbd33ad"; - let account_0 = accounts.get(0).unwrap(); - assert_eq!(id_0, account_0.id); - - let id_1 = "47db1d296a7c146eab653591583a9a4873c626d8de47ae11393edd153e40f1ed"; - let account_1 = accounts.get(1).unwrap(); - assert_eq!(id_1, account_1.id); - } - - #[test] - pub fn test_read_json_into_accounts_vec() { - let path = "../../test-data/batch0.json"; - let accounts = read_json_into_accounts_vec(&path); - - let id_0 = "320b5ea99e653bc2b593db4130d10a4efd3a0b4cc2e1a6672b678d71dfbd33ad"; - let account_0 = accounts.get(0).unwrap(); - assert_eq!(id_0, account_0.id); - - let id_1 = "47db1d296a7c146eab653591583a9a4873c626d8de47ae11393edd153e40f1ed"; - let account_1 = accounts.get(1).unwrap(); - assert_eq!(id_1, account_1.id); - } -} diff --git a/crates/zk-por-core/src/lib.rs b/crates/zk-por-core/src/lib.rs index 2f0bc1c..5d9d723 100644 --- a/crates/zk-por-core/src/lib.rs +++ b/crates/zk-por-core/src/lib.rs @@ -2,7 +2,6 @@ pub mod account; pub mod circuit_config; pub mod circuit_utils; pub mod config; -pub mod core; pub mod error; pub mod merkle_sum_prover; pub mod merkle_sum_tree; diff --git a/crates/zk-por-core/src/merkle_sum_prover/prover.rs b/crates/zk-por-core/src/merkle_sum_prover/prover.rs index faee336..f88362a 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/prover.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/prover.rs @@ -53,6 +53,28 @@ impl MerkleSumTreeProver { MerkleSumTreeTarget::build_new_from_account_targets(builder, &mut account_sum_targets); } + pub fn get_prover_cd(&self, builder: &mut CircuitBuilder) -> CircuitData { + let mut account_targets: Vec = Vec::new(); + + for i in 0..self.accounts.len() { + // Build account targets + let account_target = + AccountTargets::new_from_account(self.accounts.get(i).unwrap(), builder); + account_targets.push(account_target); + } + + let mut account_sum_targets: Vec = account_targets + .iter() + .map(|x| AccountSumTargets::from_account_target(x, builder)) + .collect(); + + // build merkle sum tree + let _merkle_tree_targets = + MerkleSumTreeTarget::build_new_from_account_targets(builder, &mut account_sum_targets); + + builder.clone().build::() + } + /// Get the merkle sum tree proof of this batch of accounts. pub fn get_proof(&self) -> ProofWithPublicInputs { let mut builder = CircuitBuilder::::new(STANDARD_CONFIG); From 6a949d99bcd65feb0cf347fb79dc05a85c73de9c Mon Sep 17 00:00:00 2001 From: EkamSinghPandher Date: Mon, 5 Aug 2024 12:43:59 +0800 Subject: [PATCH 15/17] chore:Add-removed-fn --- Cargo.lock | 8 +- Cargo.toml | 4 +- crates/zk-por-core/benches/batch_circuit.rs | 10 +- .../zk-por-core/benches/recursive_circuit.rs | 2 +- .../circuits/account_circuit.rs | 2 - .../src/merkle_sum_prover/prover.rs | 87 ++++++++++--- .../src/recursive_prover/prover.rs | 117 ++++++++++-------- .../src/recursive_prover/recursive_circuit.rs | 27 +--- crates/zk-por-core/tests/recursive_circuit.rs | 2 +- 9 files changed, 152 insertions(+), 107 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8c88cae..616c2db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1233,7 +1233,7 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "plonky2" version = "0.2.0" -source = "git+https://github.com/okx/plonky2#140d97a8081cfae1d08e43199e13084c1acf1dae" +source = "git+https://github.com/okx/plonky2?branch=clone-circuit#e07494fd2b52033fae5a7e0d65411266be34db60" dependencies = [ "ahash 0.8.11", "anyhow", @@ -1259,7 +1259,7 @@ dependencies = [ [[package]] name = "plonky2_field" version = "0.2.0" -source = "git+https://github.com/okx/plonky2#140d97a8081cfae1d08e43199e13084c1acf1dae" +source = "git+https://github.com/okx/plonky2?branch=clone-circuit#e07494fd2b52033fae5a7e0d65411266be34db60" dependencies = [ "anyhow", "itertools 0.11.0", @@ -1278,7 +1278,7 @@ dependencies = [ [[package]] name = "plonky2_maybe_rayon" version = "0.2.0" -source = "git+https://github.com/okx/plonky2#140d97a8081cfae1d08e43199e13084c1acf1dae" +source = "git+https://github.com/okx/plonky2?branch=clone-circuit#e07494fd2b52033fae5a7e0d65411266be34db60" dependencies = [ "rayon", ] @@ -1286,7 +1286,7 @@ dependencies = [ [[package]] name = "plonky2_util" version = "0.2.0" -source = "git+https://github.com/okx/plonky2#140d97a8081cfae1d08e43199e13084c1acf1dae" +source = "git+https://github.com/okx/plonky2?branch=clone-circuit#e07494fd2b52033fae5a7e0d65411266be34db60" [[package]] name = "powerfmt" diff --git a/Cargo.toml b/Cargo.toml index 1101b6f..915bd71 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,8 +34,8 @@ once_cell = "1.14" static_assertions = { version = "1.1.0", default-features = false } unroll = { version = "0.1.5", default-features = false } # zkp -plonky2 = { git = "https://github.com/okx/plonky2"} -plonky2_field = { git = "https://github.com/okx/plonky2"} +plonky2 = { git = "https://github.com/okx/plonky2", branch="clone-circuit"} +plonky2_field = { git = "https://github.com/okx/plonky2", branch="clone-circuit"} # computing rayon = "1.8" # data diff --git a/crates/zk-por-core/benches/batch_circuit.rs b/crates/zk-por-core/benches/batch_circuit.rs index adb5f50..b471185 100644 --- a/crates/zk-por-core/benches/batch_circuit.rs +++ b/crates/zk-por-core/benches/batch_circuit.rs @@ -1,17 +1,21 @@ #![feature(test)] - +use plonky2::plonk::circuit_builder::CircuitBuilder; use zk_por_core::{ - account::gen_accounts_with_random_data, merkle_sum_prover::prover::MerkleSumTreeProver, + account::gen_accounts_with_random_data, circuit_config::STANDARD_CONFIG, merkle_sum_prover::{circuits::account_circuit::AccountTargets, prover::MerkleSumTreeProver}, types::{C, D, F} }; extern crate test; use test::Bencher; fn bench(b: &mut Bencher, batch_size: usize) { + let mut builder = CircuitBuilder::::new(STANDARD_CONFIG); let num_assets = 50; let accounts = gen_accounts_with_random_data(batch_size, num_assets); let prover = MerkleSumTreeProver { accounts }; - b.iter(|| _ = prover.get_proof()); + let account_targets: Vec = prover.build_merkle_tree_targets(&mut builder); + let data = &builder.build::(); + + b.iter(|| _ = prover.get_proof_with_circuit_data(&account_targets, data)); } #[bench] diff --git a/crates/zk-por-core/benches/recursive_circuit.rs b/crates/zk-por-core/benches/recursive_circuit.rs index dbcafba..2f34494 100644 --- a/crates/zk-por-core/benches/recursive_circuit.rs +++ b/crates/zk-por-core/benches/recursive_circuit.rs @@ -17,7 +17,7 @@ fn bench(b: &mut Bencher, batch_size: usize) { let accounts = gen_accounts_with_random_data(batch_size, asset_num); let prover = MerkleSumTreeProver { accounts }; - let (merkle_sum_proof, merkle_sum_cd) = prover.get_proof_with_cd(); + let (merkle_sum_proof, merkle_sum_cd) = prover.get_proof_and_circuit_data(); let sub_proofs: [ProofWithPublicInputs; SUBPROOF_NUM] = std::array::from_fn(|_| merkle_sum_proof.clone()); diff --git a/crates/zk-por-core/src/merkle_sum_prover/circuits/account_circuit.rs b/crates/zk-por-core/src/merkle_sum_prover/circuits/account_circuit.rs index 96e5f34..fb614cb 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/circuits/account_circuit.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/circuits/account_circuit.rs @@ -37,8 +37,6 @@ impl AccountTargets { assert_eq!(self.equity.len(), account_info.equity.len()); assert_eq!(self.debt.len(), account_info.debt.len()); - println!("{:?}", account_info.get_user_id_in_field()); - pw.set_target_arr(self.equity.as_slice(), account_info.equity.as_slice()); pw.set_target_arr(self.debt.as_slice(), account_info.debt.as_slice()); pw.set_target_arr(self.id.as_slice(), &account_info.get_user_id_in_field().as_slice()); diff --git a/crates/zk-por-core/src/merkle_sum_prover/prover.rs b/crates/zk-por-core/src/merkle_sum_prover/prover.rs index f88362a..72e1c52 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/prover.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/prover.rs @@ -14,24 +14,32 @@ use plonky2::{ util::timing::TimingTree, }; -use tracing::error; +use tracing::{error, trace}; use super::circuits::merkle_sum_circuit::MerkleSumTreeTarget; /// A merkle sum tree prover with a batch id representing its index in the recursive proof tree and a Vec of accounts representing accounts in this batch. -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct MerkleSumTreeProver { // batch_id: usize, pub accounts: Vec, } impl MerkleSumTreeProver { - /// Build the merkle sum tree targets and set the account targets with the account info. - pub fn build_and_set_merkle_tree_targets( + /// Sets provided account targets with values from accounts in the prover batch. + pub fn set_merkle_tree_targets( &self, - builder: &mut CircuitBuilder, pw: &mut PartialWitness, + account_targets: &Vec ) { + for i in 0..self.accounts.len() { + // Set account targets + account_targets.get(i).unwrap().set_account_targets(self.accounts.get(i).unwrap(), pw); + } + } + + /// Builds a merkle sum tree targets and returns the account targets to be set with input values. + pub fn build_merkle_tree_targets( &self, builder: &mut CircuitBuilder,)-> Vec{ let mut account_targets: Vec = Vec::new(); for i in 0..self.accounts.len() { @@ -39,7 +47,6 @@ impl MerkleSumTreeProver { let account_target = AccountTargets::new_from_account(self.accounts.get(i).unwrap(), builder); // Set account targets - account_target.set_account_targets(self.accounts.get(i).unwrap(), pw); account_targets.push(account_target); } @@ -51,9 +58,12 @@ impl MerkleSumTreeProver { // build merkle sum tree let _merkle_tree_targets = MerkleSumTreeTarget::build_new_from_account_targets(builder, &mut account_sum_targets); + + account_targets } - pub fn get_prover_cd(&self, builder: &mut CircuitBuilder) -> CircuitData { + /// Builds the circuit for the merkle sum tree proof and returns the circuit data, useful in pre compiling the circuit data for a merkle sum circuit of a given length. + pub fn get_prover_circuit_data(&self, builder: &mut CircuitBuilder) -> CircuitData { let mut account_targets: Vec = Vec::new(); for i in 0..self.accounts.len() { @@ -80,7 +90,9 @@ impl MerkleSumTreeProver { let mut builder = CircuitBuilder::::new(STANDARD_CONFIG); let mut pw = PartialWitness::::new(); - self.build_and_set_merkle_tree_targets(&mut builder, &mut pw); + // Build and set merkle tree targets + let account_targets = self.build_merkle_tree_targets(&mut builder); + self.set_merkle_tree_targets(&mut pw, &account_targets); builder.print_gate_counts(0); @@ -91,7 +103,7 @@ impl MerkleSumTreeProver { println!("Started Proving"); - let proof_res = prove(&prover_only, &common, pw.clone(), &mut timing); + let proof_res = prove(&prover_only, &common, pw, &mut timing); match proof_res { Ok(proof) => { @@ -113,12 +125,53 @@ impl MerkleSumTreeProver { } } - /// Get the merkle sum tree proof of this batch of accounts. - pub fn get_proof_with_cd(&self) -> (ProofWithPublicInputs, CircuitData) { + /// Get proof with a pre-compiled merkle sum circuit and account targets. In this method we do not need to build the circuit as we use a pre-built circuit. + pub fn get_proof_with_circuit_data(&self, account_targets: &Vec, circuit_data: &CircuitData)-> ProofWithPublicInputs{ + let mut pw = PartialWitness::::new(); + for i in 0..self.accounts.len() { + // Build account targets + let account_target = + account_targets.get(i).unwrap(); + // Set account targets + account_target.set_account_targets(self.accounts.get(i).unwrap(), &mut pw); + } + + let mut timing = TimingTree::new("prove", Level::Info); + + let CircuitData { prover_only, common, verifier_only: _ } = &circuit_data; + + log::debug!("Starting proving!"); + + let proof_res = prove(&prover_only, &common, pw, &mut timing); + + match proof_res { + Ok(proof) => { + log::debug!("Finished proving!"); + + let proof_verification_res = circuit_data.verify(proof.clone()); + match proof_verification_res { + Ok(_) => proof, + Err(e) => { + error!("Proof verification failed: {:?}", e); + panic!("Proof verification failed!"); + } + } + } + Err(e) => { + error!("Proof generation failed: {:?}", e); + panic!("Proof generation failed!"); + } + } + } + + /// Get the merkle sum tree proof of this batch of accounts and the circuit data of the corresponding proof. + pub fn get_proof_and_circuit_data(&self) -> (ProofWithPublicInputs, CircuitData) { let mut builder = CircuitBuilder::::new(STANDARD_CONFIG); let mut pw = PartialWitness::::new(); - self.build_and_set_merkle_tree_targets(&mut builder, &mut pw); + // Build and set merkle tree targets + let account_targets = self.build_merkle_tree_targets(&mut builder); + self.set_merkle_tree_targets(&mut pw, &account_targets); builder.print_gate_counts(0); @@ -127,13 +180,13 @@ impl MerkleSumTreeProver { let CircuitData { prover_only, common, verifier_only: _ } = &data; - println!("Started Proving"); + log::debug!("Starting proving!"); - let proof_res = prove(&prover_only, &common, pw.clone(), &mut timing); + let proof_res = prove(&prover_only, &common, pw, &mut timing); match proof_res { Ok(proof) => { - println!("Finished Proving"); + log::debug!("Finished proving!"); let proof_verification_res = data.verify(proof.clone()); match proof_verification_res { @@ -168,7 +221,9 @@ pub mod test { accounts, }; - prover.build_and_set_merkle_tree_targets(builder, pw); + // Build and set merkle tree targets + let account_targets = prover.build_merkle_tree_targets(builder); + prover.set_merkle_tree_targets(pw, &account_targets); }); } diff --git a/crates/zk-por-core/src/recursive_prover/prover.rs b/crates/zk-por-core/src/recursive_prover/prover.rs index cc79de8..ea4d95f 100644 --- a/crates/zk-por-core/src/recursive_prover/prover.rs +++ b/crates/zk-por-core/src/recursive_prover/prover.rs @@ -1,9 +1,9 @@ use log::Level; use plonky2::{ - iop::witness::{PartialWitness, WitnessWrite}, + iop::witness::PartialWitness, plonk::{ circuit_builder::CircuitBuilder, - circuit_data::{CircuitData, VerifierOnlyCircuitData}, + circuit_data::CircuitData, config::{AlgebraicHasher, GenericConfig}, proof::ProofWithPublicInputs, prover::prove, @@ -16,9 +16,8 @@ use crate::{ circuit_config::STANDARD_CONFIG, types::{D, F}, }; -use anyhow::Result; -use super::recursive_circuit::{build_new_recursive_n_circuit_targets, RecursiveTargets}; +use super::recursive_circuit::{verify_n_subproof_circuit, RecursiveTargets}; pub struct RecursiveProver, const N: usize> { // pub batch_id: usize, @@ -27,6 +26,30 @@ pub struct RecursiveProver, const N: usize> { } impl, const N: usize> RecursiveProver { + + /// build recursive circuit that proves N subproofs and geneate parent merkle sum node targets + /// This circuit hardcode the constraint that the verifier_circuit_target.circuit_digest must be equal to that inner_verifier_circuit_data.circuit_digest; + pub fn build_new_recursive_n_circuit_targets( + &self, + builder: &mut CircuitBuilder, + ) -> RecursiveTargets + where + C::Hasher: AlgebraicHasher, + { + // Verify n subproofs in circuit + let mut recursive_targets = + verify_n_subproof_circuit(builder, &self.merkle_sum_circuit.common, &self.merkle_sum_circuit.verifier_only); + + // Build the recursive merkle sum tree targets to get the next merkle sum tree root. + recursive_targets.build_recursive_merkle_sum_tree_circuit(builder); + + #[cfg(debug_assertions)] + builder.print_gate_counts(0); + + recursive_targets + } + + pub fn build_and_set_recursive_targets( &self, builder: &mut CircuitBuilder, @@ -34,9 +57,7 @@ impl, const N: usize> RecursiveProver { ) where >::Hasher: AlgebraicHasher, { - let recursive_targets: RecursiveTargets = build_new_recursive_n_circuit_targets( - &self.merkle_sum_circuit.common, - &self.merkle_sum_circuit.verifier_only, + let recursive_targets: RecursiveTargets = self.build_new_recursive_n_circuit_targets( builder, ); @@ -47,6 +68,7 @@ impl, const N: usize> RecursiveProver { ) } + /// Gets the proof with pis of this batch of recursive proofs. pub fn get_proof(&self) -> ProofWithPublicInputs where >::Hasher: AlgebraicHasher, @@ -58,7 +80,7 @@ impl, const N: usize> RecursiveProver { builder.print_gate_counts(0); - let mut timing = TimingTree::new("prove", Level::Debug); + let mut timing = TimingTree::new("prove", Level::Info); let data = builder.build::(); let CircuitData { prover_only, common, verifier_only: _ } = &data; @@ -89,56 +111,43 @@ impl, const N: usize> RecursiveProver { } } } -} -pub fn prove_n_subproofs< - C: GenericConfig, - InnerC: GenericConfig, - const N: usize, ->( - sub_proofs: Vec>, - inner_circuit_vd: &VerifierOnlyCircuitData, - recursive_circuit: &CircuitData, - recursive_targets: RecursiveTargets, -) -> Result> -where - InnerC::Hasher: AlgebraicHasher, - // [(); C::Hasher::HASH_SIZE]:, // TODO: figure out how to make this work -{ - // tracing::debug!("before build recurisve {} circuit", N); - // let circuit_data = builder.build::(); - // tracing::debug!("after build recurisve {} circuit", N); - if sub_proofs.len() != N { - return Err(anyhow::anyhow!(format!( - "number of proofs [{}] is not consistent with N [{}]", - sub_proofs.len(), - N - ))); - } + /// Get proof with a pre-compiled merkle sum circuit and recursive targets. In this method we do not need to build the circuit as we use a pre-built circuit. + pub fn get_proof_with_circuit_data(&self, recursive_targets: &RecursiveTargets, cd: &CircuitData) -> ProofWithPublicInputs + where + >::Hasher: AlgebraicHasher, + { + let mut pw = PartialWitness::::new(); + let CircuitData { prover_only, common, verifier_only } = &cd; - let mut pw = PartialWitness::new(); - pw.set_verifier_data_target(&recursive_targets.verifier_circuit_target, inner_circuit_vd); + recursive_targets.set_targets(&mut pw, self.sub_proofs.to_vec(), verifier_only); - (0..N).for_each(|i| { - pw.set_proof_with_pis_target( - &recursive_targets.proof_with_pub_input_targets[i], - &sub_proofs[i], - ); - }); + let mut timing = TimingTree::new("prove", Level::Info); - let mut timing = TimingTree::new("prove_N_subproofs", log::Level::Debug); - #[cfg(not(debug_assertions))] - let mut timing = TimingTree::new("prove_N_subproofs", log::Level::Info); + log::debug!("before prove"); + let start = std::time::Instant::now(); - let start = std::time::Instant::now(); - log::debug!("before prove"); - let proof = prove(&recursive_circuit.prover_only, &recursive_circuit.common, pw, &mut timing)?; - log::debug!("time for {:?} proofs, {:?}", N, start.elapsed().as_millis()); + let proof_res = prove(&prover_only, &common, pw.clone(), &mut timing); - #[cfg(debug_assertions)] - { - recursive_circuit.verify(proof.clone())?; - } + log::debug!("time for {:?} proofs, {:?}", N, start.elapsed().as_millis()); - Ok(proof) -} + match proof_res { + Ok(proof) => { + println!("Finished Proving"); + + let proof_verification_res = cd.verify(proof.clone()); + match proof_verification_res { + Ok(_) => proof, + Err(e) => { + error!("Proof verification failed: {:?}", e); + panic!("Proof verification failed!"); + } + } + } + Err(e) => { + error!("Proof generation failed: {:?}", e); + panic!("Proof generation failed!"); + } + } + } +} \ No newline at end of file diff --git a/crates/zk-por-core/src/recursive_prover/recursive_circuit.rs b/crates/zk-por-core/src/recursive_prover/recursive_circuit.rs index 7ced5e0..2ec07e7 100644 --- a/crates/zk-por-core/src/recursive_prover/recursive_circuit.rs +++ b/crates/zk-por-core/src/recursive_prover/recursive_circuit.rs @@ -24,7 +24,7 @@ pub struct RecursiveTargets { } impl RecursiveTargets { - /// Builds a N-ary merkle sum tree and sets its root as a public input. + /// Builds a N-ary merkle sum tree and sets its root as a public input. We use a N-ary merkle sum tree instead of the binary one since it requires less hash gates. pub fn build_recursive_merkle_sum_tree_circuit(&mut self, builder: &mut CircuitBuilder) { let mut merkle_sum_node_targets: Vec = Vec::new(); merkle_sum_node_targets.push(MerkleSumNodeTarget::from( @@ -67,29 +67,8 @@ impl RecursiveTargets { } } -/// build recursive circuit that proves N subproofs and geneate parent merkle sum node targets -/// This circuit hardcode the constraint that the verifier_circuit_target.circuit_digest must be equal to that inner_verifier_circuit_data.circuit_digest; -pub fn build_new_recursive_n_circuit_targets, const N: usize>( - inner_common_circuit_data: &CommonCircuitData, - inner_verifier_circuit_data: &VerifierOnlyCircuitData, - builder: &mut CircuitBuilder, -) -> RecursiveTargets -where - C::Hasher: AlgebraicHasher, -{ - // Verify n subproofs in circuit - let mut recursive_targets = - verify_n_subproof_circuit(builder, inner_common_circuit_data, inner_verifier_circuit_data); - - // Build the recursive merkle sum tree targets to get the next merkle sum tree root. - recursive_targets.build_recursive_merkle_sum_tree_circuit(builder); - - #[cfg(debug_assertions)] - builder.print_gate_counts(0); - - recursive_targets -} - +/// We verify N subproofs in the circuit using the verifier CD. We also ensure the verifier data = constant vd_digest in the circuit to ensure the +/// vd is embedded in circuit. pub fn verify_n_subproof_circuit< // C: GenericConfig, InnerC: GenericConfig, diff --git a/crates/zk-por-core/tests/recursive_circuit.rs b/crates/zk-por-core/tests/recursive_circuit.rs index 073a7f8..6d224f7 100644 --- a/crates/zk-por-core/tests/recursive_circuit.rs +++ b/crates/zk-por-core/tests/recursive_circuit.rs @@ -27,7 +27,7 @@ fn test() { let prover = MerkleSumTreeProver { accounts }; - let (merkle_sum_proof, cd) = prover.get_proof_with_cd(); + let (merkle_sum_proof, cd) = prover.get_proof_and_circuit_data(); let sub_proofs: [ProofWithPublicInputs; RECURSIVE_FACTOR] = std::array::from_fn(|_| merkle_sum_proof.clone()); From 20cdb339c7d6519334b2360674e91fe89de43fdb Mon Sep 17 00:00:00 2001 From: cliff0412 Date: Mon, 5 Aug 2024 13:16:36 +0800 Subject: [PATCH 16/17] refactor: log, gitignore --- .gitignore | 3 ++- Cargo.lock | 8 ++++---- Cargo.toml | 4 ++-- crates/zk-por-core/src/merkle_sum_prover/prover.rs | 6 +++--- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index caeac47..5b20f31 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ .vscode/ target/ logs/ -plonky2/ \ No newline at end of file +plonky2/ +my_permanent_leveldb/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 616c2db..8c88cae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1233,7 +1233,7 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "plonky2" version = "0.2.0" -source = "git+https://github.com/okx/plonky2?branch=clone-circuit#e07494fd2b52033fae5a7e0d65411266be34db60" +source = "git+https://github.com/okx/plonky2#140d97a8081cfae1d08e43199e13084c1acf1dae" dependencies = [ "ahash 0.8.11", "anyhow", @@ -1259,7 +1259,7 @@ dependencies = [ [[package]] name = "plonky2_field" version = "0.2.0" -source = "git+https://github.com/okx/plonky2?branch=clone-circuit#e07494fd2b52033fae5a7e0d65411266be34db60" +source = "git+https://github.com/okx/plonky2#140d97a8081cfae1d08e43199e13084c1acf1dae" dependencies = [ "anyhow", "itertools 0.11.0", @@ -1278,7 +1278,7 @@ dependencies = [ [[package]] name = "plonky2_maybe_rayon" version = "0.2.0" -source = "git+https://github.com/okx/plonky2?branch=clone-circuit#e07494fd2b52033fae5a7e0d65411266be34db60" +source = "git+https://github.com/okx/plonky2#140d97a8081cfae1d08e43199e13084c1acf1dae" dependencies = [ "rayon", ] @@ -1286,7 +1286,7 @@ dependencies = [ [[package]] name = "plonky2_util" version = "0.2.0" -source = "git+https://github.com/okx/plonky2?branch=clone-circuit#e07494fd2b52033fae5a7e0d65411266be34db60" +source = "git+https://github.com/okx/plonky2#140d97a8081cfae1d08e43199e13084c1acf1dae" [[package]] name = "powerfmt" diff --git a/Cargo.toml b/Cargo.toml index 915bd71..1101b6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,8 +34,8 @@ once_cell = "1.14" static_assertions = { version = "1.1.0", default-features = false } unroll = { version = "0.1.5", default-features = false } # zkp -plonky2 = { git = "https://github.com/okx/plonky2", branch="clone-circuit"} -plonky2_field = { git = "https://github.com/okx/plonky2", branch="clone-circuit"} +plonky2 = { git = "https://github.com/okx/plonky2"} +plonky2_field = { git = "https://github.com/okx/plonky2"} # computing rayon = "1.8" # data diff --git a/crates/zk-por-core/src/merkle_sum_prover/prover.rs b/crates/zk-por-core/src/merkle_sum_prover/prover.rs index 72e1c52..94f2d3c 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/prover.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/prover.rs @@ -14,7 +14,7 @@ use plonky2::{ util::timing::TimingTree, }; -use tracing::{error, trace}; +use tracing::{info, error}; use super::circuits::merkle_sum_circuit::MerkleSumTreeTarget; @@ -101,13 +101,13 @@ impl MerkleSumTreeProver { let CircuitData { prover_only, common, verifier_only: _ } = &data; - println!("Started Proving"); + info!("Started Proving"); let proof_res = prove(&prover_only, &common, pw, &mut timing); match proof_res { Ok(proof) => { - println!("Finished Proving"); + info!("Finished Proving"); let proof_verification_res = data.verify(proof.clone()); match proof_verification_res { From 8187a6ef6c01c6c8a92090237fa2fa5d3de6b935 Mon Sep 17 00:00:00 2001 From: cliff0412 Date: Mon, 5 Aug 2024 13:36:15 +0800 Subject: [PATCH 17/17] chore fix fmt --- crates/zk-por-core/benches/batch_circuit.rs | 5 ++- .../src/merkle_sum_prover/prover.rs | 31 +++++++++++++------ .../src/recursive_prover/prover.rs | 22 +++++++------ 3 files changed, 38 insertions(+), 20 deletions(-) diff --git a/crates/zk-por-core/benches/batch_circuit.rs b/crates/zk-por-core/benches/batch_circuit.rs index b471185..2e9870f 100644 --- a/crates/zk-por-core/benches/batch_circuit.rs +++ b/crates/zk-por-core/benches/batch_circuit.rs @@ -1,7 +1,10 @@ #![feature(test)] use plonky2::plonk::circuit_builder::CircuitBuilder; use zk_por_core::{ - account::gen_accounts_with_random_data, circuit_config::STANDARD_CONFIG, merkle_sum_prover::{circuits::account_circuit::AccountTargets, prover::MerkleSumTreeProver}, types::{C, D, F} + account::gen_accounts_with_random_data, + circuit_config::STANDARD_CONFIG, + merkle_sum_prover::{circuits::account_circuit::AccountTargets, prover::MerkleSumTreeProver}, + types::{C, D, F}, }; extern crate test; diff --git a/crates/zk-por-core/src/merkle_sum_prover/prover.rs b/crates/zk-por-core/src/merkle_sum_prover/prover.rs index 94f2d3c..af33b89 100644 --- a/crates/zk-por-core/src/merkle_sum_prover/prover.rs +++ b/crates/zk-por-core/src/merkle_sum_prover/prover.rs @@ -14,7 +14,7 @@ use plonky2::{ util::timing::TimingTree, }; -use tracing::{info, error}; +use tracing::{error, info}; use super::circuits::merkle_sum_circuit::MerkleSumTreeTarget; @@ -30,7 +30,7 @@ impl MerkleSumTreeProver { pub fn set_merkle_tree_targets( &self, pw: &mut PartialWitness, - account_targets: &Vec + account_targets: &Vec, ) { for i in 0..self.accounts.len() { // Set account targets @@ -39,7 +39,10 @@ impl MerkleSumTreeProver { } /// Builds a merkle sum tree targets and returns the account targets to be set with input values. - pub fn build_merkle_tree_targets( &self, builder: &mut CircuitBuilder,)-> Vec{ + pub fn build_merkle_tree_targets( + &self, + builder: &mut CircuitBuilder, + ) -> Vec { let mut account_targets: Vec = Vec::new(); for i in 0..self.accounts.len() { @@ -63,7 +66,10 @@ impl MerkleSumTreeProver { } /// Builds the circuit for the merkle sum tree proof and returns the circuit data, useful in pre compiling the circuit data for a merkle sum circuit of a given length. - pub fn get_prover_circuit_data(&self, builder: &mut CircuitBuilder) -> CircuitData { + pub fn get_prover_circuit_data( + &self, + builder: &mut CircuitBuilder, + ) -> CircuitData { let mut account_targets: Vec = Vec::new(); for i in 0..self.accounts.len() { @@ -126,12 +132,15 @@ impl MerkleSumTreeProver { } /// Get proof with a pre-compiled merkle sum circuit and account targets. In this method we do not need to build the circuit as we use a pre-built circuit. - pub fn get_proof_with_circuit_data(&self, account_targets: &Vec, circuit_data: &CircuitData)-> ProofWithPublicInputs{ + pub fn get_proof_with_circuit_data( + &self, + account_targets: &Vec, + circuit_data: &CircuitData, + ) -> ProofWithPublicInputs { let mut pw = PartialWitness::::new(); for i in 0..self.accounts.len() { // Build account targets - let account_target = - account_targets.get(i).unwrap(); + let account_target = account_targets.get(i).unwrap(); // Set account targets account_target.set_account_targets(self.accounts.get(i).unwrap(), &mut pw); } @@ -164,8 +173,10 @@ impl MerkleSumTreeProver { } } - /// Get the merkle sum tree proof of this batch of accounts and the circuit data of the corresponding proof. - pub fn get_proof_and_circuit_data(&self) -> (ProofWithPublicInputs, CircuitData) { + /// Get the merkle sum tree proof of this batch of accounts and the circuit data of the corresponding proof. + pub fn get_proof_and_circuit_data( + &self, + ) -> (ProofWithPublicInputs, CircuitData) { let mut builder = CircuitBuilder::::new(STANDARD_CONFIG); let mut pw = PartialWitness::::new(); @@ -221,7 +232,7 @@ pub mod test { accounts, }; - // Build and set merkle tree targets + // Build and set merkle tree targets let account_targets = prover.build_merkle_tree_targets(builder); prover.set_merkle_tree_targets(pw, &account_targets); }); diff --git a/crates/zk-por-core/src/recursive_prover/prover.rs b/crates/zk-por-core/src/recursive_prover/prover.rs index ea4d95f..fa253e7 100644 --- a/crates/zk-por-core/src/recursive_prover/prover.rs +++ b/crates/zk-por-core/src/recursive_prover/prover.rs @@ -26,7 +26,6 @@ pub struct RecursiveProver, const N: usize> { } impl, const N: usize> RecursiveProver { - /// build recursive circuit that proves N subproofs and geneate parent merkle sum node targets /// This circuit hardcode the constraint that the verifier_circuit_target.circuit_digest must be equal to that inner_verifier_circuit_data.circuit_digest; pub fn build_new_recursive_n_circuit_targets( @@ -37,8 +36,11 @@ impl, const N: usize> RecursiveProver { C::Hasher: AlgebraicHasher, { // Verify n subproofs in circuit - let mut recursive_targets = - verify_n_subproof_circuit(builder, &self.merkle_sum_circuit.common, &self.merkle_sum_circuit.verifier_only); + let mut recursive_targets = verify_n_subproof_circuit( + builder, + &self.merkle_sum_circuit.common, + &self.merkle_sum_circuit.verifier_only, + ); // Build the recursive merkle sum tree targets to get the next merkle sum tree root. recursive_targets.build_recursive_merkle_sum_tree_circuit(builder); @@ -49,7 +51,6 @@ impl, const N: usize> RecursiveProver { recursive_targets } - pub fn build_and_set_recursive_targets( &self, builder: &mut CircuitBuilder, @@ -57,9 +58,8 @@ impl, const N: usize> RecursiveProver { ) where >::Hasher: AlgebraicHasher, { - let recursive_targets: RecursiveTargets = self.build_new_recursive_n_circuit_targets( - builder, - ); + let recursive_targets: RecursiveTargets = + self.build_new_recursive_n_circuit_targets(builder); recursive_targets.set_targets( pw, @@ -113,7 +113,11 @@ impl, const N: usize> RecursiveProver { } /// Get proof with a pre-compiled merkle sum circuit and recursive targets. In this method we do not need to build the circuit as we use a pre-built circuit. - pub fn get_proof_with_circuit_data(&self, recursive_targets: &RecursiveTargets, cd: &CircuitData) -> ProofWithPublicInputs + pub fn get_proof_with_circuit_data( + &self, + recursive_targets: &RecursiveTargets, + cd: &CircuitData, + ) -> ProofWithPublicInputs where >::Hasher: AlgebraicHasher, { @@ -150,4 +154,4 @@ impl, const N: usize> RecursiveProver { } } } -} \ No newline at end of file +}