From 9fdff8ea08380ba218ad3fe061e9d56ece222a84 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Fri, 26 Feb 2021 13:18:41 -0800 Subject: [PATCH] Gate infra --- Cargo.toml | 1 + src/circuit_builder.rs | 94 +++++++++++++++++++++++++++ src/constraint_polynomial.rs | 47 +++++++++++--- src/field/crandall_field.rs | 1 + src/field/field.rs | 1 + src/gates/constant.rs | 31 +++++++++ src/gates/deterministic_gate.rs | 39 ++++++----- src/gates/gate.rs | 3 +- src/gates/gmimc.rs | 111 ++++++++++++++++---------------- src/gates/mod.rs | 2 + src/gates/output_graph.rs | 66 +++++++++++++++++++ src/generator.rs | 14 ++-- src/main.rs | 3 +- src/proof.rs | 33 +++++++--- src/recursive_verifier.rs | 5 ++ src/target.rs | 10 +-- src/witness.rs | 20 +++--- 17 files changed, 370 insertions(+), 111 deletions(-) create mode 100644 src/circuit_builder.rs create mode 100644 src/gates/constant.rs create mode 100644 src/gates/output_graph.rs create mode 100644 src/recursive_verifier.rs diff --git a/Cargo.toml b/Cargo.toml index b99a4bd3..c4b40ab9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" [dependencies] unroll = "0.1.5" rayon = "1.5.0" +num = "0.3" [profile.release] opt-level = 3 diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs new file mode 100644 index 00000000..4aaeb537 --- /dev/null +++ b/src/circuit_builder.rs @@ -0,0 +1,94 @@ +use std::collections::HashSet; + +use crate::circuit_data::CircuitConfig; +use crate::field::field::Field; +use crate::gates::gate::{GateInstance, GateRef}; +use crate::generator::{CopyGenerator, WitnessGenerator2}; +use crate::target::Target; +use crate::gates::constant::ConstantGate2; +use crate::wire::Wire; + +pub struct CircuitBuilder2 { + config: CircuitConfig, + gates: HashSet>, + gate_instances: Vec>, + generators: Vec>>, +} + +impl CircuitBuilder2 { + pub fn new(config: CircuitConfig) -> Self { + CircuitBuilder2 { + config, + gates: HashSet::new(), + gate_instances: Vec::new(), + generators: Vec::new(), + } + } + + /// Adds a gate to the circuit, and returns its index. + pub fn add_gate(&mut self, gate_type: GateRef, constants: Vec) -> usize { + // If we haven't seen a gate of this type before, check that it's compatible with our + // circuit configuration, then register it. + if !self.gates.contains(&gate_type) { + self.check_gate_compatibility(&gate_type); + self.gates.insert(gate_type.clone()); + } + + let index = self.gate_instances.len(); + self.gate_instances.push(GateInstance { gate_type, constants }); + index + } + + fn check_gate_compatibility(&self, gate: &GateRef) { + assert!(gate.0.min_wires(self.config) <= self.config.num_wires); + } + + /// Shorthand for `generate_copy` and `assert_equal`. + /// Both elements must be routable, otherwise this method will panic. + pub fn route(&mut self, src: Target, dst: Target) { + self.generate_copy(src, dst); + self.assert_equal(src, dst); + } + + /// Adds a generator which will copy `src` to `dst`. + pub fn generate_copy(&mut self, src: Target, dst: Target) { + self.add_generator(CopyGenerator { src, dst }); + } + + /// Uses Plonk's permutation argument to require that two elements be equal. + /// Both elements must be routable, otherwise this method will panic. + pub fn assert_equal(&mut self, x: Target, y: Target) { + assert!(x.is_routable(self.config)); + assert!(y.is_routable(self.config)); + } + + pub fn add_generator>(&mut self, generator: G) { + self.generators.push(Box::new(generator)); + } + + /// Returns a routable target with a value of 0. + pub fn zero(&mut self) -> Target { + self.constant(F::ZERO) + } + + /// Returns a routable target with a value of 1. + pub fn one(&mut self) -> Target { + self.constant(F::ONE) + } + + /// Returns a routable target with a value of 2. + pub fn two(&mut self) -> Target { + self.constant(F::TWO) + } + + /// Returns a routable target with a value of `ORDER - 1`. + pub fn neg_one(&mut self) -> Target { + self.constant(F::NEG_ONE) + } + + /// Returns a routable target with the given constant value. + pub fn constant(&mut self, c: F) -> Target { + let gate = self.add_gate(ConstantGate2::get(), vec![c]); + Target::Wire(Wire { gate, input: ConstantGate2::WIRE_OUTPUT }) + } +} diff --git a/src/constraint_polynomial.rs b/src/constraint_polynomial.rs index cf32f619..ca048e30 100644 --- a/src/constraint_polynomial.rs +++ b/src/constraint_polynomial.rs @@ -5,8 +5,11 @@ use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use std::ptr; use std::rc::Rc; +use num::{BigUint, FromPrimitive, One, Zero}; + use crate::field::field::Field; use crate::wire::Wire; +use crate::gates::output_graph::GateOutputLocation; pub(crate) struct EvaluationVars<'a, F: Field> { pub(crate) local_constants: &'a [F], @@ -58,6 +61,13 @@ impl ConstraintPolynomial { Self::from_inner(ConstraintPolynomialInner::NextWireValue(index)) } + pub fn from_gate_output(gate_output: GateOutputLocation) -> Self { + match gate_output { + GateOutputLocation::LocalWire(i) => Self::local_wire_value(i), + GateOutputLocation::NextWire(i) => Self::next_wire_value(i), + } + } + // TODO: Have these take references? pub fn add(&self, rhs: &Self) -> Self { // TODO: Special case for either operand being 0. @@ -105,7 +115,7 @@ impl ConstraintPolynomial { self * self * self } - pub(crate) fn degree(&self) -> usize { + pub(crate) fn degree(&self) -> BigUint { (self.0).0.degree() } @@ -149,6 +159,15 @@ impl ConstraintPolynomial { .collect() } + /// Replace all occurrences of `from` with `to` in this polynomial graph. + pub(crate) fn replace_all( + &self, + from: Self, + to: Self, + ) -> Self { + Self(self.0.replace_all(from.0, to.0)) + } + fn from_inner(inner: ConstraintPolynomialInner) -> Self { Self(ConstraintPolynomialRef::new(inner)) } @@ -413,16 +432,17 @@ impl ConstraintPolynomialInner { } } - fn degree(&self) -> usize { + fn degree(&self) -> BigUint { match self { - ConstraintPolynomialInner::Constant(_) => 0, - ConstraintPolynomialInner::LocalConstant(_) => 1, - ConstraintPolynomialInner::NextConstant(_) => 1, - ConstraintPolynomialInner::LocalWireValue(_) => 1, - ConstraintPolynomialInner::NextWireValue(_) => 1, + ConstraintPolynomialInner::Constant(_) => BigUint::zero(), + ConstraintPolynomialInner::LocalConstant(_) => BigUint::one(), + ConstraintPolynomialInner::NextConstant(_) => BigUint::one(), + ConstraintPolynomialInner::LocalWireValue(_) => BigUint::one(), + ConstraintPolynomialInner::NextWireValue(_) => BigUint::one(), ConstraintPolynomialInner::Sum { lhs, rhs } => lhs.0.degree().max(rhs.0.degree()), ConstraintPolynomialInner::Product { lhs, rhs } => lhs.0.degree() + rhs.0.degree(), - ConstraintPolynomialInner::Exponentiation { base, exponent } => base.0.degree() * exponent, + ConstraintPolynomialInner::Exponentiation { base, exponent } => + base.0.degree() * BigUint::from_usize(*exponent).unwrap(), } } } @@ -431,7 +451,7 @@ impl ConstraintPolynomialInner { /// than content. This is useful when we want to use constraint polynomials as `HashMap` keys, but /// we want address-based hashing for performance reasons. #[derive(Clone)] -struct ConstraintPolynomialRef(Rc>); +pub(crate) struct ConstraintPolynomialRef(Rc>); impl ConstraintPolynomialRef { fn new(inner: ConstraintPolynomialInner) -> Self { @@ -451,6 +471,15 @@ impl ConstraintPolynomialRef { result } } + + /// Replace all occurrences of `from` with `to` in this polynomial graph. + fn replace_all( + &self, + from: ConstraintPolynomialRef, + to: ConstraintPolynomialRef, + ) -> ConstraintPolynomialRef { + todo!() + } } impl PartialEq for ConstraintPolynomialRef { diff --git a/src/field/crandall_field.rs b/src/field/crandall_field.rs index b324b2d1..66ea5966 100644 --- a/src/field/crandall_field.rs +++ b/src/field/crandall_field.rs @@ -38,6 +38,7 @@ impl Debug for CrandallField { impl Field for CrandallField { const ZERO: Self = Self(0); const ONE: Self = Self(1); + const TWO: Self = Self(2); const NEG_ONE: Self = Self(P - 1); #[inline(always)] diff --git a/src/field/field.rs b/src/field/field.rs index 430a9a92..4c3776e5 100644 --- a/src/field/field.rs +++ b/src/field/field.rs @@ -20,6 +20,7 @@ pub trait Field: 'static + Sync { const ZERO: Self; const ONE: Self; + const TWO: Self; const NEG_ONE: Self; fn sq(&self) -> Self; diff --git a/src/gates/constant.rs b/src/gates/constant.rs new file mode 100644 index 00000000..8bd2c89f --- /dev/null +++ b/src/gates/constant.rs @@ -0,0 +1,31 @@ +use crate::circuit_data::CircuitConfig; +use crate::constraint_polynomial::ConstraintPolynomial; +use crate::field::field::Field; +use crate::gates::deterministic_gate::{DeterministicGate, DeterministicGateAdapter}; +use crate::gates::gate::GateRef; +use crate::gates::output_graph::{GateOutputLocation, OutputGraph}; + +/// A gate which takes a single constant parameter and outputs that value. +pub struct ConstantGate2; + +impl ConstantGate2 { + pub fn get() -> GateRef { + GateRef::new(DeterministicGateAdapter::new(ConstantGate2)) + } + + pub const CONST_INPUT: usize = 0; + + pub const WIRE_OUTPUT: usize = 0; +} + +impl DeterministicGate for ConstantGate2 { + fn id(&self) -> String { + "ConstantGate".into() + } + + fn outputs(&self, _config: CircuitConfig) -> OutputGraph { + let loc = GateOutputLocation::LocalWire(Self::WIRE_OUTPUT); + let out = ConstraintPolynomial::local_constant(Self::CONST_INPUT); + OutputGraph::single_output(loc, out) + } +} diff --git a/src/gates/deterministic_gate.rs b/src/gates/deterministic_gate.rs index 2420831f..a70bcaa3 100644 --- a/src/gates/deterministic_gate.rs +++ b/src/gates/deterministic_gate.rs @@ -5,9 +5,10 @@ use crate::constraint_polynomial::{ConstraintPolynomial, EvaluationVars}; use crate::field::field::Field; use crate::gates::gate::Gate; use crate::generator::{SimpleGenerator, WitnessGenerator2}; -use crate::target::Target2; +use crate::target::Target; use crate::wire::Wire; use crate::witness::PartialWitness; +use crate::gates::output_graph::{OutputGraph, GateOutputLocation}; /// A deterministic gate. Each entry in `outputs()` describes how that output is evaluated; this is /// used to create both the constraint set and the generator set. @@ -18,9 +19,9 @@ pub trait DeterministicGate: 'static { /// A unique identifier for this gate. fn id(&self) -> String; - /// A vector of `(i, c)` pairs, where `i` is the index of an output and `c` is the polynomial - /// defining how that output is evaluated. - fn outputs(&self, config: CircuitConfig) -> Vec<(usize, ConstraintPolynomial)>; + /// A vector of `(loc, out)` pairs, where `loc` is the location of an output and `out` is a + /// polynomial defining how that output is evaluated. + fn outputs(&self, config: CircuitConfig) -> OutputGraph; /// Any additional constraints to be enforced, besides the (automatically provided) ones that /// constraint output values. @@ -60,8 +61,8 @@ impl> Gate for DeterministicGateAdapter Vec> { // For each output, we add a constraint of the form `out - expression = 0`, // then we append any additional constraints that the gate defines. - self.gate.outputs(config).into_iter() - .map(|(i, out)| out - ConstraintPolynomial::local_wire_value(i)) + self.gate.outputs(config).outputs.into_iter() + .map(|(output_loc, out)| out - ConstraintPolynomial::from_gate_output(output_loc)) .chain(self.gate.additional_constraints(config).into_iter()) .collect() } @@ -73,12 +74,12 @@ impl> Gate for DeterministicGateAdapter, next_constants: Vec, ) -> Vec>> { - self.gate.outputs(config) + self.gate.outputs(config).outputs .into_iter() - .map(|(input_index, out)| { + .map(|(location, out)| { let og = OutputGenerator { gate_index, - input_index, + location, out, local_constants: local_constants.clone(), next_constants: next_constants.clone(), @@ -96,17 +97,17 @@ impl> Gate for DeterministicGateAdapter { gate_index: usize, - input_index: usize, + location: GateOutputLocation, out: ConstraintPolynomial, local_constants: Vec, next_constants: Vec, } impl SimpleGenerator for OutputGenerator { - fn dependencies(&self) -> Vec { + fn dependencies(&self) -> Vec { self.out.dependencies(self.gate_index) .into_iter() - .map(Target2::Wire) + .map(Target::Wire) .collect() } @@ -125,8 +126,8 @@ impl SimpleGenerator for OutputGenerator { // Lookup the values if they exist. If not, we can just insert a zero, knowing // that it will not be used. (If it was used, it would have been included in our // dependencies, and this generator would not have run yet.) - let local_value = witness.try_get_target(Target2::Wire(local_wire)).unwrap_or(F::ZERO); - let next_value = witness.try_get_target(Target2::Wire(next_wire)).unwrap_or(F::ZERO); + let local_value = witness.try_get_target(Target::Wire(local_wire)).unwrap_or(F::ZERO); + let next_value = witness.try_get_target(Target::Wire(next_wire)).unwrap_or(F::ZERO); local_wire_values.push(local_value); next_wire_values.push(next_value); @@ -139,8 +140,14 @@ impl SimpleGenerator for OutputGenerator { next_wire_values: &next_wire_values, }; - let result_wire = Wire { gate: self.gate_index, input: self.input_index }; + let result_wire = match self.location { + GateOutputLocation::LocalWire(input) => + Wire { gate: self.gate_index, input }, + GateOutputLocation::NextWire(input) => + Wire { gate: self.gate_index + 1, input }, + }; + let result_value = self.out.evaluate(vars); - PartialWitness::singleton(Target2::Wire(result_wire), result_value) + PartialWitness::singleton(Target::Wire(result_wire), result_value) } } diff --git a/src/gates/gate.rs b/src/gates/gate.rs index 5af85949..10e11d15 100644 --- a/src/gates/gate.rs +++ b/src/gates/gate.rs @@ -5,6 +5,7 @@ use crate::circuit_data::CircuitConfig; use crate::constraint_polynomial::ConstraintPolynomial; use crate::field::field::Field; use crate::generator::WitnessGenerator2; +use num::ToPrimitive; /// A custom gate. // TODO: Remove CircuitConfig params? Could just use fields within each struct. @@ -44,7 +45,7 @@ pub trait Gate: 'static { fn degree(&self, config: CircuitConfig) -> usize { self.constraints(config) .into_iter() - .map(|c| c.degree()) + .map(|c| c.degree().to_usize().expect("degree too large")) .max() .unwrap_or(0) } diff --git a/src/gates/gmimc.rs b/src/gates/gmimc.rs index 221400e0..5b36ca4a 100644 --- a/src/gates/gmimc.rs +++ b/src/gates/gmimc.rs @@ -4,11 +4,12 @@ use std::sync::Arc; use crate::circuit_data::CircuitConfig; use crate::constraint_polynomial::ConstraintPolynomial; use crate::field::field::Field; -use crate::gates::deterministic_gate::DeterministicGate; +use crate::gates::deterministic_gate::{DeterministicGate, DeterministicGateAdapter}; use crate::gates::gate::{Gate, GateRef}; +use crate::gates::output_graph::{GateOutputLocation, OutputGraph}; use crate::generator::{SimpleGenerator, WitnessGenerator2}; -use crate::gmimc::{gmimc_permute_array, gmimc_permute}; -use crate::target::Target2; +use crate::gmimc::{gmimc_permute, gmimc_permute_array}; +use crate::target::Target; use crate::wire::Wire; use crate::witness::PartialWitness; @@ -21,25 +22,60 @@ pub struct GMiMCGate { impl GMiMCGate { pub fn with_constants(constants: Arc<[F; R]>) -> GateRef { - GateRef::new(GMiMCGate:: { constants }) + let gate = GMiMCGate:: { constants }; + let adapter = DeterministicGateAdapter::new(gate); + GateRef::new(adapter) } pub fn with_automatic_constants() -> GateRef { todo!() } + + /// If this is set to 1, the first four inputs will be swapped with the next four inputs. This + /// is useful for ordering hashes in Merkle proofs. Otherwise, this should be set to 0. + // TODO: Assert binary. + pub const WIRE_SWITCH: usize = 0; + + /// The wire index for the i'th input to the permutation. + pub fn wire_input(i: usize) -> usize { + i + 1 + } + + /// The wire index for the i'th output to the permutation. + /// Note that outputs are written to the next gate's wires. + pub fn wire_output(i: usize) -> usize { + i + 1 + } } -impl Gate for GMiMCGate { +impl DeterministicGate for GMiMCGate { fn id(&self) -> String { - // TODO: Add W/R + // TODO: This won't include generic params? format!("{:?}", self) } - fn constraints(&self, config: CircuitConfig) -> Vec> { - let mut state = (0..W) - .map(|i| ConstraintPolynomial::local_wire_value(i)) + fn outputs(&self, config: CircuitConfig) -> OutputGraph { + let original_inputs = (0..W) + .map(|i| ConstraintPolynomial::local_wire_value(Self::wire_input(i))) .collect::>(); + // Conditionally switch inputs based on the (boolean) switch wire. + let switch = ConstraintPolynomial::local_wire_value(Self::WIRE_SWITCH); + let mut state = Vec::new(); + for i in 0..4 { + let a = &original_inputs[i]; + let b = &original_inputs[i + 4]; + state.push(a + &switch * (b - a)); + } + for i in 0..4 { + let a = &original_inputs[i + 4]; + let b = &original_inputs[i]; + state.push(a + &switch * (b - a)); + } + for i in 8..W { + state.push(original_inputs[i].clone()); + } + // Value that is implicitly added to each element. // See https://affine.group/2020/02/starkware-challenge let mut addition_buffer = ConstraintPolynomial::zero(); @@ -56,52 +92,19 @@ impl Gate for GMiMCGate { state[i] += &addition_buffer; } - state + let outputs = state.into_iter() + .enumerate() + .map(|(i, out)| (GateOutputLocation::NextWire(Self::wire_output(i)), out)) + .collect(); + + // A degree of 9 is reasonable for most circuits, and it means that we only need wires for + // every other addition buffer state. + OutputGraph { outputs }.shrink_degree(9) } - fn generators( - &self, - config: CircuitConfig, - gate_index: usize, - local_constants: Vec, - next_constants: Vec, - ) -> Vec>> { - let generator = GMiMCGenerator:: { - round_constants: self.constants.clone(), - gate_index, - }; - vec![Box::new(generator)] - } -} - -struct GMiMCGenerator { - round_constants: Arc<[F; R]>, - gate_index: usize, -} - -impl SimpleGenerator for GMiMCGenerator { - fn dependencies(&self) -> Vec { - (0..W) - .map(|i| Target2::Wire( - Wire { gate: self.gate_index, input: i })) - .collect() - } - - fn run_once(&mut self, witness: &PartialWitness) -> PartialWitness { - let mut inputs: [F; W] = [F::ZERO; W]; - for i in 0..W { - inputs[i] = witness.get_wire( - Wire { gate: self.gate_index, input: i }); - } - - let outputs = gmimc_permute::(inputs, self.round_constants.clone()); - - let mut result = PartialWitness::new(); - for i in 0..W { - result.set_wire( - Wire { gate: self.gate_index + 1, input: i }, - outputs[i]); - } - result + fn additional_constraints(&self, _config: CircuitConfig) -> Vec> { + let switch = ConstraintPolynomial::local_wire_value(Self::WIRE_SWITCH); + let switch_bool_constraint = &switch * (&switch - 1); + vec![switch_bool_constraint] } } diff --git a/src/gates/mod.rs b/src/gates/mod.rs index e44d34b0..a476af32 100644 --- a/src/gates/mod.rs +++ b/src/gates/mod.rs @@ -1,3 +1,5 @@ +pub(crate) mod constant; pub(crate) mod deterministic_gate; pub(crate) mod gate; pub(crate) mod gmimc; +pub(crate) mod output_graph; diff --git a/src/gates/output_graph.rs b/src/gates/output_graph.rs new file mode 100644 index 00000000..9815b5df --- /dev/null +++ b/src/gates/output_graph.rs @@ -0,0 +1,66 @@ +use std::iter; + +use crate::constraint_polynomial::{ConstraintPolynomial, ConstraintPolynomialRef}; +use crate::field::field::Field; + +/// Represents a set of deterministic gate outputs, expressed as polynomials over witness +/// values. +pub struct OutputGraph { + pub(crate) outputs: Vec<(GateOutputLocation, ConstraintPolynomial)> +} + +/// Represents an output location of a deterministic gate. +#[derive(Copy, Clone)] +pub enum GateOutputLocation { + /// A wire belonging to the gate itself. + LocalWire(usize), + /// A wire belonging to the following gate. + NextWire(usize), +} + +impl OutputGraph { + /// Creates an output graph with a single output. + pub fn single_output(loc: GateOutputLocation, out: ConstraintPolynomial) -> Self { + Self { outputs: vec![(loc, out)] } + } + + /// Compiles an output graph with potentially high-degree polynomials to one with low-degree + /// polynomials by introducing extra wires for some intermediate values. + /// + /// Note that this uses a simple greedy algorithm, so the result may not be optimal in terms of wire + /// count. + pub fn shrink_degree(&self, new_degree: usize) -> Self { + todo!() + } + + /// Allocate a new wire for the given target polynomial, and return a new output graph with + /// references to the target polynomial replaced with references to that wire. + fn allocate_wire(&self, target: ConstraintPolynomial) -> Self { + let new_wire_index = self.outputs.iter() + .flat_map(|(loc, out)| out.max_wire_input_index()) + .max() + .map_or(0, |i| i + 1); + + let new_wire = ConstraintPolynomial::local_wire_value(new_wire_index); + + let outputs = self.outputs.iter() + .map(|(loc, out)| (*loc, out.replace_all(target.clone(), new_wire.clone()))) + .chain(iter::once((GateOutputLocation::LocalWire(new_wire_index), target.clone()))) + .collect(); + Self { outputs } + } +} + +#[cfg(test)] +mod tests { + use crate::constraint_polynomial::ConstraintPolynomial; + use crate::gates::output_graph::shrink_degree; + + #[test] + fn shrink_exp() { + let original = ConstraintPolynomial::local_wire_value(0).exp(10); + let shrunk = shrink_degree(original, 3); + // `shrunk` should be something similar to (wire0^3)^3 * wire0. + assert_eq!(shrunk.max_wire_input_index(), Some(2)) + } +} diff --git a/src/generator.rs b/src/generator.rs index 251d8298..fcea403e 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -1,12 +1,12 @@ use crate::field::field::Field; -use crate::target::Target2; +use crate::target::Target; use crate::witness::PartialWitness; /// A generator participates in the generation of the witness. pub trait WitnessGenerator2: 'static { /// Targets to be "watched" by this generator. Whenever a target in the watch list is populated, /// the generator will be queued to run. - fn watch_list(&self) -> Vec; + fn watch_list(&self) -> Vec; /// Run this generator, returning a `PartialWitness` containing any new witness elements, and a /// flag indicating whether the generator is finished. If the flag is true, the generator will @@ -17,13 +17,13 @@ pub trait WitnessGenerator2: 'static { /// A generator which runs once after a list of dependencies is present in the witness. pub trait SimpleGenerator: 'static { - fn dependencies(&self) -> Vec; + fn dependencies(&self) -> Vec; fn run_once(&mut self, witness: &PartialWitness) -> PartialWitness; } impl> WitnessGenerator2 for SG { - fn watch_list(&self) -> Vec { + fn watch_list(&self) -> Vec { self.dependencies() } @@ -38,12 +38,12 @@ impl> WitnessGenerator2 for SG { /// A generator which copies one wire to another. pub(crate) struct CopyGenerator { - pub(crate) src: Target2, - pub(crate) dst: Target2, + pub(crate) src: Target, + pub(crate) dst: Target, } impl SimpleGenerator for CopyGenerator { - fn dependencies(&self) -> Vec { + fn dependencies(&self) -> Vec { vec![self.src] } diff --git a/src/main.rs b/src/main.rs index e5188d89..517aa742 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,8 +11,8 @@ use field::fft::fft_precompute; use crate::field::field::Field; use crate::util::log2_ceil; -use std::sync::Arc; +mod circuit_builder; mod circuit_data; mod constraint_polynomial; mod field; @@ -22,6 +22,7 @@ mod generator; mod gmimc; mod proof; mod prover; +mod recursive_verifier; mod rescue; mod target; mod util; diff --git a/src/proof.rs b/src/proof.rs index 8f323ec6..2b6e4acf 100644 --- a/src/proof.rs +++ b/src/proof.rs @@ -1,12 +1,12 @@ use crate::field::field::Field; -use crate::target::Target2; +use crate::target::Target; pub struct Hash { elements: Vec, } pub struct HashTarget { - elements: Vec, + elements: Vec, } pub struct Proof2 { @@ -34,7 +34,24 @@ pub struct ProofTarget2 { /// Purported values of each polynomial at each challenge point. pub openings: Vec, - // TODO: FRI Merkle proofs. + /// A FRI argument for each FRI query. + pub fri_proofs: Vec, +} + +/// Represents a single FRI query, i.e. a path through the reduction tree. +pub struct FriProofTarget { + /// Merkle proofs for the original purported codewords, i.e. the subject of the LDT. + pub initial_merkle_proofs: Vec, + /// Merkle proofs for the reduced polynomials that were sent in the commit phase. + pub intermediate_merkle_proofs: Vec, + /// The final polynomial in point-value form. + pub final_poly: Vec, +} + +pub struct MerkleProofTarget { + pub leaf: Vec, + pub siblings: Vec, + // TODO: Also need left/right turn info. } /// The purported values of each polynomial at a single point. @@ -49,10 +66,10 @@ pub struct OpeningSet { /// The purported values of each polynomial at a single point. pub struct OpeningSetTarget { - pub constants: Vec, - pub plonk_sigmas: Vec, - pub wires: Vec, + pub constants: Vec, + pub plonk_sigmas: Vec, + pub wires: Vec, // TODO: One or multiple? - pub plonk_z: Vec, - pub plonk_t: Vec, + pub plonk_z: Vec, + pub plonk_t: Vec, } diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs new file mode 100644 index 00000000..beaa7b15 --- /dev/null +++ b/src/recursive_verifier.rs @@ -0,0 +1,5 @@ +use crate::circuit_builder::CircuitBuilder2; +use crate::field::field::Field; + +pub fn add_recursive_verifier(builder: &mut CircuitBuilder2) { +} diff --git a/src/target.rs b/src/target.rs index 058650d0..032de2fc 100644 --- a/src/target.rs +++ b/src/target.rs @@ -7,22 +7,22 @@ use crate::wire::Wire; /// A location in the witness. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub enum Target2 { +pub enum Target { Wire(Wire), PublicInput { index: usize }, VirtualAdviceTarget { index: usize }, } -impl Target2 { +impl Target { pub fn wire(gate: usize, input: usize) -> Self { Self::Wire(Wire { gate, input }) } pub fn is_routable(&self, config: CircuitConfig) -> bool { match self { - Target2::Wire(wire) => wire.is_routable(config), - Target2::PublicInput { .. } => true, - Target2::VirtualAdviceTarget { .. } => false, + Target::Wire(wire) => wire.is_routable(config), + Target::PublicInput { .. } => true, + Target::VirtualAdviceTarget { .. } => false, } } } diff --git a/src/witness.rs b/src/witness.rs index 56dde3af..07c54bf4 100644 --- a/src/witness.rs +++ b/src/witness.rs @@ -1,12 +1,12 @@ use std::collections::HashMap; use crate::field::field::Field; -use crate::target::Target2; +use crate::target::Target; use crate::wire::Wire; #[derive(Debug)] pub struct PartialWitness { - target_values: HashMap, + target_values: HashMap, } impl PartialWitness { @@ -16,7 +16,7 @@ impl PartialWitness { } } - pub fn singleton(target: Target2, value: F) -> Self { + pub fn singleton(target: Target, value: F) -> Self { let mut witness = PartialWitness::new(); witness.set_target(target, value); witness @@ -26,31 +26,31 @@ impl PartialWitness { self.target_values.is_empty() } - pub fn get_target(&self, target: Target2) -> F { + pub fn get_target(&self, target: Target) -> F { self.target_values[&target] } - pub fn try_get_target(&self, target: Target2) -> Option { + pub fn try_get_target(&self, target: Target) -> Option { self.target_values.get(&target).cloned() } pub fn get_wire(&self, wire: Wire) -> F { - self.get_target(Target2::Wire(wire)) + self.get_target(Target::Wire(wire)) } - pub fn contains(&self, target: Target2) -> bool { + pub fn contains(&self, target: Target) -> bool { self.target_values.contains_key(&target) } - pub fn contains_all(&self, targets: &[Target2]) -> bool { + pub fn contains_all(&self, targets: &[Target]) -> bool { targets.iter().all(|&t| self.contains(t)) } - pub fn set_target(&mut self, target: Target2, value: F) { + pub fn set_target(&mut self, target: Target, value: F) { self.target_values.insert(target, value); } pub fn set_wire(&mut self, wire: Wire, value: F) { - self.set_target(Target2::Wire(wire), value) + self.set_target(Target::Wire(wire), value) } }