# Project export: VeriVote

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: TreeHacks 2024
- Tagline: Empowering democracy through QED Zero-Knowledge Proofs in order to improve, secure, and bring transparency one vote at a time!
- Devpost: https://devpost.com/software/verivote-t42xoi
- GitHub: https://github.com/certifiedp/VeriVote
- Result: winner (QED Protocol: Best Application of Zero Knowledge Proofs ($5k Cash))
- Team: 2 GitHub contributor(s) — cf (1 commits), Jameson-Crate (1 commits)

## Devpost submission (written by the team)

### Inspiration

Voting systems fail to adopt new technology and address systematic concerns. Blockchain, having the ability to create transparency and decentralize centralized powers, seemed like a plausible solution to this issue. Seeing the QED workshop and its utilization of ZKPs, we knew that would be a great opportunity to create a scalable, decentralized, and extremely secure voting platform.

### What it does

This platform uses the QED protocol as a backend to verify state changes to proposals that are part of VeriVote using ZKPs. This means that users in the network are empowered with the ability to vote on policies and verify the legitimacy of the election/system.

### How we built it

We used the QED Protocol coded in Rust to create a series of functions that allow users to vote and propose on different policies posed on our platform. We specifically created functions on the server side that helped list proposals, vote on them, and finalize them. To help run our application, we created a Python client and found ways to execute API calls from our server.

### Challenges we ran into

Our team did not have as much exposure to ZKPs which resulted in us spending the majority of the hackathon learning and building levels of abstraction for the protocol. This was a significant challenge but through cross-collaboration and help from online resources, we were able to learn and create a product we're proud of!

### Accomplishments we're proud of

We're proud of creating a back-end that uses QED and works with Rust to create ZKPs with the potential for real application. Our team adapted to using a new language and learned more about a field that is constantly developing.

### What we learned

Our team learned more about zero-knowledge proofs, contemporary solutions that are being implemented to address the Blockchain trilemma, and how to code a robust back-end in Rust. We plan on learning and diving more into open-source projects related to ZKPs and decentralized applications.

### What's next

Our next steps include: Adding a delegation feature that allows people to delegate their votes to certain proposals/users in the network Implement a front end to make the application more functional/accessible (i.e. votes sidebar) Create a means of robust authentication to ensure that people on the network are unique.

## README (from the GitHub repository)

# Recursive Zero-Knowledge Succient Proof -- Tree Hacks 2024

https://qedprotocol.com ❤️ Hackers


## Licnese
Copyright 2024 Zero Knowledge Labs Limited

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


## Detected evidence (automated analysis)

Indexed codebase: 88 recognized source files, 569 KB.
- Python (language) — detected in the code
- Rust (language) — detected in the code

## Codebase structure (from repository index)

### Files (92 of 92)

