Merge pull request #66 from mir-protocol/fix_target_partition

Enforce copy constraints in witness generation
This commit is contained in:
wborgeaud 2021-06-23 19:46:36 +02:00 committed by GitHub
commit 08338b6a3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 63 additions and 17 deletions

View File

@ -310,11 +310,12 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
sigmas_root,
};
let generators = self.generators;
let prover_only = ProverOnlyCircuitData {
generators,
generators: self.generators,
constants_commitment,
sigmas_commitment,
copy_constraints: self.copy_constraints,
gate_instances: self.gate_instances,
};
// The HashSet of gates will have a non-deterministic order. When converting to a Vec, we

View File

@ -3,11 +3,12 @@ use anyhow::Result;
use crate::field::extension_field::Extendable;
use crate::field::field::Field;
use crate::fri::FriConfig;
use crate::gates::gate::GateRef;
use crate::gates::gate::{GateInstance, GateRef};
use crate::generator::WitnessGenerator;
use crate::polynomial::commitment::ListPolynomialCommitment;
use crate::proof::{Hash, HashTarget, Proof};
use crate::prover::prove;
use crate::target::Target;
use crate::verifier::verify;
use crate::witness::PartialWitness;
@ -67,7 +68,7 @@ impl CircuitConfig {
/// Circuit data required by the prover or the verifier.
pub struct CircuitData<F: Extendable<D>, const D: usize> {
pub(crate) prover_only: ProverOnlyCircuitData<F>,
pub(crate) prover_only: ProverOnlyCircuitData<F, D>,
pub(crate) verifier_only: VerifierOnlyCircuitData<F>,
pub(crate) common: CommonCircuitData<F, D>,
}
@ -90,7 +91,7 @@ impl<F: Extendable<D>, const D: usize> CircuitData<F, D> {
/// 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<F: Extendable<D>, const D: usize> {
pub(crate) prover_only: ProverOnlyCircuitData<F>,
pub(crate) prover_only: ProverOnlyCircuitData<F, D>,
pub(crate) common: CommonCircuitData<F, D>,
}
@ -113,12 +114,16 @@ impl<F: Extendable<D>, const D: usize> VerifierCircuitData<F, D> {
}
/// Circuit data required by the prover, but not the verifier.
pub(crate) struct ProverOnlyCircuitData<F: Field> {
pub(crate) struct ProverOnlyCircuitData<F: Extendable<D>, const D: usize> {
pub generators: Vec<Box<dyn WitnessGenerator<F>>>,
/// Commitments to the constants polynomial.
pub constants_commitment: ListPolynomialCommitment<F>,
/// Commitments to the sigma polynomial.
pub sigmas_commitment: ListPolynomialCommitment<F>,
/// The circuit's copy constraints.
pub copy_constraints: Vec<(Target, Target)>,
/// The concrete placement of each gate in the circuit.
pub gate_instances: Vec<GateInstance<F, D>>,
}
/// Circuit data required by the verifier, but not the prover.

View File

@ -385,8 +385,6 @@ mod tests {
let x = FF::rand();
let y = FF::rand();
let x = FF::TWO;
let y = FF::ONE;
let z = x / y;
let xt = builder.constant_extension(x);
let yt = builder.constant_extension(y);

View File

@ -323,6 +323,8 @@ mod tests {
use crate::gates::gmimc::{GMiMCGate, W};
use crate::generator::generate_partial_witness;
use crate::gmimc::gmimc_permute_naive;
use crate::permutation_argument::TargetPartitions;
use crate::target::Target;
use crate::wire::Wire;
use crate::witness::PartialWitness;

View File

@ -2,6 +2,7 @@ use std::collections::{HashMap, HashSet};
use std::fmt::Debug;
use crate::field::field::Field;
use crate::permutation_argument::TargetPartitions;
use crate::target::Target;
use crate::witness::PartialWitness;
@ -24,10 +25,7 @@ pub(crate) fn generate_partial_witness<F: Field>(
// Build a list of "pending" generators which are queued to be run. Initially, all generators
// are queued.
let mut pending_generator_indices = HashSet::new();
for i in 0..generators.len() {
pending_generator_indices.insert(i);
}
let mut pending_generator_indices: HashSet<_> = (0..generators.len()).collect();
// We also track a list of "expired" generators which have already returned false.
let mut expired_generator_indices = HashSet::new();
@ -58,6 +56,11 @@ pub(crate) fn generate_partial_witness<F: Field>(
pending_generator_indices = next_pending_generator_indices;
}
assert_eq!(
expired_generator_indices.len(),
generators.len(),
"Some generators weren't run."
);
}
/// A generator participates in the generation of the witness.

View File

@ -1,3 +1,5 @@
use std::convert::TryInto;
use crate::circuit_builder::CircuitBuilder;
use crate::field::extension_field::target::ExtensionTarget;
use crate::field::extension_field::{Extendable, FieldExtension};
@ -5,7 +7,6 @@ use crate::field::field::Field;
use crate::hash::{permute, SPONGE_RATE, SPONGE_WIDTH};
use crate::proof::{Hash, HashTarget, OpeningSet};
use crate::target::Target;
use std::convert::TryInto;
/// Observes prover messages, and generates challenges by hashing the transcript.
#[derive(Clone)]
@ -320,6 +321,7 @@ mod tests {
use crate::field::crandall_field::CrandallField;
use crate::field::field::Field;
use crate::generator::generate_partial_witness;
use crate::permutation_argument::TargetPartitions;
use crate::plonk_challenger::{Challenger, RecursiveChallenger};
use crate::target::Target;
use crate::witness::PartialWitness;

View File

@ -20,7 +20,7 @@ use crate::wire::Wire;
use crate::witness::PartialWitness;
pub(crate) fn prove<F: Extendable<D>, const D: usize>(
prover_data: &ProverOnlyCircuitData<F>,
prover_data: &ProverOnlyCircuitData<F, D>,
common_data: &CommonCircuitData<F, D>,
inputs: PartialWitness<F>,
) -> Proof<F, D> {
@ -31,10 +31,17 @@ pub(crate) fn prove<F: Extendable<D>, const D: usize>(
let mut witness = inputs;
info!("Running {} generators", prover_data.generators.len());
timed!(
generate_partial_witness(&mut witness, &prover_data.generators),
generate_partial_witness(&mut witness, &prover_data.generators,),
"to generate witness"
);
timed!(
witness
.check_copy_constraints(&prover_data.copy_constraints, &prover_data.gate_instances)
.unwrap(), // TODO: Change return value to `Result` and use `?` here.
"to check copy constraints"
);
let config = &common_data.config;
let num_wires = config.num_wires;
let num_challenges = config.num_challenges;
@ -159,7 +166,7 @@ fn compute_z<F: Extendable<D>, const D: usize>(
fn compute_vanishing_polys<F: Extendable<D>, const D: usize>(
common_data: &CommonCircuitData<F, D>,
prover_data: &ProverOnlyCircuitData<F>,
prover_data: &ProverOnlyCircuitData<F, D>,
wires_commitment: &ListPolynomialCommitment<F>,
plonk_zs_commitment: &ListPolynomialCommitment<F>,
betas: &[F],

View File

@ -1,11 +1,14 @@
use std::collections::HashMap;
use std::convert::TryInto;
use anyhow::{ensure, Result};
use crate::field::extension_field::target::ExtensionTarget;
use crate::field::extension_field::{Extendable, FieldExtension};
use crate::field::field::Field;
use crate::gates::gate::GateInstance;
use crate::target::Target;
use crate::wire::Wire;
use std::convert::TryInto;
#[derive(Clone, Debug)]
pub struct PartialWitness<F: Field> {
@ -121,6 +124,31 @@ impl<F: Field> PartialWitness<F> {
self.set_target(target, value);
}
}
/// Checks that the copy constraints are satisfied in the witness.
pub fn check_copy_constraints<const D: usize>(
&self,
copy_constraints: &[(Target, Target)],
gate_instances: &[GateInstance<F, D>],
) -> Result<()>
where
F: Extendable<D>,
{
for &(a, b) in copy_constraints {
// TODO: Take care of public inputs once they land.
if let (Target::Wire(wa), Target::Wire(wb)) = (a, b) {
let va = self.target_values.get(&a).copied().unwrap_or(F::ZERO);
let vb = self.target_values.get(&b).copied().unwrap_or(F::ZERO);
ensure!(
va == vb,
"Copy constraint between wire {} of gate #{} (`{}`) and wire {} of gate #{} (`{}`) is not satisfied. \
Got values of {} and {} respectively.",
wa.input, wa.gate, gate_instances[wa.gate].gate_type.0.id(), wb.input, wb.gate,
gate_instances[wb.gate].gate_type.0.id(), va, vb);
}
}
Ok(())
}
}
impl<F: Field> Default for PartialWitness<F> {