use std::ops::{Range, RangeFrom}; use anyhow::Result; use crate::copy_constraint::CopyConstraint; use crate::field::extension_field::Extendable; use crate::field::field::Field; use crate::fri::FriConfig; use crate::gates::gate::{GateInstance, PrefixedGate}; use crate::generator::WitnessGenerator; use crate::polynomial::commitment::ListPolynomialCommitment; use crate::proof::{Hash, HashTarget, ProofWithPublicInputs}; use crate::prover::prove; use crate::target::Target; use crate::util::marking::MarkedTargets; use crate::verifier::verify; use crate::witness::PartialWitness; #[derive(Clone)] pub struct CircuitConfig { pub num_wires: usize, pub num_routed_wires: usize, pub security_bits: usize, pub rate_bits: usize, /// The number of challenge points to generate, for IOPs that have soundness errors of (roughly) /// `degree / |F|`. pub num_challenges: usize, pub zero_knowledge: bool, // TODO: Find a better place for this. pub fri_config: FriConfig, } impl Default for CircuitConfig { fn default() -> Self { CircuitConfig { num_wires: 4, num_routed_wires: 4, security_bits: 128, rate_bits: 3, num_challenges: 3, zero_knowledge: true, fri_config: FriConfig { proof_of_work_bits: 1, reduction_arity_bits: vec![1, 1, 1, 1], num_query_rounds: 1, }, } } } impl CircuitConfig { pub fn num_advice_wires(&self) -> usize { self.num_wires - self.num_routed_wires } pub(crate) fn large_config() -> Self { Self { num_wires: 126, num_routed_wires: 33, security_bits: 128, rate_bits: 3, num_challenges: 3, zero_knowledge: true, fri_config: FriConfig { proof_of_work_bits: 1, reduction_arity_bits: vec![1, 1, 1, 1], num_query_rounds: 1, }, } } } /// Circuit data required by the prover or the verifier. pub struct CircuitData, const D: usize> { pub(crate) prover_only: ProverOnlyCircuitData, pub(crate) verifier_only: VerifierOnlyCircuitData, pub(crate) common: CommonCircuitData, } impl, const D: usize> CircuitData { pub fn prove(&self, inputs: PartialWitness) -> Result> { prove(&self.prover_only, &self.common, inputs) } pub fn verify(&self, proof_with_pis: ProofWithPublicInputs) -> Result<()> { verify(proof_with_pis, &self.verifier_only, &self.common) } } /// Circuit data required by the prover. This may be thought of as a proving key, although it /// includes code for witness generation. /// /// The goal here is to make proof generation as fast as we can, rather than making this prover /// structure as succinct as we can. Thus we include various precomputed data which isn't strictly /// required, like LDEs of preprocessed polynomials. If more succinctness was desired, we could /// construct a more minimal prover structure and convert back and forth. pub struct ProverCircuitData, const D: usize> { pub(crate) prover_only: ProverOnlyCircuitData, pub(crate) common: CommonCircuitData, } impl, const D: usize> ProverCircuitData { pub fn prove(&self, inputs: PartialWitness) -> Result> { prove(&self.prover_only, &self.common, inputs) } } /// Circuit data required by the prover. pub struct VerifierCircuitData, const D: usize> { pub(crate) verifier_only: VerifierOnlyCircuitData, pub(crate) common: CommonCircuitData, } impl, const D: usize> VerifierCircuitData { pub fn verify(&self, proof_with_pis: ProofWithPublicInputs) -> Result<()> { verify(proof_with_pis, &self.verifier_only, &self.common) } } /// Circuit data required by the prover, but not the verifier. pub(crate) struct ProverOnlyCircuitData, const D: usize> { pub generators: Vec>>, /// Commitments to the constants polynomials and sigma polynomials. pub constants_sigmas_commitment: ListPolynomialCommitment, /// The transpose of the list of sigma polynomials. pub sigmas: Vec>, /// Subgroup of order `degree`. pub subgroup: Vec, /// The circuit's copy constraints. pub copy_constraints: Vec, /// The concrete placement of each gate in the circuit. pub gate_instances: Vec>, /// Targets to be made public. pub public_inputs: Vec, /// A vector of marked targets. The values assigned to these targets will be displayed by the prover. pub marked_targets: Vec>, } /// Circuit data required by the verifier, but not the prover. pub(crate) struct VerifierOnlyCircuitData { /// A commitment to each constant polynomial and each permutation polynomial. pub(crate) constants_sigmas_root: Hash, } /// Circuit data required by both the prover and the verifier. pub struct CommonCircuitData, const D: usize> { pub(crate) config: CircuitConfig, pub(crate) degree_bits: usize, /// The types of gates used in this circuit, along with their prefixes. pub(crate) gates: Vec>, /// The degree of the PLONK quotient polynomial. pub(crate) quotient_degree_factor: usize, /// The largest number of constraints imposed by any gate. pub(crate) num_gate_constraints: usize, /// The number of constant wires. pub(crate) num_constants: usize, /// The `{k_i}` valued used in `S_ID_i` in Plonk's permutation argument. pub(crate) k_is: Vec, /// The number of partial products needed to compute the `Z` polynomials and the number /// of partial products needed to compute the final product. pub(crate) num_partial_products: (usize, 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: Hash, } impl, const D: usize> CommonCircuitData { pub fn degree(&self) -> usize { 1 << self.degree_bits } pub fn lde_size(&self) -> usize { 1 << (self.degree_bits + self.config.rate_bits) } pub fn lde_generator(&self) -> F { F::primitive_root_of_unity(self.degree_bits + self.config.rate_bits) } pub fn constraint_degree(&self) -> usize { self.gates .iter() .map(|g| g.gate.0.degree()) .max() .expect("No gates?") } pub fn quotient_degree(&self) -> usize { self.quotient_degree_factor * self.degree() } pub fn total_constraints(&self) -> usize { // 2 constraints for each Z check. self.config.num_challenges * 2 + self.num_gate_constraints } /// Range of the constants polynomials in the `constants_sigmas_commitment`. pub fn constants_range(&self) -> Range { 0..self.num_constants } /// Range of the sigma polynomials in the `constants_sigmas_commitment`. pub fn sigmas_range(&self) -> Range { self.num_constants..self.num_constants + self.config.num_routed_wires } /// Range of the `z`s polynomials in the `zs_partial_products_commitment`. pub fn zs_range(&self) -> Range { 0..self.config.num_challenges } /// Range of the partial products polynomials in the `zs_partial_products_commitment`. pub fn partial_products_range(&self) -> RangeFrom { self.config.num_challenges.. } } /// The `Target` version of `VerifierCircuitData`, for use inside recursive circuits. Note that this /// is intentionally missing certain fields, such as `CircuitConfig`, because we support only a /// limited form of dynamic inner circuits. We can't practically make things like the wire count /// dynamic, at least not without setting a maximum wire count and paying for the worst case. pub struct VerifierCircuitTarget { /// A commitment to each constant polynomial and each permutation polynomial. pub(crate) constants_sigmas_root: HashTarget, }