```
.gitignore
benches/delta_merkle_gadget.rs
Cargo.toml
LICENSE
README.md
rust-toolchain.toml
src/challenge heuristic.rs
src/client.py
src/common/base_types/hash/hash192.rs
src/common/base_types/hash/hash256.rs
src/common/base_types/hash/mod.rs
src/common/base_types/mod.rs
src/common/binaryhelpers/bytes.rs
src/common/binaryhelpers/mod.rs
src/common/builder/connect.rs
src/common/builder/hash/blake3_truncated.rs
src/common/builder/hash/blake3.rs
src/common/builder/hash/core.rs
src/common/builder/hash/hash192.rs
src/common/builder/hash/hash256.rs
src/common/builder/hash/mod.rs
src/common/builder/hash/sha256_truncated.rs
src/common/builder/hash/sha256.rs
src/common/builder/mod.rs
src/common/builder/optional_inputs.rs
src/common/builder/select.rs
src/common/builder/verify.rs
src/common/generic.rs
src/common/hash/cached_zero_hashes.rs
src/common/hash/hashstack/gadgets/hashstack.rs
src/common/hash/hashstack/gadgets/mod.rs
src/common/hash/hashstack/helpers/mod.rs
src/common/hash/hashstack/mod.rs
src/common/hash/merkle/gadgets/blake3.rs
src/common/hash/merkle/gadgets/delta_merkle_proof.rs
src/common/hash/merkle/gadgets/generic/delta_merkle_proof.rs
src/common/hash/merkle/gadgets/generic/merkle_proof.rs
src/common/hash/merkle/gadgets/generic/mod.rs
src/common/hash/merkle/gadgets/merkle_proof.rs
src/common/hash/merkle/gadgets/mod.rs
src/common/hash/merkle/gadgets/sha2.rs
src/common/hash/merkle/gadgets/sha256_truncated/delta_merkle_proof.rs
src/common/hash/merkle/gadgets/sha256_truncated/merkle_proof.rs
src/common/hash/merkle/gadgets/sha256_truncated/mod.rs
src/common/hash/merkle/gadgets/sha256/delta_merkle_proof.rs
src/common/hash/merkle/gadgets/sha256/merkle_proof.rs
src/common/hash/merkle/gadgets/sha256/mod.rs
src/common/hash/merkle/helpers/merkle_proof.rs
src/common/hash/merkle/helpers/mod.rs
src/common/hash/merkle/helpers/zero_hashes.rs
src/common/hash/merkle/mod.rs
src/common/hash/mod.rs
src/common/hash/poseidon/hash.rs
src/common/hash/poseidon/mod.rs
src/common/hash/traits/hasher.rs
src/common/hash/traits/mod.rs
src/common/mod.rs
src/common/richer_field.rs
src/common/u32/gadgets/arithmetic_u32.rs
src/common/u32/gadgets/binary_u32.rs
src/common/u32/gadgets/interleaved_u32.rs
src/common/u32/gadgets/mod.rs
src/common/u32/gadgets/multiple_comparison.rs
src/common/u32/gadgets/range_check.rs
src/common/u32/gates/add_many_u32.rs
src/common/u32/gates/arithmetic_u32.rs
src/common/u32/gates/comparison.rs
src/common/u32/gates/interleave_u32.rs
src/common/u32/gates/mod.rs
src/common/u32/gates/range_check_u32.rs
src/common/u32/gates/subtraction_u32.rs
src/common/u32/gates/uninterleave_to_b32.rs
src/common/u32/gates/uninterleave_to_u32.rs
src/common/u32/mod.rs
src/common/u32/README.md
src/common/u32/witness.rs
src/common/verify/fingerprint.rs
src/common/verify/gadgets/fingerprint.rs
src/common/verify/gadgets/mod.rs
src/common/verify/gadgets/verify_two_to_one.rs
src/common/verify/mod.rs
src/common/whashout.rs
src/debug/debug_timer.rs
src/debug/mod.rs
src/lib.rs
src/main.rs
src/utils/mod.rs
src/utils/zmt/mod.rs
src/utils/zmt/node_store/core.rs
src/utils/zmt/node_store/mod.rs
src/utils/zmt/node_store/simple_node_store.rs
src/utils/zmt/zero_merkle_tree.rs
```

### Dependencies

- Cargo.toml: actix-web@4.0, ahash@0.8.3, anyhow@1.0.40, base64@0.13.0, bincode@1.3.3, bitflags@2.0.0-rc.1, clap@4.0.32, concurrent-queue@2.1.0, criterion@0.5.1, hashbrown@0.14.0, hex@0.4.3, hex-literal@0.4.1, itertools@0.10.5, log@0.4.17, num@0.4, num-derive@0.3.3, num-traits@0.2.15, once_cell@1.16.0, plonky2, plonky2_ecdsa, plonky2_util, rand@0.8, rand_chacha@0.3.1, reqwest@0.11, serde@1.0.145, serde_derive@1.0, serde_json@1.0.86, serde_repr@0.1.10, serde_with@2.2.0, tokio@1, unroll@0.1.5, uuid@1.0

### Recent commits (newest first)

- updated title.md
- Saved
- Saved
- TreeHax

## Key source files (fetched from GitHub, selected and truncated for size)

### Cargo.toml

