Skip to content

Commit

Permalink
Merge pull request #1219 from succinctlabs/uma/add-mock-feature-flag
Browse files Browse the repository at this point in the history
Add `mock_build` to allow for faster circuit building and partial witness generation
  • Loading branch information
npwardberkeley authored Sep 8, 2023
2 parents 180c209 + 1be1ca4 commit faa70e0
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 14 deletions.
14 changes: 14 additions & 0 deletions plonky2/src/fri/oracle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,20 @@ pub struct PolynomialBatch<F: RichField + Extendable<D>, C: GenericConfig<D, F =
pub blinding: bool,
}

impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize> Default
for PolynomialBatch<F, C, D>
{
fn default() -> Self {
PolynomialBatch {
polynomials: Vec::new(),
merkle_tree: MerkleTree::default(),
degree_log: 0,
rate_bits: 0,
blinding: false,
}
}
}

impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
PolynomialBatch<F, C, D>
{
Expand Down
16 changes: 16 additions & 0 deletions plonky2/src/hash/merkle_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ use crate::util::log2_strict;
// TODO: Change H to GenericHashOut<F>, since this only cares about the hash, not the hasher.
pub struct MerkleCap<F: RichField, H: Hasher<F>>(pub Vec<H::Hash>);

impl<F: RichField, H: Hasher<F>> Default for MerkleCap<F, H> {
fn default() -> Self {
Self(Vec::new())
}
}

impl<F: RichField, H: Hasher<F>> MerkleCap<F, H> {
pub fn len(&self) -> usize {
self.0.len()
Expand Down Expand Up @@ -54,6 +60,16 @@ pub struct MerkleTree<F: RichField, H: Hasher<F>> {
pub cap: MerkleCap<F, H>,
}

impl<F: RichField, H: Hasher<F>> Default for MerkleTree<F, H> {
fn default() -> Self {
Self {
leaves: Vec::new(),
digests: Vec::new(),
cap: MerkleCap::default(),
}
}
}

fn capacity_up_to_mut<T>(v: &mut Vec<T>, len: usize) -> &mut [MaybeUninit<T>] {
assert!(v.capacity() >= len);
let v_ptr = v.as_mut_ptr().cast::<MaybeUninit<T>>();
Expand Down
43 changes: 43 additions & 0 deletions plonky2/src/lookup_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,49 @@ mod tests {
Ok(())
}

#[test]
fn test_circuit_build_mock() {
// This code is taken from examples/fibonacci.rs
use crate::field::types::Field;
use crate::iop::witness::{PartialWitness, Witness, WitnessWrite};
use crate::plonk::circuit_builder::CircuitBuilder;
use crate::plonk::circuit_data::CircuitConfig;
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};

const D: usize = 2;
type C = PoseidonGoldilocksConfig;
type F = <C as GenericConfig<D>>::F;

let config = CircuitConfig::standard_recursion_config();
let mut builder = CircuitBuilder::<F, D>::new(config);

// The arithmetic circuit.
let initial_a = builder.add_virtual_target();
let initial_b = builder.add_virtual_target();
let mut prev_target = initial_a;
let mut cur_target = initial_b;
for _ in 0..99 {
let temp = builder.add(prev_target, cur_target);
prev_target = cur_target;
cur_target = temp;
}

// Public inputs are the two initial values (provided below) and the result (which is generated).
builder.register_public_input(initial_a);
builder.register_public_input(initial_b);
builder.register_public_input(cur_target);

// Provide initial values.
let mut pw = PartialWitness::new();
pw.set_target(initial_a, F::ZERO);
pw.set_target(initial_b, F::ONE);

let data = builder.mock_build::<C>();
let partition_witness = data.generate_witness(pw);
let result = partition_witness.try_get_target(cur_target).unwrap();
assert_eq!(result, F::from_canonical_u64(3736710860384812976));
}

fn init_logger() -> anyhow::Result<()> {
let mut builder = env_logger::Builder::from_default_env();
builder.format_timestamp(None);
Expand Down
42 changes: 30 additions & 12 deletions plonky2/src/plonk/circuit_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ use crate::iop::generator::{
use crate::iop::target::{BoolTarget, Target};
use crate::iop::wire::Wire;
use crate::plonk::circuit_data::{
CircuitConfig, CircuitData, CommonCircuitData, ProverCircuitData, ProverOnlyCircuitData,
VerifierCircuitData, VerifierCircuitTarget, VerifierOnlyCircuitData,
CircuitConfig, CircuitData, CommonCircuitData, MockCircuitData, ProverCircuitData,
ProverOnlyCircuitData, VerifierCircuitData, VerifierCircuitTarget, VerifierOnlyCircuitData,
};
use crate::plonk::config::{AlgebraicHasher, GenericConfig, GenericHashOut, Hasher};
use crate::plonk::copy_constraint::CopyConstraint;
Expand Down Expand Up @@ -916,7 +916,10 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
}

/// Builds a "full circuit", with both prover and verifier data.
pub fn build<C: GenericConfig<D, F = F>>(mut self) -> CircuitData<F, C, D> {
pub fn build_with_options<C: GenericConfig<D, F = F>>(
mut self,
commit_to_sigma: bool,
) -> CircuitData<F, C, D> {
let mut timing = TimingTree::new("preprocess", Level::Trace);

#[cfg(feature = "std")]
Expand Down Expand Up @@ -1023,15 +1026,19 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
let max_fft_points = 1 << (degree_bits + max(rate_bits, log2_ceil(quotient_degree_factor)));
let fft_root_table = fft_root_table(max_fft_points);

let constants_sigmas_vecs = [constant_vecs, sigma_vecs.clone()].concat();
let constants_sigmas_commitment = PolynomialBatch::<F, C, D>::from_values(
constants_sigmas_vecs,
rate_bits,
PlonkOracle::CONSTANTS_SIGMAS.blinding,
cap_height,
&mut timing,
Some(&fft_root_table),
);
let constants_sigmas_commitment = if commit_to_sigma {
let constants_sigmas_vecs = [constant_vecs, sigma_vecs.clone()].concat();
PolynomialBatch::<F, C, D>::from_values(
constants_sigmas_vecs,
rate_bits,
PlonkOracle::CONSTANTS_SIGMAS.blinding,
cap_height,
&mut timing,
Some(&fft_root_table),
)
} else {
PolynomialBatch::<F, C, D>::default()
};

// Map between gates where not all generators are used and the gate's number of used generators.
let incomplete_gates = self
Expand Down Expand Up @@ -1151,6 +1158,17 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
}
}

pub fn build<C: GenericConfig<D, F = F>>(self) -> CircuitData<F, C, D> {
self.build_with_options(true)
}

pub fn mock_build<C: GenericConfig<D, F = F>>(self) -> MockCircuitData<F, C, D> {
let circuit_data = self.build_with_options(false);
MockCircuitData {
prover_only: circuit_data.prover_only,
common: circuit_data.common,
}
}
/// Builds a "prover circuit", with data needed to generate proofs but not verify them.
pub fn build_prover<C: GenericConfig<D, F = F>>(self) -> ProverCircuitData<F, C, D> {
// TODO: Can skip parts of this.
Expand Down
20 changes: 18 additions & 2 deletions plonky2/src/plonk/circuit_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ use crate::gates::selectors::SelectorsInfo;
use crate::hash::hash_types::{HashOutTarget, MerkleCapTarget, RichField};
use crate::hash::merkle_tree::MerkleCap;
use crate::iop::ext_target::ExtensionTarget;
use crate::iop::generator::WitnessGeneratorRef;
use crate::iop::generator::{generate_partial_witness, WitnessGeneratorRef};
use crate::iop::target::Target;
use crate::iop::witness::PartialWitness;
use crate::iop::witness::{PartialWitness, PartitionWitness};
use crate::plonk::circuit_builder::CircuitBuilder;
use crate::plonk::config::{GenericConfig, Hasher};
use crate::plonk::plonk_common::PlonkOracle;
Expand Down Expand Up @@ -111,6 +111,22 @@ impl CircuitConfig {
}
}

/// Mock circuit data to only do witness generation without generating a proof.
#[derive(Eq, PartialEq, Debug)]
pub struct MockCircuitData<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
{
pub prover_only: ProverOnlyCircuitData<F, C, D>,
pub common: CommonCircuitData<F, D>,
}

impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
MockCircuitData<F, C, D>
{
pub fn generate_witness(&self, inputs: PartialWitness<F>) -> PartitionWitness<F> {
generate_partial_witness::<F, C, D>(inputs, &self.prover_only, &self.common)
}
}

/// Circuit data required by the prover or the verifier.
#[derive(Eq, PartialEq, Debug)]
pub struct CircuitData<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize> {
Expand Down

0 comments on commit faa70e0

Please sign in to comment.