mirror of
https://github.com/logos-storage/proof-aggregation.git
synced 2026-01-02 13:53:13 +00:00
add wrap test
This commit is contained in:
parent
c9224bf48f
commit
7948d6538d
0
proof-input/.gitignore
vendored
Normal file → Executable file
0
proof-input/.gitignore
vendored
Normal file → Executable file
0
proof-input/Cargo.toml
Normal file → Executable file
0
proof-input/Cargo.toml
Normal file → Executable file
0
proof-input/README.md
Normal file → Executable file
0
proof-input/README.md
Normal file → Executable file
0
proof-input/src/data_structs.rs
Normal file → Executable file
0
proof-input/src/data_structs.rs
Normal file → Executable file
0
proof-input/src/gen_input.rs
Normal file → Executable file
0
proof-input/src/gen_input.rs
Normal file → Executable file
0
proof-input/src/lib.rs
Normal file → Executable file
0
proof-input/src/lib.rs
Normal file → Executable file
0
proof-input/src/merkle_tree/key_compress.rs
Normal file → Executable file
0
proof-input/src/merkle_tree/key_compress.rs
Normal file → Executable file
0
proof-input/src/merkle_tree/merkle_circuit.rs
Normal file → Executable file
0
proof-input/src/merkle_tree/merkle_circuit.rs
Normal file → Executable file
0
proof-input/src/merkle_tree/merkle_safe.rs
Normal file → Executable file
0
proof-input/src/merkle_tree/merkle_safe.rs
Normal file → Executable file
0
proof-input/src/merkle_tree/mod.rs
Normal file → Executable file
0
proof-input/src/merkle_tree/mod.rs
Normal file → Executable file
0
proof-input/src/merkle_tree/test.rs
Normal file → Executable file
0
proof-input/src/merkle_tree/test.rs
Normal file → Executable file
10
proof-input/src/params.rs
Normal file → Executable file
10
proof-input/src/params.rs
Normal file → Executable file
@ -1,7 +1,7 @@
|
|||||||
// params for generating input for proof circuit
|
// params for generating input for proof circuit
|
||||||
|
|
||||||
// use plonky2::hash::poseidon::PoseidonHash;
|
use plonky2::hash::poseidon::PoseidonHash;
|
||||||
// use plonky2::plonk::config::PoseidonGoldilocksConfig;
|
use plonky2::plonk::config::PoseidonGoldilocksConfig;
|
||||||
use plonky2::plonk::config::GenericConfig;
|
use plonky2::plonk::config::GenericConfig;
|
||||||
use std::env;
|
use std::env;
|
||||||
use anyhow::{Result, Context};
|
use anyhow::{Result, Context};
|
||||||
@ -11,9 +11,11 @@ use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2Hash;
|
|||||||
|
|
||||||
// test types
|
// test types
|
||||||
pub const D: usize = 2;
|
pub const D: usize = 2;
|
||||||
pub type C = Poseidon2GoldilocksConfig;
|
pub type C = PoseidonGoldilocksConfig;
|
||||||
|
pub type C2 = Poseidon2GoldilocksConfig;
|
||||||
pub type F = <C as GenericConfig<D>>::F; // this is the goldilocks field
|
pub type F = <C as GenericConfig<D>>::F; // this is the goldilocks field
|
||||||
pub type HF = Poseidon2Hash;
|
pub type HF = PoseidonHash;
|
||||||
|
pub type HF2 = Poseidon2Hash;
|
||||||
|
|
||||||
// hardcoded default params for generating proof input
|
// hardcoded default params for generating proof input
|
||||||
const DEFAULT_MAX_DEPTH: usize = 32; // depth of big tree (slot tree depth, includes block tree depth)
|
const DEFAULT_MAX_DEPTH: usize = 32; // depth of big tree (slot tree depth, includes block tree depth)
|
||||||
|
|||||||
0
proof-input/src/recursion/leaf_test.rs
Normal file → Executable file
0
proof-input/src/recursion/leaf_test.rs
Normal file → Executable file
1
proof-input/src/recursion/mod.rs
Normal file → Executable file
1
proof-input/src/recursion/mod.rs
Normal file → Executable file
@ -8,6 +8,7 @@ use crate::params::{C, D, F, HF, Params};
|
|||||||
pub mod tree_test;
|
pub mod tree_test;
|
||||||
pub mod leaf_test;
|
pub mod leaf_test;
|
||||||
pub mod node_test;
|
pub mod node_test;
|
||||||
|
pub mod wrap_test;
|
||||||
|
|
||||||
|
|
||||||
pub fn run_sampling_circ() -> anyhow::Result<(ProofWithPublicInputs<F, C, D>, ProverCircuitData<F, C, D>, VerifierCircuitData<F, C, D>)> {
|
pub fn run_sampling_circ() -> anyhow::Result<(ProofWithPublicInputs<F, C, D>, ProverCircuitData<F, C, D>, VerifierCircuitData<F, C, D>)> {
|
||||||
|
|||||||
0
proof-input/src/recursion/node_test.rs
Normal file → Executable file
0
proof-input/src/recursion/node_test.rs
Normal file → Executable file
0
proof-input/src/recursion/tree_test.rs
Normal file → Executable file
0
proof-input/src/recursion/tree_test.rs
Normal file → Executable file
117
proof-input/src/recursion/wrap_test.rs
Executable file
117
proof-input/src/recursion/wrap_test.rs
Executable file
@ -0,0 +1,117 @@
|
|||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use plonky2::field::types::Field;
|
||||||
|
use plonky2::gates::noop::NoopGate;
|
||||||
|
use plonky2::iop::witness::{PartialWitness, WitnessWrite};
|
||||||
|
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||||
|
use plonky2::plonk::circuit_data::{CircuitConfig, VerifierCircuitData};
|
||||||
|
use plonky2::plonk::proof::ProofWithPublicInputs;
|
||||||
|
use codex_plonky2_circuits::bn254_wrapper::config::PoseidonBN254GoldilocksConfig;
|
||||||
|
use codex_plonky2_circuits::bn254_wrapper::wrap::{WrapCircuit, WrapInput};
|
||||||
|
use codex_plonky2_circuits::circuit_helper::Plonky2Circuit;
|
||||||
|
use codex_plonky2_circuits::recursion::tree::TreeRecursion;
|
||||||
|
use crate::params::{D, C, F, HF};
|
||||||
|
use crate::recursion::run_sampling_circ;
|
||||||
|
|
||||||
|
type OuterParameters = PoseidonBN254GoldilocksConfig;
|
||||||
|
|
||||||
|
fn bn254_wrap(proof: ProofWithPublicInputs<F, C, D>, vd: VerifierCircuitData<F, C, D>) -> anyhow::Result<()>{
|
||||||
|
// wrap this in the outer circuit.
|
||||||
|
let wrapper = WrapCircuit::<F,D,C,OuterParameters>::new(vd);
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
let proof = wrapper.prove(&targ, &wrap_input,&prover_data).unwrap();
|
||||||
|
|
||||||
|
assert!(verifier_data.verify(proof).is_ok());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dummy_wrap() -> anyhow::Result<()>{
|
||||||
|
|
||||||
|
let conf = CircuitConfig::standard_recursion_config();
|
||||||
|
let mut builder = CircuitBuilder::<F, D>::new(conf);
|
||||||
|
|
||||||
|
for _ in 0..(4096+10) {
|
||||||
|
builder.add_gate(NoopGate, vec![]);
|
||||||
|
}
|
||||||
|
// Add one virtual public input so that the circuit has minimal structure.
|
||||||
|
let t = builder.add_virtual_public_input();
|
||||||
|
|
||||||
|
// Set up the dummy circuit and wrapper.
|
||||||
|
let dummy_circuit = builder.build::<C>();
|
||||||
|
let mut pw = PartialWitness::new();
|
||||||
|
pw.set_target(t, F::ZERO).expect("faulty assign");
|
||||||
|
println!(
|
||||||
|
"dummy circuit degree: {}",
|
||||||
|
dummy_circuit.common.degree_bits()
|
||||||
|
);
|
||||||
|
let dummy_inner_proof = dummy_circuit.prove(pw).unwrap();
|
||||||
|
assert!(dummy_circuit.verify(dummy_inner_proof.clone()).is_ok());
|
||||||
|
println!("Verified dummy_circuit");
|
||||||
|
|
||||||
|
// wrap this in the outer circuit.
|
||||||
|
bn254_wrap(dummy_inner_proof, dummy_circuit.verifier_data())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_tree_recursion<const N: usize, const T: usize>(compress: bool) -> anyhow::Result<()> {
|
||||||
|
|
||||||
|
//------------ sampling inner circuit ----------------------
|
||||||
|
// Circuit that does the sampling - 100 samples
|
||||||
|
let (inner_proof, inner_prover_data, inner_verifier_data) = run_sampling_circ()?;
|
||||||
|
|
||||||
|
let proofs: Vec<ProofWithPublicInputs<F, C, D>> = (0..T).map(|_i| inner_proof.clone()).collect();
|
||||||
|
|
||||||
|
// ------------------- tree --------------------
|
||||||
|
// N-to-1 tree aggregation
|
||||||
|
|
||||||
|
let mut tree = TreeRecursion::<F, D,C,HF, N, T>::build_with_standard_config(inner_verifier_data.clone())?;
|
||||||
|
|
||||||
|
// aggregate
|
||||||
|
let root = if !compress {
|
||||||
|
tree.prove_tree(&proofs)?
|
||||||
|
} else {
|
||||||
|
println!("Mode: tree with compression");
|
||||||
|
tree.prove_tree_and_compress(&proofs)?
|
||||||
|
};
|
||||||
|
println!("pub input size = {}", root.public_inputs.len());
|
||||||
|
println!("pub input = {:?}", root.public_inputs);
|
||||||
|
println!("proof size = {:?} bytes", root.to_bytes().len());
|
||||||
|
|
||||||
|
// sanity check
|
||||||
|
let vd = if !compress {
|
||||||
|
tree.get_node_verifier_data()}
|
||||||
|
else{
|
||||||
|
tree.get_compression_verifier_data()};
|
||||||
|
assert!(vd.verify(root.clone()).is_ok());
|
||||||
|
|
||||||
|
bn254_wrap(root, vd)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_wrap_tree_recursion() -> anyhow::Result<()> {
|
||||||
|
// total number of proofs to aggregate
|
||||||
|
const T:usize = 4;
|
||||||
|
run_tree_recursion::<2, T>(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_wrap_tree_recursion_with_compression() -> anyhow::Result<()> {
|
||||||
|
// total number of proofs to aggregate
|
||||||
|
const T:usize = 4;
|
||||||
|
run_tree_recursion::<2, T>(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
198
proof-input/src/serialization/circuit_input.rs
Normal file → Executable file
198
proof-input/src/serialization/circuit_input.rs
Normal file → Executable file
@ -6,43 +6,12 @@ use anyhow::{anyhow, Error};
|
|||||||
use codex_plonky2_circuits::circuits::sample_cells::{Cell, MerklePath, SampleCircuitInput};
|
use codex_plonky2_circuits::circuits::sample_cells::{Cell, MerklePath, SampleCircuitInput};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufReader, Write};
|
use std::io::{BufReader, Write};
|
||||||
|
use std::path::Path;
|
||||||
use crate::gen_input::gen_testing_circuit_input;
|
use crate::gen_input::gen_testing_circuit_input;
|
||||||
use crate::params::InputParams;
|
use crate::params::InputParams;
|
||||||
use crate::serialization::file_paths::CIRC_INPUT_JSON;
|
use codex_plonky2_circuits::serialization::ensure_parent_directory_exists;
|
||||||
use crate::serialization::json::ensure_parent_directory_exists;
|
|
||||||
|
|
||||||
/// export circuit input to json file
|
|
||||||
pub fn export_circ_input_to_json<
|
|
||||||
F: RichField + Extendable<D> + Poseidon2 + Serialize,
|
|
||||||
const D: usize,
|
|
||||||
> (circ_input:SampleCircuitInput<F, D>) -> anyhow::Result<()>{
|
|
||||||
// Convert the circuit input to a serializable format
|
|
||||||
let serializable_circ_input = SerializableCircuitInput::from_circ_input(&circ_input);
|
|
||||||
|
|
||||||
// Serialize to JSON
|
|
||||||
let json_data = serde_json::to_string_pretty(&serializable_circ_input)?;
|
|
||||||
|
|
||||||
// Write to file
|
|
||||||
ensure_parent_directory_exists(CIRC_INPUT_JSON)?;
|
|
||||||
let mut file = File::create(CIRC_INPUT_JSON)?;
|
|
||||||
file.write_all(json_data.as_bytes())?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Function to generate circuit input and export to JSON
|
|
||||||
pub fn generate_and_export_circ_input_to_json<
|
|
||||||
F: RichField + Extendable<D> + Poseidon2 + Serialize,
|
|
||||||
const D: usize,
|
|
||||||
>(params: &InputParams) -> anyhow::Result<()> {
|
|
||||||
|
|
||||||
let circ_input = gen_testing_circuit_input::<F,D>(params);
|
|
||||||
|
|
||||||
export_circ_input_to_json(circ_input)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
pub const CIRC_INPUT_JSON: &str = "prover_data/input.json";
|
||||||
|
|
||||||
// Serializable versions of the circuit input
|
// Serializable versions of the circuit input
|
||||||
// naming here is not Rust friendly but only so that its compatible with Nim code.
|
// naming here is not Rust friendly but only so that its compatible with Nim code.
|
||||||
@ -268,12 +237,169 @@ impl<> SerializableCircuitInput {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// export circuit input to json file
|
||||||
|
pub fn export_circ_input_to_json<
|
||||||
|
F: RichField + Extendable<D> + Poseidon2 + Serialize,
|
||||||
|
const D: usize,
|
||||||
|
P: AsRef<Path>,
|
||||||
|
>(
|
||||||
|
circ_input: SampleCircuitInput<F, D>,
|
||||||
|
base_path: P,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
// Convert the circuit input to a serializable format
|
||||||
|
let serializable_circ_input = SerializableCircuitInput::from_circ_input(&circ_input);
|
||||||
|
|
||||||
|
// Serialize to JSON
|
||||||
|
let json_data = serde_json::to_string_pretty(&serializable_circ_input)?;
|
||||||
|
|
||||||
|
let full_path = base_path.as_ref().join(CIRC_INPUT_JSON);
|
||||||
|
|
||||||
|
// Write to file
|
||||||
|
ensure_parent_directory_exists(&full_path)?;
|
||||||
|
let mut file = File::create(&full_path)?;
|
||||||
|
file.write_all(json_data.as_bytes())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Function to generate circuit input and export to JSON
|
||||||
|
pub fn generate_and_export_circ_input_to_json<
|
||||||
|
F: RichField + Extendable<D> + Poseidon2 + Serialize,
|
||||||
|
const D: usize,
|
||||||
|
P: AsRef<Path>,
|
||||||
|
>(
|
||||||
|
params: &InputParams,
|
||||||
|
base_path: P,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
|
||||||
|
let circ_input = gen_testing_circuit_input::<F,D>(params);
|
||||||
|
|
||||||
|
export_circ_input_to_json(circ_input, base_path)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// reads the json file, converts it to circuit input (SampleCircuitInput) and returns it
|
/// reads the json file, converts it to circuit input (SampleCircuitInput) and returns it
|
||||||
pub fn import_circ_input_from_json<F: RichField + Extendable<D> + Poseidon2, const D: usize>() -> anyhow::Result<SampleCircuitInput<F, D>> {
|
pub fn import_circ_input_from_json<
|
||||||
let file = File::open(CIRC_INPUT_JSON)?;
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
|
const D: usize,
|
||||||
|
P: AsRef<Path>,
|
||||||
|
>(
|
||||||
|
base_path: P,
|
||||||
|
) -> anyhow::Result<SampleCircuitInput<F, D>> {
|
||||||
|
let full_path = base_path.as_ref().join(CIRC_INPUT_JSON);
|
||||||
|
|
||||||
|
let file = File::open(&full_path)?;
|
||||||
let reader = BufReader::new(file);
|
let reader = BufReader::new(file);
|
||||||
let serializable_circ_input: SerializableCircuitInput = serde_json::from_reader(reader)?;
|
let serializable_circ_input: SerializableCircuitInput = serde_json::from_reader(reader)?;
|
||||||
|
|
||||||
let circ_input = serializable_circ_input.to_circ_input()?;
|
let circ_input = serializable_circ_input.to_circ_input()?;
|
||||||
Ok(circ_input)
|
Ok(circ_input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::params::{C, D, F, HF, Params};
|
||||||
|
use codex_plonky2_circuits::circuits::sample_cells::{SampleCircuit, SampleCircuitInput};
|
||||||
|
use plonky2::plonk::circuit_data::{ProverCircuitData, VerifierCircuitData};
|
||||||
|
use codex_plonky2_circuits::circuit_helper::Plonky2Circuit;
|
||||||
|
use crate::gen_input::{gen_testing_circuit_input, verify_circuit_input};
|
||||||
|
use crate::serialization::circuit_input::{export_circ_input_to_json, generate_and_export_circ_input_to_json, import_circ_input_from_json};
|
||||||
|
|
||||||
|
// Test to generate the JSON file
|
||||||
|
#[test]
|
||||||
|
fn test_export_circ_input_to_json() -> anyhow::Result<()> {
|
||||||
|
// Create Params
|
||||||
|
let params = Params::default().input_params;
|
||||||
|
// Export the circuit input to JSON
|
||||||
|
generate_and_export_circ_input_to_json::<F, D,_>(¶ms, "../output/test/")?;
|
||||||
|
|
||||||
|
println!("Circuit input exported to input.json");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_import_circ_input_from_json() -> anyhow::Result<()> {
|
||||||
|
// Import the circuit input from the JSON file
|
||||||
|
// NOTE: MAKE SURE THE FILE EXISTS
|
||||||
|
let _circ_input: SampleCircuitInput<F, D> = import_circ_input_from_json("../output/test/")?;
|
||||||
|
println!("circuit input imported successfully");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// export the circuit input and then import it and checks equality
|
||||||
|
#[test]
|
||||||
|
fn test_export_import_circ_input() -> anyhow::Result<()> {
|
||||||
|
// Create Params instance
|
||||||
|
let params = Params::default().input_params;
|
||||||
|
|
||||||
|
// Export the circuit input to JSON
|
||||||
|
let original_circ_input = gen_testing_circuit_input(¶ms);
|
||||||
|
export_circ_input_to_json(original_circ_input.clone(), "../output/test/")?;
|
||||||
|
println!("circuit input exported to input.json");
|
||||||
|
|
||||||
|
// Import the circuit input from JSON
|
||||||
|
let imported_circ_input: SampleCircuitInput<F, D> = import_circ_input_from_json("../output/test/")?;
|
||||||
|
println!("circuit input imported from input.json");
|
||||||
|
|
||||||
|
// Compare the original and imported circuit input
|
||||||
|
assert_eq!(original_circ_input, imported_circ_input, "circuit input are not equal");
|
||||||
|
|
||||||
|
// cleanup: Remove the generated JSON file
|
||||||
|
// fs::remove_file("input.json")?;
|
||||||
|
|
||||||
|
println!("Test passed: Original and imported circuit input are equal.");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// reads the json input from file and runs the circuit
|
||||||
|
#[test]
|
||||||
|
fn test_read_json_and_run_circuit() -> anyhow::Result<()> {
|
||||||
|
// Create the circuit
|
||||||
|
let circuit_params = Params::default().circuit_params;
|
||||||
|
|
||||||
|
let circ = SampleCircuit::<F, D, HF>::new(circuit_params.clone());
|
||||||
|
let (targets, data) = circ.build_with_standard_config()?;
|
||||||
|
|
||||||
|
let verifier_data: VerifierCircuitData<F, C, D> = data.verifier_data();
|
||||||
|
let prover_data: ProverCircuitData<F, C, D> = data.prover_data();
|
||||||
|
println!("circuit size = {:?}", verifier_data.common.degree_bits());
|
||||||
|
|
||||||
|
// Import the circuit input from JSON
|
||||||
|
let imported_circ_input: SampleCircuitInput<F, D> = import_circ_input_from_json("../output/test/")?;
|
||||||
|
println!("circuit input imported from input.json");
|
||||||
|
|
||||||
|
let proof = circ.prove(&targets, &imported_circ_input, &prover_data)?;
|
||||||
|
|
||||||
|
// Verify the proof
|
||||||
|
assert!(
|
||||||
|
verifier_data.verify(proof).is_ok(),
|
||||||
|
"Merkle proof verification failed"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// reads the json input and verify (non-circuit)
|
||||||
|
// NOTE: expects that the json input proof uses the default params
|
||||||
|
#[test]
|
||||||
|
fn test_read_json_and_verify() -> anyhow::Result<()> {
|
||||||
|
let params = Params::default().input_params;
|
||||||
|
|
||||||
|
// Import the circuit input from JSON
|
||||||
|
let imported_circ_input: SampleCircuitInput<F, D> = import_circ_input_from_json("../output/test/")?;
|
||||||
|
println!("circuit input imported from input.json");
|
||||||
|
|
||||||
|
// Verify the proof
|
||||||
|
let ver = verify_circuit_input(imported_circ_input, ¶ms);
|
||||||
|
assert!(
|
||||||
|
ver,
|
||||||
|
"Merkle proof verification failed"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
/// File constants with full paths - Prover
|
|
||||||
pub const CIRC_INPUT_JSON: &str = "prover_data/input.json";
|
|
||||||
pub const PROVER_CIRC_DATA_JSON: &str = "prover_data/prover_circ_data.bin";
|
|
||||||
pub const TARGETS_JSON: &str = "prover_data/targets.json";
|
|
||||||
|
|
||||||
/// File constants with full paths - Verifier
|
|
||||||
pub const VERIFIER_CIRC_DATA_JSON: &str = "verifier_data/verifier_circ_data.bin";
|
|
||||||
pub const PROOF_JSON: &str = "verifier_data/proof.json";
|
|
||||||
pub const TREE_PROOF_JSON: &str = "verifier_data/tree_proof.json";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,371 +0,0 @@
|
|||||||
use serde::Serialize;
|
|
||||||
use std::{fs, io};
|
|
||||||
use std::path::Path;
|
|
||||||
use anyhow::Context;
|
|
||||||
use plonky2::hash::hash_types::RichField;
|
|
||||||
use plonky2::plonk::circuit_data::{CircuitData, ProverCircuitData, VerifierCircuitData};
|
|
||||||
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig};
|
|
||||||
use plonky2_field::extension::Extendable;
|
|
||||||
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
|
||||||
use plonky2::plonk::proof::ProofWithPublicInputs;
|
|
||||||
use serde::de::DeserializeOwned;
|
|
||||||
use plonky2_poseidon2::serialization::{DefaultGateSerializer, DefaultGeneratorSerializer};
|
|
||||||
use crate::serialization::file_paths::{PROOF_JSON, PROVER_CIRC_DATA_JSON, TARGETS_JSON, TREE_PROOF_JSON, VERIFIER_CIRC_DATA_JSON};
|
|
||||||
|
|
||||||
/// Writes the provided bytes to the specified file path using `std::fs::write`.
|
|
||||||
pub fn write_bytes_to_file<P: AsRef<Path>>(data: Vec<u8>, path: P) -> io::Result<()> {
|
|
||||||
fs::write(path, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reads the contents of the specified file and returns them as a vector of bytes using `std::fs::read`.
|
|
||||||
pub fn read_bytes_from_file<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
|
|
||||||
fs::read(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ensures that the parent directory of the given file path exists.
|
|
||||||
/// If it does not exist, the function creates the entire directory path.
|
|
||||||
pub fn ensure_parent_directory_exists(path: &str) -> anyhow::Result<()> {
|
|
||||||
if let Some(parent) = Path::new(path).parent() {
|
|
||||||
fs::create_dir_all(parent)
|
|
||||||
.with_context(|| format!("Failed to create directory {:?}", parent))?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Export the circuit data to disk. This function serializes the prover data,
|
|
||||||
/// verifier data, and circuit targets, and then writes them to their respective files.
|
|
||||||
/// The function uses the file paths defined in file_paths.rs
|
|
||||||
pub fn export_circuit_data<F, C, const D: usize>(
|
|
||||||
circ_data: CircuitData<F,C,D>,
|
|
||||||
targets: &impl Serialize,
|
|
||||||
) -> anyhow::Result<()>
|
|
||||||
where
|
|
||||||
F: RichField + Extendable<D> + Poseidon2 + Serialize,
|
|
||||||
C: GenericConfig<D, F = F> + 'static + Serialize, C:Default,
|
|
||||||
<C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>
|
|
||||||
{
|
|
||||||
// separate the prover and verifier data
|
|
||||||
let verifier_data: VerifierCircuitData<F, C,D> = circ_data.verifier_data();
|
|
||||||
let prover_data = circ_data.prover_data();
|
|
||||||
|
|
||||||
let gate_serializer = DefaultGateSerializer;
|
|
||||||
let generator_serializer =DefaultGeneratorSerializer::<C, D>::default();
|
|
||||||
|
|
||||||
// Serialize the prover data.
|
|
||||||
let prover_data_bytes = prover_data
|
|
||||||
.to_bytes(&gate_serializer, &generator_serializer)
|
|
||||||
.map_err(|e| anyhow::anyhow!("Failed to serialize prover data: {:?}", e))?;
|
|
||||||
// Serialize the verifier data.
|
|
||||||
let verifier_data_bytes = verifier_data
|
|
||||||
.to_bytes(&gate_serializer)
|
|
||||||
.map_err(|e| anyhow::anyhow!("Failed to serialize verifier data: {:?}", e))?;
|
|
||||||
// Serialize the circuit targets using serde_json.
|
|
||||||
let targets_bytes = serde_json::to_vec(targets)
|
|
||||||
.context("Failed to serialize circuit targets")?;
|
|
||||||
|
|
||||||
// Ensure that the parent directories exist.
|
|
||||||
ensure_parent_directory_exists(PROVER_CIRC_DATA_JSON)?;
|
|
||||||
ensure_parent_directory_exists(VERIFIER_CIRC_DATA_JSON)?;
|
|
||||||
ensure_parent_directory_exists(TARGETS_JSON)?;
|
|
||||||
|
|
||||||
// Write all data to the corresponding files.
|
|
||||||
write_bytes_to_file(prover_data_bytes, PROVER_CIRC_DATA_JSON)
|
|
||||||
.with_context(|| format!("Failed to write prover data to {}", PROVER_CIRC_DATA_JSON))?;
|
|
||||||
write_bytes_to_file(verifier_data_bytes, VERIFIER_CIRC_DATA_JSON)
|
|
||||||
.with_context(|| format!("Failed to write verifier data to {}", VERIFIER_CIRC_DATA_JSON))?;
|
|
||||||
write_bytes_to_file(targets_bytes, TARGETS_JSON)
|
|
||||||
.with_context(|| format!("Failed to write circuit targets to {}", TARGETS_JSON))?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Import the prover circuit data from disk and deserialize it.
|
|
||||||
pub fn import_prover_circuit_data<F, C, const D: usize>() -> anyhow::Result<ProverCircuitData<F, C, D>>
|
|
||||||
where
|
|
||||||
F: RichField + Extendable<D> + Poseidon2 + Serialize,
|
|
||||||
C: GenericConfig<D, F = F> + 'static + Serialize, C:Default,
|
|
||||||
<C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>
|
|
||||||
{
|
|
||||||
let gate_serializer = DefaultGateSerializer;
|
|
||||||
let generator_serializer =DefaultGeneratorSerializer::<C, D>::default();
|
|
||||||
|
|
||||||
let bytes = read_bytes_from_file(PROVER_CIRC_DATA_JSON)
|
|
||||||
.with_context(|| format!("Failed to read prover circuit data from {}", PROVER_CIRC_DATA_JSON))?;
|
|
||||||
let prover_data = ProverCircuitData::<F,C,D>::from_bytes(&bytes, &gate_serializer, &generator_serializer)
|
|
||||||
.map_err(|e| anyhow::anyhow!("Failed to deserialize prover data: {:?}", e))?;
|
|
||||||
Ok(prover_data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Import the verifier circuit data from disk and deserialize it.
|
|
||||||
pub fn import_verifier_circuit_data<F, C, const D: usize>(
|
|
||||||
) -> anyhow::Result<VerifierCircuitData<F, C, D>>
|
|
||||||
where
|
|
||||||
F: RichField + Extendable<D> + Poseidon2 + Serialize,
|
|
||||||
C: GenericConfig<D, F = F> + Serialize,
|
|
||||||
{
|
|
||||||
let gate_serializer = DefaultGateSerializer;
|
|
||||||
|
|
||||||
let bytes = read_bytes_from_file(VERIFIER_CIRC_DATA_JSON)
|
|
||||||
.with_context(|| format!("Failed to read verifier circuit data from {}", VERIFIER_CIRC_DATA_JSON))?;
|
|
||||||
let verifier_data = VerifierCircuitData::<F,C,D>::from_bytes(bytes, &gate_serializer)
|
|
||||||
.map_err(|e| anyhow::anyhow!("Failed to deserialize verifier data: {:?}", e))?;
|
|
||||||
Ok(verifier_data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Import the proof with public input from the JSON file.
|
|
||||||
pub fn import_proof_with_pi<F, C, const D: usize>() -> anyhow::Result<ProofWithPublicInputs<F, C, D>>
|
|
||||||
where
|
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
|
||||||
C: GenericConfig<D, F = F>,
|
|
||||||
{
|
|
||||||
let proof_json = fs::read_to_string(PROOF_JSON)
|
|
||||||
.with_context(|| format!("Failed to read file {}", PROOF_JSON))?;
|
|
||||||
let proof = serde_json::from_str(&proof_json)
|
|
||||||
.context("Failed to deserialize proof with public input")?;
|
|
||||||
Ok(proof)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Import the circuit targets from the JSON file.
|
|
||||||
/// This function is generic over the type `T` that represents the targets and
|
|
||||||
/// must implement `DeserializeOwned` so that it can be deserialized.
|
|
||||||
pub fn import_targets<T>() -> anyhow::Result<T>
|
|
||||||
where
|
|
||||||
T: DeserializeOwned,
|
|
||||||
{
|
|
||||||
let targets_json = fs::read_to_string(TARGETS_JSON)
|
|
||||||
.with_context(|| format!("Failed to read file {}", TARGETS_JSON))?;
|
|
||||||
let targets = serde_json::from_str(&targets_json)
|
|
||||||
.context("Failed to deserialize targets")?;
|
|
||||||
Ok(targets)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Function to export tree proof with public input to json file
|
|
||||||
pub fn export_tree_proof_with_pi<F, C, const D: usize>(
|
|
||||||
proof_with_pis: &ProofWithPublicInputs<F, C, D>,
|
|
||||||
) -> anyhow::Result<()>
|
|
||||||
where
|
|
||||||
F: RichField + Extendable<D> + Poseidon2 + Serialize,
|
|
||||||
C: GenericConfig<D, F = F> + Serialize,
|
|
||||||
{
|
|
||||||
export_proof_with_pi_to_given_path(proof_with_pis, TREE_PROOF_JSON)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Function to export proof with public input to json file
|
|
||||||
pub fn export_proof_with_pi<F, C, const D: usize>(
|
|
||||||
proof_with_pis: &ProofWithPublicInputs<F, C, D>,
|
|
||||||
) -> anyhow::Result<()>
|
|
||||||
where
|
|
||||||
F: RichField + Extendable<D> + Poseidon2 + Serialize,
|
|
||||||
C: GenericConfig<D, F = F> + Serialize,
|
|
||||||
{
|
|
||||||
export_proof_with_pi_to_given_path(proof_with_pis, PROOF_JSON)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Function to export proof with public input to json file
|
|
||||||
/// takes the path
|
|
||||||
fn export_proof_with_pi_to_given_path<F, C, const D: usize>(
|
|
||||||
proof_with_pis: &ProofWithPublicInputs<F, C, D>,
|
|
||||||
path: &str,
|
|
||||||
) -> anyhow::Result<()>
|
|
||||||
where
|
|
||||||
F: RichField + Extendable<D> + Poseidon2 + Serialize,
|
|
||||||
C: GenericConfig<D, F = F> + Serialize,
|
|
||||||
{
|
|
||||||
let proof_serialized= serde_json::to_vec(&proof_with_pis)
|
|
||||||
.map_err(|e| anyhow::anyhow!("Failed to serialize proof with public input: {:?}", e))?;
|
|
||||||
fs::write(path , &proof_serialized).expect("Unable to write file");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::params::{C, D, F, HF, Params};
|
|
||||||
use std::time::Instant;
|
|
||||||
use codex_plonky2_circuits::circuits::sample_cells::{SampleCircuit, SampleCircuitInput};
|
|
||||||
use plonky2::plonk::circuit_data::{ ProverCircuitData, VerifierCircuitData};
|
|
||||||
use codex_plonky2_circuits::circuit_helper::Plonky2Circuit;
|
|
||||||
use codex_plonky2_circuits::circuits::utils::read_bytes_from_file;
|
|
||||||
use plonky2_poseidon2::serialization::{DefaultGateSerializer, DefaultGeneratorSerializer};
|
|
||||||
use crate::gen_input::{gen_testing_circuit_input, verify_circuit_input};
|
|
||||||
use crate::serialization::circuit_input::{export_circ_input_to_json, generate_and_export_circ_input_to_json, import_circ_input_from_json};
|
|
||||||
use crate::serialization::json::{export_proof_with_pi, write_bytes_to_file};
|
|
||||||
|
|
||||||
// Test to generate the JSON file
|
|
||||||
#[test]
|
|
||||||
fn test_export_circ_input_to_json() -> anyhow::Result<()> {
|
|
||||||
// Create Params
|
|
||||||
let params = Params::default().input_params;
|
|
||||||
// Export the circuit input to JSON
|
|
||||||
generate_and_export_circ_input_to_json::<F,D>(¶ms)?;
|
|
||||||
|
|
||||||
println!("Circuit input exported to input.json");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_import_circ_input_from_json() -> anyhow::Result<()> {
|
|
||||||
// Import the circuit input from the JSON file
|
|
||||||
// NOTE: MAKE SURE THE FILE EXISTS
|
|
||||||
let _circ_input: SampleCircuitInput<F, D> = import_circ_input_from_json()?;
|
|
||||||
println!("circuit input imported successfully");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// export the circuit input and then import it and checks equality
|
|
||||||
#[test]
|
|
||||||
fn test_export_import_circ_input() -> anyhow::Result<()> {
|
|
||||||
// Create Params instance
|
|
||||||
let params = Params::default().input_params;
|
|
||||||
|
|
||||||
// Export the circuit input to JSON
|
|
||||||
let original_circ_input = gen_testing_circuit_input(¶ms);
|
|
||||||
export_circ_input_to_json(original_circ_input.clone())?;
|
|
||||||
println!("circuit input exported to input.json");
|
|
||||||
|
|
||||||
// Import the circuit input from JSON
|
|
||||||
let imported_circ_input: SampleCircuitInput<F, D> = import_circ_input_from_json()?;
|
|
||||||
println!("circuit input imported from input.json");
|
|
||||||
|
|
||||||
// Compare the original and imported circuit input
|
|
||||||
assert_eq!(original_circ_input, imported_circ_input, "circuit input are not equal");
|
|
||||||
|
|
||||||
// cleanup: Remove the generated JSON file
|
|
||||||
// fs::remove_file("input.json")?;
|
|
||||||
|
|
||||||
println!("Test passed: Original and imported circuit input are equal.");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// reads the json input from file and runs the circuit
|
|
||||||
#[test]
|
|
||||||
fn test_read_json_and_run_circuit() -> anyhow::Result<()> {
|
|
||||||
// Create the circuit
|
|
||||||
let circuit_params = Params::default().circuit_params;
|
|
||||||
|
|
||||||
let circ = SampleCircuit::<F,D,HF>::new(circuit_params.clone());
|
|
||||||
let (targets, data) = circ.build_with_standard_config()?;
|
|
||||||
|
|
||||||
let verifier_data: VerifierCircuitData<F, C, D> = data.verifier_data();
|
|
||||||
let prover_data: ProverCircuitData<F, C, D> = data.prover_data();
|
|
||||||
println!("circuit size = {:?}", verifier_data.common.degree_bits());
|
|
||||||
|
|
||||||
// Import the circuit input from JSON
|
|
||||||
let imported_circ_input: SampleCircuitInput<F, D> = import_circ_input_from_json()?;
|
|
||||||
println!("circuit input imported from input.json");
|
|
||||||
|
|
||||||
let proof = circ.prove(&targets, &imported_circ_input, &prover_data)?;
|
|
||||||
|
|
||||||
// Verify the proof
|
|
||||||
assert!(
|
|
||||||
verifier_data.verify(proof).is_ok(),
|
|
||||||
"Merkle proof verification failed"
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// reads the json input and verify (non-circuit)
|
|
||||||
// NOTE: expects that the json input proof uses the default params
|
|
||||||
#[test]
|
|
||||||
fn test_read_json_and_verify() -> anyhow::Result<()> {
|
|
||||||
let params = Params::default().input_params;
|
|
||||||
|
|
||||||
// Import the circuit input from JSON
|
|
||||||
let imported_circ_input: SampleCircuitInput<F, D> = import_circ_input_from_json()?;
|
|
||||||
println!("circuit input imported from input.json");
|
|
||||||
|
|
||||||
// Verify the proof
|
|
||||||
let ver = verify_circuit_input(imported_circ_input, ¶ms);
|
|
||||||
assert!(
|
|
||||||
ver,
|
|
||||||
"Merkle proof verification failed"
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// test out custom default gate and generator serializers to export/import circuit data
|
|
||||||
#[test]
|
|
||||||
fn test_circuit_data_serializer() -> anyhow::Result<()> {
|
|
||||||
let params = Params::default();
|
|
||||||
let input_params = params.input_params;
|
|
||||||
|
|
||||||
// Create the circuit
|
|
||||||
let circuit_params = params.circuit_params;
|
|
||||||
let circ = SampleCircuit::<F,D,HF>::new(circuit_params.clone());
|
|
||||||
let (targets, data) = circ.build_with_standard_config()?;
|
|
||||||
println!("circuit size = {:?}", data.common.degree_bits());
|
|
||||||
|
|
||||||
let verifier_data: VerifierCircuitData<F, C, D> = data.verifier_data();
|
|
||||||
let prover_data: ProverCircuitData<F, C, D> = data.prover_data();
|
|
||||||
|
|
||||||
// gen circ input
|
|
||||||
let imported_circ_input: SampleCircuitInput<F, D> = gen_testing_circuit_input::<F,D>(&input_params);
|
|
||||||
|
|
||||||
let gate_serializer = DefaultGateSerializer;
|
|
||||||
let generator_serializer =DefaultGeneratorSerializer::<C, D>::default();
|
|
||||||
let data_bytes = prover_data.to_bytes(&gate_serializer, &generator_serializer).unwrap();
|
|
||||||
|
|
||||||
let file_path = "circ_data.bin";
|
|
||||||
// Write data to the file
|
|
||||||
write_bytes_to_file(data_bytes.clone(), file_path).unwrap();
|
|
||||||
println!("Data written to {}", file_path);
|
|
||||||
|
|
||||||
// Read data back from the file
|
|
||||||
let read_data = read_bytes_from_file(file_path).unwrap();
|
|
||||||
let prover_data = ProverCircuitData::<F,C,D>::from_bytes(&read_data, &gate_serializer, &generator_serializer).unwrap();
|
|
||||||
|
|
||||||
// Prove the circuit with the assigned witness
|
|
||||||
let start_time = Instant::now();
|
|
||||||
let proof_with_pis = circ.prove(&targets, &imported_circ_input, &prover_data)?;
|
|
||||||
println!("prove_time = {:?}", start_time.elapsed());
|
|
||||||
|
|
||||||
// Verify the proof
|
|
||||||
assert!(
|
|
||||||
verifier_data.verify(proof_with_pis).is_ok(),
|
|
||||||
"Merkle proof verification failed"
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// test proof with public input serialization
|
|
||||||
#[test]
|
|
||||||
fn test_proof_with_pi_serializer() -> anyhow::Result<()> {
|
|
||||||
let params = Params::default();
|
|
||||||
let input_params = params.input_params;
|
|
||||||
|
|
||||||
// Create the circuit
|
|
||||||
let circuit_params = params.circuit_params;
|
|
||||||
let circ = SampleCircuit::<F,D,HF>::new(circuit_params.clone());
|
|
||||||
let (targets, data) = circ.build_with_standard_config()?;
|
|
||||||
println!("circuit size = {:?}", data.common.degree_bits());
|
|
||||||
|
|
||||||
let verifier_data: VerifierCircuitData<F, C, D> = data.verifier_data();
|
|
||||||
let prover_data: ProverCircuitData<F, C, D> = data.prover_data();
|
|
||||||
|
|
||||||
// gen circ input
|
|
||||||
let imported_circ_input: SampleCircuitInput<F, D> = gen_testing_circuit_input::<F,D>(&input_params);
|
|
||||||
|
|
||||||
// Prove the circuit with the assigned witness
|
|
||||||
let start_time = Instant::now();
|
|
||||||
let proof_with_pis = circ.prove(&targets, &imported_circ_input, &prover_data)?;
|
|
||||||
println!("prove_time = {:?}", start_time.elapsed());
|
|
||||||
println!("Proof size: {} bytes", proof_with_pis.to_bytes().len());
|
|
||||||
|
|
||||||
export_proof_with_pi(&proof_with_pis)?;
|
|
||||||
println!("Proof size: {} bytes", proof_with_pis.to_bytes().len());
|
|
||||||
|
|
||||||
// Verify the proof
|
|
||||||
assert!(
|
|
||||||
verifier_data.verify(proof_with_pis).is_ok(),
|
|
||||||
"Merkle proof verification failed"
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2
proof-input/src/serialization/mod.rs
Normal file → Executable file
2
proof-input/src/serialization/mod.rs
Normal file → Executable file
@ -1,3 +1 @@
|
|||||||
pub mod circuit_input;
|
pub mod circuit_input;
|
||||||
pub mod json;
|
|
||||||
pub mod file_paths;
|
|
||||||
|
|||||||
0
proof-input/src/sponge.rs
Normal file → Executable file
0
proof-input/src/sponge.rs
Normal file → Executable file
0
proof-input/src/utils.rs
Normal file → Executable file
0
proof-input/src/utils.rs
Normal file → Executable file
Loading…
x
Reference in New Issue
Block a user