improve workflow bash script, and update readme

This commit is contained in:
M Alghazwi 2025-06-17 12:43:53 +02:00
parent 3c3de2b26d
commit 35ee544e68
No known key found for this signature in database
GPG Key ID: 646E567CAD7DB607
22 changed files with 437 additions and 292 deletions

1
workflow/.gitignore vendored Normal file → Executable file
View File

@ -8,6 +8,7 @@ Cargo.lock
# Profile-guided optimization
/tmp
pgo-data.profdata
/output
# MacOS nuisances
.DS_Store

122
workflow/README.md Normal file → Executable file
View File

@ -10,20 +10,10 @@ This crate can be used to:
- Generate circuit input from **fake data** with given params.
- Build the Plonky2 codex storage proof circuits.
- Generate a proof with given proof input in JSON file.
- Aggregate multiple proofs with 2-to-1 tree like aggregation to generate a final proof.
- Aggregate multiple proofs with 2-to-1 tree like aggregation to generate a final proof (with optional compression).
- Wrapping proof with BN254 Poseidon Hash.
- Verify the proof.
## Code organization
- [`gen_input`](./src/bin/gen_input.rs) contains the main function to generate input with the given params as environment variables.
- [`build_circ`](./src/bin/build_circ.rs) contains the main function to build the storage proof (Sampling) circuits.
- [`prove`](./src/bin/prove.rs) contains the main function to generate a single proof.
- [`aggregate`](./src/bin/aggregate.rs) contains the main function to aggregate `k` (default = 4) proofs.
- [`verify`](./src/bin/verify) contains the main function to verify the storage proof (Sampling) proof.
- Wrap the proof with Gnark-plonky2-verifier to get a final succinct Groth16 proof.
## Usage
@ -43,11 +33,13 @@ To ensure that the nightly toolchain is used when building this crate, you can s
rustup override set nightly
```
- Go 1.22+ (for the GNARK-based verifier)
### Generate Circuit Input
The steps to generate circuit input with **fake data** are the following:
#### Step 1: Setting Up Parameters
Parameters for generating the circuit input can be defined in [`params.sh`](scripts/params.sh).
- Input params: parameters for generating the circuit input can be defined in [`params.sh`](scripts/params.sh).
You can customize the test parameters by setting the following environment variables:
```bash
@ -64,76 +56,54 @@ export NSLOTS=11 # Number of slots in the dataset
export SLOTINDEX=3 # Which slot to prove (0..NSLOTS-1)
export NCELLS=512 # Number of cells in this slot
```
#### Step 2: Run the Script
Once the params are set, you can run the script to generate the circuit input (with fake data).
- Circuit parameters: Edit [`circ_params.sh`](./scripts/circ_params.sh) for:
```bash
sudo bash ./scripts/gen_input.sh
```
export MAX_DEPTH=32 # maximum depth of the slot tree
export MAX_LOG2_N_SLOTS=8 # Depth of the dataset tree = ceiling_log2(max_slots)
export BLOCK_TREE_DEPTH=5 # depth of the mini tree (block tree)
export N_FIELD_ELEMS_PER_CELL=272 # number of field elements per cell
export N_SAMPLES=100 # number of samples to prove
### Build the Circuit
To build the circuit and measure the time to build, you can simply run the script:
export T=4 # number of proofs to aggregate
```
- GNARK-verifier params [`gnark_params.sh`](./scripts/gnark_params.sh):
```bash
sudo bash ./scripts/build_circuit.sh
export CIRCUIT_DIR="$BASE_DIR/../output/wrap/verifier_data"
export DATA_DIR="$BASE_DIR/../output/gnark_output"
export PROOF_SYSTEM="groth16"
export DUMMY="false"
```
To see the source code of how to build the circuit, see [`build_circ`](./src/bin/build_circ.rs).
### Generate the Proof
After generating the circuit input (in a JSON file), you can run the circuits to generate the proofs.
First make sure you have the circuit data and input from previous scripts then follow the steps:
#### Step 1: Setting Up Circuit Parameters
Parameters for the circuit can be defined in [`circ_params.sh`](scripts/circ_params.sh).
You can customize the test parameters by setting the following environment variables:
#### Step 2: Run the Rust CLI
All steps are unified under [`run_cli.sh`](./scripts/run_cli.sh) By default, it will run nothing until you specify the operations.
```bash
export MAX_DEPTH=32 # maximum depth of the slot tree
export MAX_LOG2_N_SLOTS=8 # Depth of the dataset tree = ceiling_log2(max_slots)
export BLOCK_TREE_DEPTH=5 # depth of the mini tree (block tree)
export N_FIELD_ELEMS_PER_CELL=272 # number of field elements per cell
export N_SAMPLES=100 # number of samples to prove
# Show help and list all available flags
./scripts/run_cli.sh -h
# Generate inputs, build, prove, aggregate, wrap & verify—all in one:
./scripts/run_cli.sh --all
# Or pick individual operations:
./scripts/run_cli.sh \
--gen-input \
--build \
--prove \
--aggregate \
--wrap-tree \
--verify-tree
```
#### Step 2: Run the Script
Once the params are set, you can run the script to generate the proof.
You can also see the time taken to generate the proof.
#### Step 3: Go/GNARK CLI workflow
To compile, prove, or verify wrapped Plonky2 circuits via GNARK, use:
```bash
sudo bash ./scripts/prove.sh
./scripts/run_gnark_cli.sh -h
# run all steps (compile, prove, verify) with defaults:
./scripts/run_gnark_cli.sh
# or individually:
./scripts/run_gnark_cli.sh --compile
./scripts/run_gnark_cli.sh --prove
./scripts/run_gnark_cli.sh --verify
```
### Verify the proof
To verify the generated proof, run the following script.
Make sure that you generate the circuit data and proof prior to this.
```bash
sudo bash ./scripts/verify.sh
```
### Build, Prove, and Verify
To automate the whole process, you can run the following script
the script builds the circuit, loads the JSON circuit input, generates the proof, and verifies it.
It also shows the time taken for each step.
Make sure that you generate the circuit input prior to this so that you have the [`JSON input file`](./input.json) and set the [`circ_params.sh`](scripts/circ_params.sh).
```bash
sudo bash ./scripts/prove_and_verify.sh
```
This script simply runs all previous scripts.
### Aggregate K Proofs
To do this, you can run the following script.
Note that we don't actually generate `K` proofs but rather just clone the single generated proof which is enough for testing.
Make sure a proof is already generated using the script for proving above.
```bash
sudo bash ./scripts/aggregate.sh
```
or the following if you want to specify the number of proofs to be aggregated
```bash
sudo bash ./scripts/aggregate.sh -- "$K_VALUE"
```