```
[package]
name = "plonky2-tree-hacks"
version = "0.1.0"
edition = "2021"



[dependencies]
actix-web = "4.0"
uuid = { version = "1.0", features = ["v4", "serde"] }
reqwest = "0.11"
tokio = { version = "1", features = ["full"] }
serde_derive = "1.0"
plonky2 = { git = "https://github.com/mir-protocol/plonky2", rev = "3de92d9ed1721cec133e4e1e1b3ec7facb756ccf", default-features = false, features = ["std"] }
plonky2_util = { git = "https://github.com/mir-protocol/plonky2", rev = "3de92d9ed1721cec133e4e1e1b3ec7facb756ccf", default-features = false }
plonky2_ecdsa = { git = "https://github.com/cf/plonky2-ecdsa", rev = "1fd71d5f5deec382ac192f4ce28764996f8e6085", default-features = false  }
bitflags = "2.0.0-rc.1"
rand = "0.8"
hex = "0.4.3"
serde = { version = "1.0.145", features = ["derive"] }
serde_with = { version = "2.2.0", features = ["hex"] }
ahash = { version = "0.8.3", default-features = false, features = ["compile-time-rng"] } # NOTE: Be sure to keep this version the same as the dependency in `hashbrown`.
anyhow = { version = "1.0.40", default-features = false }
hashbrown = { version = "0.14.0", default-features = false, features = ["ahash", "serde"] } # NOTE: When upgrading, see `ahash` dependency.
log = "0.4.17"
base64 = "0.13.0"
serde_json = "1.0.86"
itertools = "0.10.5"
num = { version = "0.4", features = [ "rand" ] }
clap = { version = "4.0.32", features = ["derive"] }
bincode = "1.3.3"
serde_repr = "0.1.10"
concurrent-queue = "2.1.0"
num-derive = "0.3.3"
num-traits = "0.2.15"
once_cell = "1.16.0"
unroll = "0.1.5"

[dev-dependencies]
criterion = "0.5.1"
rand_chacha = "0.3.1"
hex-literal = "0.4.1"

[[bench]]
name = "delta_merkle_gadget"
harness = false


[features]
default = ["std"]
std = ["anyhow/std", "rand/std"]

[profile.release]
opt-level = 3
debug = true


[profile.bench]
opt-level = 3

[profile.test]
opt-level = 3

```

### src/main.rs

