Add upgradeability to AllRecursiveCircuits and output verifier data (#1387)

* Add upgradeable preprocessed sizes

* Add verifier data
This commit is contained in:
Robin Salen 2023-11-28 12:23:20 -05:00 committed by GitHub
parent 3440ba94e6
commit 6dd2e313c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 123 additions and 4 deletions

View File

@ -15,7 +15,7 @@ use plonky2::iop::target::{BoolTarget, Target};
use plonky2::iop::witness::{PartialWitness, WitnessWrite};
use plonky2::plonk::circuit_builder::CircuitBuilder;
use plonky2::plonk::circuit_data::{
CircuitConfig, CircuitData, CommonCircuitData, VerifierCircuitTarget,
CircuitConfig, CircuitData, CommonCircuitData, VerifierCircuitData, VerifierCircuitTarget,
};
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig};
use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget};
@ -430,6 +430,78 @@ where
}
}
/// Expand the preprocessed STARK table circuits with the provided ranges.
///
/// If a range for a given table is contained within the current one, this will be a no-op.
/// Otherwise, it will add the circuits for the missing table sizes, and regenerate the upper circuits.
pub fn expand(
&mut self,
all_stark: &AllStark<F, D>,
degree_bits_ranges: &[Range<usize>; NUM_TABLES],
stark_config: &StarkConfig,
) {
self.by_table[Table::Arithmetic as usize].expand(
Table::Arithmetic,
&all_stark.arithmetic_stark,
degree_bits_ranges[Table::Arithmetic as usize].clone(),
&all_stark.cross_table_lookups,
stark_config,
);
self.by_table[Table::BytePacking as usize].expand(
Table::BytePacking,
&all_stark.byte_packing_stark,
degree_bits_ranges[Table::BytePacking as usize].clone(),
&all_stark.cross_table_lookups,
stark_config,
);
self.by_table[Table::Cpu as usize].expand(
Table::Cpu,
&all_stark.cpu_stark,
degree_bits_ranges[Table::Cpu as usize].clone(),
&all_stark.cross_table_lookups,
stark_config,
);
self.by_table[Table::Keccak as usize].expand(
Table::Keccak,
&all_stark.keccak_stark,
degree_bits_ranges[Table::Keccak as usize].clone(),
&all_stark.cross_table_lookups,
stark_config,
);
self.by_table[Table::KeccakSponge as usize].expand(
Table::KeccakSponge,
&all_stark.keccak_sponge_stark,
degree_bits_ranges[Table::KeccakSponge as usize].clone(),
&all_stark.cross_table_lookups,
stark_config,
);
self.by_table[Table::Logic as usize].expand(
Table::Logic,
&all_stark.logic_stark,
degree_bits_ranges[Table::Logic as usize].clone(),
&all_stark.cross_table_lookups,
stark_config,
);
self.by_table[Table::Memory as usize].expand(
Table::Memory,
&all_stark.memory_stark,
degree_bits_ranges[Table::Memory as usize].clone(),
&all_stark.cross_table_lookups,
stark_config,
);
// Regenerate the upper circuits.
self.root = Self::create_root_circuit(&self.by_table, stark_config);
self.aggregation = Self::create_aggregation_circuit(&self.root);
self.block = Self::create_block_circuit(&self.aggregation);
}
/// Outputs the `VerifierCircuitData` needed to verify any block proof
/// generated by an honest prover.
pub fn final_verifier_data(&self) -> VerifierCircuitData<F, C, D> {
self.block.circuit.verifier_data()
}
fn create_root_circuit(
by_table: &[RecursiveCircuitsForTable<F, C, D>; NUM_TABLES],
stark_config: &StarkConfig,
@ -1201,6 +1273,32 @@ where
Self { by_stark_size }
}
fn expand<S: Stark<F, D>>(
&mut self,
table: Table,
stark: &S,
degree_bits_range: Range<usize>,
all_ctls: &[CrossTableLookup<F>],
stark_config: &StarkConfig,
) {
let new_ranges = degree_bits_range
.filter(|degree_bits| !self.by_stark_size.contains_key(degree_bits))
.collect_vec();
for degree_bits in new_ranges {
self.by_stark_size.insert(
degree_bits,
RecursiveCircuitsForTableSize::new::<S>(
table,
stark,
degree_bits,
all_ctls,
stark_config,
),
);
}
}
/// For each initial `degree_bits`, get the final circuit at the end of that shrinking chain.
/// Each of these final circuits should have degree `THRESHOLD_DEGREE_BITS`.
fn final_circuits(&self) -> Vec<&CircuitData<F, C, D>> {

View File

@ -77,9 +77,12 @@ fn test_empty_txn_list() -> anyhow::Result<()> {
addresses: vec![],
};
let all_circuits = AllRecursiveCircuits::<F, C, D>::new(
// Initialize the preprocessed circuits for the zkEVM.
// The provided ranges are the minimal ones to prove an empty list, except the one of the CPU
// that is wrong for testing purposes, see below.
let mut all_circuits = AllRecursiveCircuits::<F, C, D>::new(
&all_stark,
&[16..17, 10..11, 15..16, 14..15, 9..11, 12..13, 18..19], // Minimal ranges to prove an empty list
&[16..17, 10..11, 12..13, 14..15, 9..11, 12..13, 18..19], // Minimal ranges to prove an empty list
&config,
);
@ -111,6 +114,20 @@ fn test_empty_txn_list() -> anyhow::Result<()> {
assert_eq!(all_circuits, all_circuits_from_bytes);
}
let mut timing = TimingTree::new("prove", log::Level::Info);
// We're missing some preprocessed circuits.
assert!(all_circuits
.prove_root(&all_stark, &config, inputs.clone(), &mut timing)
.is_err());
// Expand the preprocessed circuits.
// We pass an empty range if we don't want to add different table sizes.
all_circuits.expand(
&all_stark,
&[0..0, 0..0, 15..16, 0..0, 0..0, 0..0, 0..0],
&StarkConfig::standard_fast_config(),
);
let mut timing = TimingTree::new("prove", log::Level::Info);
let (root_proof, public_values) =
all_circuits.prove_root(&all_stark, &config, inputs, &mut timing)?;
@ -129,7 +146,11 @@ fn test_empty_txn_list() -> anyhow::Result<()> {
all_circuits.verify_aggregation(&agg_proof)?;
let (block_proof, _) = all_circuits.prove_block(None, &agg_proof, public_values)?;
all_circuits.verify_block(&block_proof)
all_circuits.verify_block(&block_proof)?;
// Get the verifier associated to these preprocessed circuits, and have it verify the block_proof.
let verifier = all_circuits.final_verifier_data();
verifier.verify(block_proof)
}
fn init_logger() {