View File

@ -1,14 +0,0 @@
#!/bin/bash
# Source the parameters from the scripts directory
source "params.sh"
# Change to the parent directory of the script
cd "$(dirname "$0")/.." || { echo "Failed to change directory"; exit 1; }
# Build
cargo build --release || { echo "prove.sh: cargo build failed"; exit 101; }
# Run the Rust executable
K_VALUE=${1:-4}
cargo run --bin aggregate --features "parallel" -- "$K_VALUE" || { echo "prove.sh: cargo run failed"; exit 102; }

View File

@ -1,14 +0,0 @@
#!/bin/bash
# Source the parameters from the scripts directory
source "params.sh"
# Change to the parent directory of the script
cd "$(dirname "$0")/.." || { echo "Failed to change directory"; exit 1; }
# Build
cargo build --release || { echo "build_circuit.sh: cargo build failed"; exit 101; }
# Run the Rust executable
cargo run --bin build_circ --features "parallel" || { echo "build_circuit.sh: cargo run failed"; exit 102; }

View File

@ -4,4 +4,6 @@ export MAX_DEPTH=32 # maximum depth of the slot tree
export MAX_LOG2_N_SLOTS=8 # Depth of the dataset tree = ceiling_log2(max_slots)
export BLOCK_TREE_DEPTH=5 # depth of the mini tree (block tree)
export N_FIELD_ELEMS_PER_CELL=272 # number of field elements per cell
export N_SAMPLES=100 # number of samples to prove
export N_SAMPLES=100 # number of samples to prove
export T=4 # number of proofs to aggregate

View File

@ -1,13 +0,0 @@
#!/bin/bash
# Source the parameters from params.sh
source ./params.sh
# Change to the parent directory of the script
cd "$(dirname "$0")/.." || { echo "Failed to change directory"; exit 1; }
# Build
cargo build --release || { echo "gen_input.sh: cargo build failed"; exit 101; }
# Run the Rust executable
cargo run --bin gen_input --features "parallel" || { echo "gen_input.sh: cargo run failed"; exit 102; }

View File

@ -0,0 +1,8 @@
#!/usr/bin/env bash
# current dir
BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
export CIRCUIT_DIR="$BASE_DIR/../output/wrap/verifier_data"
export DATA_DIR="$BASE_DIR/../output/gnark_output"
export PROOF_SYSTEM="groth16"
export DUMMY="false"