```rust
use actix_web::{web, App, HttpResponse, HttpServer, Responder};
use serde::Deserialize;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use uuid::Uuid;

use plonky2::{
    field::{extension::Extendable, goldilocks_field::GoldilocksField},
    hash::{hash_types::RichField, poseidon::PoseidonHash},
    iop::witness::PartialWitness,
    plonk::{
        circuit_builder::CircuitBuilder,
        circuit_data::{CircuitConfig, CircuitData},
        config::{AlgebraicHasher, GenericConfig, PoseidonGoldilocksConfig},
        proof::ProofWithPublicInputs,
    },
};
use plonky2_tree_hacks::{
    common::{
        hash::merkle::{
            gadgets::delta_merkle_proof::DeltaMerkleProofGadget,
            helpers::merkle_proof::DeltaMerkleProof,
        },
        u32::multiple_comparison::list_le_circuit,
        WHashOut,
    },
    utils::zmt::{
        node_store::simple_node_store::SimpleNodeStore, zero_merkle_tree::ZeroMerkleTree,
    },
};

pub struct BalanceUpdateGadget {
    pub sender_update: DeltaMerkleProofGadget,
    pub receiver_update: DeltaMerkleProofGadget,
}
pub struct BalanceUpdate<F: RichField> {
    pub sender_update: DeltaMerkleProof<F>,
    pub receiver_update: DeltaMerkleProof<F>,
}
impl BalanceUpdateGadget {
    pub fn add_virtual_to<H: AlgebraicHasher<F>, F: RichField + Extendable<D>, const D: usize>(
        builder: &mut CircuitBuilder<F, D>,
        tree_height: usize,
    ) -> Self {
        let sender_update = DeltaMerkleProofGadget::add_virtual_to::<H, F, D>(builder, tree_height);
        let receiver_update =
            DeltaMerkleProofGadget::add_virtual_to::<H, F, D>(builder, tree_height);

        let amount_recv = builder.sub(
            receiver_update.new_value.elements[0],
            receiver_update.old_value.elements[0],
        );
        let amount_send = builder.sub(
            sender_update.old_value.elements[0],
            sender_update.new_value.elements[0],
        );
        builder.connect(amount_recv, amount_send);

        let overflow_checks = list_le_circuit(
            builder,
            vec![
                receiver_update.old_value.elements[0],
                sender_update.new_value.elements[0],
            ],
            vec![
                receiver_update.new_value.elements[0],
                sender_update.old_value.elements[0],
            ],
            32,
        );
        let true_target = builder.one();
        builder.connect(overflow_checks.target, true_target);

        builder.connect_hashes(sender_update.new_root, receiver_update.old_root);
        Self {
            sender_update,
            receiver_update,
        }
    }
    pub fn set_witness_proof<F: RichField>(
        &self,
        witness: &mut PartialWitness<F>,
        input: &BalanceUpdate<F>,
    ) {
        self.sender_update
            .set_witness_proof(witness, &input.sender_update);
        self.receiver_update
            .set_witness_proof(witness, &input.receiver_update);
    }
}

pub struct UpdateBalanceCircuit<
    F: RichField + Extendable<D>,
    C: GenericConfig<D, F = F> + 'static,
    const D: usize,
> where
    <C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>,
{
    pub updates: Vec<BalanceUpdateGadget>,
    pub base_circuit_data: CircuitData<F, C, D>,
}

impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F> + 'static, const D: usize>
    UpdateBalanceCircuit<F, C, D>
where
    <C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>,
{
    pub fn new(number_updates: usize, tree_height: usize) -> Self {
        let config = CircuitConfig::standard_recursion_config();
        let mut builder = CircuitBuilder::<F, D>::new(config);
        let updates: Vec<BalanceUpdateGadget> = (0..number_updates)
            .map(|_| {
                BalanceUpdateGadget::add_virtual_to::<C::Hasher, F, D>(&mut builder, tree_height)
            })
            .collect();
        for i in 1..number_updates {
            builder.connect_hashes(
                updates[i - 1].receiver_update.new_root,
                updates[i].sender_update.old_root,
            );
        }
        builder.register_public_inputs(&updates[0].sender_update.old_root.elements);
        builder
            .register_public_inputs(&updates[updates.len() - 1].receiver_update.new_root.elements);
        let base_circuit_data = builder.build::<C>();
        Self {
            updates,
            base_circuit_data,
        }
    }
    pub fn prove(
        &self,
        proofs: &Vec<BalanceUpdate<F>>,
    ) -> anyhow::Result<ProofWithPublicInputs<F, C, D>> {
        let num_updates = self.updates.len();
        assert_eq!(proofs.len(), num_updates);
        let mut pw = PartialWitness::<F>::new();
        for i in 0..num_updates {
            self.updates[i].set_witness_proof(&mut pw, &proofs[i])
        }
        self.base_circuit_data.prove(pw)
    }
}
pub struct BalanceStorage {
    pub tree: ZeroMerkleTree<GoldilocksField, PoseidonHash, SimpleNodeStore>,
}

impl BalanceStorage {
    pub fn new(height: u8, start_balances: Vec<u32>) -> Self {
        let mut tree = ZeroMerkleTree::<GoldilocksField, PoseidonHash, SimpleNodeStore>::new(
            height,
            SimpleNodeStore::new(),
        );

        for (i, balance) in start_balances.iter().enumerate() {
            tree.set_leaf(i as u64, WHashOut::from_values((*balance) as u64, 0, 0, 0))
                .unwrap();
        }
        Self { tree }
    }
    pub fn get_balance(&self, index: u64) -> anyhow::Result<u32> {
        let balance_proof = self.tree.get_leaf(index)?;

        Ok(balance_proof.value.0.elements[0].0 as u32)
    }
    pub fn set_balance(
        &mut self,
        index: u64,
        value: u32,
    ) -> anyhow::Result<DeltaMerkleProof<GoldilocksField>> {
        let leaf_value = WHashOut::from_values(value as u64, 0, 0, 0);

        self.tree.set_leaf(index, leaf_value)
    }
    pub fn process_tx(
        &mut self,
        sender: u64,
        receiver: u64,
        amount: u3
[truncated — 8113 more characters]
```

### src/lib.rs

```rust

pub mod common;
pub mod utils;
pub mod debug;
extern crate alloc;

```

### src/challenge heuristic.rs

```rust
use web3::contract::{Contract, Options};
use web3::types::{Address, H256, U256};
use web3::Web3;
use web3::transports::Http;

use num_bigint::BigInt;
use sha3::{Digest, Keccak256};

#[tokio::main]
async fn main() -> web3::Result<()> {
    // Set up an HTTP transport layer.
    let http = Http::new("http://localhost:8545")?;
    let web3 = Web3::new(http);

    // Your contract's address here
    let contract_address = "YOUR_CONTRACT_ADDRESS_HERE";
    let address = Address::from_slice(&hex::decode(contract_address).unwrap());

    // Your contract's ABI here
    let contract_abi = include_str!("FiatShamirZKP.abi.json");

    // Create a contract instance
    let contract = Contract::from_json(
        web3.eth(),
        address,
        contract_abi.as_bytes(),
    )?;

    // Example of calling a constant function
    let result: U256 = contract.query("yourConstantFunction", (), None, Options::default(), None).await?;
    println!("Result: {}", result);

    // Example of sending a transaction to a non-constant function
    let tx = contract.call("yourNonConstantFunction", (param1, param2), "YOUR_WALLET_ADDRESS_HERE", Options::default()).await?;
    println!("Transaction Hash: {:?}", tx);

    Ok(())
}
```

