mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-07 08:13:11 +00:00
Refactor recursion tests (#285)
* Refactor recursion tests E.g. the main part of `test_recursive_recursive_verifier` is now ```rust let (proof, vd, cd) = dummy_proof::<F, D>(&config, 8_000)?; let (proof, vd, cd) = recursive_proof(proof, vd, cd, &config, &config, false)?; let (proof, _vd, cd) = recursive_proof(proof, vd, cd, &config, &config, true)?; ``` Also adds a new `test_size_optimized_recursion` to see how small we can make the final proof in a recursion chain. The final proof is ~74kb (depending on compression luck) and takes ~20s to prove on my M1 (depending on PoW luck). * Refactor serialization * Don't log timestamps
This commit is contained in:
parent
73f9a0be6b
commit
cb129fb095
@ -45,7 +45,7 @@ pub fn fri_proof<F: RichField + Extendable<D>, const D: usize>(
|
||||
let current_hash = challenger.get_hash();
|
||||
let pow_witness = timed!(
|
||||
timing,
|
||||
"find for proof-of-work witness",
|
||||
"find proof-of-work witness",
|
||||
fri_proof_of_work(current_hash, &common_data.config.fri_config)
|
||||
);
|
||||
|
||||
|
||||
@ -60,6 +60,24 @@ impl CircuitConfig {
|
||||
self.num_wires - self.num_routed_wires
|
||||
}
|
||||
|
||||
/// A typical recursion config, without zero-knowledge, targeting ~100 bit security.
|
||||
pub(crate) fn standard_recursion_config() -> Self {
|
||||
Self {
|
||||
num_wires: 143,
|
||||
num_routed_wires: 64,
|
||||
security_bits: 128,
|
||||
rate_bits: 3,
|
||||
num_challenges: 3,
|
||||
zero_knowledge: false,
|
||||
cap_height: 3,
|
||||
fri_config: FriConfig {
|
||||
proof_of_work_bits: 16,
|
||||
reduction_strategy: FriReductionStrategy::ConstantArityBits(3, 5),
|
||||
num_query_rounds: 28,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn large_config() -> Self {
|
||||
Self {
|
||||
|
||||
@ -127,7 +127,6 @@ mod tests {
|
||||
use log::info;
|
||||
|
||||
use super::*;
|
||||
use crate::field::field_types::Field;
|
||||
use crate::field::goldilocks_field::GoldilocksField;
|
||||
use crate::fri::proof::{
|
||||
FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget, FriQueryStepTarget,
|
||||
@ -137,11 +136,11 @@ mod tests {
|
||||
use crate::gadgets::polynomial::PolynomialCoeffsExtTarget;
|
||||
use crate::hash::merkle_proofs::MerkleProofTarget;
|
||||
use crate::iop::witness::{PartialWitness, Witness};
|
||||
use crate::plonk::circuit_data::VerifierOnlyCircuitData;
|
||||
use crate::plonk::proof::{
|
||||
CompressedProofWithPublicInputs, OpeningSetTarget, Proof, ProofTarget,
|
||||
ProofWithPublicInputs,
|
||||
};
|
||||
use crate::plonk::verifier::verify;
|
||||
use crate::util::log2_strict;
|
||||
|
||||
// Construct a `FriQueryRoundTarget` with the same dimensions as the ones in `proof`.
|
||||
@ -362,145 +361,156 @@ mod tests {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_recursive_verifier() -> Result<()> {
|
||||
env_logger::init();
|
||||
init_logger();
|
||||
type F = GoldilocksField;
|
||||
const D: usize = 4;
|
||||
let config = CircuitConfig {
|
||||
num_wires: 143,
|
||||
num_routed_wires: 33,
|
||||
security_bits: 128,
|
||||
rate_bits: 3,
|
||||
num_challenges: 3,
|
||||
zero_knowledge: false,
|
||||
cap_height: 2,
|
||||
fri_config: FriConfig {
|
||||
proof_of_work_bits: 15,
|
||||
reduction_strategy: FriReductionStrategy::ConstantArityBits(3, 5),
|
||||
num_query_rounds: 27,
|
||||
},
|
||||
};
|
||||
let (proof_with_pis, vd, cd) = {
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config.clone());
|
||||
let _two = builder.two();
|
||||
let _two = builder.hash_n_to_hash(vec![_two], true).elements[0];
|
||||
for _ in 0..10000 {
|
||||
let _two = builder.mul(_two, _two);
|
||||
}
|
||||
let data = builder.build();
|
||||
(
|
||||
data.prove(PartialWitness::new())?,
|
||||
data.verifier_only,
|
||||
data.common,
|
||||
)
|
||||
};
|
||||
verify(proof_with_pis.clone(), &vd, &cd)?;
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config.clone());
|
||||
let mut pw = PartialWitness::new();
|
||||
let pt = proof_to_proof_target(&proof_with_pis, &mut builder);
|
||||
set_proof_target(&proof_with_pis, &pt, &mut pw);
|
||||
let (proof, vd, cd) = dummy_proof::<F, D>(&config, 8_000)?;
|
||||
let (proof, _vd, cd) = recursive_proof(proof, vd, cd, &config, &config, true)?;
|
||||
test_serialization(&proof, &cd)?;
|
||||
|
||||
let inner_data = VerifierCircuitTarget {
|
||||
constants_sigmas_cap: builder.add_virtual_cap(config.cap_height),
|
||||
};
|
||||
pw.set_cap_target(&inner_data.constants_sigmas_cap, &vd.constants_sigmas_cap);
|
||||
|
||||
builder.add_recursive_verifier(pt, &config, &inner_data, &cd);
|
||||
|
||||
builder.print_gate_counts(0);
|
||||
let data = builder.build();
|
||||
let recursive_proof = data.prove(pw)?;
|
||||
|
||||
verify(recursive_proof, &data.verifier_only, &data.common)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_recursive_recursive_verifier() -> Result<()> {
|
||||
env_logger::init();
|
||||
init_logger();
|
||||
type F = GoldilocksField;
|
||||
const D: usize = 4;
|
||||
let config = CircuitConfig {
|
||||
num_wires: 143,
|
||||
num_routed_wires: 64,
|
||||
security_bits: 128,
|
||||
rate_bits: 3,
|
||||
num_challenges: 3,
|
||||
zero_knowledge: false,
|
||||
cap_height: 3,
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
|
||||
let (proof, vd, cd) = dummy_proof::<F, D>(&config, 8_000)?;
|
||||
let (proof, vd, cd) = recursive_proof(proof, vd, cd, &config, &config, false)?;
|
||||
let (proof, _vd, cd) = recursive_proof(proof, vd, cd, &config, &config, true)?;
|
||||
|
||||
test_serialization(&proof, &cd)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Creates a chain of recursive proofs where the last proof is made as small as reasonably
|
||||
/// possible, using a high rate, high PoW bits, etc.
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_size_optimized_recursion() -> Result<()> {
|
||||
init_logger();
|
||||
type F = GoldilocksField;
|
||||
const D: usize = 4;
|
||||
|
||||
let normal_config = CircuitConfig::standard_recursion_config();
|
||||
let final_config = CircuitConfig {
|
||||
rate_bits: 7,
|
||||
fri_config: FriConfig {
|
||||
proof_of_work_bits: 15,
|
||||
reduction_strategy: FriReductionStrategy::ConstantArityBits(3, 5),
|
||||
num_query_rounds: 27,
|
||||
proof_of_work_bits: 23,
|
||||
reduction_strategy: FriReductionStrategy::MinSize,
|
||||
num_query_rounds: 11,
|
||||
},
|
||||
};
|
||||
let (proof_with_pis, vd, cd) = {
|
||||
let (proof_with_pis, vd, cd) = {
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config.clone());
|
||||
for i in 0..8_000 {
|
||||
builder.constant(F::from_canonical_u64(i));
|
||||
}
|
||||
let data = builder.build();
|
||||
(
|
||||
data.prove(PartialWitness::new())?,
|
||||
data.verifier_only,
|
||||
data.common,
|
||||
)
|
||||
};
|
||||
verify(proof_with_pis.clone(), &vd, &cd)?;
|
||||
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config.clone());
|
||||
let mut pw = PartialWitness::new();
|
||||
let pt = proof_to_proof_target(&proof_with_pis, &mut builder);
|
||||
set_proof_target(&proof_with_pis, &pt, &mut pw);
|
||||
|
||||
let inner_data = VerifierCircuitTarget {
|
||||
constants_sigmas_cap: builder.add_virtual_cap(config.cap_height),
|
||||
};
|
||||
pw.set_cap_target(&inner_data.constants_sigmas_cap, &vd.constants_sigmas_cap);
|
||||
|
||||
builder.add_recursive_verifier(pt, &config, &inner_data, &cd);
|
||||
|
||||
let data = builder.build();
|
||||
let recursive_proof = data.prove(pw)?;
|
||||
(recursive_proof, data.verifier_only, data.common)
|
||||
..normal_config
|
||||
};
|
||||
|
||||
verify(proof_with_pis.clone(), &vd, &cd)?;
|
||||
let (proof, vd, cd) = dummy_proof::<F, D>(&normal_config, 8_000)?;
|
||||
let (proof, vd, cd) =
|
||||
recursive_proof(proof, vd, cd, &normal_config, &normal_config, false)?;
|
||||
let (proof, _vd, cd) = recursive_proof(proof, vd, cd, &normal_config, &final_config, true)?;
|
||||
|
||||
test_serialization(&proof, &cd)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn dummy_proof<F: RichField + Extendable<D>, const D: usize>(
|
||||
config: &CircuitConfig,
|
||||
num_dummy_gates: u64,
|
||||
) -> Result<(
|
||||
ProofWithPublicInputs<F, D>,
|
||||
VerifierOnlyCircuitData<F>,
|
||||
CommonCircuitData<F, D>,
|
||||
)> {
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config.clone());
|
||||
for i in 0..num_dummy_gates {
|
||||
builder.constant(F::from_canonical_u64(i));
|
||||
}
|
||||
|
||||
let data = builder.build();
|
||||
let proof = data.prove(PartialWitness::new())?;
|
||||
data.verify(proof.clone())?;
|
||||
|
||||
Ok((proof, data.verifier_only, data.common))
|
||||
}
|
||||
|
||||
fn recursive_proof<F: RichField + Extendable<D>, const D: usize>(
|
||||
inner_proof: ProofWithPublicInputs<F, D>,
|
||||
inner_vd: VerifierOnlyCircuitData<F>,
|
||||
inner_cd: CommonCircuitData<F, D>,
|
||||
inner_config: &CircuitConfig,
|
||||
config: &CircuitConfig,
|
||||
print_gate_counts: bool,
|
||||
) -> Result<(
|
||||
ProofWithPublicInputs<F, D>,
|
||||
VerifierOnlyCircuitData<F>,
|
||||
CommonCircuitData<F, D>,
|
||||
)> {
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config.clone());
|
||||
let mut pw = PartialWitness::new();
|
||||
let pt = proof_to_proof_target(&proof_with_pis, &mut builder);
|
||||
set_proof_target(&proof_with_pis, &pt, &mut pw);
|
||||
let pt = proof_to_proof_target(&inner_proof, &mut builder);
|
||||
set_proof_target(&inner_proof, &pt, &mut pw);
|
||||
|
||||
let inner_data = VerifierCircuitTarget {
|
||||
constants_sigmas_cap: builder.add_virtual_cap(config.cap_height),
|
||||
constants_sigmas_cap: builder.add_virtual_cap(inner_config.cap_height),
|
||||
};
|
||||
pw.set_cap_target(&inner_data.constants_sigmas_cap, &vd.constants_sigmas_cap);
|
||||
pw.set_cap_target(
|
||||
&inner_data.constants_sigmas_cap,
|
||||
&inner_vd.constants_sigmas_cap,
|
||||
);
|
||||
|
||||
builder.add_recursive_verifier(pt, &config, &inner_data, &cd);
|
||||
builder.add_recursive_verifier(pt, &inner_config, &inner_data, &inner_cd);
|
||||
|
||||
if print_gate_counts {
|
||||
builder.print_gate_counts(0);
|
||||
}
|
||||
|
||||
builder.print_gate_counts(0);
|
||||
let data = builder.build();
|
||||
let recursive_proof = data.prove(pw)?;
|
||||
let proof_bytes = recursive_proof.to_bytes()?;
|
||||
let proof = data.prove(pw)?;
|
||||
data.verify(proof.clone())?;
|
||||
|
||||
Ok((proof, data.verifier_only, data.common))
|
||||
}
|
||||
|
||||
/// Test serialization and print some size info.
|
||||
fn test_serialization<F: RichField + Extendable<D>, const D: usize>(
|
||||
proof: &ProofWithPublicInputs<F, D>,
|
||||
cd: &CommonCircuitData<F, D>,
|
||||
) -> Result<()> {
|
||||
let proof_bytes = proof.to_bytes()?;
|
||||
info!("Proof length: {} bytes", proof_bytes.len());
|
||||
let proof_from_bytes = ProofWithPublicInputs::from_bytes(proof_bytes, &data.common)?;
|
||||
assert_eq!(recursive_proof, proof_from_bytes);
|
||||
let proof_from_bytes = ProofWithPublicInputs::from_bytes(proof_bytes, &cd)?;
|
||||
assert_eq!(proof, &proof_from_bytes);
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
let compressed_recursive_proof = recursive_proof.clone().compress(&data.common)?;
|
||||
let decompressed_compressed_proof = compressed_recursive_proof
|
||||
.clone()
|
||||
.decompress(&data.common)?;
|
||||
assert_eq!(recursive_proof, decompressed_compressed_proof);
|
||||
info!("{:.4} to compress proof", now.elapsed().as_secs_f64());
|
||||
let compressed_proof_bytes = compressed_recursive_proof.to_bytes()?;
|
||||
let compressed_proof = proof.clone().compress(&cd)?;
|
||||
let decompressed_compressed_proof = compressed_proof.clone().decompress(&cd)?;
|
||||
info!("{:.4}s to compress proof", now.elapsed().as_secs_f64());
|
||||
assert_eq!(proof, &decompressed_compressed_proof);
|
||||
|
||||
let compressed_proof_bytes = compressed_proof.to_bytes()?;
|
||||
info!(
|
||||
"Compressed proof length: {} bytes",
|
||||
compressed_proof_bytes.len()
|
||||
);
|
||||
let compressed_proof_from_bytes =
|
||||
CompressedProofWithPublicInputs::from_bytes(compressed_proof_bytes, &data.common)?;
|
||||
assert_eq!(compressed_recursive_proof, compressed_proof_from_bytes);
|
||||
verify(recursive_proof, &data.verifier_only, &data.common)
|
||||
CompressedProofWithPublicInputs::from_bytes(compressed_proof_bytes, &cd)?;
|
||||
assert_eq!(compressed_proof, compressed_proof_from_bytes);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init_logger() {
|
||||
let _ = env_logger::builder()
|
||||
.format_timestamp(None)
|
||||
.is_test(true)
|
||||
.try_init();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user