View File

@ -1,13 +0,0 @@
#!/bin/bash
# Source the parameters from params.sh
source ./circ_params.sh
# Change to the parent directory of the script
cd "$(dirname "$0")/.." || { echo "Failed to change directory"; exit 1; }
# Build
cargo build --release || { echo "prove.sh: cargo build failed"; exit 101; }
# Run the Rust executable
cargo run --bin prove --features "parallel" || { echo "prove.sh: cargo run failed"; exit 102; }

View File

@ -1,42 +0,0 @@
#!/bin/bash
# Source the parameters
source ./params.sh
source ./circ_params.sh
# Change to the parent directory of the script
cd "$(dirname "$0")/.." || { echo "Failed to change directory"; exit 1; }
# Build
cargo build --release > /dev/null 2>&1 || { echo "prove_and_verify.sh: cargo build failed"; exit 101; }
# Run all steps
echo "START"
echo "Generating Input"
start=$(date +%s)
cargo run --bin gen_input --features "parallel" > /dev/null 2>&1 || { echo "gen_input.sh: cargo run failed"; exit 102; }
end=$(date +%s)
echo "Generating Input took $((end - start)) seconds."
echo "Building the circuit"
start=$(date +%s)
cargo run --bin build_circ --features "parallel" > /dev/null 2>&1 || { echo "build_circuit.sh: cargo run failed"; exit 102; }
end=$(date +%s)
echo "Building the circuit took $((end - start)) seconds."
echo "Generating a proof"
start=$(date +%s)
cargo run --bin prove --features "parallel" > /dev/null 2>&1 || { echo "prove.sh: cargo run failed"; exit 102; }
end=$(date +%s)
echo "Generating a proof took $((end - start)) seconds."
echo "Verifying the proof"
start=$(date +%s)
cargo run --bin verify --features "parallel" > /dev/null 2>&1 || { echo "verify.sh: cargo run failed"; exit 102; }
end=$(date +%s)
echo "Verifying the proof took $((end - start)) seconds."
echo "DONE"

98
workflow/scripts/run_cli.sh Executable file
View File

@ -0,0 +1,98 @@
#!/usr/bin/env bash
set -euo pipefail
# Load global and circuit-specific parameters
source "$(dirname "$0")/params.sh"
source "$(dirname "$0")/circ_params.sh"
usage() {
cat <<EOF
Usage: $(basename "$0") [OPTIONS]
OPTIONS:
--gen-input Generate witness inputs
--build Compile/build the circuit
--prove Run the prover
--aggregate Aggregate proofs
--aggregate-and-compress Aggregate proofs and compress
--wrap-sampling Wrap sampling proof
--wrap-tree Wrap tree proof
--wrap-compress Wrap compressed-tree proof
--verify-sampling Verify sampling proof
--verify-tree Verify tree proof
--verify-compressed Verify compressed-tree proof
--verify-wrapped Verify wrapped proof
--all Run the full pipeline in order
-h, --help Show this help and exit
EOF
exit 1
}
# operation flags
DO_GEN=false DO_BUILD=false DO_PROVE=false DO_AGG=false DO_AGG_COMP=false
DO_WRAP_SAMP=false DO_WRAP_TREE=false DO_WRAP_COMP=false
DO_VER_SAMP=false DO_VER_TREE=false DO_VER_COMP=false DO_VER_WRAP=false
# parse args
while [[ $# -gt 0 ]]; do
case $1 in
--gen-input) DO_GEN=true; shift ;;
--build) DO_BUILD=true; shift ;;
--prove) DO_PROVE=true; shift ;;
--aggregate) DO_AGG=true; shift ;;
--aggregate-and-compress) DO_AGG_COMP=true; shift ;;
--wrap-sampling) DO_WRAP_SAMP=true; shift ;;
--wrap-tree) DO_WRAP_TREE=true; shift ;;
--wrap-compress) DO_WRAP_COMP=true; shift ;;
--verify-sampling) DO_VER_SAMP=true; shift ;;
--verify-tree) DO_VER_TREE=true; shift ;;
--verify-compressed) DO_VER_COMP=true; shift ;;
--verify-wrapped) DO_VER_WRAP=true; shift ;;
--all)
DO_GEN=true; DO_BUILD=true; DO_PROVE=true
DO_AGG=true;
DO_WRAP_TREE=true;
DO_VER_SAMP=true; DO_VER_TREE=true; DO_VER_WRAP=true
shift
;;
-h|--help) usage ;;
*) echo "Unknown option: $1"; usage ;;
esac
done
# If nothing selected, show help
if ! $DO_GEN && ! $DO_BUILD && ! $DO_PROVE && ! $DO_AGG && ! $DO_AGG_COMP \
&& ! $DO_WRAP_SAMP && ! $DO_WRAP_TREE && ! $DO_WRAP_COMP \
&& ! $DO_VER_SAMP && ! $DO_VER_TREE && ! $DO_VER_COMP && ! $DO_VER_WRAP; then
echo "No stages selected."
usage
fi
# Ensure the Rust binary is built
echo "[build] Compiling Rust CLI…"
cargo build --release --features parallel
# run a named subcommand
run_cmd() {
local name=$1
local cmd=$2
echo "[$name] Starting"
echo "[run] $name"
cargo run -q --release --features parallel -- $cmd #> /dev/null
echo "[$name] Completed"
}
$DO_GEN && run_cmd "GenInput" gen-input
$DO_BUILD && run_cmd "Build" build
$DO_PROVE && run_cmd "Prove" prove
$DO_AGG && run_cmd "Aggregate" aggregate
$DO_AGG_COMP && run_cmd "AggregateAndCompress" aggregate-and-compress
$DO_WRAP_SAMP && run_cmd "WrapSampling" wrap
$DO_WRAP_TREE && run_cmd "WrapTree" wrap-tree
$DO_WRAP_COMP && run_cmd "WrapCompress" wrap-compress
$DO_VER_SAMP && run_cmd "VerifySampling" verify
$DO_VER_TREE && run_cmd "VerifyTree" verify-tree
$DO_VER_COMP && run_cmd "VerifyCompressed" verify-compressed
$DO_VER_WRAP && run_cmd "VerifyWrapped" verify-wrapped
echo "All requested steps done."

