2025-01-30 13:46:37 +01:00
|
|
|
use std::marker::PhantomData;
|
|
|
|
|
use plonky2::hash::hash_types::RichField;
|
2025-03-20 10:45:03 +01:00
|
|
|
use plonky2::iop::target::BoolTarget;
|
2025-01-30 13:46:37 +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, VerifierCircuitTarget, VerifierOnlyCircuitData};
|
2025-01-30 13:46:37 +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-01-30 13:46:37 +01:00
|
|
|
|
2025-03-10 14:53:59 +01:00
|
|
|
/// recursion node circuit - verifies M leaf proofs
|
2025-01-30 13:46:37 +01:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
|
pub struct NodeCircuit<
|
|
|
|
|
F: RichField + Extendable<D> + Poseidon2,
|
|
|
|
|
const D: usize,
|
|
|
|
|
C: GenericConfig<D, F = F>,
|
|
|
|
|
H: AlgebraicHasher<F>,
|
2025-02-07 10:27:04 +01:00
|
|
|
const M: usize,
|
2025-01-30 13:46:37 +01:00
|
|
|
> where
|
|
|
|
|
<C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>
|
|
|
|
|
{
|
2025-03-20 10:45:03 +01:00
|
|
|
common_data: CommonCircuitData<F, D>,
|
|
|
|
|
leaf_verifier_data: VerifierOnlyCircuitData<C, D>,
|
|
|
|
|
phantom_data: PhantomData<H>
|
2025-01-30 13:46:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
|
pub struct NodeTargets<
|
|
|
|
|
const D: usize,
|
|
|
|
|
>{
|
2025-02-07 10:27:04 +01:00
|
|
|
pub leaf_proofs: Vec<ProofWithPublicInputsTarget<D>>,
|
2025-03-20 10:45:03 +01:00
|
|
|
pub node_verifier_data: VerifierCircuitTarget,
|
|
|
|
|
pub condition: BoolTarget,
|
2025-01-30 13:46:37 +01:00
|
|
|
}
|
|
|
|
|
|
2025-04-08 12:02:22 +02:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
|
pub struct NodeInput<
|
|
|
|
|
F: RichField + Extendable<D> + Poseidon2,
|
|
|
|
|
const D: usize,
|
|
|
|
|
C: GenericConfig<D, F = F>,
|
|
|
|
|
>{
|
|
|
|
|
pub node_proofs: Vec<ProofWithPublicInputs<F, C, D>>,
|
|
|
|
|
pub verifier_only_data: VerifierOnlyCircuitData<C, D>,
|
|
|
|
|
pub condition: bool,
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-30 13:46:37 +01:00
|
|
|
impl<
|
|
|
|
|
F: RichField + Extendable<D> + Poseidon2,
|
|
|
|
|
const D: usize,
|
|
|
|
|
C: GenericConfig<D, F = F>,
|
|
|
|
|
H: AlgebraicHasher<F>,
|
2025-02-07 10:27:04 +01:00
|
|
|
const M: usize,
|
|
|
|
|
> NodeCircuit<F,D,C,H,M> where
|
2025-01-30 13:46:37 +01:00
|
|
|
<C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>
|
|
|
|
|
{
|
|
|
|
|
|
2025-03-20 10:45:03 +01:00
|
|
|
pub fn new(
|
|
|
|
|
common_data: CommonCircuitData<F,D>,
|
|
|
|
|
leaf_verifier_data: VerifierOnlyCircuitData<C, D>,
|
|
|
|
|
) -> Self {
|
2025-02-07 10:27:04 +01:00
|
|
|
Self{
|
2025-03-20 10:45:03 +01:00
|
|
|
common_data,
|
|
|
|
|
leaf_verifier_data,
|
2025-02-07 10:27:04 +01:00
|
|
|
phantom_data:PhantomData::default(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-08 12:02:22 +02:00
|
|
|
}
|
2025-01-30 13:46:37 +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>,
|
|
|
|
|
const M: usize,
|
|
|
|
|
> Plonky2Circuit<F, C, D> for NodeCircuit<F, D, C, H, M> where
|
|
|
|
|
<C as GenericConfig<D>>::Hasher: AlgebraicHasher<F>
|
|
|
|
|
{
|
|
|
|
|
type Targets = NodeTargets<D>;
|
|
|
|
|
type Input = NodeInput<F, D, C>;
|
|
|
|
|
|
|
|
|
|
fn add_targets(&self, builder: &mut CircuitBuilder<F, D>, register_pi: bool) -> Result<Self::Targets> {
|
2025-03-20 10:45:03 +01:00
|
|
|
let inner_common = self.common_data.clone();
|
2025-01-30 13:46:37 +01:00
|
|
|
|
2025-01-31 12:18:14 +01:00
|
|
|
// assert public input is of size 8 - 2 hashout
|
|
|
|
|
assert_eq!(inner_common.num_public_inputs, 8);
|
|
|
|
|
|
2025-02-07 10:27:04 +01:00
|
|
|
// the proof virtual targets - M proofs
|
2025-01-30 13:46:37 +01:00
|
|
|
let mut vir_proofs = vec![];
|
|
|
|
|
let mut pub_input = vec![];
|
2025-02-07 10:27:04 +01:00
|
|
|
for _i in 0..M {
|
2025-01-30 13:46:37 +01:00
|
|
|
let vir_proof = builder.add_virtual_proof_with_pis(&inner_common);
|
|
|
|
|
let inner_pub_input = vir_proof.public_inputs.clone();
|
|
|
|
|
vir_proofs.push(vir_proof);
|
2025-01-31 12:18:14 +01:00
|
|
|
pub_input.extend_from_slice(&inner_pub_input[0..4]);
|
2025-01-30 13:46:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// hash the public input & make it public
|
|
|
|
|
let hash_inner_pub_input = builder.hash_n_to_hash_no_pad::<H>(pub_input);
|
2025-04-08 12:02:22 +02:00
|
|
|
if register_pi{
|
|
|
|
|
builder.register_public_inputs(&hash_inner_pub_input.elements);
|
|
|
|
|
}
|
2025-01-30 13:46:37 +01:00
|
|
|
|
|
|
|
|
// virtual target for the verifier data
|
2025-03-20 10:45:03 +01:00
|
|
|
let node_verifier_data = builder.add_virtual_verifier_data(inner_common.config.fri_config.cap_height);
|
2025-01-30 13:46:37 +01:00
|
|
|
|
2025-03-20 10:45:03 +01:00
|
|
|
// virtual target for the verifier data
|
|
|
|
|
let const_leaf_verifier_data = builder.constant_verifier_data(&self.leaf_verifier_data);
|
|
|
|
|
|
|
|
|
|
// register only the node verifier data hash as public input.
|
2025-01-31 12:18:14 +01:00
|
|
|
let mut vd_pub_input = vec![];
|
2025-03-20 10:45:03 +01:00
|
|
|
vd_pub_input.extend_from_slice(&node_verifier_data.circuit_digest.elements);
|
2025-01-31 12:18:14 +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(&node_verifier_data.constants_sigmas_cap.0[i].elements);
|
2025-01-31 12:18:14 +01:00
|
|
|
}
|
|
|
|
|
let vd_hash = builder.hash_n_to_hash_no_pad::<H>(vd_pub_input);
|
2025-04-08 12:02:22 +02:00
|
|
|
if register_pi {
|
|
|
|
|
builder.register_public_inputs(&vd_hash.elements);
|
|
|
|
|
}
|
2025-03-20 10:45:03 +01:00
|
|
|
|
|
|
|
|
// condition for switching between node and leaf
|
|
|
|
|
let condition = builder.add_virtual_bool_target_safe();
|
|
|
|
|
|
|
|
|
|
// true -> node, false -> leaf
|
|
|
|
|
let selected_vd = builder.select_verifier_data(condition.clone(), &node_verifier_data, &const_leaf_verifier_data);
|
2025-01-31 12:18:14 +01:00
|
|
|
|
2025-02-07 10:27:04 +01:00
|
|
|
// verify the proofs in-circuit - M proofs
|
|
|
|
|
for i in 0..M {
|
2025-04-08 12:02:22 +02:00
|
|
|
builder.verify_proof::<C>(&vir_proofs[i], &selected_vd, &inner_common);
|
2025-03-20 10:45:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make sure we have every gate to match `common_data`.
|
|
|
|
|
for g in &inner_common.gates {
|
|
|
|
|
builder.add_gate_to_gate_set(g.clone());
|
2025-01-30 13:46:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// return targets
|
|
|
|
|
let t = NodeTargets {
|
2025-02-07 10:27:04 +01:00
|
|
|
leaf_proofs: vir_proofs,
|
2025-03-20 10:45:03 +01:00
|
|
|
node_verifier_data,
|
|
|
|
|
condition,
|
2025-01-30 13:46:37 +01:00
|
|
|
};
|
|
|
|
|
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-01-31 12:18:14 +01:00
|
|
|
// assert size of proofs vec
|
2025-04-08 12:02:22 +02:00
|
|
|
assert_eq!(input.node_proofs.len(), M);
|
2025-01-31 12:18:14 +01:00
|
|
|
|
2025-01-30 13:46:37 +01:00
|
|
|
// assign the proofs
|
2025-02-07 10:27:04 +01:00
|
|
|
for i in 0..M {
|
2025-04-08 12:02:22 +02:00
|
|
|
pw.set_proof_with_pis_target(&targets.leaf_proofs[i], &input.node_proofs[i])
|
2025-01-30 13:46:37 +01:00
|
|
|
.map_err(|e| {
|
|
|
|
|
CircuitError::ProofTargetAssignmentError("inner-proof".to_string(), e.to_string())
|
|
|
|
|
})?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// assign the verifier data
|
2025-04-08 12:02:22 +02:00
|
|
|
pw.set_verifier_data_target(&targets.node_verifier_data, &input.verifier_only_data)
|
2025-01-30 13:46:37 +01:00
|
|
|
.map_err(|e| {
|
|
|
|
|
CircuitError::VerifierDataTargetAssignmentError(e.to_string())
|
|
|
|
|
})?;
|
|
|
|
|
|
2025-03-20 10:45:03 +01:00
|
|
|
// assign the condition
|
2025-04-08 12:02:22 +02:00
|
|
|
pw.set_bool_target(targets.condition, input.condition)
|
2025-03-20 10:45:03 +01:00
|
|
|
.map_err(|e| CircuitError::BoolTargetAssignmentError("condition".to_string(), e.to_string()))?;
|
|
|
|
|
|
2025-01-30 13:46:37 +01:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|