mirror of
https://github.com/codex-storage/proof-aggregation.git
synced 2025-02-13 15:16:58 +00:00
refactor tests to follow changes in circuit impl
This commit is contained in:
parent
c8a8ec0f5e
commit
209eda8240
@ -6,7 +6,7 @@ use codex_plonky2_circuits::circuits::sample_cells::Cell;
|
||||
use plonky2_field::types::Sample;
|
||||
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
||||
use crate::merkle_tree::merkle_safe::{MerkleProof, MerkleTree};
|
||||
use crate::params::{InputParams,Params, HF};
|
||||
use crate::params::{InputParams, HF};
|
||||
use crate::sponge::hash_bytes_no_padding;
|
||||
use crate::utils::{bits_le_padded_to_usize, calculate_cell_index_bits, usize_to_bits_le};
|
||||
|
||||
|
@ -3,7 +3,6 @@ use plonky2::plonk::config::{GenericConfig, Hasher};
|
||||
use plonky2_field::extension::Extendable;
|
||||
use plonky2_field::types::Field;
|
||||
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
||||
use codex_plonky2_circuits::circuits::params::CircuitParams;
|
||||
use crate::params::{Params,InputParams};
|
||||
use crate::utils::{bits_le_padded_to_usize, calculate_cell_index_bits, ceiling_log2, usize_to_bits_le};
|
||||
use crate::merkle_tree::merkle_safe::MerkleProof;
|
||||
|
@ -2,7 +2,7 @@
|
||||
pub mod gen_input;
|
||||
pub mod params;
|
||||
pub mod utils;
|
||||
// pub mod recursion;
|
||||
pub mod recursion;
|
||||
pub mod sponge;
|
||||
pub mod merkle_tree;
|
||||
pub mod data_structs;
|
||||
|
@ -38,9 +38,9 @@ pub fn build_circuit<
|
||||
const D: usize,
|
||||
H: AlgebraicHasher<F>,
|
||||
>(
|
||||
builder: &mut CircuitBuilder::<F, D>,
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
depth: usize,
|
||||
) -> Result<(MerkleTreeTargets, HashOutTarget)> {
|
||||
) -> (MerkleTreeTargets, HashOutTarget) {
|
||||
|
||||
// Create virtual targets
|
||||
let leaf = builder.add_virtual_hash();
|
||||
@ -69,10 +69,10 @@ pub fn build_circuit<
|
||||
};
|
||||
|
||||
// Add Merkle proof verification constraints to the circuit
|
||||
let reconstructed_root_target = MerkleTreeCircuit::<F,D,H>::reconstruct_merkle_root_circuit_with_mask(builder, &mut targets, depth)?;
|
||||
let reconstructed_root_target = MerkleTreeCircuit::<F,D,H>::reconstruct_merkle_root_circuit_with_mask(builder, &mut targets, depth).unwrap();
|
||||
|
||||
// Return MerkleTreeTargets
|
||||
Ok((targets, reconstructed_root_target))
|
||||
(targets, reconstructed_root_target)
|
||||
}
|
||||
|
||||
/// assign the witness values in the circuit targets
|
||||
@ -176,7 +176,7 @@ mod tests {
|
||||
// create the circuit
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
let (mut targets, reconstructed_root_target) = build_circuit::<F,D,H>(&mut builder, max_depth)?;
|
||||
let (mut targets, reconstructed_root_target) = build_circuit::<F,D,H>(&mut builder, max_depth);
|
||||
|
||||
// expected Merkle root
|
||||
let expected_root = builder.add_virtual_hash();
|
||||
@ -252,7 +252,7 @@ mod tests {
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
let (mut targets, reconstructed_root_target) = build_circuit::<F,D,H>(&mut builder, max_depth)?;
|
||||
let (mut targets, reconstructed_root_target) = build_circuit::<F,D,H>(&mut builder, max_depth);
|
||||
|
||||
// expected Merkle root
|
||||
let expected_root_target = builder.add_virtual_hash();
|
||||
@ -276,7 +276,7 @@ mod tests {
|
||||
let mut pw = PartialWitness::new();
|
||||
|
||||
let path_bits = usize_to_bits_le(leaf_index, max_depth);
|
||||
let last_index = (nleaves - 1) as usize;
|
||||
let last_index = nleaves - 1;
|
||||
let last_bits = usize_to_bits_le(last_index, max_depth);
|
||||
let mask_bits = usize_to_bits_le(last_index, max_depth+1);
|
||||
|
||||
|
@ -5,8 +5,6 @@ use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
use std::env;
|
||||
use anyhow::{Result, Context};
|
||||
use codex_plonky2_circuits::circuits::params::CircuitParams;
|
||||
use plonky2_field::goldilocks_field::GoldilocksField;
|
||||
use plonky2_poseidon2::config::Poseidon2GoldilocksConfig;
|
||||
|
||||
// test types
|
||||
pub const D: usize = 2;
|
||||
|
@ -10,34 +10,28 @@ mod tests {
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::config::GenericConfig;
|
||||
use codex_plonky2_circuits::params::{F, D, C, Plonky2Proof};
|
||||
use crate::params::{F, D, C, HF};
|
||||
use codex_plonky2_circuits::recursion::circuits::sampling_inner_circuit::SamplingRecursion;
|
||||
use plonky2_poseidon2::poseidon2_hash::poseidon2::{Poseidon2, Poseidon2Hash};
|
||||
use crate::gen_input::gen_testing_circuit_input;
|
||||
use crate::params::TestParams;
|
||||
use crate::params::Params;
|
||||
use codex_plonky2_circuits::recursion::cyclic::CyclicCircuit;
|
||||
|
||||
|
||||
/// Uses cyclic recursion to sample the dataset
|
||||
#[test]
|
||||
fn test_cyclic_recursion() -> Result<()> {
|
||||
// const D: usize = 2;
|
||||
// type C = PoseidonGoldilocksConfig;
|
||||
// type F = <C as GenericConfig<D>>::F;
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
let one = builder.one();
|
||||
|
||||
let inner_sampling_circuit = SamplingRecursion::default();
|
||||
let mut params = TestParams::default();
|
||||
params.n_samples = 10;
|
||||
let circ_input = gen_testing_circuit_input::<F,D>(¶ms);
|
||||
|
||||
let mut cyclic_circ = CyclicCircuit::new(inner_sampling_circuit);
|
||||
let mut params = Params::default();
|
||||
let inner_sampling_circuit = SamplingRecursion::<F,D,HF,C>::new(params.circuit_params);
|
||||
let circ_input = gen_testing_circuit_input::<F,D>(¶ms.input_params);
|
||||
|
||||
let s = Instant::now();
|
||||
cyclic_circ.build_circuit()?;
|
||||
let mut cyclic_circ = CyclicCircuit::<F,D,_,C>::build_circuit::<HF>(inner_sampling_circuit)?;
|
||||
println!("build = {:?}", s.elapsed());
|
||||
let s = Instant::now();
|
||||
let proof = cyclic_circ.prove_one_layer(&circ_input)?;
|
||||
@ -51,12 +45,12 @@ mod tests {
|
||||
);
|
||||
println!("verify = {:?}", s.elapsed());
|
||||
|
||||
// check public input hash is correct
|
||||
let mut hash_input = vec![];
|
||||
hash_input.push(circ_input.slot_index);
|
||||
hash_input.extend_from_slice(&circ_input.dataset_root.elements);
|
||||
hash_input.extend_from_slice(&circ_input.entropy.elements);
|
||||
|
||||
// let hash_res = PoseidonHash::hash_no_pad(&hash_input);
|
||||
let hash_res = hash_n_to_hash_no_pad::<F, PoseidonPermutation<F>>(&hash_input);
|
||||
let zero_hash = HashOut::<F>::ZERO;
|
||||
let mut hash_input2 = vec![];
|
||||
@ -65,7 +59,11 @@ mod tests {
|
||||
let hash_res = hash_n_to_hash_no_pad::<F, PoseidonPermutation<F>>(&hash_input2);
|
||||
|
||||
println!("hash input = {:?}", hash_res.elements);
|
||||
|
||||
assert_eq!(
|
||||
proof.public_inputs[0..4].to_vec(),
|
||||
hash_res.elements.to_vec(),
|
||||
"public input hash incorrect"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -73,30 +71,24 @@ mod tests {
|
||||
/// Uses cyclic recursion to sample the dataset n times
|
||||
#[test]
|
||||
fn test_cyclic_recursion_n_layers() -> Result<()> {
|
||||
// const D: usize = 2;
|
||||
// type C = PoseidonGoldilocksConfig;
|
||||
// type F = <C as GenericConfig<D>>::F;
|
||||
const N : usize = 2;
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
let one = builder.one();
|
||||
|
||||
let inner_sampling_circuit = SamplingRecursion::default();
|
||||
let mut params = TestParams::default();
|
||||
params.n_samples = 10;
|
||||
let mut params = Params::default();
|
||||
let inner_sampling_circuit = SamplingRecursion::<F,D,HF,C>::new(params.circuit_params);
|
||||
let mut circ_inputs = vec![];
|
||||
for i in 0..N {
|
||||
circ_inputs.push(gen_testing_circuit_input::<F, D>(¶ms));
|
||||
circ_inputs.push(gen_testing_circuit_input::<F, D>(¶ms.input_params));
|
||||
}
|
||||
|
||||
let mut cyclic_circ = CyclicCircuit::new(inner_sampling_circuit);
|
||||
|
||||
let s = Instant::now();
|
||||
cyclic_circ.build_circuit()?;
|
||||
let mut cyclic_circ = CyclicCircuit::<F,D,_,C>::build_circuit::<HF>(inner_sampling_circuit)?;
|
||||
println!("build = {:?}", s.elapsed());
|
||||
let s = Instant::now();
|
||||
let proof = cyclic_circ.prove_n_layers(N,circ_inputs)?;
|
||||
let proof = cyclic_circ.prove_n_layers(circ_inputs)?;
|
||||
println!("prove = {:?}", s.elapsed());
|
||||
println!("num of pi = {}", proof.public_inputs.len());
|
||||
println!("pub input: {:?}", proof.public_inputs);
|
||||
|
@ -1,4 +1,5 @@
|
||||
pub mod simple_recursion;
|
||||
pub mod simple_tree;
|
||||
pub mod cyclic_recursion;
|
||||
pub mod tree_recursion1;
|
||||
pub mod tree_recursion2;
|
||||
pub mod tree1;
|
||||
pub mod tree2;
|
||||
|
@ -1,149 +1,43 @@
|
||||
// tests for simple recursion approaches
|
||||
|
||||
use std::time::Instant;
|
||||
use plonky2::hash::hash_types::HashOut;
|
||||
use plonky2::hash::hash_types::{HashOut, NUM_HASH_OUT_ELTS};
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData};
|
||||
use plonky2::plonk::config::AlgebraicHasher;
|
||||
use plonky2_field::types::Field;
|
||||
use codex_plonky2_circuits::recursion::circuits::sampling_inner_circuit::SamplingRecursion;
|
||||
use codex_plonky2_circuits::recursion::simple::simple_recursion::{aggregate_sampling_proofs, SimpleRecursionCircuit, SimpleRecursionInput};
|
||||
use codex_plonky2_circuits::recursion::simple::simple_tree_recursion::aggregate_sampling_proofs_tree;
|
||||
use plonky2_poseidon2::serialization::{DefaultGateSerializer, DefaultGeneratorSerializer};
|
||||
use codex_plonky2_circuits::recursion::simple::simple_recursion::{SimpleRecursionCircuit, SimpleRecursionInput};
|
||||
use codex_plonky2_circuits::recursion::simple::simple_recursion_hashed_pi::{SimpleRecursionCircuitHashedPI, SimpleRecursionInputHashedPI};
|
||||
use crate::gen_input::{build_circuit, prove_circuit};
|
||||
use crate::json::write_bytes_to_file;
|
||||
use crate::params::{C, D, F};
|
||||
use crate::params::{C, D, F, HF, Params};
|
||||
|
||||
// Test simple recursion
|
||||
|
||||
// test the simple recursion approach
|
||||
#[test]
|
||||
fn test_simple_recursion() -> anyhow::Result<()> {
|
||||
// number of samples in each proof
|
||||
let n_samples = 10;
|
||||
// number of inner proofs:
|
||||
let n_inner = 4;
|
||||
|
||||
let mut data: Option<CircuitData<F, C, D>> = None;
|
||||
|
||||
// get proofs
|
||||
let mut proofs_with_pi = vec![];
|
||||
for i in 0..n_inner{
|
||||
// build the circuit
|
||||
let (data_i, pw) = build_circuit(n_samples, i)?;
|
||||
// prove
|
||||
proofs_with_pi.push(prove_circuit(&data_i, &pw)?);
|
||||
data = Some(data_i);
|
||||
|
||||
}
|
||||
|
||||
println!("num of public inputs inner proof = {}", proofs_with_pi[0].public_inputs.len());
|
||||
|
||||
// Create the circuit
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
// Create a PartialWitness
|
||||
let mut pw_agg = PartialWitness::new();
|
||||
// aggregate proofs
|
||||
aggregate_sampling_proofs(&proofs_with_pi, &data.unwrap().verifier_data(), &mut builder, &mut pw_agg)?;
|
||||
|
||||
let data_agg = builder.build::<C>();
|
||||
|
||||
// Prove the circuit with the assigned witness
|
||||
let start_time = Instant::now();
|
||||
let proof_with_pis_agg = data_agg.prove(pw_agg)?;
|
||||
println!("prove_time = {:?}", start_time.elapsed());
|
||||
|
||||
println!("num of public inputs = {}", proof_with_pis_agg.public_inputs.len());
|
||||
|
||||
// Verify the proof
|
||||
let verifier_data = data_agg.verifier_data();
|
||||
assert!(
|
||||
verifier_data.verify(proof_with_pis_agg).is_ok(),
|
||||
"Merkle proof verification failed"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Test simple tree recursion
|
||||
#[test]
|
||||
fn test_simple_tree_recursion() -> anyhow::Result<()> {
|
||||
// number of samples in each proof
|
||||
let n_samples = 10;
|
||||
// number of inner proofs:
|
||||
let n_inner = 4;
|
||||
let mut data: Option<CircuitData<F, C, D>> = None;
|
||||
|
||||
// get proofs
|
||||
let mut proofs_with_pi = vec![];
|
||||
for i in 0..n_inner{
|
||||
// build the circuit
|
||||
let (data_i, pw) = build_circuit(n_samples, i)?;
|
||||
proofs_with_pi.push(prove_circuit(&data_i, &pw)?);
|
||||
data = Some(data_i);
|
||||
}
|
||||
|
||||
let data = data.unwrap();
|
||||
println!("inner circuit size = {:?}", data.common.degree_bits());
|
||||
// serialization
|
||||
// let gate_serializer = DefaultGateSerializer;
|
||||
// let generator_serializer =DefaultGeneratorSerializer::<C, D>::default();
|
||||
// let data_bytes = data.to_bytes(&gate_serializer, &generator_serializer).unwrap();
|
||||
// println!("inner proof circuit data size = {} bytes", data_bytes.len());
|
||||
// let file_path = "inner_circ_data.bin";
|
||||
// // Write data to the file
|
||||
// write_bytes_to_file(data_bytes, file_path).unwrap();
|
||||
// println!("Data written to {}", file_path);
|
||||
|
||||
let start_time = Instant::now();
|
||||
let (proof, vd_agg) = aggregate_sampling_proofs_tree(&proofs_with_pi, data)?;
|
||||
println!("prove_time = {:?}", start_time.elapsed());
|
||||
println!("num of public inputs = {}", proof.public_inputs.len());
|
||||
println!("agg pub input = {:?}", proof.public_inputs);
|
||||
println!("outer circuit size = {:?}", vd_agg.common.degree_bits());
|
||||
|
||||
// serialization
|
||||
// // let gate_serializer = DefaultGateSerializer;
|
||||
// // let generator_serializer =DefaultGeneratorSerializer::<C, D>::default();
|
||||
// let outer_data_bytes = vd_agg.to_bytes(&gate_serializer, &generator_serializer).unwrap();
|
||||
// println!("outer proof circuit data size = {} bytes", outer_data_bytes.len());
|
||||
// let file_path = "outer_circ_data.bin";
|
||||
// // Write data to the file
|
||||
// write_bytes_to_file(outer_data_bytes, file_path).unwrap();
|
||||
// println!("Data written to {}", file_path);
|
||||
|
||||
// Verify the proof
|
||||
let verifier_data = vd_agg.verifier_data();
|
||||
assert!(
|
||||
verifier_data.verify(proof).is_ok(),
|
||||
"Merkle proof verification failed"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// test another approach of the simple recursion
|
||||
#[test]
|
||||
pub fn test_simple_recursion_approach2()-> anyhow::Result<()>{
|
||||
pub fn test_simple_recursion()-> anyhow::Result<()>{
|
||||
// number of samples in each proof
|
||||
let n_samples = 5;
|
||||
// number of inner proofs:
|
||||
const n_inner: usize = 4;
|
||||
const N_INNER: usize = 4;
|
||||
let mut data: Option<CircuitData<F, C, D>> = None;
|
||||
|
||||
// get proofs
|
||||
let mut proofs_with_pi = vec![];
|
||||
for i in 0..n_inner{
|
||||
for i in 0..N_INNER {
|
||||
// build the circuit
|
||||
let (data_i, pw) = build_circuit(n_samples, i)?;
|
||||
proofs_with_pi.push(prove_circuit(&data_i, &pw)?);
|
||||
data = Some(data_i);
|
||||
}
|
||||
let data = data.unwrap();
|
||||
println!("inner circuit size = {:?}", data.common.degree_bits());
|
||||
|
||||
// careful here, the sampling recursion is the default so proofs should be for circuit
|
||||
// with default params
|
||||
let sampling_inner_circ = SamplingRecursion::default();
|
||||
let rec_circuit = SimpleRecursionCircuit::<_,n_inner>::new(sampling_inner_circ);
|
||||
let sampling_inner_circ = SamplingRecursion::<F,D,HF,C>::new(Params::default().circuit_params);
|
||||
let rec_circuit = SimpleRecursionCircuit::<F,D, _, N_INNER, C>::new(sampling_inner_circ);
|
||||
|
||||
// Create the circuit
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
@ -156,7 +50,7 @@ pub fn test_simple_recursion_approach2()-> anyhow::Result<()>{
|
||||
let start = Instant::now();
|
||||
let agg_data = builder.build::<C>();
|
||||
println!("build time = {:?}", start.elapsed());
|
||||
println!("circuit size = {:?}", data.common.degree_bits());
|
||||
println!("agg circuit size = {:?}", agg_data.common.degree_bits());
|
||||
|
||||
let mut default_entropy = HashOut::ZERO;
|
||||
default_entropy.elements[0] = F::from_canonical_u64(1234567);
|
||||
@ -172,13 +66,97 @@ pub fn test_simple_recursion_approach2()-> anyhow::Result<()>{
|
||||
let start = Instant::now();
|
||||
let proof = agg_data.prove(pw)?;
|
||||
println!("prove time = {:?}", start.elapsed());
|
||||
println!("public input count = {:?}", proof.public_inputs.len());
|
||||
|
||||
// Verify the proof
|
||||
let verifier_data = agg_data.verifier_data();
|
||||
assert!(
|
||||
verifier_data.verify(proof).is_ok(),
|
||||
"Merkle proof verification failed"
|
||||
"proof verification failed"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// test the simple recursion approach with hashed public input
|
||||
#[test]
|
||||
pub fn test_simple_recursion_with_hashed_pi()-> anyhow::Result<()>{
|
||||
// number of samples in each proof
|
||||
let n_samples = 5;
|
||||
// number of inner proofs:
|
||||
const N_INNER: usize = 4;
|
||||
let mut data: Option<CircuitData<F, C, D>> = None;
|
||||
|
||||
// get proofs
|
||||
let mut proofs_with_pi = vec![];
|
||||
for i in 0..N_INNER {
|
||||
// build the circuit
|
||||
let (data_i, pw) = build_circuit(n_samples, i)?;
|
||||
proofs_with_pi.push(prove_circuit(&data_i, &pw)?);
|
||||
data = Some(data_i);
|
||||
}
|
||||
let data = data.unwrap();
|
||||
println!("inner circuit size = {:?}", data.common.degree_bits());
|
||||
|
||||
// careful here, the sampling recursion is the default so proofs should be for circuit
|
||||
// with default params
|
||||
let sampling_inner_circ = SamplingRecursion::<F,D,HF,C>::new(Params::default().circuit_params);
|
||||
let rec_circuit = SimpleRecursionCircuitHashedPI::<F,D, _, N_INNER, C>::new(sampling_inner_circ);
|
||||
|
||||
// Create the circuit
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
// Create a PartialWitness
|
||||
let mut pw = PartialWitness::new();
|
||||
|
||||
let targets = rec_circuit.build_circuit::<HF>(&mut builder)?;
|
||||
|
||||
let start = Instant::now();
|
||||
let agg_data = builder.build::<C>();
|
||||
println!("build time = {:?}", start.elapsed());
|
||||
println!("agg circuit size = {:?}", agg_data.common.degree_bits());
|
||||
|
||||
let mut default_entropy = HashOut::ZERO;
|
||||
default_entropy.elements[0] = F::from_canonical_u64(1234567);
|
||||
|
||||
let w = SimpleRecursionInputHashedPI{
|
||||
proofs: proofs_with_pi.clone(),
|
||||
verifier_data: data.verifier_data(),
|
||||
};
|
||||
|
||||
rec_circuit.assign_witness(&mut pw,&targets,w)?;
|
||||
|
||||
let start = Instant::now();
|
||||
let proof = agg_data.prove(pw)?;
|
||||
println!("prove time = {:?}", start.elapsed());
|
||||
println!("public input count = {:?}", proof.public_inputs.len());
|
||||
|
||||
// Verify the proof
|
||||
let verifier_data = agg_data.verifier_data();
|
||||
assert!(
|
||||
verifier_data.verify(proof.clone()).is_ok(),
|
||||
"proof verification failed"
|
||||
);
|
||||
|
||||
let inner_pi: Vec<F> = proofs_with_pi.iter()
|
||||
.flat_map(|p| p.public_inputs.iter())
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
assert!(
|
||||
check_agg_proof_hash::<HF>(inner_pi, proof.public_inputs),
|
||||
"public input verification failed"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check_agg_proof_hash<H: AlgebraicHasher<F>>(inner_pi: Vec<F>, agg_pi: Vec<F>) -> bool{
|
||||
|
||||
if agg_pi.len() != NUM_HASH_OUT_ELTS {
|
||||
return false;
|
||||
}
|
||||
let expected = H::hash_no_pad(&inner_pi);
|
||||
|
||||
expected == HashOut::from_vec(agg_pi)
|
||||
}
|
64
proof-input/src/recursion/simple_tree.rs
Normal file
64
proof-input/src/recursion/simple_tree.rs
Normal file
@ -0,0 +1,64 @@
|
||||
// tests for simple recursion approaches
|
||||
|
||||
use std::time::Instant;
|
||||
use plonky2::plonk::circuit_data::{CircuitData};
|
||||
use crate::gen_input::{build_circuit, prove_circuit};
|
||||
use codex_plonky2_circuits::recursion::simple::simple_tree_recursion::aggregate_sampling_proofs_tree;
|
||||
use crate::params::{C, D, F,HF};
|
||||
|
||||
// Test simple tree recursion
|
||||
#[test]
|
||||
fn test_simple_tree_recursion() -> anyhow::Result<()> {
|
||||
// number of samples in each proof
|
||||
let n_samples = 5;
|
||||
// number of inner proofs:
|
||||
let n_inner = 4;
|
||||
let mut data: Option<CircuitData<F, C, D>> = None;
|
||||
|
||||
// get proofs
|
||||
let mut proofs_with_pi = vec![];
|
||||
for i in 0..n_inner{
|
||||
// build the circuit
|
||||
let (data_i, pw) = build_circuit(n_samples, i)?;
|
||||
proofs_with_pi.push(prove_circuit(&data_i, &pw)?);
|
||||
data = Some(data_i);
|
||||
}
|
||||
|
||||
let data = data.unwrap();
|
||||
println!("inner circuit size = {:?}", data.common.degree_bits());
|
||||
// serialization
|
||||
// let gate_serializer = DefaultGateSerializer;
|
||||
// let generator_serializer =DefaultGeneratorSerializer::<C, D>::default();
|
||||
// let data_bytes = data.to_bytes(&gate_serializer, &generator_serializer).unwrap();
|
||||
// println!("inner proof circuit data size = {} bytes", data_bytes.len());
|
||||
// let file_path = "inner_circ_data.bin";
|
||||
// // Write data to the file
|
||||
// write_bytes_to_file(data_bytes, file_path).unwrap();
|
||||
// println!("Data written to {}", file_path);
|
||||
|
||||
let start_time = Instant::now();
|
||||
let (proof, vd_agg) = aggregate_sampling_proofs_tree::<F,D,C,HF>(&proofs_with_pi, data.verifier_data())?;
|
||||
println!("prove_time = {:?}", start_time.elapsed());
|
||||
println!("num of public inputs = {}", proof.public_inputs.len());
|
||||
println!("agg pub input = {:?}", proof.public_inputs);
|
||||
println!("outer circuit size = {:?}", vd_agg.common.degree_bits());
|
||||
|
||||
// serialization
|
||||
// // let gate_serializer = DefaultGateSerializer;
|
||||
// // let generator_serializer =DefaultGeneratorSerializer::<C, D>::default();
|
||||
// let outer_data_bytes = vd_agg.to_bytes(&gate_serializer, &generator_serializer).unwrap();
|
||||
// println!("outer proof circuit data size = {} bytes", outer_data_bytes.len());
|
||||
// let file_path = "outer_circ_data.bin";
|
||||
// // Write data to the file
|
||||
// write_bytes_to_file(outer_data_bytes, file_path).unwrap();
|
||||
// println!("Data written to {}", file_path);
|
||||
|
||||
// Verify the proof
|
||||
let verifier_data = vd_agg;//.verifier_data();
|
||||
assert!(
|
||||
verifier_data.verify(proof).is_ok(),
|
||||
"Merkle proof verification failed"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
@ -3,47 +3,35 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::time::Instant;
|
||||
use anyhow::{anyhow, Result};
|
||||
use plonky2::hash::poseidon::PoseidonHash;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, CommonCircuitData, VerifierCircuitData, VerifierCircuitTarget, VerifierOnlyCircuitData};
|
||||
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, GenericHashOut, Hasher, PoseidonGoldilocksConfig};
|
||||
use plonky2::plonk::config::{GenericConfig, GenericHashOut, Hasher};
|
||||
use plonky2_field::types::Field;
|
||||
use codex_plonky2_circuits::circuits::sample_cells::{SampleCircuit, SampleCircuitInput};
|
||||
use codex_plonky2_circuits::params::{F, D, C, Plonky2Proof};
|
||||
use codex_plonky2_circuits::circuits::sample_cells::SampleCircuitInput;
|
||||
use crate::params::{C, D, F, HF, Params};
|
||||
use codex_plonky2_circuits::recursion::circuits::sampling_inner_circuit::SamplingRecursion;
|
||||
use codex_plonky2_circuits::recursion::circuits::inner_circuit::InnerCircuit;
|
||||
use plonky2_poseidon2::poseidon2_hash::poseidon2::{Poseidon2, Poseidon2Hash};
|
||||
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
||||
use crate::gen_input::get_m_default_circ_input;
|
||||
use codex_plonky2_circuits::recursion::tree_recursion::{NodeCircuit, TreeRecursion};
|
||||
use codex_plonky2_circuits::recursion::tree1::tree_circuit::TreeRecursion;
|
||||
|
||||
/// Uses node recursion to sample the dataset
|
||||
#[test]
|
||||
fn test_node_recursion() -> Result<()> {
|
||||
// const D: usize = 2;
|
||||
// type C = PoseidonGoldilocksConfig;
|
||||
// type F = <C as GenericConfig<D>>::F;
|
||||
fn test_tree1_node_recursion() -> anyhow::Result<()> {
|
||||
const M: usize = 1;
|
||||
const N: usize = 2;
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
let one = builder.one();
|
||||
let default_params = Params::default().circuit_params;
|
||||
let inner_sampling_circuit = SamplingRecursion::<F,D,HF,C>::new(default_params);
|
||||
|
||||
let inner_sampling_circuit = SamplingRecursion::default();
|
||||
|
||||
let mut node = NodeCircuit::<_,M,N>::new(inner_sampling_circuit);
|
||||
let mut tree_circ = TreeRecursion::new(node);
|
||||
let circ_input = get_m_default_circ_input::<M>();
|
||||
|
||||
let s = Instant::now();
|
||||
tree_circ.build()?;
|
||||
let mut tree_circ = TreeRecursion::<F,D,_,M,N,C>::build::<HF>(inner_sampling_circuit)?;
|
||||
println!("build = {:?}", s.elapsed());
|
||||
println!("tree circuit size = {:?}", tree_circ.node_circ.cyclic_circuit_data.common.degree_bits());
|
||||
let s = Instant::now();
|
||||
let proof = tree_circ.prove(&circ_input,None, true)?;
|
||||
println!("prove = {:?}", s.elapsed());
|
||||
println!("num of pi = {}", proof.public_inputs.len());
|
||||
println!("pub input: {:?}", proof.public_inputs);
|
||||
let s = Instant::now();
|
||||
assert!(
|
||||
tree_circ.verify_proof(proof).is_ok(),
|
||||
@ -56,40 +44,32 @@ mod tests {
|
||||
|
||||
/// Uses node recursion to sample the dataset
|
||||
#[test]
|
||||
fn test_tree_recursion_approach1() -> Result<()> {
|
||||
// const D: usize = 2;
|
||||
// type C = PoseidonGoldilocksConfig;
|
||||
// type F = <C as GenericConfig<D>>::F;
|
||||
fn test_tree_recursion_approach1() -> anyhow::Result<()> {
|
||||
const M: usize = 1;
|
||||
const N: usize = 2;
|
||||
|
||||
const DEPTH: usize = 3;
|
||||
const TOTAL_INPUT: usize = (N.pow(DEPTH as u32) - 1) / (N - 1);
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let inner_sampling_circuit = SamplingRecursion::default();
|
||||
|
||||
let mut node = NodeCircuit::<_,M,N>::new(inner_sampling_circuit);
|
||||
let mut tree_circ = TreeRecursion::new(node);
|
||||
let default_params = Params::default().circuit_params;
|
||||
let inner_sampling_circuit = SamplingRecursion::<F,D,HF,C>::new(default_params);
|
||||
|
||||
let all_circ_input = get_m_default_circ_input::<TOTAL_INPUT>().to_vec();
|
||||
|
||||
let s = Instant::now();
|
||||
tree_circ.build()?;
|
||||
let mut tree_circ = TreeRecursion::<F,D,_,M,N,C>::build::<HF>(inner_sampling_circuit)?;
|
||||
println!("build = {:?}", s.elapsed());
|
||||
println!("tree circuit size = {:?}", tree_circ.node_circ.cyclic_circuit_data.common.degree_bits());
|
||||
let s = Instant::now();
|
||||
let proof = tree_circ.prove_tree(all_circ_input.clone(),DEPTH)?;
|
||||
println!("prove = {:?}", s.elapsed());
|
||||
println!("num of pi = {}", proof.public_inputs.len());
|
||||
println!("pub input: {:?}", proof.public_inputs);
|
||||
|
||||
// Extract the final public input hash from the proof
|
||||
let final_proof_hash = &proof.public_inputs[0..4];
|
||||
|
||||
// Recompute the expected final public input hash (outside the circuit)
|
||||
let expected_hash = compute_expected_pub_input_hash::<SamplingRecursion>(
|
||||
let expected_hash = compute_expected_pub_input_hash(
|
||||
&all_circ_input,
|
||||
DEPTH,
|
||||
M,
|
||||
@ -112,8 +92,8 @@ mod tests {
|
||||
/// Recursively compute the final public input hash for a single node in the recursion tree.
|
||||
/// This is the same logic from `NodeCircuit::build_circuit`
|
||||
/// TODO: optimize this
|
||||
fn compute_node_hash<I: InnerCircuit<Input = SampleCircuitInput<F,D>>>(
|
||||
all_circ_inputs: &[I::Input],
|
||||
fn compute_node_hash(
|
||||
all_circ_inputs: &[SampleCircuitInput<F, D>],
|
||||
depth: usize,
|
||||
current_depth: usize,
|
||||
node_idx: usize,
|
||||
@ -133,12 +113,12 @@ mod tests {
|
||||
let mut pi_vec = vec![inp.slot_index];
|
||||
pi_vec.extend_from_slice(&inp.dataset_root.elements);
|
||||
pi_vec.extend_from_slice(&inp.entropy.elements);
|
||||
let hash_res = PoseidonHash::hash_no_pad(&pi_vec);
|
||||
let hash_res = HF::hash_no_pad(&pi_vec);
|
||||
outer_pi_hashes.extend_from_slice(&hash_res.elements);
|
||||
}
|
||||
|
||||
// hash all these M hashes into one
|
||||
let outer_pi_hash = PoseidonHash::hash_no_pad(&outer_pi_hashes);
|
||||
let outer_pi_hash = HF::hash_no_pad(&outer_pi_hashes);
|
||||
|
||||
let is_leaf = current_depth == depth - 1;
|
||||
|
||||
@ -153,11 +133,11 @@ mod tests {
|
||||
|
||||
let mut inner_pub_input_hashes = vec![];
|
||||
for i in child_start..child_start + N {
|
||||
let child_hash = compute_node_hash::<I>(all_circ_inputs, depth, next_depth, i, M, N);
|
||||
let child_hash = compute_node_hash(all_circ_inputs, depth, next_depth, i, M, N);
|
||||
inner_pub_input_hashes.extend_from_slice(&child_hash);
|
||||
}
|
||||
|
||||
let inner_pub_input_hash = PoseidonHash::hash_no_pad(&inner_pub_input_hashes);
|
||||
let inner_pub_input_hash = HF::hash_no_pad(&inner_pub_input_hashes);
|
||||
inner_pub_input_hash.elements
|
||||
};
|
||||
|
||||
@ -166,20 +146,20 @@ mod tests {
|
||||
final_input.extend_from_slice(&outer_pi_hash.elements);
|
||||
final_input.extend_from_slice(&inner_pi_hash_or_zero);
|
||||
|
||||
let final_hash = PoseidonHash::hash_no_pad(&final_input);
|
||||
let final_hash = HF::hash_no_pad(&final_input);
|
||||
final_hash.elements
|
||||
}
|
||||
|
||||
/// Compute the expected public input hash for the entire recursion tree.
|
||||
/// This function calls `compute_node_hash` starting from the root (layer 0, node 0).
|
||||
pub fn compute_expected_pub_input_hash<I: InnerCircuit<Input = SampleCircuitInput<F,D>>>(
|
||||
all_circ_inputs: &[I::Input],
|
||||
pub fn compute_expected_pub_input_hash(
|
||||
all_circ_inputs: &[SampleCircuitInput<F, D>],
|
||||
depth: usize,
|
||||
M: usize,
|
||||
N: usize,
|
||||
) -> Result<Vec<F>> {
|
||||
) -> anyhow::Result<Vec<F>> {
|
||||
// The root node is at layer = 0 and node_idx = 0
|
||||
let final_hash = compute_node_hash::<I>(all_circ_inputs, depth, 0, 0, M, N);
|
||||
let final_hash = compute_node_hash(all_circ_inputs, depth, 0, 0, M, N);
|
||||
Ok(final_hash.to_vec())
|
||||
}
|
||||
}
|
@ -3,41 +3,38 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::time::Instant;
|
||||
use anyhow::{anyhow, Result};
|
||||
use plonky2::hash::hash_types::HashOut;
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, CommonCircuitData, VerifierCircuitData, VerifierCircuitTarget, VerifierOnlyCircuitData};
|
||||
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, GenericHashOut, Hasher, PoseidonGoldilocksConfig};
|
||||
use plonky2::plonk::proof::ProofWithPublicInputs;
|
||||
use codex_plonky2_circuits::circuits::params::CircuitParams;
|
||||
use codex_plonky2_circuits::circuits::sample_cells::{SampleCircuit, SampleCircuitInput};
|
||||
use codex_plonky2_circuits::params::{F, D, C, Plonky2Proof};
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::config::{GenericConfig, Hasher};
|
||||
use plonky2::plonk::proof::{ProofWithPublicInputs};
|
||||
use codex_plonky2_circuits::circuits::sample_cells::SampleCircuit;
|
||||
use crate::params::{F, D, C, HF};
|
||||
use codex_plonky2_circuits::recursion::circuits::sampling_inner_circuit::SamplingRecursion;
|
||||
use codex_plonky2_circuits::recursion::circuits::inner_circuit::InnerCircuit;
|
||||
use codex_plonky2_circuits::recursion::leaf_circuit::{LeafCircuit, LeafInput};
|
||||
use plonky2_poseidon2::poseidon2_hash::poseidon2::{Poseidon2, Poseidon2Hash};
|
||||
use codex_plonky2_circuits::recursion::tree2::leaf_circuit::{LeafCircuit, LeafInput};
|
||||
// use plonky2_poseidon2::poseidon2_hash::poseidon2::{Poseidon2, Poseidon2Hash};
|
||||
use crate::gen_input::gen_testing_circuit_input;
|
||||
use crate::params::TestParams;
|
||||
use codex_plonky2_circuits::recursion::tree_recursion2::{NodeCircuit as nodeC, TreeRecursion as TR};
|
||||
use codex_plonky2_circuits::recursion::tree2::utils::{get_dummy_leaf_proof, get_dummy_node_proof};
|
||||
use crate::gen_input::get_m_default_circ_input;
|
||||
use crate::params::Params;
|
||||
use codex_plonky2_circuits::recursion::tree2::{node_circuit::NodeCircuit, tree_circuit::TreeRecursion};
|
||||
use codex_plonky2_circuits::recursion::tree2::dummy_gen::DummyProofGen;
|
||||
use codex_plonky2_circuits::circuits::utils::vec_to_array;
|
||||
|
||||
|
||||
/// Uses node recursion to sample the dataset
|
||||
#[test]
|
||||
fn test_leaf_circuit() -> Result<()> {
|
||||
// const D: usize = 2;
|
||||
// type C = PoseidonGoldilocksConfig;
|
||||
// type F = <C as GenericConfig<D>>::F;
|
||||
fn test_leaf_circuit() -> anyhow::Result<()> {
|
||||
const M: usize = 1;
|
||||
const N: usize = 2;
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
let params = TestParams::default();
|
||||
let params = Params::default();
|
||||
|
||||
let one_circ_input = gen_testing_circuit_input::<F,D>(¶ms);
|
||||
let samp_circ = SampleCircuit::<F,D>::new(CircuitParams::default());
|
||||
let inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut builder);
|
||||
let one_circ_input = gen_testing_circuit_input::<F,D>(¶ms.input_params);
|
||||
let samp_circ = SampleCircuit::<F,D, HF>::new(params.circuit_params);
|
||||
let inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut builder)?;
|
||||
let mut pw = PartialWitness::<F>::new();
|
||||
samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input);
|
||||
let inner_d = builder.build::<C>();
|
||||
@ -50,21 +47,20 @@ mod tests {
|
||||
let config2 = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config2);
|
||||
|
||||
let inner_circ = SamplingRecursion::default();
|
||||
let leaf_circuit = LeafCircuit::new(inner_circ);
|
||||
let inner_circ = SamplingRecursion::<F,D,HF,C>::new(Params::default().circuit_params);
|
||||
let leaf_circuit = LeafCircuit::<F,D,_>::new(inner_circ);
|
||||
|
||||
let s = Instant::now();
|
||||
let leaf_tar = leaf_circuit.build(&mut builder)?;
|
||||
let leaf_tar = leaf_circuit.build::<C,HF>(&mut builder)?;
|
||||
let circ_data = builder.build::<C>();
|
||||
println!("build = {:?}", s.elapsed());
|
||||
println!("sampling circuit size = {:?}", circ_data.common.degree_bits());
|
||||
let s = Instant::now();
|
||||
// let proof = tree_circ.prove(&[leaf_in],None, true)?;
|
||||
let mut pw = PartialWitness::<F>::new();
|
||||
leaf_circuit.assign_targets(&mut pw, &leaf_tar, &leaf_in)?;
|
||||
leaf_circuit.assign_targets::<C,HF>(&mut pw, &leaf_tar, &leaf_in)?;
|
||||
let proof = circ_data.prove(pw)?;
|
||||
println!("prove = {:?}", s.elapsed());
|
||||
println!("num of pi = {}", proof.public_inputs.len());
|
||||
println!("pub input: {:?}", proof.public_inputs);
|
||||
let s = Instant::now();
|
||||
assert!(
|
||||
circ_data.verify(proof).is_ok(),
|
||||
@ -76,8 +72,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_node_circuit_approach2() -> Result<()> {
|
||||
// use predefined: C, D, F c
|
||||
fn test_node_circuit_approach2() -> anyhow::Result<()> {
|
||||
const N: usize = 2; // binary tree
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
@ -85,11 +80,10 @@ mod tests {
|
||||
|
||||
//------------ sampling inner circuit ----------------------
|
||||
// Circuit that does the sampling - default input
|
||||
let mut params = TestParams::default();
|
||||
// params.n_samples = 10;
|
||||
let one_circ_input = gen_testing_circuit_input::<F,D>(¶ms);
|
||||
let samp_circ = SampleCircuit::<F,D>::new(CircuitParams::default());
|
||||
let inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut sampling_builder);
|
||||
let mut params = Params::default();
|
||||
let one_circ_input = gen_testing_circuit_input::<F,D>(¶ms.input_params);
|
||||
let samp_circ = SampleCircuit::<F,D,HF>::new(params.circuit_params);
|
||||
let inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut sampling_builder)?;
|
||||
// get generate a sampling proof
|
||||
let mut pw = PartialWitness::<F>::new();
|
||||
samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input);
|
||||
@ -98,8 +92,8 @@ mod tests {
|
||||
|
||||
// ------------------- leaf --------------------
|
||||
// leaf circuit that verifies the sampling proof
|
||||
let inner_circ = SamplingRecursion::default();
|
||||
let leaf_circuit = LeafCircuit::new(inner_circ);
|
||||
let inner_circ = SamplingRecursion::<F,D,HF,C>::new(Params::default().circuit_params);
|
||||
let leaf_circuit = LeafCircuit::<F,D,_>::new(inner_circ);
|
||||
|
||||
let leaf_in = LeafInput{
|
||||
inner_proof,
|
||||
@ -109,17 +103,17 @@ mod tests {
|
||||
let mut leaf_builder = CircuitBuilder::<F, D>::new(config);
|
||||
// build
|
||||
let s = Instant::now();
|
||||
let leaf_targets = leaf_circuit.build(&mut leaf_builder)?;
|
||||
let leaf_targets = leaf_circuit.build::<C,HF>(&mut leaf_builder)?;
|
||||
let leaf_circ_data = leaf_builder.build::<C>();
|
||||
println!("build = {:?}", s.elapsed());
|
||||
println!("leaf circuit size = {:?}", leaf_circ_data.common.degree_bits());
|
||||
// prove
|
||||
let s = Instant::now();
|
||||
let mut pw = PartialWitness::<F>::new();
|
||||
leaf_circuit.assign_targets(&mut pw, &leaf_targets, &leaf_in)?;
|
||||
leaf_circuit.assign_targets::<C,HF>(&mut pw, &leaf_targets, &leaf_in)?;
|
||||
let leaf_proof = leaf_circ_data.prove(pw)?;
|
||||
println!("prove = {:?}", s.elapsed());
|
||||
println!("num of pi = {}", leaf_proof.public_inputs.len());
|
||||
println!("pub input: {:?}", leaf_proof.public_inputs);
|
||||
// verify
|
||||
let s = Instant::now();
|
||||
assert!(
|
||||
@ -132,34 +126,30 @@ mod tests {
|
||||
// node circuit that verifies leafs or itself
|
||||
// build
|
||||
let s = Instant::now();
|
||||
let mut node = nodeC::build_circuit()?;
|
||||
let mut node = NodeCircuit::<F,D,C,N>::build_circuit::<_,HF>(leaf_circuit)?;
|
||||
println!("build = {:?}", s.elapsed());
|
||||
println!("leaf circuit size = {:?}", node.node_data.node_circuit_data.common.degree_bits());
|
||||
|
||||
// prove leaf
|
||||
let s = Instant::now();
|
||||
let mut pw = PartialWitness::<F>::new();
|
||||
let leaf_proofs: [ProofWithPublicInputs<F, C, D>; N] = (0..N)
|
||||
let leaf_proofs: [ProofWithPublicInputs<F, C, D>; N] =
|
||||
vec_to_array::<N, ProofWithPublicInputs<F, C, D>>(
|
||||
(0..N)
|
||||
.map(|_| {
|
||||
leaf_proof.clone()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.map_err(|_| anyhow!("Expected exactly M inner circuits"))?;
|
||||
let dummy_node_proof = get_dummy_node_proof(
|
||||
)?;
|
||||
let dummy_node_proofs: [ProofWithPublicInputs<F, C, D>; N] =
|
||||
DummyProofGen::<F, D, C>::gen_n_dummy_node_proofs::<N>(
|
||||
&node.node_data.inner_node_common_data,
|
||||
&node.node_data.node_circuit_data.verifier_only,
|
||||
);
|
||||
let dummy_node_proofs: [ProofWithPublicInputs<F, C, D>; N] = (0..N)
|
||||
.map(|_| {
|
||||
dummy_node_proof.clone()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.map_err(|_| anyhow!("Expected exactly M inner circuits"))?;
|
||||
nodeC::<N>::assign_targets(
|
||||
)?;
|
||||
NodeCircuit::<F,D,C,N>::assign_targets(
|
||||
node.node_targets.clone(), //targets
|
||||
Some(leaf_proofs), // leaf proofs
|
||||
Some(dummy_node_proofs), // node proofs (dummy here)
|
||||
leaf_proofs, // leaf proofs
|
||||
dummy_node_proofs, // node proofs (dummy here)
|
||||
&node.node_data.leaf_circuit_data.verifier_only, // leaf verifier data
|
||||
&mut pw, // partial witness
|
||||
true // is leaf
|
||||
@ -167,7 +157,6 @@ mod tests {
|
||||
let node_proof = node.node_data.node_circuit_data.prove(pw)?;
|
||||
println!("prove = {:?}", s.elapsed());
|
||||
println!("num of pi = {}", node_proof.public_inputs.len());
|
||||
println!("pub input: {:?}", node_proof.public_inputs);
|
||||
let s = Instant::now();
|
||||
assert!(
|
||||
node.node_data.node_circuit_data.verify(node_proof.clone()).is_ok(),
|
||||
@ -175,30 +164,26 @@ mod tests {
|
||||
);
|
||||
println!("verify = {:?}", s.elapsed());
|
||||
|
||||
|
||||
// prove node
|
||||
let s = Instant::now();
|
||||
let mut pw = PartialWitness::<F>::new();
|
||||
let node_proofs: [ProofWithPublicInputs<F, C, D>; N] = (0..N)
|
||||
let node_proofs: [ProofWithPublicInputs<F, C, D>; N] =
|
||||
vec_to_array::<N, ProofWithPublicInputs<F, C, D>>(
|
||||
(0..N)
|
||||
.map(|_| {
|
||||
node_proof.clone()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.map_err(|_| anyhow!("Expected exactly M inner circuits"))?;
|
||||
let dummy_leaf_proof = get_dummy_leaf_proof(
|
||||
)?;
|
||||
let dummy_leaf_proofs: [ProofWithPublicInputs<F, C, D>; N] =
|
||||
DummyProofGen::<F, D, C>::gen_n_dummy_leaf_proofs::<N>(
|
||||
&node.node_data.leaf_circuit_data.common
|
||||
);
|
||||
let dummy_leaf_proofs: [ProofWithPublicInputs<F, C, D>; N] = (0..N)
|
||||
.map(|_| {
|
||||
dummy_leaf_proof.clone()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.map_err(|_| anyhow!("Expected exactly M inner circuits"))?;
|
||||
nodeC::<N>::assign_targets(
|
||||
)?;
|
||||
NodeCircuit::<F,D,C,N>::assign_targets(
|
||||
node.node_targets.clone(), //targets
|
||||
Some(dummy_leaf_proofs), // leaf proofs
|
||||
Some(node_proofs), // node proofs (dummy here)
|
||||
dummy_leaf_proofs, // leaf proofs
|
||||
node_proofs, // node proofs (dummy here)
|
||||
&node.node_data.leaf_circuit_data.verifier_only, // leaf verifier data
|
||||
&mut pw, // partial witness
|
||||
false // is leaf
|
||||
@ -207,7 +192,6 @@ mod tests {
|
||||
// let node_proof = node_d.prove(pw)?;
|
||||
println!("prove = {:?}", s.elapsed());
|
||||
println!("num of pi = {}", node_proof.public_inputs.len());
|
||||
println!("pub input: {:?}", node_proof.public_inputs);
|
||||
let s = Instant::now();
|
||||
assert!(
|
||||
node.node_data.node_circuit_data.verify(node_proof.clone()).is_ok(),
|
||||
@ -219,8 +203,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tree_recursion_approach2() -> Result<()> {
|
||||
// use predefined: C, D, F c
|
||||
fn test_tree_recursion_approach2() -> anyhow::Result<()> {
|
||||
const N: usize = 2; // binary tree
|
||||
const K: usize = 4; // number of leaves/slots sampled - should be power of 2
|
||||
|
||||
@ -229,22 +212,21 @@ mod tests {
|
||||
|
||||
//------------ sampling inner circuit ----------------------
|
||||
// Circuit that does the sampling - default input
|
||||
let mut params = TestParams::default();
|
||||
params.n_samples = 10;
|
||||
let one_circ_input = gen_testing_circuit_input::<F,D>(¶ms);
|
||||
let samp_circ = SampleCircuit::<F,D>::new(CircuitParams::default());
|
||||
let inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut sampling_builder);
|
||||
let mut params = Params::default();
|
||||
let one_circ_input = gen_testing_circuit_input::<F,D>(¶ms.input_params);
|
||||
let samp_circ = SampleCircuit::<F,D,HF>::new(params.circuit_params);
|
||||
let inner_tar = samp_circ.sample_slot_circuit_with_public_input(&mut sampling_builder)?;
|
||||
// get generate a sampling proof
|
||||
let mut pw = PartialWitness::<F>::new();
|
||||
samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input);
|
||||
samp_circ.sample_slot_assign_witness(&mut pw,&inner_tar,&one_circ_input)?;
|
||||
let inner_data = sampling_builder.build::<C>();
|
||||
println!("sampling circuit degree bits = {:?}", inner_data.common.degree_bits());
|
||||
let inner_proof = inner_data.prove(pw)?;
|
||||
|
||||
// ------------------- leaf --------------------
|
||||
// leaf circuit that verifies the sampling proof
|
||||
let inner_circ = SamplingRecursion::default();
|
||||
let leaf_circuit = LeafCircuit::new(inner_circ);
|
||||
let inner_circ = SamplingRecursion::<F,D,HF,C>::new(Params::default().circuit_params);
|
||||
let leaf_circuit = LeafCircuit::<F,D,_>::new(inner_circ);
|
||||
|
||||
let leaf_in = LeafInput{
|
||||
inner_proof,
|
||||
@ -254,18 +236,17 @@ mod tests {
|
||||
let mut leaf_builder = CircuitBuilder::<F, D>::new(config);
|
||||
// build
|
||||
let s = Instant::now();
|
||||
let leaf_targets = leaf_circuit.build(&mut leaf_builder)?;
|
||||
let leaf_targets = leaf_circuit.build::<C,HF>(&mut leaf_builder)?;
|
||||
let leaf_circ_data = leaf_builder.build::<C>();
|
||||
println!("build = {:?}", s.elapsed());
|
||||
println!("leaf circuit degree bits = {:?}", leaf_circ_data.common.degree_bits());
|
||||
println!("leaf circuit size = {:?}", leaf_circ_data.common.degree_bits());
|
||||
// prove
|
||||
let s = Instant::now();
|
||||
let mut pw = PartialWitness::<F>::new();
|
||||
leaf_circuit.assign_targets(&mut pw, &leaf_targets, &leaf_in)?;
|
||||
leaf_circuit.assign_targets::<C,HF>(&mut pw, &leaf_targets, &leaf_in)?;
|
||||
let leaf_proof = leaf_circ_data.prove(pw)?;
|
||||
println!("prove = {:?}", s.elapsed());
|
||||
println!("num of pi = {}", leaf_proof.public_inputs.len());
|
||||
println!("pub input: {:?}", leaf_proof.public_inputs);
|
||||
// verify
|
||||
let s = Instant::now();
|
||||
assert!(
|
||||
@ -278,30 +259,73 @@ mod tests {
|
||||
// node circuit that verifies leafs or itself
|
||||
// build
|
||||
let s = Instant::now();
|
||||
let mut tree = TR::<N>::build()?;
|
||||
let mut tree = TreeRecursion::<F,D,C,N>::build::<_,HF>(leaf_circuit)?;
|
||||
println!("build = {:?}", s.elapsed());
|
||||
println!("tree circuit degree bits = {:?}", tree.node.node_data.node_circuit_data.common.degree_bits());
|
||||
println!("node circuit degree bits = {:?}", tree.node.node_data.node_circuit_data.common.degree_bits());
|
||||
|
||||
// prove leaf
|
||||
let s = Instant::now();
|
||||
// let mut pw = PartialWitness::<F>::new();
|
||||
let leaf_proofs: Vec<ProofWithPublicInputs<F, C, D>> = (0..K)
|
||||
.map(|_| {
|
||||
leaf_proof.clone()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let tree_root_proof = tree.prove_tree(leaf_proofs)?;
|
||||
let tree_root_proof = tree.prove_tree(leaf_proofs.clone())?;
|
||||
println!("prove = {:?}", s.elapsed());
|
||||
println!("num of pi = {}", tree_root_proof.public_inputs.len());
|
||||
println!("pub input: {:?}", tree_root_proof.public_inputs);
|
||||
let s = Instant::now();
|
||||
assert!(
|
||||
tree.verify_proof(tree_root_proof.clone()).is_ok(),
|
||||
tree.verify_proof(tree_root_proof.clone(),false).is_ok(),
|
||||
"proof verification failed"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
tree_root_proof.public_inputs[0..4].to_vec(),
|
||||
get_expected_tree_root_pi_hash::<N>(leaf_proofs),
|
||||
"Public input of tree_root_proof does not match the expected root hash"
|
||||
);
|
||||
println!("verify = {:?}", s.elapsed());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ------------ Public Input Verification ------------
|
||||
/// Recompute the expected root public input hash outside the circuit
|
||||
fn get_expected_tree_root_pi_hash<const N:usize>(leaf_proofs: Vec<ProofWithPublicInputs<F, C, D>>)
|
||||
-> Vec<F>{
|
||||
// Step 1: Extract relevant public inputs from each leaf proof
|
||||
// Assuming the first public input is the hash used for tree hashing
|
||||
let mut current_hashes: Vec<HashOut<F>> = leaf_proofs
|
||||
.iter()
|
||||
.map(|p|HashOut::from_vec(p.public_inputs.clone())) // Adjust index if different
|
||||
.collect();
|
||||
|
||||
// Step 2: Iteratively compute parent hashes until one root hash remains
|
||||
while current_hashes.len() > 1 {
|
||||
let mut next_level_hashes = Vec::new();
|
||||
|
||||
for chunk in current_hashes.chunks(N) {
|
||||
// Ensure each chunk has exactly N elements
|
||||
assert!(
|
||||
chunk.len() == N,
|
||||
"Number of proofs is not divisible by N"
|
||||
);
|
||||
|
||||
// collect field elements
|
||||
let chunk_f: Vec<F> = chunk.iter()
|
||||
.flat_map(|h| h.elements.iter().cloned())
|
||||
.collect();
|
||||
|
||||
// Compute Poseidon2 hash of the concatenated chunk
|
||||
let hash = HF::hash_no_pad(&chunk_f);
|
||||
next_level_hashes.push(hash);
|
||||
}
|
||||
|
||||
current_hashes = next_level_hashes;
|
||||
}
|
||||
|
||||
// The final hash is the expected root hash
|
||||
current_hashes[0].elements.to_vec()
|
||||
}
|
||||
}
|
@ -12,7 +12,6 @@ use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
||||
use codex_plonky2_circuits::circuits::sample_cells::SampleCircuitInput;
|
||||
use plonky2::plonk::proof::CompressedProofWithPublicInputs;
|
||||
use serde_json::to_writer_pretty;
|
||||
use crate::params::InputParams;
|
||||
|
||||
// Function to export proof with public input to json file
|
||||
fn export_proof_with_pi_to_json<F, C, const D: usize>(
|
||||
@ -46,9 +45,8 @@ pub fn read_bytes_from_file<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::params::{C, D, F, HF, InputParams, Params};
|
||||
use crate::params::{C, D, F, HF, Params};
|
||||
use std::time::Instant;
|
||||
use codex_plonky2_circuits::circuits::params::CircuitParams;
|
||||
use codex_plonky2_circuits::circuits::sample_cells::SampleCircuit;
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
|
@ -2,7 +2,6 @@ use plonky2::hash::hash_types::{HashOut, RichField};
|
||||
use plonky2_field::extension::Extendable;
|
||||
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
||||
use crate::params::HF;
|
||||
use anyhow::Result;
|
||||
use plonky2::hash::hashing::PlonkyPermutation;
|
||||
use crate::sponge::hash_n_with_padding;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user