View File

@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -euo pipefail
# script to invoke run_gnark_cli.sh
# path to this directory
WRAPPER_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Path to run_gnark_cli.sh
SCRIPT="$WRAPPER_DIR/../../gnark-wrapper/run_gnark_cli.sh"
if [[ ! -x "$SCRIPT" ]]; then
echo "Error: Cannot find or execute run_gnark_cli.sh at $SCRIPT" >&2
exit 1
fi
# params file in current working directory
PARAMS_FILE="$(pwd)/gnark_params.sh"
if [[ ! -f "$PARAMS_FILE" ]]; then
echo "Error: params.sh not found in current directory ($PARAMS_FILE)" >&2
exit 1
fi
# Save CWD and switch into gnark-wrapper directory
TARGET_DIR="$(dirname "$SCRIPT")"
cd "$TARGET_DIR"
# Build and run the command
cmd=("$SCRIPT" -P "$PARAMS_FILE" "$@")
echo "Running in $TARGET_DIR: ${cmd[*]}"
exec "${cmd[@]}"

View File

@ -1,13 +0,0 @@
#!/bin/bash
# Source the parameters from params.sh
source ./circ_params.sh
# Change to the parent directory of the script
cd "$(dirname "$0")/.." || { echo "Failed to change directory"; exit 1; }
# Build
cargo build --release || { echo "prove.sh: cargo build failed"; exit 101; }
# Run the Rust executable
cargo run --bin verify --features "parallel" || { echo "prove.sh: cargo run failed"; exit 102; }

76
workflow/src/aggregate.rs Executable file
View File

