mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-09 17:23:08 +00:00
Test not working
This commit is contained in:
parent
29e0aef376
commit
f194553345
@ -144,6 +144,10 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
targets.iter().for_each(|&t| self.register_public_input(t));
|
targets.iter().for_each(|&t| self.register_public_input(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn num_public_inputs(&self) -> usize {
|
||||||
|
self.public_inputs.len()
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds a new "virtual" target. This is not an actual wire in the witness, but just a target
|
/// Adds a new "virtual" target. This is not an actual wire in the witness, but just a target
|
||||||
/// that help facilitate witness generation. In particular, a generator can assign a values to a
|
/// that help facilitate witness generation. In particular, a generator can assign a values to a
|
||||||
/// virtual target, which can then be copied to other (virtual or concrete) targets. When we
|
/// virtual target, which can then be copied to other (virtual or concrete) targets. When we
|
||||||
|
|||||||
@ -66,9 +66,9 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
pub fn conditionally_verify_proof<C: GenericConfig<D, F = F>>(
|
pub fn conditionally_verify_proof<C: GenericConfig<D, F = F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
condition: BoolTarget,
|
condition: BoolTarget,
|
||||||
proof_with_pis0: ProofWithPublicInputsTarget<D>,
|
proof_with_pis0: &ProofWithPublicInputsTarget<D>,
|
||||||
inner_verifier_data0: &VerifierCircuitTarget,
|
inner_verifier_data0: &VerifierCircuitTarget,
|
||||||
proof_with_pis1: ProofWithPublicInputsTarget<D>,
|
proof_with_pis1: &ProofWithPublicInputsTarget<D>,
|
||||||
inner_verifier_data1: &VerifierCircuitTarget,
|
inner_verifier_data1: &VerifierCircuitTarget,
|
||||||
inner_common_data: &CommonCircuitData<F, C, D>,
|
inner_common_data: &CommonCircuitData<F, C, D>,
|
||||||
) where
|
) where
|
||||||
@ -124,8 +124,8 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
let selected_verifier_data = VerifierCircuitTarget {
|
let selected_verifier_data = VerifierCircuitTarget {
|
||||||
constants_sigmas_cap: self.select_cap(
|
constants_sigmas_cap: self.select_cap(
|
||||||
condition,
|
condition,
|
||||||
inner_verifier_data0.constants_sigmas_cap.clone(),
|
&inner_verifier_data0.constants_sigmas_cap,
|
||||||
inner_verifier_data1.constants_sigmas_cap.clone(),
|
&inner_verifier_data1.constants_sigmas_cap,
|
||||||
),
|
),
|
||||||
circuit_digest: self.select_hash(
|
circuit_digest: self.select_hash(
|
||||||
condition,
|
condition,
|
||||||
@ -137,10 +137,10 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
self.verify_proof(selected_proof, &selected_verifier_data, inner_common_data);
|
self.verify_proof(selected_proof, &selected_verifier_data, inner_common_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_vec(&mut self, b: BoolTarget, v0: Vec<Target>, v1: Vec<Target>) -> Vec<Target> {
|
fn select_vec(&mut self, b: BoolTarget, v0: &[Target], v1: &[Target]) -> Vec<Target> {
|
||||||
v0.into_iter()
|
v0.iter()
|
||||||
.zip_eq(v1)
|
.zip_eq(v1)
|
||||||
.map(|(t0, t1)| self.select(b, t0, t1))
|
.map(|(t0, t1)| self.select(b, *t0, *t1))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,15 +158,15 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
fn select_cap(
|
fn select_cap(
|
||||||
&mut self,
|
&mut self,
|
||||||
b: BoolTarget,
|
b: BoolTarget,
|
||||||
cap0: MerkleCapTarget,
|
cap0: &MerkleCapTarget,
|
||||||
cap1: MerkleCapTarget,
|
cap1: &MerkleCapTarget,
|
||||||
) -> MerkleCapTarget {
|
) -> MerkleCapTarget {
|
||||||
assert_eq!(cap0.0.len(), cap1.0.len());
|
assert_eq!(cap0.0.len(), cap1.0.len());
|
||||||
MerkleCapTarget(
|
MerkleCapTarget(
|
||||||
cap0.0
|
cap0.0
|
||||||
.into_iter()
|
.iter()
|
||||||
.zip_eq(cap1.0)
|
.zip_eq(&cap1.0)
|
||||||
.map(|(h0, h1)| self.select_hash(b, h0, h1))
|
.map(|(h0, h1)| self.select_hash(b, *h0, *h1))
|
||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -174,10 +174,10 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
fn select_vec_cap(
|
fn select_vec_cap(
|
||||||
&mut self,
|
&mut self,
|
||||||
b: BoolTarget,
|
b: BoolTarget,
|
||||||
v0: Vec<MerkleCapTarget>,
|
v0: &[MerkleCapTarget],
|
||||||
v1: Vec<MerkleCapTarget>,
|
v1: &[MerkleCapTarget],
|
||||||
) -> Vec<MerkleCapTarget> {
|
) -> Vec<MerkleCapTarget> {
|
||||||
v0.into_iter()
|
v0.iter()
|
||||||
.zip_eq(v1)
|
.zip_eq(v1)
|
||||||
.map(|(c0, c1)| self.select_cap(b, c0, c1))
|
.map(|(c0, c1)| self.select_cap(b, c0, c1))
|
||||||
.collect()
|
.collect()
|
||||||
@ -186,53 +186,53 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
fn select_opening_set(
|
fn select_opening_set(
|
||||||
&mut self,
|
&mut self,
|
||||||
b: BoolTarget,
|
b: BoolTarget,
|
||||||
os0: OpeningSetTarget<D>,
|
os0: &OpeningSetTarget<D>,
|
||||||
os1: OpeningSetTarget<D>,
|
os1: &OpeningSetTarget<D>,
|
||||||
) -> OpeningSetTarget<D> {
|
) -> OpeningSetTarget<D> {
|
||||||
OpeningSetTarget {
|
OpeningSetTarget {
|
||||||
constants: self.select_vec_ext(b, os0.constants, os1.constants),
|
constants: self.select_vec_ext(b, &os0.constants, &os1.constants),
|
||||||
plonk_sigmas: self.select_vec_ext(b, os0.plonk_sigmas, os1.plonk_sigmas),
|
plonk_sigmas: self.select_vec_ext(b, &os0.plonk_sigmas, &os1.plonk_sigmas),
|
||||||
wires: self.select_vec_ext(b, os0.wires, os1.wires),
|
wires: self.select_vec_ext(b, &os0.wires, &os1.wires),
|
||||||
plonk_zs: self.select_vec_ext(b, os0.plonk_zs, os1.plonk_zs),
|
plonk_zs: self.select_vec_ext(b, &os0.plonk_zs, &os1.plonk_zs),
|
||||||
plonk_zs_next: self.select_vec_ext(b, os0.plonk_zs_next, os1.plonk_zs_next),
|
plonk_zs_next: self.select_vec_ext(b, &os0.plonk_zs_next, &os1.plonk_zs_next),
|
||||||
partial_products: self.select_vec_ext(b, os0.partial_products, os1.partial_products),
|
partial_products: self.select_vec_ext(b, &os0.partial_products, &os1.partial_products),
|
||||||
quotient_polys: self.select_vec_ext(b, os0.quotient_polys, os1.quotient_polys),
|
quotient_polys: self.select_vec_ext(b, &os0.quotient_polys, &os1.quotient_polys),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_vec_ext(
|
fn select_vec_ext(
|
||||||
&mut self,
|
&mut self,
|
||||||
b: BoolTarget,
|
b: BoolTarget,
|
||||||
v0: Vec<ExtensionTarget<D>>,
|
v0: &[ExtensionTarget<D>],
|
||||||
v1: Vec<ExtensionTarget<D>>,
|
v1: &[ExtensionTarget<D>],
|
||||||
) -> Vec<ExtensionTarget<D>> {
|
) -> Vec<ExtensionTarget<D>> {
|
||||||
v0.into_iter()
|
v0.iter()
|
||||||
.zip_eq(v1)
|
.zip_eq(v1)
|
||||||
.map(|(e0, e1)| self.select_ext(b, e0, e1))
|
.map(|(e0, e1)| self.select_ext(b, *e0, *e1))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_opening_proof(
|
fn select_opening_proof(
|
||||||
&mut self,
|
&mut self,
|
||||||
b: BoolTarget,
|
b: BoolTarget,
|
||||||
proof0: FriProofTarget<D>,
|
proof0: &FriProofTarget<D>,
|
||||||
proof1: FriProofTarget<D>,
|
proof1: &FriProofTarget<D>,
|
||||||
) -> FriProofTarget<D> {
|
) -> FriProofTarget<D> {
|
||||||
FriProofTarget {
|
FriProofTarget {
|
||||||
commit_phase_merkle_caps: self.select_vec_cap(
|
commit_phase_merkle_caps: self.select_vec_cap(
|
||||||
b,
|
b,
|
||||||
proof0.commit_phase_merkle_caps,
|
&proof0.commit_phase_merkle_caps,
|
||||||
proof1.commit_phase_merkle_caps,
|
&proof1.commit_phase_merkle_caps,
|
||||||
),
|
),
|
||||||
query_round_proofs: self.select_vec_query_round(
|
query_round_proofs: self.select_vec_query_round(
|
||||||
b,
|
b,
|
||||||
proof0.query_round_proofs,
|
&proof0.query_round_proofs,
|
||||||
proof1.query_round_proofs,
|
&proof1.query_round_proofs,
|
||||||
),
|
),
|
||||||
final_poly: PolynomialCoeffsExtTarget(self.select_vec_ext(
|
final_poly: PolynomialCoeffsExtTarget(self.select_vec_ext(
|
||||||
b,
|
b,
|
||||||
proof0.final_poly.0,
|
&proof0.final_poly.0,
|
||||||
proof1.final_poly.0,
|
&proof1.final_poly.0,
|
||||||
)),
|
)),
|
||||||
pow_witness: self.select(b, proof0.pow_witness, proof1.pow_witness),
|
pow_witness: self.select(b, proof0.pow_witness, proof1.pow_witness),
|
||||||
}
|
}
|
||||||
@ -241,26 +241,26 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
fn select_query_round(
|
fn select_query_round(
|
||||||
&mut self,
|
&mut self,
|
||||||
b: BoolTarget,
|
b: BoolTarget,
|
||||||
qr0: FriQueryRoundTarget<D>,
|
qr0: &FriQueryRoundTarget<D>,
|
||||||
qr1: FriQueryRoundTarget<D>,
|
qr1: &FriQueryRoundTarget<D>,
|
||||||
) -> FriQueryRoundTarget<D> {
|
) -> FriQueryRoundTarget<D> {
|
||||||
FriQueryRoundTarget {
|
FriQueryRoundTarget {
|
||||||
initial_trees_proof: self.select_initial_tree_proof(
|
initial_trees_proof: self.select_initial_tree_proof(
|
||||||
b,
|
b,
|
||||||
qr0.initial_trees_proof,
|
&qr0.initial_trees_proof,
|
||||||
qr1.initial_trees_proof,
|
&qr1.initial_trees_proof,
|
||||||
),
|
),
|
||||||
steps: self.select_vec_query_step(b, qr0.steps, qr1.steps),
|
steps: self.select_vec_query_step(b, &qr0.steps, &qr1.steps),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_vec_query_round(
|
fn select_vec_query_round(
|
||||||
&mut self,
|
&mut self,
|
||||||
b: BoolTarget,
|
b: BoolTarget,
|
||||||
v0: Vec<FriQueryRoundTarget<D>>,
|
v0: &[FriQueryRoundTarget<D>],
|
||||||
v1: Vec<FriQueryRoundTarget<D>>,
|
v1: &[FriQueryRoundTarget<D>],
|
||||||
) -> Vec<FriQueryRoundTarget<D>> {
|
) -> Vec<FriQueryRoundTarget<D>> {
|
||||||
v0.into_iter()
|
v0.iter()
|
||||||
.zip_eq(v1)
|
.zip_eq(v1)
|
||||||
.map(|(qr0, qr1)| self.select_query_round(b, qr0, qr1))
|
.map(|(qr0, qr1)| self.select_query_round(b, qr0, qr1))
|
||||||
.collect()
|
.collect()
|
||||||
@ -269,14 +269,14 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
fn select_initial_tree_proof(
|
fn select_initial_tree_proof(
|
||||||
&mut self,
|
&mut self,
|
||||||
b: BoolTarget,
|
b: BoolTarget,
|
||||||
proof0: FriInitialTreeProofTarget,
|
proof0: &FriInitialTreeProofTarget,
|
||||||
proof1: FriInitialTreeProofTarget,
|
proof1: &FriInitialTreeProofTarget,
|
||||||
) -> FriInitialTreeProofTarget {
|
) -> FriInitialTreeProofTarget {
|
||||||
FriInitialTreeProofTarget {
|
FriInitialTreeProofTarget {
|
||||||
evals_proofs: proof0
|
evals_proofs: proof0
|
||||||
.evals_proofs
|
.evals_proofs
|
||||||
.into_iter()
|
.iter()
|
||||||
.zip_eq(proof1.evals_proofs)
|
.zip_eq(&proof1.evals_proofs)
|
||||||
.map(|((v0, p0), (v1, p1))| {
|
.map(|((v0, p0), (v1, p1))| {
|
||||||
(
|
(
|
||||||
self.select_vec(b, v0, v1),
|
self.select_vec(b, v0, v1),
|
||||||
@ -290,15 +290,15 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
fn select_merkle_proof(
|
fn select_merkle_proof(
|
||||||
&mut self,
|
&mut self,
|
||||||
b: BoolTarget,
|
b: BoolTarget,
|
||||||
proof0: MerkleProofTarget,
|
proof0: &MerkleProofTarget,
|
||||||
proof1: MerkleProofTarget,
|
proof1: &MerkleProofTarget,
|
||||||
) -> MerkleProofTarget {
|
) -> MerkleProofTarget {
|
||||||
MerkleProofTarget {
|
MerkleProofTarget {
|
||||||
siblings: proof0
|
siblings: proof0
|
||||||
.siblings
|
.siblings
|
||||||
.into_iter()
|
.iter()
|
||||||
.zip_eq(proof1.siblings)
|
.zip_eq(&proof1.siblings)
|
||||||
.map(|(h0, h1)| self.select_hash(b, h0, h1))
|
.map(|(h0, h1)| self.select_hash(b, *h0, *h1))
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -306,22 +306,22 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
fn select_query_step(
|
fn select_query_step(
|
||||||
&mut self,
|
&mut self,
|
||||||
b: BoolTarget,
|
b: BoolTarget,
|
||||||
qs0: FriQueryStepTarget<D>,
|
qs0: &FriQueryStepTarget<D>,
|
||||||
qs1: FriQueryStepTarget<D>,
|
qs1: &FriQueryStepTarget<D>,
|
||||||
) -> FriQueryStepTarget<D> {
|
) -> FriQueryStepTarget<D> {
|
||||||
FriQueryStepTarget {
|
FriQueryStepTarget {
|
||||||
evals: self.select_vec_ext(b, qs0.evals, qs1.evals),
|
evals: self.select_vec_ext(b, &qs0.evals, &qs1.evals),
|
||||||
merkle_proof: self.select_merkle_proof(b, qs0.merkle_proof, qs1.merkle_proof),
|
merkle_proof: self.select_merkle_proof(b, &qs0.merkle_proof, &qs1.merkle_proof),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_vec_query_step(
|
fn select_vec_query_step(
|
||||||
&mut self,
|
&mut self,
|
||||||
b: BoolTarget,
|
b: BoolTarget,
|
||||||
v0: Vec<FriQueryStepTarget<D>>,
|
v0: &[FriQueryStepTarget<D>],
|
||||||
v1: Vec<FriQueryStepTarget<D>>,
|
v1: &[FriQueryStepTarget<D>],
|
||||||
) -> Vec<FriQueryStepTarget<D>> {
|
) -> Vec<FriQueryStepTarget<D>> {
|
||||||
v0.into_iter()
|
v0.iter()
|
||||||
.zip_eq(v1)
|
.zip_eq(v1)
|
||||||
.map(|(qs0, qs1)| self.select_query_step(b, qs0, qs1))
|
.map(|(qs0, qs1)| self.select_query_step(b, qs0, qs1))
|
||||||
.collect()
|
.collect()
|
||||||
@ -384,9 +384,9 @@ mod tests {
|
|||||||
let b = builder.constant_bool(F::rand().0 % 2 == 0);
|
let b = builder.constant_bool(F::rand().0 % 2 == 0);
|
||||||
builder.conditionally_verify_proof(
|
builder.conditionally_verify_proof(
|
||||||
b,
|
b,
|
||||||
pt,
|
&pt,
|
||||||
&inner_data,
|
&inner_data,
|
||||||
dummy_pt,
|
&dummy_pt,
|
||||||
&dummy_inner_data,
|
&dummy_inner_data,
|
||||||
&data.common,
|
&data.common,
|
||||||
);
|
);
|
||||||
|
|||||||
227
plonky2/src/recursion/cyclic_recursion.rs
Normal file
227
plonky2/src/recursion/cyclic_recursion.rs
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use plonky2_field::extension::Extendable;
|
||||||
|
|
||||||
|
use crate::gates::noop::NoopGate;
|
||||||
|
use crate::hash::hash_types::RichField;
|
||||||
|
use crate::iop::target::BoolTarget;
|
||||||
|
use crate::iop::witness::{PartialWitness, Witness};
|
||||||
|
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||||
|
use crate::plonk::circuit_data::{
|
||||||
|
CircuitData, CommonCircuitData, VerifierCircuitTarget, VerifierOnlyCircuitData,
|
||||||
|
};
|
||||||
|
use crate::plonk::config::Hasher;
|
||||||
|
use crate::plonk::config::{AlgebraicHasher, GenericConfig};
|
||||||
|
use crate::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget};
|
||||||
|
use crate::recursion::conditional_recursive_verifier::dummy_proof;
|
||||||
|
|
||||||
|
pub struct CyclicRecursionData<
|
||||||
|
'a,
|
||||||
|
F: RichField + Extendable<D>,
|
||||||
|
C: GenericConfig<D, F = F>,
|
||||||
|
const D: usize,
|
||||||
|
> {
|
||||||
|
proof: &'a Option<ProofWithPublicInputs<F, C, D>>,
|
||||||
|
verifier_data: &'a VerifierOnlyCircuitData<C, D>,
|
||||||
|
common_data: &'a CommonCircuitData<F, C, D>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CyclicRecursionTarget<const D: usize> {
|
||||||
|
pub proof: ProofWithPublicInputsTarget<D>,
|
||||||
|
pub verifier_data: VerifierCircuitTarget,
|
||||||
|
pub dummy_proof: ProofWithPublicInputsTarget<D>,
|
||||||
|
pub dummy_verifier_data: VerifierCircuitTarget,
|
||||||
|
pub base_case: BoolTarget,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||||
|
pub fn cyclic_recursion<C: GenericConfig<D, F = F>>(
|
||||||
|
mut self,
|
||||||
|
mut common_data: CommonCircuitData<F, C, D>,
|
||||||
|
) -> Result<(CircuitData<F, C, D>, CyclicRecursionTarget<D>)>
|
||||||
|
where
|
||||||
|
C::Hasher: AlgebraicHasher<F>,
|
||||||
|
[(); C::Hasher::HASH_SIZE]:,
|
||||||
|
{
|
||||||
|
let verifier_data = VerifierCircuitTarget {
|
||||||
|
constants_sigmas_cap: self.add_virtual_cap(self.config.fri_config.cap_height),
|
||||||
|
circuit_digest: self.add_virtual_hash(),
|
||||||
|
};
|
||||||
|
self.register_public_inputs(&verifier_data.circuit_digest.elements);
|
||||||
|
for i in 0..self.config.fri_config.num_cap_elements() {
|
||||||
|
self.register_public_inputs(&verifier_data.constants_sigmas_cap.0[i].elements);
|
||||||
|
}
|
||||||
|
let dummy_verifier_data = VerifierCircuitTarget {
|
||||||
|
constants_sigmas_cap: self.add_virtual_cap(self.config.fri_config.cap_height),
|
||||||
|
circuit_digest: self.add_virtual_hash(),
|
||||||
|
};
|
||||||
|
let base_case = self.add_virtual_bool_target();
|
||||||
|
self.register_public_input(base_case.target);
|
||||||
|
|
||||||
|
common_data.num_public_inputs = self.num_public_inputs();
|
||||||
|
common_data.degree_bits = common_data.degree_bits.max(13);
|
||||||
|
dbg!(common_data.degree_bits);
|
||||||
|
|
||||||
|
let proof = self.add_virtual_proof_with_pis(&common_data);
|
||||||
|
let dummy_proof = self.add_virtual_proof_with_pis(&common_data);
|
||||||
|
|
||||||
|
self.conditionally_verify_proof(
|
||||||
|
base_case,
|
||||||
|
&dummy_proof,
|
||||||
|
&dummy_verifier_data,
|
||||||
|
&proof,
|
||||||
|
&verifier_data,
|
||||||
|
&common_data,
|
||||||
|
);
|
||||||
|
|
||||||
|
while self.num_gates() < 1 << (common_data.degree_bits - 1) {
|
||||||
|
self.add_gate(NoopGate, vec![]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = self.build::<C>();
|
||||||
|
dbg!(&data.common.degree_bits, common_data.degree_bits);
|
||||||
|
assert_eq!(&data.common, &common_data);
|
||||||
|
Ok((
|
||||||
|
data,
|
||||||
|
CyclicRecursionTarget {
|
||||||
|
proof,
|
||||||
|
verifier_data,
|
||||||
|
dummy_proof,
|
||||||
|
dummy_verifier_data,
|
||||||
|
base_case,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the targets in a `ProofTarget` to their corresponding values in a `Proof`.
|
||||||
|
pub fn set_cyclic_recursion_data_target<
|
||||||
|
F: RichField + Extendable<D>,
|
||||||
|
C: GenericConfig<D, F = F>,
|
||||||
|
const D: usize,
|
||||||
|
>(
|
||||||
|
pw: &mut PartialWitness<F>,
|
||||||
|
cyclic_recursion_data_target: &CyclicRecursionTarget<D>,
|
||||||
|
cyclic_recursion_data: &CyclicRecursionData<F, C, D>,
|
||||||
|
) -> Result<()>
|
||||||
|
where
|
||||||
|
F: RichField + Extendable<D>,
|
||||||
|
C::Hasher: AlgebraicHasher<F>,
|
||||||
|
[(); C::Hasher::HASH_SIZE]:,
|
||||||
|
{
|
||||||
|
if let Some(proof) = cyclic_recursion_data.proof {
|
||||||
|
pw.set_bool_target(cyclic_recursion_data_target.base_case, false);
|
||||||
|
pw.set_proof_with_pis_target(&cyclic_recursion_data_target.proof, proof);
|
||||||
|
pw.set_verifier_data_target(
|
||||||
|
&cyclic_recursion_data_target.verifier_data,
|
||||||
|
cyclic_recursion_data.verifier_data,
|
||||||
|
);
|
||||||
|
pw.set_proof_with_pis_target(&cyclic_recursion_data_target.dummy_proof, proof);
|
||||||
|
pw.set_verifier_data_target(
|
||||||
|
&cyclic_recursion_data_target.dummy_verifier_data,
|
||||||
|
cyclic_recursion_data.verifier_data,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let (dummy_proof, dummy_data) = dummy_proof(cyclic_recursion_data.common_data)?;
|
||||||
|
pw.set_bool_target(cyclic_recursion_data_target.base_case, true);
|
||||||
|
pw.set_proof_with_pis_target(&cyclic_recursion_data_target.proof, &dummy_proof);
|
||||||
|
pw.set_verifier_data_target(
|
||||||
|
&cyclic_recursion_data_target.verifier_data,
|
||||||
|
&dummy_data.verifier_only,
|
||||||
|
);
|
||||||
|
pw.set_proof_with_pis_target(&cyclic_recursion_data_target.dummy_proof, &dummy_proof);
|
||||||
|
pw.set_verifier_data_target(
|
||||||
|
&cyclic_recursion_data_target.dummy_verifier_data,
|
||||||
|
&dummy_data.verifier_only,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use anyhow::Result;
|
||||||
|
use plonky2_field::extension::Extendable;
|
||||||
|
|
||||||
|
use crate::field::types::Field;
|
||||||
|
use crate::hash::hash_types::RichField;
|
||||||
|
use crate::hash::poseidon::PoseidonHash;
|
||||||
|
use crate::iop::witness::{PartialWitness, Witness};
|
||||||
|
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||||
|
use crate::plonk::circuit_data::{CircuitConfig, CommonCircuitData, VerifierCircuitTarget};
|
||||||
|
use crate::plonk::config::{AlgebraicHasher, GenericConfig, Hasher, PoseidonGoldilocksConfig};
|
||||||
|
use crate::recursion::cyclic_recursion::{
|
||||||
|
set_cyclic_recursion_data_target, CyclicRecursionData,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn common_data_for_recursion<
|
||||||
|
F: RichField + Extendable<D>,
|
||||||
|
C: GenericConfig<D, F = F>,
|
||||||
|
const D: usize,
|
||||||
|
>() -> CommonCircuitData<F, C, D>
|
||||||
|
where
|
||||||
|
C::Hasher: AlgebraicHasher<F>,
|
||||||
|
[(); C::Hasher::HASH_SIZE]:,
|
||||||
|
{
|
||||||
|
let config = CircuitConfig::standard_recursion_config();
|
||||||
|
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||||
|
let data = builder.build::<C>();
|
||||||
|
let config = CircuitConfig::standard_recursion_config();
|
||||||
|
let mut pw = PartialWitness::<F>::new();
|
||||||
|
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||||
|
let proof = builder.add_virtual_proof_with_pis(&data.common);
|
||||||
|
let verifier_data = VerifierCircuitTarget {
|
||||||
|
constants_sigmas_cap: builder.add_virtual_cap(data.common.config.fri_config.cap_height),
|
||||||
|
circuit_digest: builder.add_virtual_hash(),
|
||||||
|
};
|
||||||
|
builder.verify_proof(proof, &verifier_data, &data.common);
|
||||||
|
let data = builder.build::<C>();
|
||||||
|
|
||||||
|
let config = CircuitConfig::standard_recursion_config();
|
||||||
|
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||||
|
let data = builder.build::<C>();
|
||||||
|
let config = CircuitConfig::standard_recursion_config();
|
||||||
|
let mut pw = PartialWitness::<F>::new();
|
||||||
|
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||||
|
let proof = builder.add_virtual_proof_with_pis(&data.common);
|
||||||
|
let verifier_data = VerifierCircuitTarget {
|
||||||
|
constants_sigmas_cap: builder.add_virtual_cap(data.common.config.fri_config.cap_height),
|
||||||
|
circuit_digest: builder.add_virtual_hash(),
|
||||||
|
};
|
||||||
|
builder.verify_proof(proof, &verifier_data, &data.common);
|
||||||
|
builder.build::<C>().common
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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 pw = PartialWitness::new();
|
||||||
|
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||||
|
|
||||||
|
// Build realistic circuit
|
||||||
|
let t = builder.add_virtual_target();
|
||||||
|
pw.set_target(t, F::rand());
|
||||||
|
let t_inv = builder.inverse(t);
|
||||||
|
let h = builder.hash_n_to_hash_no_pad::<PoseidonHash>(vec![t_inv]);
|
||||||
|
builder.register_public_inputs(&h.elements);
|
||||||
|
|
||||||
|
let common_data = common_data_for_recursion::<F, C, D>();
|
||||||
|
dbg!(common_data.degree_bits);
|
||||||
|
|
||||||
|
let (cyclic_circuit_data, cyclic_data_target) = builder.cyclic_recursion(common_data)?;
|
||||||
|
let cyclic_recursion_data = CyclicRecursionData {
|
||||||
|
proof: &None,
|
||||||
|
verifier_data: &cyclic_circuit_data.verifier_only,
|
||||||
|
common_data: &cyclic_circuit_data.common,
|
||||||
|
};
|
||||||
|
set_cyclic_recursion_data_target(&mut pw, &cyclic_data_target, &cyclic_recursion_data)?;
|
||||||
|
let proof = cyclic_circuit_data.prove(pw)?;
|
||||||
|
cyclic_circuit_data.verify(proof);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,2 +1,3 @@
|
|||||||
pub mod conditional_recursive_verifier;
|
pub mod conditional_recursive_verifier;
|
||||||
|
pub mod cyclic_recursion;
|
||||||
pub mod recursive_verifier;
|
pub mod recursive_verifier;
|
||||||
|
|||||||
@ -455,199 +455,4 @@ mod tests {
|
|||||||
fn init_logger() {
|
fn init_logger() {
|
||||||
let _ = env_logger::builder().format_timestamp(None).try_init();
|
let _ = env_logger::builder().format_timestamp(None).try_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_cyclic_recursion() -> Result<()> {
|
|
||||||
const D: usize = 2;
|
|
||||||
type C = PoseidonGoldilocksConfig;
|
|
||||||
type F = <C as GenericConfig<D>>::F;
|
|
||||||
// type FF = <C as GenericConfig<D>>::FE;
|
|
||||||
|
|
||||||
let config = CircuitConfig::standard_recursion_config();
|
|
||||||
let (proof, vd, cd) = dummy_proof::<F, C, D>(&config, 1 << 14)?;
|
|
||||||
|
|
||||||
let (proof, vd, cd) =
|
|
||||||
recursive_proof::<F, C, C, D>(proof, vd, cd, &config, None, false, false)?;
|
|
||||||
let (_proof, _vd, mut cd) =
|
|
||||||
recursive_proof::<F, C, C, D>(proof, vd, cd, &config, Some(14), false, false)?;
|
|
||||||
cd.num_public_inputs = 69;
|
|
||||||
|
|
||||||
// First proof
|
|
||||||
let config = CircuitConfig::standard_recursion_config();
|
|
||||||
let mut pw = PartialWitness::new();
|
|
||||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
|
||||||
|
|
||||||
let verifier_data = VerifierCircuitTarget {
|
|
||||||
constants_sigmas_cap: builder.add_virtual_cap(builder.config.fri_config.cap_height),
|
|
||||||
circuit_digest: builder.add_virtual_hash(),
|
|
||||||
};
|
|
||||||
builder.register_public_inputs(&verifier_data.circuit_digest.elements);
|
|
||||||
for i in 0..1 << builder.config.fri_config.cap_height {
|
|
||||||
builder.register_public_inputs(&verifier_data.constants_sigmas_cap.0[i].elements);
|
|
||||||
}
|
|
||||||
let dummy_verifier_data = VerifierCircuitTarget {
|
|
||||||
constants_sigmas_cap: builder.add_virtual_cap(builder.config.fri_config.cap_height),
|
|
||||||
circuit_digest: builder.add_virtual_hash(),
|
|
||||||
};
|
|
||||||
let condition = builder.add_virtual_bool_target();
|
|
||||||
builder.register_public_input(condition.target);
|
|
||||||
pw.set_bool_target(condition, false);
|
|
||||||
|
|
||||||
let (dummy_proof, dummy_data) =
|
|
||||||
crate::recursion::conditional_recursive_verifier::dummy_proof(&cd)?;
|
|
||||||
let pt0 = builder.add_virtual_proof_with_pis(&cd);
|
|
||||||
let pt1 = builder.add_virtual_proof_with_pis(&cd);
|
|
||||||
|
|
||||||
pw.set_proof_with_pis_target(&pt0, &dummy_proof);
|
|
||||||
pw.set_proof_with_pis_target(&pt1, &dummy_proof);
|
|
||||||
pw.set_hash_target(
|
|
||||||
dummy_verifier_data.circuit_digest,
|
|
||||||
dummy_data.verifier_only.circuit_digest,
|
|
||||||
);
|
|
||||||
pw.set_cap_target(
|
|
||||||
&dummy_verifier_data.constants_sigmas_cap,
|
|
||||||
&dummy_data.verifier_only.constants_sigmas_cap,
|
|
||||||
);
|
|
||||||
|
|
||||||
builder.conditionally_verify_proof(
|
|
||||||
condition,
|
|
||||||
pt0,
|
|
||||||
&verifier_data,
|
|
||||||
pt1,
|
|
||||||
&dummy_verifier_data,
|
|
||||||
&cd,
|
|
||||||
);
|
|
||||||
|
|
||||||
while builder.num_gates() < 1 << 13 {
|
|
||||||
builder.add_gate(NoopGate, vec![]);
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = builder.build::<C>();
|
|
||||||
dbg!(cd.degree_bits);
|
|
||||||
dbg!(data.common.degree_bits);
|
|
||||||
assert_eq!(&data.common, &cd);
|
|
||||||
pw.set_verifier_data_target(&verifier_data, &data.verifier_only);
|
|
||||||
let proof = data.prove(pw)?;
|
|
||||||
assert_eq!(
|
|
||||||
data.verifier_only.circuit_digest.elements[0],
|
|
||||||
proof.public_inputs[0]
|
|
||||||
);
|
|
||||||
data.verify(proof.clone())?;
|
|
||||||
|
|
||||||
// Second proof
|
|
||||||
let config = CircuitConfig::standard_recursion_config();
|
|
||||||
let mut pw = PartialWitness::new();
|
|
||||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
|
||||||
|
|
||||||
let verifier_data = VerifierCircuitTarget {
|
|
||||||
constants_sigmas_cap: builder.add_virtual_cap(builder.config.fri_config.cap_height),
|
|
||||||
circuit_digest: builder.add_virtual_hash(),
|
|
||||||
};
|
|
||||||
builder.register_public_inputs(&verifier_data.circuit_digest.elements);
|
|
||||||
for i in 0..1 << builder.config.fri_config.cap_height {
|
|
||||||
builder.register_public_inputs(&verifier_data.constants_sigmas_cap.0[i].elements);
|
|
||||||
}
|
|
||||||
let dummy_verifier_data = VerifierCircuitTarget {
|
|
||||||
constants_sigmas_cap: builder.add_virtual_cap(builder.config.fri_config.cap_height),
|
|
||||||
circuit_digest: builder.add_virtual_hash(),
|
|
||||||
};
|
|
||||||
let condition = builder.add_virtual_bool_target();
|
|
||||||
builder.register_public_input(condition.target);
|
|
||||||
pw.set_bool_target(condition, true);
|
|
||||||
|
|
||||||
let pt0 = builder.add_virtual_proof_with_pis(&data.common);
|
|
||||||
let pt1 = builder.add_virtual_proof_with_pis(&data.common);
|
|
||||||
|
|
||||||
pw.set_proof_with_pis_target(&pt0, &proof);
|
|
||||||
pw.set_proof_with_pis_target(&pt1, &proof);
|
|
||||||
|
|
||||||
builder.conditionally_verify_proof(
|
|
||||||
condition,
|
|
||||||
pt0,
|
|
||||||
&verifier_data,
|
|
||||||
pt1,
|
|
||||||
&dummy_verifier_data,
|
|
||||||
&data.common,
|
|
||||||
);
|
|
||||||
|
|
||||||
while builder.num_gates() < 1 << 13 {
|
|
||||||
builder.add_gate(NoopGate, vec![]);
|
|
||||||
}
|
|
||||||
|
|
||||||
let data1 = builder.build::<C>();
|
|
||||||
assert_eq!(data.common, data1.common);
|
|
||||||
assert_eq!(data.verifier_only, data1.verifier_only);
|
|
||||||
dbg!(cd.degree_bits);
|
|
||||||
dbg!(data1.common.degree_bits);
|
|
||||||
pw.set_verifier_data_target(&verifier_data, &data.verifier_only);
|
|
||||||
pw.set_verifier_data_target(&dummy_verifier_data, &data.verifier_only);
|
|
||||||
let proof = data.prove(pw)?;
|
|
||||||
assert_eq!(
|
|
||||||
data.verifier_only.circuit_digest.elements[0],
|
|
||||||
proof.public_inputs[0]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
data1.verifier_only.circuit_digest.elements[0],
|
|
||||||
proof.public_inputs[0]
|
|
||||||
);
|
|
||||||
data.verify(proof.clone())?;
|
|
||||||
|
|
||||||
// Second proof
|
|
||||||
let config = CircuitConfig::standard_recursion_config();
|
|
||||||
let mut pw = PartialWitness::new();
|
|
||||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
|
||||||
|
|
||||||
let verifier_data = VerifierCircuitTarget {
|
|
||||||
constants_sigmas_cap: builder.add_virtual_cap(builder.config.fri_config.cap_height),
|
|
||||||
circuit_digest: builder.add_virtual_hash(),
|
|
||||||
};
|
|
||||||
builder.register_public_inputs(&verifier_data.circuit_digest.elements);
|
|
||||||
for i in 0..1 << builder.config.fri_config.cap_height {
|
|
||||||
builder.register_public_inputs(&verifier_data.constants_sigmas_cap.0[i].elements);
|
|
||||||
}
|
|
||||||
let dummy_verifier_data = VerifierCircuitTarget {
|
|
||||||
constants_sigmas_cap: builder.add_virtual_cap(builder.config.fri_config.cap_height),
|
|
||||||
circuit_digest: builder.add_virtual_hash(),
|
|
||||||
};
|
|
||||||
let condition = builder.add_virtual_bool_target();
|
|
||||||
builder.register_public_input(condition.target);
|
|
||||||
pw.set_bool_target(condition, true);
|
|
||||||
|
|
||||||
let pt0 = builder.add_virtual_proof_with_pis(&data.common);
|
|
||||||
let pt1 = builder.add_virtual_proof_with_pis(&data.common);
|
|
||||||
|
|
||||||
pw.set_proof_with_pis_target(&pt0, &proof);
|
|
||||||
pw.set_proof_with_pis_target(&pt1, &proof);
|
|
||||||
|
|
||||||
builder.conditionally_verify_proof(
|
|
||||||
condition,
|
|
||||||
pt0,
|
|
||||||
&verifier_data,
|
|
||||||
pt1,
|
|
||||||
&dummy_verifier_data,
|
|
||||||
&data.common,
|
|
||||||
);
|
|
||||||
|
|
||||||
while builder.num_gates() < 1 << 13 {
|
|
||||||
builder.add_gate(NoopGate, vec![]);
|
|
||||||
}
|
|
||||||
|
|
||||||
let data2 = builder.build::<C>();
|
|
||||||
assert_eq!(data.common, data2.common);
|
|
||||||
assert_eq!(data.verifier_only, data2.verifier_only);
|
|
||||||
dbg!(cd.degree_bits);
|
|
||||||
dbg!(data1.common.degree_bits);
|
|
||||||
pw.set_verifier_data_target(&verifier_data, &data.verifier_only);
|
|
||||||
pw.set_verifier_data_target(&dummy_verifier_data, &data.verifier_only);
|
|
||||||
let proof = data.prove(pw)?;
|
|
||||||
assert_eq!(
|
|
||||||
data.verifier_only.circuit_digest.elements[0],
|
|
||||||
proof.public_inputs[0]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
data1.verifier_only.circuit_digest.elements[0],
|
|
||||||
proof.public_inputs[0]
|
|
||||||
);
|
|
||||||
data.verify(proof)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user