### src/client.py

```python
import requests
import asyncio
import argparse


def list_proposals(base_url: str):
    response = requests.get(f"{base_url}/")
    print("List of proposals:")
    print(response.text)


def propose(base_url: str, proposer_id: int, statement: str):
    proposal_data = {"proposer_id": proposer_id, "statement": statement}
    response = requests.post(f"{base_url}/propose", json=proposal_data)
    print("Proposal submission response:")
    print(response.text)


def vote(base_url: str, proposal_id: str, voter_id: int, vote: int):
    vote_data = {"proposal_id": proposal_id,
                 "voter_id": voter_id, "is_yes": vote}
    response = requests.post(f"{base_url}/vote", json=vote_data)
    print("Voting response:")
    print(response.text)


def delegate(base_url: str, proposal_id: str, voter_id: int, delegator_id: int):
    delegate_data = {"proposal_id": proposal_id,
                     "voter_id": voter_id, "delegator_id": delegator_id}
    response = requests.post(f"{base_url}/delegate", json=delegate_data)
    print("Delegation response:")
    print(response.text)


def finalize(base_url: str, proposal_id: str, finalizer_id: int):
    finalize_data = {"proposal_id": proposal_id, 'finalizer_id': finalizer_id}
    response = requests.post(f"{base_url}/finalize", json=finalize_data)
    print("Finalize response:")
    print(response.text)


BASE_URL = "http://127.0.0.1:8080"

parser = argparse.ArgumentParser(
    prog='VotingClient',)
subparsers = parser.add_subparsers(dest='method', help='Subcommand help')

parser_vote = subparsers.add_parser('vote', help='vote help')
parser_vote.add_argument('proposal_id', type=str)
parser_vote.add_argument('voter_id', type=int)
parser_vote.add_argument('vote', type=int)

parser_delegate = subparsers.add_parser('delegate', help='delegate help')
parser_delegate.add_argument('proposal_id', type=str)
parser_delegate.add_argument('voter_id', type=int)
parser_delegate.add_argument('delegator_id', type=int)

parser_list_proposals = subparsers.add_parser('list')

parser_propose = subparsers.add_parser('propose', help='propose help')
parser_propose.add_argument('proposer_id', type=int)
parser_propose.add_argument('statement', type=str)

parser_finalize = subparsers.add_parser('finalize', help='finalize help')
parser_finalize.add_argument('proposal_id', type=str)
parser_finalize.add_argument('finalizer_id', type=int)


args = parser.parse_args()
if args.method == 'vote':
    vote(BASE_URL, args.proposal_id, args.voter_id, bool(args.vote))
elif args.method == 'propose':
    propose(BASE_URL, args.proposer_id, args.statement)
elif args.method == 'finalize':
    finalize(BASE_URL, args.proposal_id, args.finalizer_id)
elif args.method == 'list':
    list_proposals(BASE_URL)
elif args.method == 'delegate':
    delegate(BASE_URL, args.proposal_id, args.voter_id, args.delegator_id)

```

### benches/delta_merkle_gadget.rs