@ -0,0 +1,76 @@
use std::env;
use std::time::Instant;
use anyhow::{Context, Result};
use plonky2::plonk::proof::ProofWithPublicInputs;
use codex_plonky2_circuits::recursion::tree::TreeRecursion;
use proof_input::params::{D, C, F, HF};
use codex_plonky2_circuits::serialization::{export_proof_with_pi, export_verifier_circuit_data, import_proof_with_pi, import_verifier_circuit_data};
use crate::file_paths::{SAMPLING_CIRC_BASE_PATH, TREE_CIRC_BASE_PATH, COMPRESS_CIRC_BASE_PATH};
pub fn run(compress: bool) -> Result<()> {
// load the parameters from environment variables
const N: usize = 2;
// take k = "number of proofs" from env
let t: usize = env::var("T")
.context("T not set")?
.parse::<usize>()
.context("Invalid T")?;
match t {
2 => run_tree::<N,2>(compress)?,
4 => run_tree::<N, 4>(compress)?,
8 => run_tree::<N, 8>(compress)?,
16 => run_tree::<N, 16>(compress)?,
32 => run_tree::<N, 32>(compress)?,
64 => run_tree::<N, 64>(compress)?,
128 => run_tree::<N, 128>(compress)?,
256 => run_tree::<N, 256>(compress)?,
512 => run_tree::<N, 512>(compress)?,
1024 => run_tree::<N, 1024>(compress)?,
other => panic!("unsupported proof count: {}", other),
}
Ok(())
}
fn run_tree<const N: usize, const T: usize>(compress: bool) -> Result<()> {
let circuit_path = SAMPLING_CIRC_BASE_PATH;
// Read the proof
let proof_with_pi = import_proof_with_pi::<F,C,D,_>(circuit_path)?;
println!("Proof with public input imported from: {}", circuit_path);
// read the circuit data
let verifier_data = import_verifier_circuit_data::<F,C,D,_>(circuit_path)?;
println!("Verifier circuit data imported from: {}", circuit_path);
// duplicate the proof to get k proofs
// this is just for testing - in real scenario we would need to load k proofs
let proofs: Vec<ProofWithPublicInputs<F, C, D>> = (0..T).map(|_i| proof_with_pi.clone()).collect();
let start_time = Instant::now();
let mut tree = TreeRecursion::<F,D,C,HF, N, T>::build_with_standard_config(verifier_data.clone()).unwrap();
println!("build tree time: {:?}", start_time.elapsed());
let start_time = Instant::now();
let tree_proof = if !compress {
tree.prove_tree(&proofs)?
} else { tree.prove_tree_and_compress(&proofs)? };
println!("aggregate time: {:?}", start_time.elapsed());
//export the proof to json file
let dis_path = if !compress {TREE_CIRC_BASE_PATH} else { COMPRESS_CIRC_BASE_PATH };
export_proof_with_pi(&tree_proof, dis_path)?;
println!("Tree proof written to: {}", dis_path);
let node_ver_data = tree.get_node_verifier_data();
export_verifier_circuit_data(node_ver_data, TREE_CIRC_BASE_PATH)?;
let compression_ver_data = tree.get_compression_verifier_data();
export_verifier_circuit_data(compression_ver_data, COMPRESS_CIRC_BASE_PATH)?;
let inner_pi: Vec<Vec<F>> = proofs.iter().map(|p| p.public_inputs.clone()).collect();
assert!(tree.verify_proof_and_public_input(tree_proof,inner_pi.clone(),compress).is_ok());
Ok(())
}

View File

@ -1,59 +0,0 @@
use std::env;
use anyhow::Result;
use plonky2::plonk::proof::ProofWithPublicInputs;
use codex_plonky2_circuits::recursion::tree::TreeRecursion;
use proof_input::params::{D, C, F, HF};
use proof_input::serialization::file_paths::{PROOF_JSON, TREE_PROOF_JSON, VERIFIER_CIRC_DATA_JSON};
use proof_input::serialization::json::{export_tree_proof_with_pi, import_proof_with_pi, import_verifier_circuit_data};
fn main() -> Result<()> {
// load the parameters from environment variables
const N: usize = 2;
// take k = "number of proofs" from env arguments; default to 4 if not there
let args: Vec<String> = env::args().collect();
let t: usize = args.get(1).and_then(|s| s.parse().ok()).unwrap_or(4);
match t {
2 => run_tree::<N,2>()?,
4 => run_tree::<N, 4>()?,
8 => run_tree::<N, 8>()?,
16 => run_tree::<N, 16>()?,
32 => run_tree::<N, 32>()?,
64 => run_tree::<N, 64>()?,
128 => run_tree::<N, 128>()?,
256 => run_tree::<N, 256>()?,
512 => run_tree::<N, 512>()?,
1024 => run_tree::<N, 1024>()?,
other => panic!("unsupported proof count: {}", other),
}
Ok(())
}
fn run_tree<const N: usize, const T: usize>() -> Result<()> {
// Read the proof
let proof_with_pi = import_proof_with_pi::<F,C,D>()?;
println!("Proof with public input imported from: {}", PROOF_JSON);
// read the circuit data
let verifier_data = import_verifier_circuit_data::<F,C,D>()?;
println!("Verifier circuit data imported from: {}", VERIFIER_CIRC_DATA_JSON);
// duplicate the proof to get k proofs
// this is just for testing - in real scenario we would need to load k proofs
let proofs: Vec<ProofWithPublicInputs<F, C, D>> = (0..T).map(|_i| proof_with_pi.clone()).collect();
let mut tree = TreeRecursion::<F,D,C,HF, N, T>::build_with_standard_config(verifier_data.clone()).unwrap();
let tree_proof = tree.prove_tree_and_compress(&proofs).unwrap();
//export the proof to json file
export_tree_proof_with_pi(&tree_proof)?;
println!("Tree proof written to: {}", TREE_PROOF_JSON);
let inner_pi: Vec<Vec<F>> = proofs.iter().map(|p| p.public_inputs.clone()).collect();
assert!(tree.verify_proof_and_public_input(tree_proof,inner_pi.clone(),false).is_ok());
Ok(())
}

