2025-03-10 14:53:59 +01:00
|
|
|
use std::marker::PhantomData;
|
2025-03-20 10:45:03 +01:00
|
|
|
use plonky2::hash::hash_types::{HashOutTarget, RichField};
|
2025-03-10 14:53:59 +01:00
|
|
|
use plonky2::iop::witness::{PartialWitness, WitnessWrite};
|
|
|
|
|
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
2025-04-08 12:02:22 +02:00
|
|
|
use plonky2::plonk::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData};
|
2025-03-10 14:53:59 +01:00
|
|
|
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig};
|
|
|
|
|
use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget};
|
|
|
|
|
use plonky2_field::extension::Extendable;
|
|
|
|
|
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
|
|
|
|
use crate::{error::CircuitError,Result};
|
2025-04-08 12:02:22 +02:00
|
|
|
use crate::circuit_helper::Plonky2Circuit;
|
2025-03-10 14:53:59 +01:00
|
|
|
|
2025-04-24 20:54:59 +02:00
|
|
|
//TODO: include the flag_buckets in the public input
|
2025-04-08 12:02:22 +02:00
|
|
|
/// recursion compression circuit
|
|
|
|
|
/// verifies 1 inner proof and as result should shrink it
|
2025-03-10 14:53:59 +01:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
|
pub struct CompressionCircuit<
|
|
|
|
|
F: RichField + Extendable<D> + Poseidon2,
|
|
|
|
|
const D: usize,
|
|
|
|
|
C: GenericConfig<D, F = F>,
|
|
|
|
|
H: AlgebraicHasher<F>,
|
|
|
|
|
> where
|
|
|
|
|
<C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>
|
|
|
|
|
{
|
|
|
|
|
inner_common_data: CommonCircuitData<F, D>,
|
2025-03-20 10:45:03 +01:00
|
|
|
inner_verifier_data: VerifierOnlyCircuitData<C, D>,
|
|
|
|
|
phantom_data: PhantomData<H>
|
2025-03-10 14:53:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
|
pub struct CompressionTargets<
|
|
|
|
|
const D: usize,
|
|
|
|
|
>{
|
|
|
|
|
pub inner_proof: ProofWithPublicInputsTarget<D>,
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-08 12:02:22 +02:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
|
pub struct CompressionInput<
|
|
|
|
|
F: RichField + Extendable<D> + Poseidon2,
|
|
|
|
|
const D: usize,
|
|
|
|
|
C: GenericConfig<D, F = F>,
|
|
|
|
|
>{
|
|
|
|
|
pub inner_proof: ProofWithPublicInputs<F, C, D>
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-10 14:53:59 +01:00
|
|
|
impl<
|
|
|
|
|
F: RichField + Extendable<D> + Poseidon2,
|
|
|
|
|
const D: usize,
|
|
|
|
|
C: GenericConfig<D, F = F>,
|
|
|
|
|
H: AlgebraicHasher<F>,
|
|
|
|
|
> CompressionCircuit<F,D,C,H> where
|
|
|
|
|
<C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>
|
|
|
|
|
{
|
2025-03-20 10:45:03 +01:00
|
|
|
pub fn new(
|
|
|
|
|
inner_common_data: CommonCircuitData<F,D>,
|
|
|
|
|
inner_verifier_data: VerifierOnlyCircuitData<C, D>,
|
|
|
|
|
) -> Self {
|
2025-03-10 14:53:59 +01:00
|
|
|
Self{
|
|
|
|
|
inner_common_data,
|
2025-03-20 10:45:03 +01:00
|
|
|
inner_verifier_data,
|
2025-03-10 14:53:59 +01:00
|
|
|
phantom_data:PhantomData::default(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-08 12:02:22 +02:00
|
|
|
}
|
2025-03-10 14:53:59 +01:00
|
|
|
|
2025-04-08 12:02:22 +02:00
|
|
|
impl<
|
|
|
|
|
F: RichField + Extendable<D> + Poseidon2,
|
|
|
|
|
const D: usize,
|
|
|
|
|
C: GenericConfig<D, F = F>,
|
|
|
|
|
H: AlgebraicHasher<F>,
|
|
|
|
|
> Plonky2Circuit<F, C, D> for CompressionCircuit<F, D, C, H> where
|
|
|
|
|
<C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>
|
|
|
|
|
{
|
|
|
|
|
type Targets = CompressionTargets<D>;
|
|
|
|
|
type Input = CompressionInput<F, D, C>;
|
|
|
|
|
|
|
|
|
|
fn add_targets(&self, builder: &mut CircuitBuilder<F, D>, register_pi: bool) -> Result<Self::Targets> {
|
2025-03-10 14:53:59 +01:00
|
|
|
let inner_common = self.inner_common_data.clone();
|
|
|
|
|
|
|
|
|
|
// the proof virtual targets
|
|
|
|
|
let vir_proof = builder.add_virtual_proof_with_pis(&inner_common);
|
|
|
|
|
let inner_pub_input = vir_proof.public_inputs.clone();
|
|
|
|
|
|
|
|
|
|
// take the public input from inner proof & make it public
|
2025-04-24 20:54:59 +02:00
|
|
|
assert!(inner_pub_input.len() >= 8);
|
2025-04-08 12:02:22 +02:00
|
|
|
if register_pi {
|
|
|
|
|
builder.register_public_inputs(&inner_pub_input[0..4]);
|
|
|
|
|
}
|
2025-03-10 14:53:59 +01:00
|
|
|
|
2025-03-20 10:45:03 +01:00
|
|
|
// constant target for the verifier data
|
|
|
|
|
let const_verifier_data = builder.constant_verifier_data(&self.inner_verifier_data);
|
2025-03-10 14:53:59 +01:00
|
|
|
|
|
|
|
|
// register verifier data hash as public input.
|
|
|
|
|
let mut vd_pub_input = vec![];
|
2025-03-20 10:45:03 +01:00
|
|
|
vd_pub_input.extend_from_slice(&const_verifier_data.circuit_digest.elements);
|
2025-03-10 14:53:59 +01:00
|
|
|
for i in 0..builder.config.fri_config.num_cap_elements() {
|
2025-03-20 10:45:03 +01:00
|
|
|
vd_pub_input.extend_from_slice(&const_verifier_data.constants_sigmas_cap.0[i].elements);
|
2025-03-10 14:53:59 +01:00
|
|
|
}
|
2025-03-20 10:45:03 +01:00
|
|
|
|
2025-03-10 14:53:59 +01:00
|
|
|
let hash_inner_vd_pub_input = builder.hash_n_to_hash_no_pad::<H>(vd_pub_input);
|
2025-03-20 10:45:03 +01:00
|
|
|
|
|
|
|
|
// make sure the VerifierData we use is the same as the tree root hash of the VerifierData
|
|
|
|
|
builder.connect_hashes(hash_inner_vd_pub_input,HashOutTarget::from_vec(inner_pub_input[4..8].to_vec()));
|
|
|
|
|
|
2025-04-08 12:02:22 +02:00
|
|
|
if register_pi {
|
|
|
|
|
builder.register_public_inputs(&hash_inner_vd_pub_input.elements);
|
|
|
|
|
}
|
2025-03-10 14:53:59 +01:00
|
|
|
|
|
|
|
|
// verify the proofs in-circuit
|
2025-03-20 10:45:03 +01:00
|
|
|
builder.verify_proof::<C>(&vir_proof, &const_verifier_data, &inner_common);
|
2025-03-10 14:53:59 +01:00
|
|
|
|
|
|
|
|
// return targets
|
|
|
|
|
let t = CompressionTargets {
|
|
|
|
|
inner_proof: vir_proof,
|
|
|
|
|
};
|
|
|
|
|
Ok(t)
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-08 12:02:22 +02:00
|
|
|
fn assign_targets(&self, pw: &mut PartialWitness<F>, targets: &Self::Targets, input: &Self::Input) -> Result<()> {
|
2025-03-10 14:53:59 +01:00
|
|
|
// assign the proof
|
2025-04-08 12:02:22 +02:00
|
|
|
pw.set_proof_with_pis_target(&targets.inner_proof, &input.inner_proof)
|
2025-03-10 14:53:59 +01:00
|
|
|
.map_err(|e| {
|
|
|
|
|
CircuitError::ProofTargetAssignmentError("inner-proof".to_string(), e.to_string())
|
|
|
|
|
})?;
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|