```rust
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use plonky2_tree_hacks::{utils::zmt::{zero_merkle_tree::ZeroMerkleTree, node_store::{core::ZMTNodeStore, simple_node_store::SimpleNodeStore}}, common::{hash::{traits::hasher::WHasher, merkle::{helpers::merkle_proof::DeltaMerkleProof, gadgets::delta_merkle_proof::DeltaMerkleProofGadget}}, WHashOut}};
use plonky2::{field::{goldilocks_field::GoldilocksField, extension::Extendable}, hash::{hash_types::RichField, poseidon::PoseidonHash}, plonk::{circuit_data::{CircuitData, CircuitConfig}, config::{GenericConfig, AlgebraicHasher, PoseidonGoldilocksConfig}, circuit_builder::CircuitBuilder, proof::ProofWithPublicInputs}, iop::witness::PartialWitness};
use rand::random;

fn gen_random_delta_merkle_proofs<F: RichField, H: WHasher<F>, S: ZMTNodeStore<F>>(tree: &mut ZeroMerkleTree<F, H, S>, count: usize) -> anyhow::Result<Vec<DeltaMerkleProof<F>>>{
    let mut proofs: Vec<DeltaMerkleProof<F>> = vec![];
    let max_leaves = tree.max_leaves();
    for _ in 0..count {
        let index = random::<u64>() % max_leaves;
        let value = WHashOut::<F>::rand();
        let proof = tree.set_leaf(index, value)?;
        proofs.push(proof);
    }
    Ok(proofs)
}

struct DeltaMerkleProofTestCircuit<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize> {
    pub data: CircuitData<F, C, D>,
    pub verify_gadgets: Vec<DeltaMerkleProofGadget>,
}
impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize> DeltaMerkleProofTestCircuit<F,C,D> {
    pub fn new<H: AlgebraicHasher<F>>(height: u8, num_proofs: usize)->Self {
        let config = CircuitConfig::standard_recursion_config();
        let mut builder = CircuitBuilder::<F, D>::new(config);
        let verify_gadgets: Vec<DeltaMerkleProofGadget> = (0..num_proofs).map(|_| {
            DeltaMerkleProofGadget::add_virtual_to::<H, F, D>(
                &mut builder,
                height as usize
            )
        }).collect();
        for i in 1..num_proofs {
            builder.connect_hashes(verify_gadgets[i-1].new_root, verify_gadgets[i].old_root);
        }
        builder.register_public_inputs(&verify_gadgets[0].old_root.elements);
        builder.register_public_inputs(&verify_gadgets[verify_gadgets.len()-1].new_root.elements);
        let data = builder.build::<C>();

        Self {
            data,
            verify_gadgets,
        }
    }
    pub fn prove(&self, proofs: &Vec<DeltaMerkleProof<F>>) -> anyhow::Result<ProofWithPublicInputs<F, C, D>> {
        let num_verify_gadgets = self.verify_gadgets.len();
        assert_eq!(proofs.len(), num_verify_gadgets);
        let mut pw = PartialWitness::<F>::new();
        for i in 0..num_verify_gadgets {
            self.verify_gadgets[i].set_witness_proof(&mut pw,&proofs[i])
        }
        self.data.prove(pw)
    }
    pub fn prove_and_verify(&self, proofs: &Vec<DeltaMerkleProof<F>>) -> anyhow::Result<()>{
        let proof = self.prove(proofs)?;
        self.data.verify(proof)?;
        Ok(())
    }
}

pub fn criterion_benchmark(c: &mut Criterion) {
    type F = GoldilocksField;
    type H = PoseidonHash;
    type S = SimpleNodeStore;
    type C = PoseidonGoldilocksConfig;
    const D: usize = 2;

    let num_proofs_per_circuit = 8;
    let tree_height = 32;

    let mut zmt = ZeroMerkleTree::<F, H, S>::new(tree_height, S::new());
    let proofs = gen_random_delta_merkle_proofs(&mut zmt, num_proofs_per_circuit).unwrap();
    
    let circuit = DeltaMerkleProofTestCircuit::<F, C, D>::new::<H>(tree_height, num_proofs_per_circuit);
    c.bench_function("prove", |b| b.iter(|| circuit.prove(black_box(&proofs))));
    c.bench_function("prove and verify", |b| b.iter(|| circuit.prove_and_verify(black_box(&proofs))));



    //c.bench_function("fib 20", |b| b.iter(|| fibonacci(black_box(20))));
}
 



criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);

```

### src/utils/mod.rs

```rust
pub mod zmt;

```

### src/debug/mod.rs

```rust
pub mod debug_timer;
```

### src/common/richer_field.rs

```rust
use plonky2::{hash::hash_types::RichField, field::goldilocks_field::GoldilocksField};


pub trait RicherField: RichField {
}
impl RicherField for GoldilocksField{}
```

### src/common/mod.rs

```rust
pub mod whashout;
pub use whashout::*;
pub mod u32;
pub mod hash;
pub mod builder;
pub mod verify;
pub mod base_types;
pub mod binaryhelpers;
pub mod generic;
pub mod richer_field;
```

[74 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]