View File

@ -1,23 +0,0 @@
use std::time::Instant;
use anyhow::Result;
use proof_input::params::{D, C, F};
use proof_input::serialization::file_paths::{PROOF_JSON, VERIFIER_CIRC_DATA_JSON};
use proof_input::serialization::json::{import_proof_with_pi, import_verifier_circuit_data};
fn main() -> Result<()> {
// read the circuit data
let verifier_data = import_verifier_circuit_data::<F,C,D>()?;
println!("Verifier circuit data imported from: {}", VERIFIER_CIRC_DATA_JSON);
// Read the proof
let proof_with_pi = import_proof_with_pi::<F,C,D>()?;
println!("Proof with public input imported from: {}", PROOF_JSON);
// verify the proof
let start_time = Instant::now();
assert!(verifier_data.verify(proof_with_pi).is_ok(), "proof is NOT VALID");
println!("Verifying time: {:?}", start_time.elapsed());
Ok(())
}

51
workflow/src/bn254_wrap.rs Executable file
View File

@ -0,0 +1,51 @@
use std::time::Instant;
use anyhow::Result;
use codex_plonky2_circuits::bn254_wrapper::config::PoseidonBN254GoldilocksConfig;
use codex_plonky2_circuits::bn254_wrapper::wrap::{WrapCircuit, WrapInput, WrappedOutput};
use codex_plonky2_circuits::circuit_helper::Plonky2Circuit;
use codex_plonky2_circuits::serialization::{export_verifier_circuit_data, import_proof_with_pi, import_verifier_circuit_data};
use proof_input::params::{D, C, F};
use crate::file_paths::WRAP_CIRC_BASE_PATH;
type OuterParameters = PoseidonBN254GoldilocksConfig;
pub fn run(circuit_path: &str) -> Result<()> {
// Read the proof
let proof_with_pi = import_proof_with_pi::<F,C,D,_>(&circuit_path)?;
println!("Proof with public input imported from: {}", &circuit_path);
// read the circuit data
let verifier_data = import_verifier_circuit_data::<F,C,D,_>(&circuit_path)?;
println!("Verifier circuit data imported from: {}", &circuit_path);
let wrapper = WrapCircuit::<F,D,C,OuterParameters>::new(verifier_data);
let (targ, data) = wrapper.build_with_standard_config().unwrap();
println!(
"wrapper circuit degree: {}",
data.common.degree_bits()
);
let verifier_data = data.verifier_data();
let prover_data = data.prover_data();
let wrap_input = WrapInput{
inner_proof: proof_with_pi,
};
let start_time = Instant::now();
let proof = wrapper.prove(&targ, &wrap_input,&prover_data).unwrap();
println!("Wrap time: {:?}", start_time.elapsed());
let wrap_circ = WrappedOutput::<F, OuterParameters,D>{
proof,
common_data: verifier_data.common.clone(),
verifier_data: verifier_data.verifier_only.clone(),
};
// export the circuit data
export_verifier_circuit_data::<F,OuterParameters,D, _>(verifier_data, WRAP_CIRC_BASE_PATH)?;
println!("all data written to {}", WRAP_CIRC_BASE_PATH);
wrap_circ.save(WRAP_CIRC_BASE_PATH).unwrap();
println!("Saved wrapped circuit");
Ok(())
}

View File

