mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-03 14:23:07 +00:00
Merge branch 'generate_dummy_proof' into cyclic_recursion
# Conflicts: # plonky2/src/fri/mod.rs # plonky2/src/plonk/circuit_data.rs
This commit is contained in:
commit
f497fc652c
@ -586,6 +586,7 @@ where
|
||||
VerifierCircuitTarget {
|
||||
constants_sigmas_cap: builder
|
||||
.constant_merkle_cap(&verifier_data.verifier_only.constants_sigmas_cap),
|
||||
circuit_digest: builder.add_virtual_hash(),
|
||||
}
|
||||
});
|
||||
RecursiveAllProofTargetWithData {
|
||||
|
||||
@ -117,11 +117,9 @@ where
|
||||
|
||||
let inner_data = VerifierCircuitTarget {
|
||||
constants_sigmas_cap: builder.add_virtual_cap(inner_cd.config.fri_config.cap_height),
|
||||
circuit_digest: builder.add_virtual_hash(),
|
||||
};
|
||||
pw.set_cap_target(
|
||||
&inner_data.constants_sigmas_cap,
|
||||
&inner_vd.constants_sigmas_cap,
|
||||
);
|
||||
pw.set_verifier_data_target(&inner_data, inner_vd);
|
||||
|
||||
builder.verify_proof(pt, &inner_data, inner_cd);
|
||||
builder.print_gate_counts(0);
|
||||
@ -151,6 +149,7 @@ where
|
||||
/// Test serialization and print some size info.
|
||||
fn test_serialization<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>(
|
||||
proof: &ProofWithPublicInputs<F, C, D>,
|
||||
vd: &VerifierOnlyCircuitData<C, D>,
|
||||
cd: &CommonCircuitData<F, C, D>,
|
||||
) -> Result<()>
|
||||
where
|
||||
@ -162,8 +161,10 @@ where
|
||||
assert_eq!(proof, &proof_from_bytes);
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
let compressed_proof = proof.clone().compress(cd)?;
|
||||
let decompressed_compressed_proof = compressed_proof.clone().decompress(cd)?;
|
||||
let compressed_proof = proof.clone().compress(&vd.circuit_digest, cd)?;
|
||||
let decompressed_compressed_proof = compressed_proof
|
||||
.clone()
|
||||
.decompress(&vd.circuit_digest, cd)?;
|
||||
info!("{:.4}s to compress proof", now.elapsed().as_secs_f64());
|
||||
assert_eq!(proof, &decompressed_compressed_proof);
|
||||
|
||||
@ -204,14 +205,14 @@ fn benchmark(config: &CircuitConfig, log2_inner_size: usize) -> Result<()> {
|
||||
|
||||
// Add a second layer of recursion to shrink the proof size further
|
||||
let outer = recursive_proof::<F, C, C, D>(&middle, config, None)?;
|
||||
let (proof, _, cd) = &outer;
|
||||
let (proof, vd, cd) = &outer;
|
||||
info!(
|
||||
"Double recursion proof degree {} = 2^{}",
|
||||
cd.degree(),
|
||||
cd.degree_bits
|
||||
);
|
||||
|
||||
test_serialization(proof, cd)?;
|
||||
test_serialization(proof, vd, cd)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ impl FriConfig {
|
||||
|
||||
/// FRI parameters, including generated parameters which are specific to an instance size, in
|
||||
/// contrast to `FriConfig` which is user-specified and independent of instance size.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct FriParams {
|
||||
/// User-specified FRI configuration.
|
||||
pub config: FriConfig,
|
||||
|
||||
@ -9,7 +9,7 @@ use crate::hash::hash_types::RichField;
|
||||
/// Placeholder value to indicate that a gate doesn't use a selector polynomial.
|
||||
pub(crate) const UNUSED_SELECTOR: usize = u32::MAX as usize;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub(crate) struct SelectorsInfo {
|
||||
pub(crate) selector_indices: Vec<usize>,
|
||||
pub(crate) groups: Vec<Range<usize>>,
|
||||
|
||||
@ -13,6 +13,7 @@ use crate::hash::merkle_tree::MerkleCap;
|
||||
use crate::iop::ext_target::ExtensionTarget;
|
||||
use crate::iop::target::{BoolTarget, Target};
|
||||
use crate::iop::wire::Wire;
|
||||
use crate::plonk::circuit_data::{VerifierCircuitTarget, VerifierOnlyCircuitData};
|
||||
use crate::plonk::config::{AlgebraicHasher, GenericConfig};
|
||||
use crate::plonk::proof::{Proof, ProofTarget, ProofWithPublicInputs, ProofWithPublicInputsTarget};
|
||||
|
||||
@ -197,6 +198,18 @@ pub trait Witness<F: Field> {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_verifier_data_target<C: GenericConfig<D, F = F>, const D: usize>(
|
||||
&mut self,
|
||||
vdt: &VerifierCircuitTarget,
|
||||
vd: &VerifierOnlyCircuitData<C, D>,
|
||||
) where
|
||||
F: RichField + Extendable<D>,
|
||||
C::Hasher: AlgebraicHasher<F>,
|
||||
{
|
||||
self.set_cap_target(&vdt.constants_sigmas_cap, &vd.constants_sigmas_cap);
|
||||
self.set_hash_target(vdt.circuit_digest, vd.circuit_digest);
|
||||
}
|
||||
|
||||
fn set_wire(&mut self, wire: Wire, value: F) {
|
||||
self.set_target(Target::Wire(wire), value)
|
||||
}
|
||||
|
||||
@ -271,6 +271,10 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
);
|
||||
}
|
||||
|
||||
pub fn add_gate_to_gate_set(&mut self, gate: GateRef<F, D>) {
|
||||
self.gates.insert(gate);
|
||||
}
|
||||
|
||||
pub fn connect_extension(&mut self, src: ExtensionTarget<D>, dst: ExtensionTarget<D>) {
|
||||
for i in 0..D {
|
||||
self.connect(src.0[i], dst.0[i]);
|
||||
@ -751,11 +755,6 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
Some(&fft_root_table),
|
||||
);
|
||||
|
||||
let constants_sigmas_cap = constants_sigmas_commitment.merkle_tree.cap.clone();
|
||||
let verifier_only = VerifierOnlyCircuitData {
|
||||
constants_sigmas_cap: constants_sigmas_cap.clone(),
|
||||
};
|
||||
|
||||
// Map between gates where not all generators are used and the gate's number of used generators.
|
||||
let incomplete_gates = self
|
||||
.current_slots
|
||||
@ -796,17 +795,6 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
indices.shrink_to_fit();
|
||||
}
|
||||
|
||||
let prover_only = ProverOnlyCircuitData {
|
||||
generators: self.generators,
|
||||
generator_indices_by_watches,
|
||||
constants_sigmas_commitment,
|
||||
sigmas: transpose_poly_values(sigma_vecs),
|
||||
subgroup,
|
||||
public_inputs: self.public_inputs,
|
||||
representative_map: forest.parents,
|
||||
fft_root_table: Some(fft_root_table),
|
||||
};
|
||||
|
||||
let num_gate_constraints = gates
|
||||
.iter()
|
||||
.map(|gate| gate.0.num_constraints())
|
||||
@ -816,6 +804,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
let num_partial_products =
|
||||
num_partial_products(self.config.num_routed_wires, quotient_degree_factor);
|
||||
|
||||
let constants_sigmas_cap = constants_sigmas_commitment.merkle_tree.cap.clone();
|
||||
// TODO: This should also include an encoding of gate constraints.
|
||||
let circuit_digest_parts = [
|
||||
constants_sigmas_cap.flatten(),
|
||||
@ -838,6 +827,22 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
num_public_inputs,
|
||||
k_is,
|
||||
num_partial_products,
|
||||
};
|
||||
|
||||
let prover_only = ProverOnlyCircuitData {
|
||||
generators: self.generators,
|
||||
generator_indices_by_watches,
|
||||
constants_sigmas_commitment,
|
||||
sigmas: transpose_poly_values(sigma_vecs),
|
||||
subgroup,
|
||||
public_inputs: self.public_inputs,
|
||||
representative_map: forest.parents,
|
||||
fft_root_table: Some(fft_root_table),
|
||||
circuit_digest,
|
||||
};
|
||||
|
||||
let verifier_only = VerifierOnlyCircuitData {
|
||||
constants_sigmas_cap,
|
||||
circuit_digest,
|
||||
};
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ use crate::fri::structure::{
|
||||
use crate::fri::{FriConfig, FriParams};
|
||||
use crate::gates::gate::GateRef;
|
||||
use crate::gates::selectors::SelectorsInfo;
|
||||
use crate::hash::hash_types::{MerkleCapTarget, RichField};
|
||||
use crate::hash::hash_types::{HashOutTarget, MerkleCapTarget, RichField};
|
||||
use crate::hash::merkle_tree::MerkleCap;
|
||||
use crate::iop::ext_target::ExtensionTarget;
|
||||
use crate::iop::generator::WitnessGenerator;
|
||||
@ -29,7 +29,7 @@ use crate::plonk::prover::prove;
|
||||
use crate::plonk::verifier::verify;
|
||||
use crate::util::timing::TimingTree;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct CircuitConfig {
|
||||
pub num_wires: usize,
|
||||
pub num_routed_wires: usize,
|
||||
@ -141,6 +141,23 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
compressed_proof_with_pis.verify(&self.verifier_only, &self.common)
|
||||
}
|
||||
|
||||
pub fn compress(
|
||||
&self,
|
||||
proof: ProofWithPublicInputs<F, C, D>,
|
||||
) -> Result<CompressedProofWithPublicInputs<F, C, D>> {
|
||||
proof.compress(&self.verifier_only.circuit_digest, &self.common)
|
||||
}
|
||||
|
||||
pub fn decompress(
|
||||
&self,
|
||||
proof: CompressedProofWithPublicInputs<F, C, D>,
|
||||
) -> Result<ProofWithPublicInputs<F, C, D>>
|
||||
where
|
||||
[(); C::Hasher::HASH_SIZE]:,
|
||||
{
|
||||
proof.decompress(&self.verifier_only.circuit_digest, &self.common)
|
||||
}
|
||||
|
||||
pub fn verifier_data(self) -> VerifierCircuitData<F, C, D> {
|
||||
let CircuitData {
|
||||
verifier_only,
|
||||
@ -253,6 +270,9 @@ pub struct ProverOnlyCircuitData<
|
||||
pub representative_map: Vec<usize>,
|
||||
/// Pre-computed roots for faster FFT.
|
||||
pub fft_root_table: Option<FftRootTable<F>>,
|
||||
/// A digest of the "circuit" (i.e. the instance, minus public inputs), which can be used to
|
||||
/// seed Fiat-Shamir.
|
||||
pub circuit_digest: <<C as GenericConfig<D>>::Hasher as Hasher<F>>::Hash,
|
||||
}
|
||||
|
||||
/// Circuit data required by the verifier, but not the prover.
|
||||
@ -260,10 +280,13 @@ pub struct ProverOnlyCircuitData<
|
||||
pub struct VerifierOnlyCircuitData<C: GenericConfig<D>, const D: usize> {
|
||||
/// A commitment to each constant polynomial and each permutation polynomial.
|
||||
pub constants_sigmas_cap: MerkleCap<C::F, C::Hasher>,
|
||||
/// A digest of the "circuit" (i.e. the instance, minus public inputs), which can be used to
|
||||
/// seed Fiat-Shamir.
|
||||
pub circuit_digest: <<C as GenericConfig<D>>::Hasher as Hasher<C::F>>::Hash,
|
||||
}
|
||||
|
||||
/// Circuit data required by both the prover and the verifier.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct CommonCircuitData<
|
||||
F: RichField + Extendable<D>,
|
||||
C: GenericConfig<D, F = F>,
|
||||
@ -276,7 +299,7 @@ pub struct CommonCircuitData<
|
||||
pub degree_bits: usize,
|
||||
|
||||
/// The types of gates used in this circuit, along with their prefixes.
|
||||
pub(crate) gates: Vec<GateRef<F, D>>,
|
||||
pub(crate) gates: Vec<GateRef<C::F, D>>,
|
||||
|
||||
/// Information on the circuit's selector polynomials.
|
||||
pub(crate) selectors_info: SelectorsInfo,
|
||||
@ -293,14 +316,10 @@ pub struct CommonCircuitData<
|
||||
pub(crate) num_public_inputs: usize,
|
||||
|
||||
/// The `{k_i}` valued used in `S_ID_i` in Plonk's permutation argument.
|
||||
pub(crate) k_is: Vec<F>,
|
||||
pub(crate) k_is: Vec<C::F>,
|
||||
|
||||
/// The number of partial products needed to compute the `Z` polynomials.
|
||||
pub(crate) num_partial_products: usize,
|
||||
|
||||
/// A digest of the "circuit" (i.e. the instance, minus public inputs), which can be used to
|
||||
/// seed Fiat-Shamir.
|
||||
pub(crate) circuit_digest: <<C as GenericConfig<D>>::Hasher as Hasher<F>>::Hash,
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
@ -476,4 +495,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
pub struct VerifierCircuitTarget {
|
||||
/// A commitment to each constant polynomial and each permutation polynomial.
|
||||
pub constants_sigmas_cap: MerkleCapTarget,
|
||||
/// A digest of the "circuit" (i.e. the instance, minus public inputs), which can be used to
|
||||
/// seed Fiat-Shamir.
|
||||
pub circuit_digest: HashOutTarget,
|
||||
}
|
||||
|
||||
@ -1,20 +1,65 @@
|
||||
use anyhow::{ensure, Result};
|
||||
use itertools::Itertools;
|
||||
use plonky2_field::extension::Extendable;
|
||||
use plonky2_util::ceil_div_usize;
|
||||
|
||||
use crate::fri::proof::{
|
||||
FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget, FriQueryStepTarget,
|
||||
};
|
||||
use crate::gadgets::polynomial::PolynomialCoeffsExtTarget;
|
||||
use crate::gates::noop::NoopGate;
|
||||
use crate::hash::hash_types::{HashOutTarget, MerkleCapTarget, RichField};
|
||||
use crate::hash::merkle_proofs::MerkleProofTarget;
|
||||
use crate::iop::ext_target::ExtensionTarget;
|
||||
use crate::iop::target::{BoolTarget, Target};
|
||||
use crate::iop::witness::{PartialWitness, Witness};
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::{CommonCircuitData, VerifierCircuitTarget};
|
||||
use crate::plonk::config::{AlgebraicHasher, GenericConfig};
|
||||
use crate::plonk::proof::{OpeningSetTarget, ProofTarget, ProofWithPublicInputsTarget};
|
||||
use crate::plonk::circuit_data::{CircuitData, CommonCircuitData, VerifierCircuitTarget};
|
||||
use crate::plonk::config::{AlgebraicHasher, GenericConfig, Hasher};
|
||||
use crate::plonk::proof::{
|
||||
OpeningSetTarget, ProofTarget, ProofWithPublicInputs, ProofWithPublicInputsTarget,
|
||||
};
|
||||
use crate::with_context;
|
||||
|
||||
/// Generate a proof having a given `CommonCircuitData`.
|
||||
pub fn dummy_proof<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>(
|
||||
common_data: &CommonCircuitData<F, C, D>,
|
||||
) -> Result<(ProofWithPublicInputs<F, C, D>, CircuitData<F, C, D>)>
|
||||
where
|
||||
[(); C::Hasher::HASH_SIZE]:,
|
||||
{
|
||||
let config = common_data.config.clone();
|
||||
|
||||
let mut pw = PartialWitness::new();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
ensure!(
|
||||
!common_data.config.zero_knowledge,
|
||||
"Degree calculation can be off if zero-knowledge is on."
|
||||
);
|
||||
let degree = 1 << common_data.degree_bits;
|
||||
// Number of `NoopGate`s to add to get a circuit of size `degree` in the end.
|
||||
// Need to account for public input hashing, a `PublicInputGate` and a `ConstantGate`.
|
||||
let num_noop_gate = degree - ceil_div_usize(common_data.num_public_inputs, 8) - 2;
|
||||
|
||||
for _ in 0..num_noop_gate {
|
||||
builder.add_gate(NoopGate, vec![]);
|
||||
}
|
||||
for gate in &common_data.gates {
|
||||
builder.add_gate_to_gate_set(gate.clone());
|
||||
}
|
||||
for _ in 0..common_data.num_public_inputs {
|
||||
let t = builder.add_virtual_public_input();
|
||||
pw.set_target(t, F::ZERO);
|
||||
}
|
||||
|
||||
let data = builder.build::<C>();
|
||||
assert_eq!(&data.common, common_data);
|
||||
let proof = data.prove(pw)?;
|
||||
|
||||
Ok((proof, data))
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
/// Verify `proof0` if `condition` else verify `proof1`.
|
||||
/// `proof0` and `proof1` are assumed to use the same `CommonCircuitData`.
|
||||
@ -82,6 +127,11 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
inner_verifier_data0.constants_sigmas_cap.clone(),
|
||||
inner_verifier_data1.constants_sigmas_cap.clone(),
|
||||
),
|
||||
circuit_digest: self.select_hash(
|
||||
condition,
|
||||
inner_verifier_data0.circuit_digest,
|
||||
inner_verifier_data1.circuit_digest,
|
||||
),
|
||||
};
|
||||
|
||||
self.verify_proof(selected_proof, &selected_verifier_data, inner_common_data);
|
||||
@ -297,6 +347,7 @@ mod tests {
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
|
||||
// Generate proof.
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config.clone());
|
||||
let mut pw = PartialWitness::new();
|
||||
let t = builder.add_virtual_target();
|
||||
@ -310,27 +361,26 @@ mod tests {
|
||||
let proof = data.prove(pw)?;
|
||||
data.verify(proof.clone())?;
|
||||
|
||||
// Generate dummy proof with the same `CommonCircuitData`.
|
||||
let (dummy_proof, dummy_data) = dummy_proof(&data.common)?;
|
||||
|
||||
// Conditionally verify the two proofs.
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
let mut pw = PartialWitness::new();
|
||||
let pt = builder.add_virtual_proof_with_pis(&data.common);
|
||||
pw.set_proof_with_pis_target(&pt, &proof);
|
||||
let dummy_pt = builder.add_virtual_proof_with_pis(&data.common);
|
||||
pw.set_proof_with_pis_target(&dummy_pt, &proof);
|
||||
|
||||
pw.set_proof_with_pis_target(&dummy_pt, &dummy_proof);
|
||||
let inner_data = VerifierCircuitTarget {
|
||||
constants_sigmas_cap: builder.add_virtual_cap(data.common.config.fri_config.cap_height),
|
||||
circuit_digest: builder.add_virtual_hash(),
|
||||
};
|
||||
pw.set_cap_target(
|
||||
&inner_data.constants_sigmas_cap,
|
||||
&data.verifier_only.constants_sigmas_cap,
|
||||
);
|
||||
pw.set_verifier_data_target(&inner_data, &data.verifier_only);
|
||||
let dummy_inner_data = VerifierCircuitTarget {
|
||||
constants_sigmas_cap: builder.add_virtual_cap(data.common.config.fri_config.cap_height),
|
||||
circuit_digest: builder.add_virtual_hash(),
|
||||
};
|
||||
pw.set_cap_target(
|
||||
&dummy_inner_data.constants_sigmas_cap,
|
||||
&data.verifier_only.constants_sigmas_cap,
|
||||
);
|
||||
pw.set_verifier_data_target(&dummy_inner_data, &dummy_data.verifier_only);
|
||||
let b = builder.constant_bool(F::rand().0 % 2 == 0);
|
||||
builder.conditionally_verify_proof(
|
||||
b,
|
||||
|
||||
@ -29,6 +29,7 @@ fn get_challenges<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, cons
|
||||
commit_phase_merkle_caps: &[MerkleCap<F, C::Hasher>],
|
||||
final_poly: &PolynomialCoeffs<F::Extension>,
|
||||
pow_witness: F,
|
||||
circuit_digest: &<<C as GenericConfig<D>>::Hasher as Hasher<C::F>>::Hash,
|
||||
common_data: &CommonCircuitData<F, C, D>,
|
||||
) -> anyhow::Result<ProofChallenges<F, D>> {
|
||||
let config = &common_data.config;
|
||||
@ -37,7 +38,7 @@ fn get_challenges<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, cons
|
||||
let mut challenger = Challenger::<F, C::Hasher>::new();
|
||||
|
||||
// Observe the instance.
|
||||
challenger.observe_hash::<C::Hasher>(common_data.circuit_digest);
|
||||
challenger.observe_hash::<C::Hasher>(*circuit_digest);
|
||||
challenger.observe_hash::<C::InnerHasher>(public_inputs_hash);
|
||||
|
||||
challenger.observe_cap(wires_cap);
|
||||
@ -72,10 +73,11 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
{
|
||||
pub(crate) fn fri_query_indices(
|
||||
&self,
|
||||
circuit_digest: &<<C as GenericConfig<D>>::Hasher as Hasher<C::F>>::Hash,
|
||||
common_data: &CommonCircuitData<F, C, D>,
|
||||
) -> anyhow::Result<Vec<usize>> {
|
||||
Ok(self
|
||||
.get_challenges(self.get_public_inputs_hash(), common_data)?
|
||||
.get_challenges(self.get_public_inputs_hash(), circuit_digest, common_data)?
|
||||
.fri_challenges
|
||||
.fri_query_indices)
|
||||
}
|
||||
@ -84,6 +86,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
pub(crate) fn get_challenges(
|
||||
&self,
|
||||
public_inputs_hash: <<C as GenericConfig<D>>::InnerHasher as Hasher<F>>::Hash,
|
||||
circuit_digest: &<<C as GenericConfig<D>>::Hasher as Hasher<C::F>>::Hash,
|
||||
common_data: &CommonCircuitData<F, C, D>,
|
||||
) -> anyhow::Result<ProofChallenges<F, D>> {
|
||||
let Proof {
|
||||
@ -109,6 +112,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
commit_phase_merkle_caps,
|
||||
final_poly,
|
||||
*pow_witness,
|
||||
circuit_digest,
|
||||
common_data,
|
||||
)
|
||||
}
|
||||
@ -121,6 +125,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
pub(crate) fn get_challenges(
|
||||
&self,
|
||||
public_inputs_hash: <<C as GenericConfig<D>>::InnerHasher as Hasher<F>>::Hash,
|
||||
circuit_digest: &<<C as GenericConfig<D>>::Hasher as Hasher<C::F>>::Hash,
|
||||
common_data: &CommonCircuitData<F, C, D>,
|
||||
) -> anyhow::Result<ProofChallenges<F, D>> {
|
||||
let CompressedProof {
|
||||
@ -146,6 +151,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
commit_phase_merkle_caps,
|
||||
final_poly,
|
||||
*pow_witness,
|
||||
circuit_digest,
|
||||
common_data,
|
||||
)
|
||||
}
|
||||
@ -237,6 +243,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
commit_phase_merkle_caps: &[MerkleCapTarget],
|
||||
final_poly: &PolynomialCoeffsExtTarget<D>,
|
||||
pow_witness: Target,
|
||||
inner_circuit_digest: HashOutTarget,
|
||||
inner_common_data: &CommonCircuitData<F, C, D>,
|
||||
) -> ProofChallengesTarget<D>
|
||||
where
|
||||
@ -248,9 +255,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
let mut challenger = RecursiveChallenger::<F, C::Hasher, D>::new(self);
|
||||
|
||||
// Observe the instance.
|
||||
let digest =
|
||||
HashOutTarget::from_vec(self.constants(&inner_common_data.circuit_digest.elements));
|
||||
challenger.observe_hash(&digest);
|
||||
challenger.observe_hash(&inner_circuit_digest);
|
||||
challenger.observe_hash(&public_inputs_hash);
|
||||
|
||||
challenger.observe_cap(wires_cap);
|
||||
@ -286,6 +291,7 @@ impl<const D: usize> ProofWithPublicInputsTarget<D> {
|
||||
&self,
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
public_inputs_hash: HashOutTarget,
|
||||
inner_circuit_digest: HashOutTarget,
|
||||
inner_common_data: &CommonCircuitData<F, C, D>,
|
||||
) -> ProofChallengesTarget<D>
|
||||
where
|
||||
@ -314,6 +320,7 @@ impl<const D: usize> ProofWithPublicInputsTarget<D> {
|
||||
commit_phase_merkle_caps,
|
||||
final_poly,
|
||||
*pow_witness,
|
||||
inner_circuit_digest,
|
||||
inner_common_data,
|
||||
)
|
||||
}
|
||||
|
||||
@ -81,9 +81,10 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
{
|
||||
pub fn compress(
|
||||
self,
|
||||
circuit_digest: &<<C as GenericConfig<D>>::Hasher as Hasher<C::F>>::Hash,
|
||||
common_data: &CommonCircuitData<F, C, D>,
|
||||
) -> anyhow::Result<CompressedProofWithPublicInputs<F, C, D>> {
|
||||
let indices = self.fri_query_indices(common_data)?;
|
||||
let indices = self.fri_query_indices(circuit_digest, common_data)?;
|
||||
let compressed_proof = self.proof.compress(&indices, &common_data.fri_params);
|
||||
Ok(CompressedProofWithPublicInputs {
|
||||
public_inputs: self.public_inputs,
|
||||
@ -176,12 +177,14 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
{
|
||||
pub fn decompress(
|
||||
self,
|
||||
circuit_digest: &<<C as GenericConfig<D>>::Hasher as Hasher<C::F>>::Hash,
|
||||
common_data: &CommonCircuitData<F, C, D>,
|
||||
) -> anyhow::Result<ProofWithPublicInputs<F, C, D>>
|
||||
where
|
||||
[(); C::Hasher::HASH_SIZE]:,
|
||||
{
|
||||
let challenges = self.get_challenges(self.get_public_inputs_hash(), common_data)?;
|
||||
let challenges =
|
||||
self.get_challenges(self.get_public_inputs_hash(), circuit_digest, common_data)?;
|
||||
let fri_inferred_elements = self.get_inferred_elements(&challenges, common_data);
|
||||
let decompressed_proof =
|
||||
self.proof
|
||||
@ -205,7 +208,11 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
"Number of public inputs doesn't match circuit data."
|
||||
);
|
||||
let public_inputs_hash = self.get_public_inputs_hash();
|
||||
let challenges = self.get_challenges(public_inputs_hash, common_data)?;
|
||||
let challenges = self.get_challenges(
|
||||
public_inputs_hash,
|
||||
&verifier_data.circuit_digest,
|
||||
common_data,
|
||||
)?;
|
||||
let fri_inferred_elements = self.get_inferred_elements(&challenges, common_data);
|
||||
let decompressed_proof =
|
||||
self.proof
|
||||
@ -418,8 +425,8 @@ mod tests {
|
||||
verify(proof.clone(), &data.verifier_only, &data.common)?;
|
||||
|
||||
// Verify that `decompress ∘ compress = identity`.
|
||||
let compressed_proof = proof.clone().compress(&data.common)?;
|
||||
let decompressed_compressed_proof = compressed_proof.clone().decompress(&data.common)?;
|
||||
let compressed_proof = data.compress(proof.clone())?;
|
||||
let decompressed_compressed_proof = data.decompress(compressed_proof.clone())?;
|
||||
assert_eq!(proof, decompressed_compressed_proof);
|
||||
|
||||
verify(proof, &data.verifier_only, &data.common)?;
|
||||
|
||||
@ -81,7 +81,7 @@ where
|
||||
let mut challenger = Challenger::<F, C::Hasher>::new();
|
||||
|
||||
// Observe the instance.
|
||||
challenger.observe_hash::<C::Hasher>(common_data.circuit_digest);
|
||||
challenger.observe_hash::<C::Hasher>(prover_data.circuit_digest);
|
||||
challenger.observe_hash::<C::InnerHasher>(public_inputs_hash);
|
||||
|
||||
challenger.observe_cap(&wires_commitment.merkle_tree.cap);
|
||||
|
||||
@ -29,7 +29,12 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
);
|
||||
let public_inputs_hash =
|
||||
self.hash_n_to_hash_no_pad::<C::InnerHasher>(proof_with_pis.public_inputs.clone());
|
||||
let challenges = proof_with_pis.get_challenges(self, public_inputs_hash, inner_common_data);
|
||||
let challenges = proof_with_pis.get_challenges(
|
||||
self,
|
||||
public_inputs_hash,
|
||||
inner_verifier_data.circuit_digest,
|
||||
inner_common_data,
|
||||
);
|
||||
|
||||
self.verify_proof_with_challenges(
|
||||
proof_with_pis.proof,
|
||||
@ -205,9 +210,9 @@ mod tests {
|
||||
let config = CircuitConfig::standard_recursion_zk_config();
|
||||
|
||||
let (proof, vd, cd) = dummy_proof::<F, C, D>(&config, 4_000)?;
|
||||
let (proof, _vd, cd) =
|
||||
let (proof, vd, cd) =
|
||||
recursive_proof::<F, C, C, D>(proof, vd, cd, &config, None, true, true)?;
|
||||
test_serialization(&proof, &cd)?;
|
||||
test_serialization(&proof, &vd, &cd)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -231,11 +236,11 @@ mod tests {
|
||||
assert_eq!(cd.degree_bits, 13);
|
||||
|
||||
// Shrink it to 2^12.
|
||||
let (proof, _vd, cd) =
|
||||
let (proof, vd, cd) =
|
||||
recursive_proof::<F, C, C, D>(proof, vd, cd, &config, None, true, true)?;
|
||||
assert_eq!(cd.degree_bits, 12);
|
||||
|
||||
test_serialization(&proof, &cd)?;
|
||||
test_serialization(&proof, &vd, &cd)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -287,11 +292,11 @@ mod tests {
|
||||
},
|
||||
..high_rate_config
|
||||
};
|
||||
let (proof, _vd, cd) =
|
||||
let (proof, vd, cd) =
|
||||
recursive_proof::<F, KC, C, D>(proof, vd, cd, &final_config, None, true, true)?;
|
||||
assert_eq!(cd.degree_bits, 12, "final proof too large");
|
||||
|
||||
test_serialization(&proof, &cd)?;
|
||||
test_serialization(&proof, &vd, &cd)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -309,11 +314,11 @@ mod tests {
|
||||
|
||||
let (proof, vd, cd) =
|
||||
recursive_proof::<F, PC, PC, D>(proof, vd, cd, &config, None, false, false)?;
|
||||
test_serialization(&proof, &cd)?;
|
||||
test_serialization(&proof, &vd, &cd)?;
|
||||
|
||||
let (proof, _vd, cd) =
|
||||
let (proof, vd, cd) =
|
||||
recursive_proof::<F, KC, PC, D>(proof, vd, cd, &config, None, false, false)?;
|
||||
test_serialization(&proof, &cd)?;
|
||||
test_serialization(&proof, &vd, &cd)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -372,11 +377,13 @@ mod tests {
|
||||
|
||||
let inner_data = VerifierCircuitTarget {
|
||||
constants_sigmas_cap: builder.add_virtual_cap(inner_cd.config.fri_config.cap_height),
|
||||
circuit_digest: builder.add_virtual_hash(),
|
||||
};
|
||||
pw.set_cap_target(
|
||||
&inner_data.constants_sigmas_cap,
|
||||
&inner_vd.constants_sigmas_cap,
|
||||
);
|
||||
pw.set_hash_target(inner_data.circuit_digest, inner_vd.circuit_digest);
|
||||
|
||||
builder.verify_proof(pt, &inner_data, &inner_cd);
|
||||
|
||||
@ -414,6 +421,7 @@ mod tests {
|
||||
const D: usize,
|
||||
>(
|
||||
proof: &ProofWithPublicInputs<F, C, D>,
|
||||
vd: &VerifierOnlyCircuitData<C, D>,
|
||||
cd: &CommonCircuitData<F, C, D>,
|
||||
) -> Result<()>
|
||||
where
|
||||
@ -425,8 +433,10 @@ mod tests {
|
||||
assert_eq!(proof, &proof_from_bytes);
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
let compressed_proof = proof.clone().compress(cd)?;
|
||||
let decompressed_compressed_proof = compressed_proof.clone().decompress(cd)?;
|
||||
let compressed_proof = proof.clone().compress(&vd.circuit_digest, cd)?;
|
||||
let decompressed_compressed_proof = compressed_proof
|
||||
.clone()
|
||||
.decompress(&vd.circuit_digest, cd)?;
|
||||
info!("{:.4}s to compress proof", now.elapsed().as_secs_f64());
|
||||
assert_eq!(proof, &decompressed_compressed_proof);
|
||||
|
||||
|
||||
@ -23,7 +23,11 @@ where
|
||||
validate_proof_with_pis_shape(&proof_with_pis, common_data)?;
|
||||
|
||||
let public_inputs_hash = proof_with_pis.get_public_inputs_hash();
|
||||
let challenges = proof_with_pis.get_challenges(public_inputs_hash, common_data)?;
|
||||
let challenges = proof_with_pis.get_challenges(
|
||||
public_inputs_hash,
|
||||
&verifier_data.circuit_digest,
|
||||
common_data,
|
||||
)?;
|
||||
|
||||
verify_with_challenges(
|
||||
proof_with_pis.proof,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user