@ -2,12 +2,12 @@ use std::time::Instant;
use anyhow::Result;
use codex_plonky2_circuits::circuit_helper::Plonky2Circuit;
use codex_plonky2_circuits::circuits::sample_cells::SampleCircuit;
use proof_input::serialization::json::export_circuit_data;
use codex_plonky2_circuits::serialization::export_circuit_data;
use proof_input::params::Params;
use proof_input::params::{D, C, F,HF};
use proof_input::serialization::file_paths::{PROVER_CIRC_DATA_JSON, TARGETS_JSON, VERIFIER_CIRC_DATA_JSON};
use crate::file_paths::SAMPLING_CIRC_BASE_PATH;
fn main() -> Result<()> {
pub fn run() -> Result<()> {
// Load the parameters from environment variables
let params = Params::from_env()?;
@ -20,10 +20,8 @@ fn main() -> Result<()> {
println!("Circuit size (degree bits): {:?}", data.common.degree_bits());
// export the circuit data
export_circuit_data::<F,C,D>(data, &targets)?;
println!("Prover Data written to {}", PROVER_CIRC_DATA_JSON);
println!("Verifier Data written to {}", VERIFIER_CIRC_DATA_JSON);
println!("Targets written to {}", TARGETS_JSON);
export_circuit_data::<F,C,D, _>(data, &targets, SAMPLING_CIRC_BASE_PATH)?;
println!("all data written to {}", SAMPLING_CIRC_BASE_PATH);
Ok(())
}

4
workflow/src/file_paths.rs Executable file
View File

@ -0,0 +1,4 @@
pub(crate) const SAMPLING_CIRC_BASE_PATH: &str = "../output/sampling_circuit/";
pub(crate) const TREE_CIRC_BASE_PATH: &str = "../output/tree/";
pub(crate) const COMPRESS_CIRC_BASE_PATH: &str = "../output/compression/";
pub(crate) const WRAP_CIRC_BASE_PATH: &str = "../output/wrap/";

View File

@ -4,9 +4,9 @@ use proof_input::serialization::circuit_input::export_circ_input_to_json;
use proof_input::gen_input::gen_testing_circuit_input;
use proof_input::params::Params;
use proof_input::params::{D, F};
use proof_input::serialization::file_paths::CIRC_INPUT_JSON;
use crate::file_paths::SAMPLING_CIRC_BASE_PATH;
fn main() -> Result<()> {
pub fn run() -> Result<()> {
// Load the parameters from environment variables
let params = Params::from_env()?;
@ -16,8 +16,8 @@ fn main() -> Result<()> {
println!("Generating input time: {:?}", start_time.elapsed());
// export circuit parameters to json file
export_circ_input_to_json(circ_input)?;
println!("proof input written to {}", CIRC_INPUT_JSON);
export_circ_input_to_json(circ_input, SAMPLING_CIRC_BASE_PATH)?;
println!("proof input written to {}", SAMPLING_CIRC_BASE_PATH);
Ok(())
}

71
workflow/src/main.rs Executable file
View File

@ -0,0 +1,71 @@
use anyhow::Result;
use clap::{Parser, Subcommand};
use codex_plonky2_circuits::bn254_wrapper::config::PoseidonBN254GoldilocksConfig;
use crate::file_paths::{COMPRESS_CIRC_BASE_PATH, SAMPLING_CIRC_BASE_PATH, TREE_CIRC_BASE_PATH, WRAP_CIRC_BASE_PATH};
use proof_input::params::C;
type OuterParameters = PoseidonBN254GoldilocksConfig;
mod build_circ;
mod prove;
mod verify;
mod gen_input;
mod aggregate;
mod bn254_wrap;
mod file_paths;
/// Codex_zk_cli: unified CLI for all zk operations
#[derive(Parser)]
#[command(name = "codex_zk_cli", version, about = "gen_input, build, prove, aggregate, wrap, verify")]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
/// Generate witness inputs
GenInput,
/// build the circuit
Build,
/// Run the prover
Prove,
/// Aggregate proofs
Aggregate,
/// Aggregate and compress proofs
AggregateAndCompress,
/// Wrap sampling proof
Wrap,
/// Wrap aggregated tree proof
WrapTree,
/// Wrap compressed proof
WrapCompress,
/// Verify a sampling proof
Verify,
/// Verify a tree proof
VerifyTree,
/// Verify a compressed tree proof
VerifyCompressed,
/// Verify a wrapped proof
VerifyWrapped,
}
fn main() -> Result<()> {
let cli = Cli::parse();
match cli.command {
Commands::GenInput => gen_input::run()?,
Commands::Build => build_circ::run()?,
Commands::Prove => prove::run()?,
Commands::Aggregate => aggregate::run(false)?,
Commands::AggregateAndCompress => aggregate::run(true)?,
Commands::Wrap => bn254_wrap::run(SAMPLING_CIRC_BASE_PATH)?,
Commands::WrapTree => bn254_wrap::run(TREE_CIRC_BASE_PATH)?,
Commands::WrapCompress => bn254_wrap::run(COMPRESS_CIRC_BASE_PATH)?,
Commands::Verify => verify::run::<C>(SAMPLING_CIRC_BASE_PATH)?,
Commands::VerifyTree => verify::run::<C>(TREE_CIRC_BASE_PATH)?,
Commands::VerifyCompressed => verify::run::<C>(COMPRESS_CIRC_BASE_PATH)?,
Commands::VerifyWrapped => verify::run::<OuterParameters>(WRAP_CIRC_BASE_PATH)?,
}
Ok(())
}

25
workflow/src/bin/prove.rs → workflow/src/prove.rs Normal file → Executable file
View File

@ -1,28 +1,27 @@
use anyhow::Result;
use std::time::Instant;
use codex_plonky2_circuits::circuit_helper::Plonky2Circuit;
use proof_input::serialization::circuit_input::import_circ_input_from_json;
use proof_input::serialization::circuit_input::{import_circ_input_from_json};
use codex_plonky2_circuits::circuits::sample_cells::{SampleCircuit, SampleCircuitInput, SampleTargets};
use codex_plonky2_circuits::circuits::params::CircuitParams;
use proof_input::params::{D, C, F, HF};
use proof_input::serialization::file_paths::{CIRC_INPUT_JSON, PROVER_CIRC_DATA_JSON, TARGETS_JSON, TREE_PROOF_JSON};
use proof_input::serialization::json::{export_proof_with_pi, import_prover_circuit_data, import_targets};
fn main() -> Result<()> {
use codex_plonky2_circuits::serialization::{export_proof_with_pi, import_prover_circuit_data, import_targets};
use crate::file_paths::SAMPLING_CIRC_BASE_PATH;
pub fn run() -> Result<()> {
// Load the parameters from environment variables
let circuit_params = CircuitParams::from_env()?;
// Read the witness from input.json
let circ_input: SampleCircuitInput<F, D> = import_circ_input_from_json()?;
println!("Witness imported from: {}", CIRC_INPUT_JSON);
let circ_input: SampleCircuitInput<F, D> = import_circ_input_from_json(SAMPLING_CIRC_BASE_PATH)?;
println!("Witness imported from: {}", SAMPLING_CIRC_BASE_PATH);
// read the targets
let circ_targets: SampleTargets = import_targets()?;
println!("circuit targets imported from: {}", TARGETS_JSON);
let circ_targets: SampleTargets = import_targets(SAMPLING_CIRC_BASE_PATH)?;
println!("circuit targets imported from: {}", SAMPLING_CIRC_BASE_PATH);
// read the circuit data
let prover_data = import_prover_circuit_data::<F,C,D>()?;
println!("Prover circuit data imported from: {}", PROVER_CIRC_DATA_JSON);
let prover_data = import_prover_circuit_data::<F,C,D,_>(SAMPLING_CIRC_BASE_PATH)?;
println!("Prover circuit data imported from: {}", SAMPLING_CIRC_BASE_PATH);
println!("Circuit size (degree bits): {:?}", prover_data.common.degree_bits());
// Prove the circuit with the assigned witness
@ -32,8 +31,8 @@ fn main() -> Result<()> {
println!("Proving time: {:?}", start_time.elapsed());
//export the proof to json file
export_proof_with_pi(&proof_with_pis)?;
println!("Tree proof written to: {}", TREE_PROOF_JSON);
export_proof_with_pi(&proof_with_pis, SAMPLING_CIRC_BASE_PATH)?;
println!("proof written to: {}", SAMPLING_CIRC_BASE_PATH);
Ok(())
}

27
workflow/src/verify.rs Executable file
View File

@ -0,0 +1,27 @@
use std::time::Instant;
use anyhow::Result;
use plonky2::plonk::config::GenericConfig;
use serde::Serialize;
use proof_input::params::{D, F};
use codex_plonky2_circuits::serialization::{import_proof_with_pi, import_verifier_circuit_data};
pub fn run<
// F: RichField + Extendable<D> + Poseidon2 + Serialize,
C: GenericConfig<D, F = F> + Serialize,
>(circuit_path: &str) -> Result<()> {
// read the circuit data
let verifier_data = import_verifier_circuit_data::<F,C,D,_>(circuit_path)?;
println!("Verifier circuit data imported from: {}", circuit_path);
// Read the proof
let proof_with_pi = import_proof_with_pi::<F,C,D,_>(circuit_path)?;
println!("Proof with public input imported from: {}", circuit_path);
// verify the proof
let start_time = Instant::now();
assert!(verifier_data.verify(proof_with_pi).is_ok(), "proof is NOT VALID");
println!("Verifying time: {:?}", start_time.elapsed());
Ok(())
}