mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-02 13:53:07 +00:00
More prover work
This commit is contained in:
parent
8c95dd11d7
commit
ba96ab4e99
10
Cargo.toml
10
Cargo.toml
@ -5,11 +5,13 @@ authors = ["Daniel Lubarov <daniel@lubarov.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
unroll = "0.1.5"
|
||||
rayon = "1.5.0"
|
||||
env_logger = "0.8.3"
|
||||
log = "0.4.14"
|
||||
num = "0.3"
|
||||
rayon = "1.5.0"
|
||||
unroll = "0.1.5"
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
lto = "fat"
|
||||
codegen-units = 1
|
||||
#lto = "fat"
|
||||
#codegen-units = 1
|
||||
|
||||
@ -1,14 +1,21 @@
|
||||
use std::collections::HashSet;
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::circuit_data::{CircuitConfig, CircuitData, ProverCircuitData, VerifierCircuitData};
|
||||
use log::info;
|
||||
|
||||
use crate::circuit_data::{CircuitConfig, CircuitData, CommonCircuitData, ProverCircuitData, ProverOnlyCircuitData, VerifierCircuitData, VerifierOnlyCircuitData};
|
||||
use crate::field::fft::lde_multiple;
|
||||
use crate::field::field::Field;
|
||||
use crate::gates::constant::ConstantGate2;
|
||||
use crate::gates::gate::{GateInstance, GateRef};
|
||||
use crate::generator::{CopyGenerator, WitnessGenerator};
|
||||
use crate::hash::merkle_root_bit_rev_order;
|
||||
use crate::target::Target;
|
||||
use crate::wire::Wire;
|
||||
use crate::gates::noop::NoopGate;
|
||||
use crate::util::transpose;
|
||||
|
||||
pub struct CircuitBuilder2<F: Field> {
|
||||
pub struct CircuitBuilder<F: Field> {
|
||||
config: CircuitConfig,
|
||||
|
||||
/// The types of gates used in this circuit.
|
||||
@ -19,9 +26,9 @@ pub struct CircuitBuilder2<F: Field> {
|
||||
generators: Vec<Box<dyn WitnessGenerator<F>>>,
|
||||
}
|
||||
|
||||
impl<F: Field> CircuitBuilder2<F> {
|
||||
impl<F: Field> CircuitBuilder<F> {
|
||||
pub fn new(config: CircuitConfig) -> Self {
|
||||
CircuitBuilder2 {
|
||||
CircuitBuilder {
|
||||
config,
|
||||
gates: HashSet::new(),
|
||||
gate_instances: Vec::new(),
|
||||
@ -29,6 +36,10 @@ impl<F: Field> CircuitBuilder2<F> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_gate_no_constants(&mut self, gate_type: GateRef<F>) -> usize {
|
||||
self.add_gate(gate_type, Vec::new())
|
||||
}
|
||||
|
||||
/// Adds a gate to the circuit, and returns its index.
|
||||
pub fn add_gate(&mut self, gate_type: GateRef<F>, constants: Vec<F>) -> usize {
|
||||
// If we haven't seen a gate of this type before, check that it's compatible with our
|
||||
@ -96,18 +107,93 @@ impl<F: Field> CircuitBuilder2<F> {
|
||||
Target::Wire(Wire { gate, input: ConstantGate2::WIRE_OUTPUT })
|
||||
}
|
||||
|
||||
fn blind_and_pad(&mut self) {
|
||||
// TODO: Blind.
|
||||
|
||||
while !self.gate_instances.len().is_power_of_two() {
|
||||
self.add_gate_no_constants(NoopGate::get());
|
||||
}
|
||||
}
|
||||
|
||||
fn get_generators(&self) -> Vec<Box<dyn WitnessGenerator<F>>> {
|
||||
self.gate_instances.iter()
|
||||
.enumerate()
|
||||
.flat_map(|(gate_index, gate_inst)| gate_inst.gate_type.0.generators(
|
||||
self.config,
|
||||
gate_index,
|
||||
gate_inst.constants.clone(),
|
||||
vec![])) // TODO: Not supporting next_const for now.
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn constant_vecs(&self) -> Vec<Vec<F>> {
|
||||
let num_constants = self.gate_instances.iter()
|
||||
.map(|gate_inst| gate_inst.constants.len())
|
||||
.max()
|
||||
.unwrap();
|
||||
let constants_per_gate = self.gate_instances.iter()
|
||||
.map(|gate_inst| {
|
||||
let mut padded_constants = gate_inst.constants.clone();
|
||||
for _ in padded_constants.len()..num_constants {
|
||||
padded_constants.push(F::ZERO);
|
||||
}
|
||||
padded_constants
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
transpose(&constants_per_gate)
|
||||
}
|
||||
|
||||
fn sigma_vecs(&self) -> Vec<Vec<F>> {
|
||||
vec![vec![F::ZERO]] // TODO
|
||||
}
|
||||
|
||||
/// Builds a "full circuit", with both prover and verifier data.
|
||||
pub fn build(&self) -> CircuitData<F> {
|
||||
todo!()
|
||||
pub fn build(mut self) -> CircuitData<F> {
|
||||
let start = Instant::now();
|
||||
info!("degree before blinding & padding: {}", self.gate_instances.len());
|
||||
self.blind_and_pad();
|
||||
let degree = self.gate_instances.len();
|
||||
info!("degree after blinding & padding: {}", degree);
|
||||
|
||||
let constant_vecs = self.constant_vecs();
|
||||
let constant_ldes = lde_multiple(constant_vecs, self.config.rate_bits);
|
||||
let constants_root = merkle_root_bit_rev_order(constant_ldes);
|
||||
|
||||
let sigma_vecs = self.sigma_vecs();
|
||||
let sigma_ldes = lde_multiple(sigma_vecs, self.config.rate_bits);
|
||||
let sigmas_root = merkle_root_bit_rev_order(sigma_ldes);
|
||||
|
||||
let generators = self.get_generators();
|
||||
let prover_only = ProverOnlyCircuitData { generators };
|
||||
let verifier_only = VerifierOnlyCircuitData {};
|
||||
|
||||
let common = CommonCircuitData {
|
||||
config: self.config,
|
||||
degree,
|
||||
gates: self.gates.iter().cloned().collect(),
|
||||
constants_root,
|
||||
sigmas_root,
|
||||
};
|
||||
|
||||
info!("Building circuit took {}s", start.elapsed().as_secs_f32());
|
||||
CircuitData {
|
||||
prover_only,
|
||||
verifier_only,
|
||||
common,
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a "prover circuit", with data needed to generate proofs but not verify them.
|
||||
pub fn build_prover(&self) -> ProverCircuitData<F> {
|
||||
todo!()
|
||||
pub fn build_prover(mut self) -> ProverCircuitData<F> {
|
||||
// TODO: Can skip parts of this.
|
||||
let CircuitData { prover_only, verifier_only, common } = self.build();
|
||||
ProverCircuitData { prover_only, common }
|
||||
}
|
||||
|
||||
/// Builds a "verifier circuit", with data needed to verify proofs but not generate them.
|
||||
pub fn build_verifier(&self) -> VerifierCircuitData<F> {
|
||||
todo!()
|
||||
pub fn build_verifier(mut self) -> VerifierCircuitData<F> {
|
||||
// TODO: Can skip parts of this.
|
||||
let CircuitData { prover_only, verifier_only, common } = self.build();
|
||||
VerifierCircuitData { verifier_only, common }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
use crate::field::fft::FftPrecomputation;
|
||||
use crate::field::field::Field;
|
||||
use crate::generator::WitnessGenerator;
|
||||
use crate::proof::{Hash, Proof2};
|
||||
use crate::prover::prove;
|
||||
use crate::verifier::verify;
|
||||
use crate::witness::PartialWitness;
|
||||
use crate::gates::gate::{GateRef, Gate};
|
||||
use crate::gates::gate::{GateRef};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct CircuitConfig {
|
||||
pub num_wires: usize,
|
||||
pub num_routed_wires: usize,
|
||||
pub security_bits: usize,
|
||||
pub rate_bits: usize,
|
||||
}
|
||||
|
||||
impl CircuitConfig {
|
||||
@ -22,9 +22,9 @@ impl CircuitConfig {
|
||||
|
||||
/// Circuit data required by the prover or the verifier.
|
||||
pub struct CircuitData<F: Field> {
|
||||
prover_only: ProverOnlyCircuitData<F>,
|
||||
verifier_only: VerifierOnlyCircuitData,
|
||||
common: CommonCircuitData<F>,
|
||||
pub(crate) prover_only: ProverOnlyCircuitData<F>,
|
||||
pub(crate) verifier_only: VerifierOnlyCircuitData,
|
||||
pub(crate) common: CommonCircuitData<F>,
|
||||
}
|
||||
|
||||
impl<F: Field> CircuitData<F> {
|
||||
@ -39,8 +39,8 @@ impl<F: Field> CircuitData<F> {
|
||||
|
||||
/// Circuit data required by the prover.
|
||||
pub struct ProverCircuitData<F: Field> {
|
||||
prover_only: ProverOnlyCircuitData<F>,
|
||||
common: CommonCircuitData<F>,
|
||||
pub(crate) prover_only: ProverOnlyCircuitData<F>,
|
||||
pub(crate) common: CommonCircuitData<F>,
|
||||
}
|
||||
|
||||
impl<F: Field> ProverCircuitData<F> {
|
||||
@ -51,8 +51,8 @@ impl<F: Field> ProverCircuitData<F> {
|
||||
|
||||
/// Circuit data required by the prover.
|
||||
pub struct VerifierCircuitData<F: Field> {
|
||||
verifier_only: VerifierOnlyCircuitData,
|
||||
common: CommonCircuitData<F>,
|
||||
pub(crate) verifier_only: VerifierOnlyCircuitData,
|
||||
pub(crate) common: CommonCircuitData<F>,
|
||||
}
|
||||
|
||||
impl<F: Field> VerifierCircuitData<F> {
|
||||
@ -71,18 +71,18 @@ pub(crate) struct VerifierOnlyCircuitData {}
|
||||
|
||||
/// Circuit data required by both the prover and the verifier.
|
||||
pub(crate) struct CommonCircuitData<F: Field> {
|
||||
pub config: CircuitConfig,
|
||||
pub(crate) config: CircuitConfig,
|
||||
|
||||
pub degree: usize,
|
||||
pub(crate) degree: usize,
|
||||
|
||||
/// The types of gates used in this circuit.
|
||||
pub gates: Vec<GateRef<F>>,
|
||||
pub(crate) gates: Vec<GateRef<F>>,
|
||||
|
||||
/// A commitment to each constant polynomial.
|
||||
pub constants_root: Hash<F>,
|
||||
pub(crate) constants_root: Hash<F>,
|
||||
|
||||
/// A commitment to each permutation polynomial.
|
||||
pub sigmas_root: Hash<F>,
|
||||
pub(crate) sigmas_root: Hash<F>,
|
||||
}
|
||||
|
||||
impl<F: Field> CommonCircuitData<F> {
|
||||
|
||||
@ -27,7 +27,7 @@ pub(crate) struct EvaluationVars<'a, F: Field> {
|
||||
/// This type implements `Hash` and `Eq` based on references rather
|
||||
/// 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, Debug)]
|
||||
#[derive(Clone)]
|
||||
pub struct ConstraintPolynomial<F: Field>(pub(crate) Rc<ConstraintPolynomialInner<F>>);
|
||||
|
||||
impl<F: Field> ConstraintPolynomial<F> {
|
||||
@ -115,7 +115,7 @@ impl<F: Field> ConstraintPolynomial<F> {
|
||||
}
|
||||
|
||||
pub fn cube(&self) -> Self {
|
||||
self.exp(3)
|
||||
self * self * self
|
||||
}
|
||||
|
||||
pub fn degree(&self) -> BigUint {
|
||||
@ -239,6 +239,12 @@ impl<F: Field> ConstraintPolynomial<F> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field> Debug for ConstraintPolynomial<F> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field> Display for ConstraintPolynomial<F> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
Display::fmt(&self.0, f)
|
||||
|
||||
@ -3,6 +3,7 @@ use std::fmt;
|
||||
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
|
||||
use crate::field::field::Field;
|
||||
use num::Integer;
|
||||
|
||||
/// P = 2**64 - EPSILON
|
||||
/// = 2**64 - 9 * 2**28 + 1
|
||||
@ -58,7 +59,55 @@ impl Field for CrandallField {
|
||||
}
|
||||
|
||||
fn try_inverse(&self) -> Option<Self> {
|
||||
unimplemented!()
|
||||
if *self == Self::ZERO {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Based on Algorithm 16 of "Efficient Software-Implementation of Finite Fields with
|
||||
// Applications to Cryptography".
|
||||
|
||||
let mut u = self.0;
|
||||
let mut v = P;
|
||||
let mut b = 1;
|
||||
let mut c = 0;
|
||||
|
||||
while u != 1 && v != 1 {
|
||||
while u.is_even() {
|
||||
u >>= 1;
|
||||
if b.is_odd() {
|
||||
b += P;
|
||||
}
|
||||
b >>= 1;
|
||||
}
|
||||
|
||||
while v.is_even() {
|
||||
v >>= 1;
|
||||
if c.is_odd() {
|
||||
c += P;
|
||||
}
|
||||
c >>= 1;
|
||||
}
|
||||
|
||||
if u < v {
|
||||
v -= u;
|
||||
if c < b {
|
||||
c += P;
|
||||
}
|
||||
c -= b;
|
||||
} else {
|
||||
u -= v;
|
||||
if b < c {
|
||||
b += P;
|
||||
}
|
||||
b -= c;
|
||||
}
|
||||
}
|
||||
|
||||
Some(Self(if u == 1 {
|
||||
b
|
||||
} else {
|
||||
c
|
||||
}))
|
||||
}
|
||||
|
||||
fn primitive_root_of_unity(n_power: usize) -> Self {
|
||||
|
||||
@ -141,6 +141,20 @@ pub fn coset_ifft<F: Field>(points: Vec<F>, shift: F) -> Vec<F> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn lde_multiple<F: Field>(points: Vec<Vec<F>>, rate_bits: usize) -> Vec<Vec<F>> {
|
||||
points.into_iter().map(|p| lde(p, rate_bits)).collect()
|
||||
}
|
||||
|
||||
pub fn lde<F: Field>(points: Vec<F>, rate_bits: usize) -> Vec<F> {
|
||||
let original_size = points.len();
|
||||
let lde_size = original_size << rate_bits;
|
||||
let mut coeffs = ifft(points);
|
||||
for _ in 0..(lde_size - original_size) {
|
||||
coeffs.push(F::ZERO);
|
||||
}
|
||||
fft(coeffs)
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
// mod tests {
|
||||
// use crate::{Bls12377Scalar, fft_precompute, fft_with_precomputation, CrandallField, ifft_with_precomputation_power_of_2};
|
||||
|
||||
@ -43,6 +43,7 @@ pub fn split_le_generator_local_wires<F: Field>(
|
||||
Box::new(SplitGenerator { integer, bits })
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SplitGenerator {
|
||||
integer: Target,
|
||||
bits: Vec<Target>,
|
||||
|
||||
@ -98,6 +98,7 @@ impl<F: Field, DG: DeterministicGate<F>> Gate<F> for DeterministicGateAdapter<F,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct OutputGenerator<F: Field> {
|
||||
gate_index: usize,
|
||||
location: GateOutputLocation,
|
||||
|
||||
@ -34,7 +34,7 @@ use crate::gadgets::conditionals::conditional_multiply_poly;
|
||||
/// - Evaluates the purported interpolant at `y`, and checks that the result matches the opening
|
||||
/// of `f^(i + 1)(y)`.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct FriConsistencyGate {
|
||||
pub(crate) struct FriConsistencyGate {
|
||||
/// The arity of this reduction step.
|
||||
arity_bits: usize,
|
||||
|
||||
@ -163,6 +163,7 @@ impl FriConsistencyGate {
|
||||
for i in 0..shared_path_bits {
|
||||
let bit = ConstraintPolynomial::local_wire(self.wire_path_bit_i(i));
|
||||
g_exp_path_common = conditional_multiply_poly(&g_exp_path_common, &squares[i], &bit);
|
||||
g_exp_path_common = output_graph.add(g_exp_path_common);
|
||||
}
|
||||
|
||||
// Then, we factor in the "extra" powers of g specific to each child.
|
||||
@ -231,7 +232,7 @@ impl<F: Field> DeterministicGate<F> for FriConsistencyGate {
|
||||
format!("{:?}", self)
|
||||
}
|
||||
|
||||
fn outputs(&self, config: CircuitConfig) -> OutputGraph<F> {
|
||||
fn outputs(&self, _config: CircuitConfig) -> OutputGraph<F> {
|
||||
let mut output_graph = ExpandableOutputGraph::new(self.start_unnamed_wires());
|
||||
self.add_s_j_outputs(&mut output_graph);
|
||||
self.add_y_output(&mut output_graph);
|
||||
@ -263,7 +264,7 @@ impl<F: Field> DeterministicGate<F> for FriConsistencyGate {
|
||||
_config: CircuitConfig,
|
||||
gate_index: usize,
|
||||
local_constants: Vec<F>,
|
||||
next_constants: Vec<F>,
|
||||
_next_constants: Vec<F>,
|
||||
) -> Vec<Box<dyn WitnessGenerator<F>>> {
|
||||
let interpolant_generator = Box::new(
|
||||
InterpolantGenerator {
|
||||
@ -283,6 +284,7 @@ impl<F: Field> DeterministicGate<F> for FriConsistencyGate {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InterpolantGenerator<F: Field> {
|
||||
gate: FriConsistencyGate,
|
||||
gate_index: usize,
|
||||
|
||||
@ -2,7 +2,7 @@ use std::hash::{Hash, Hasher};
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::circuit_data::CircuitConfig;
|
||||
use crate::constraint_polynomial::ConstraintPolynomial;
|
||||
use crate::constraint_polynomial::{ConstraintPolynomial, EvaluationVars};
|
||||
use crate::field::field::Field;
|
||||
use crate::generator::WitnessGenerator;
|
||||
use num::ToPrimitive;
|
||||
@ -15,10 +15,18 @@ pub trait Gate<F: Field>: 'static {
|
||||
/// A set of expressions which must evaluate to zero.
|
||||
fn constraints(&self, config: CircuitConfig) -> Vec<ConstraintPolynomial<F>>;
|
||||
|
||||
// fn eval_constraints(&self, config: CircuitConfig, vars: EvaluationVars<F>) -> Vec<F> {
|
||||
// self.constraints(config)
|
||||
// .into_iter()
|
||||
// .map(|c| c.evaluate(vars))
|
||||
// .collect()
|
||||
// }
|
||||
|
||||
fn generators(
|
||||
&self,
|
||||
config: CircuitConfig,
|
||||
gate_index: usize,
|
||||
// TODO: Switch to slices?
|
||||
local_constants: Vec<F>,
|
||||
next_constants: Vec<F>,
|
||||
) -> Vec<Box<dyn WitnessGenerator<F>>>;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
pub(crate) mod constant;
|
||||
pub(crate) mod deterministic_gate;
|
||||
pub(crate) mod fri_consistency_gate;
|
||||
pub(crate) mod gate;
|
||||
pub(crate) mod gmimc;
|
||||
pub(crate) mod noop;
|
||||
pub(crate) mod output_graph;
|
||||
pub(crate) mod fri_consistency_gate;
|
||||
|
||||
35
src/gates/noop.rs
Normal file
35
src/gates/noop.rs
Normal file
@ -0,0 +1,35 @@
|
||||
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::{Gate, GateRef};
|
||||
use crate::generator::WitnessGenerator;
|
||||
|
||||
/// A gate which takes a single constant parameter and outputs that value.
|
||||
pub struct NoopGate;
|
||||
|
||||
impl NoopGate {
|
||||
pub fn get<F: Field>() -> GateRef<F> {
|
||||
GateRef::new(NoopGate)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field> Gate<F> for NoopGate {
|
||||
fn id(&self) -> String {
|
||||
"NoopGate".into()
|
||||
}
|
||||
|
||||
fn constraints(&self, _config: CircuitConfig) -> Vec<ConstraintPolynomial<F>> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn generators(
|
||||
&self,
|
||||
_config: CircuitConfig,
|
||||
_gate_index: usize,
|
||||
_local_constants: Vec<F>,
|
||||
_next_constants: Vec<F>
|
||||
) -> Vec<Box<dyn WitnessGenerator<F>>> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,8 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::Debug;
|
||||
use std::time::Instant;
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::field::field::Field;
|
||||
use crate::target::Target;
|
||||
@ -36,7 +40,9 @@ pub(crate) fn generate_partial_witness<F: Field>(
|
||||
let mut next_pending_generator_indices = HashSet::new();
|
||||
|
||||
for &generator_idx in &pending_generator_indices {
|
||||
let start = Instant::now();
|
||||
let (result, finished) = generators[generator_idx].run(&witness);
|
||||
trace!("run {:?} took {}", generators[generator_idx], start.elapsed().as_secs_f32());
|
||||
if finished {
|
||||
expired_generator_indices.insert(generator_idx);
|
||||
}
|
||||
@ -60,7 +66,7 @@ pub(crate) fn generate_partial_witness<F: Field>(
|
||||
}
|
||||
|
||||
/// A generator participates in the generation of the witness.
|
||||
pub trait WitnessGenerator<F: Field>: 'static {
|
||||
pub trait WitnessGenerator<F: Field>: 'static + Debug {
|
||||
/// 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<Target>;
|
||||
@ -73,7 +79,7 @@ pub trait WitnessGenerator<F: Field>: 'static {
|
||||
}
|
||||
|
||||
/// A generator which runs once after a list of dependencies is present in the witness.
|
||||
pub trait SimpleGenerator<F: Field>: 'static {
|
||||
pub trait SimpleGenerator<F: Field>: 'static + Debug {
|
||||
fn dependencies(&self) -> Vec<Target>;
|
||||
|
||||
fn run_once(&self, witness: &PartialWitness<F>) -> PartialWitness<F>;
|
||||
@ -94,6 +100,7 @@ impl<F: Field, SG: SimpleGenerator<F>> WitnessGenerator<F> for SG {
|
||||
}
|
||||
|
||||
/// A generator which copies one wire to another.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CopyGenerator {
|
||||
pub(crate) src: Target,
|
||||
pub(crate) dst: Target,
|
||||
|
||||
47
src/hash.rs
47
src/hash.rs
@ -2,9 +2,13 @@
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
use num::traits::real::Real;
|
||||
use rayon::prelude::*;
|
||||
|
||||
use crate::field::field::Field;
|
||||
use crate::gmimc::{gmimc_compress, gmimc_permute_array};
|
||||
use crate::proof::Hash;
|
||||
use crate::util::{reverse_index_bits, transpose};
|
||||
|
||||
const RATE: usize = 8;
|
||||
const CAPACITY: usize = 4;
|
||||
@ -13,6 +17,24 @@ const WIDTH: usize = RATE + CAPACITY;
|
||||
const GMIMC_ROUNDS: usize = 101;
|
||||
const GMIMC_CONSTANTS: [u64; GMIMC_ROUNDS] = [11875528958976719239, 6107683892976199900, 7756999550758271958, 14819109722912164804, 9716579428412441110, 13627117528901194436, 16260683900833506663, 5942251937084147420, 3340009544523273897, 5103423085715007461, 17051583366444092101, 11122892258227244197, 16564300648907092407, 978667924592675864, 17676416205210517593, 1938246372790494499, 8857737698008340728, 1616088456497468086, 15961521580811621978, 17427220057097673602, 14693961562064090188, 694121596646283736, 554241305747273747, 5783347729647881086, 14933083198980931734, 2600898787591841337, 9178797321043036456, 18068112389665928586, 14493389459750307626, 1650694762687203587, 12538946551586403559, 10144328970401184255, 4215161528137084719, 17559540991336287827, 1632269449854444901, 986434918028205468, 14921385763379308253, 4345141219277982730, 2645897826751167170, 9815223670029373528, 7687983869685434132, 13956100321958014639, 519639453142393369, 15617837024229225911, 1557446238053329052, 8130006133842942201, 864716631341688017, 2860289738131495304, 16723700803638270299, 8363528906277648001, 13196016034228493087, 2514677332206134618, 15626342185220554936, 466271571343554681, 17490024028988898434, 6454235936129380878, 15187752952940298536, 18043495619660620405, 17118101079533798167, 13420382916440963101, 535472393366793763, 1071152303676936161, 6351382326603870931, 12029593435043638097, 9983185196487342247, 414304527840226604, 1578977347398530191, 13594880016528059526, 13219707576179925776, 6596253305527634647, 17708788597914990288, 7005038999589109658, 10171979740390484633, 1791376803510914239, 2405996319967739434, 12383033218117026776, 17648019043455213923, 6600216741450137683, 5359884112225925883, 1501497388400572107, 11860887439428904719, 64080876483307031, 11909038931518362287, 14166132102057826906, 14172584203466994499, 593515702472765471, 3423583343794830614, 10041710997716717966, 13434212189787960052, 9943803922749087030, 3216887087479209126, 17385898166602921353, 617799950397934255, 9245115057096506938, 13290383521064450731, 10193883853810413351, 14648839921475785656, 14635698366607946133, 9134302981480720532, 10045888297267997632, 10752096344939765738];
|
||||
|
||||
/// Hash the vector if necessary to reduce its length to ~256 bits. If it already fits, this is a
|
||||
/// no-op.
|
||||
pub fn hash_or_noop<F: Field>(mut inputs: Vec<F>) -> Hash<F> {
|
||||
if inputs.len() <= 4 {
|
||||
Hash::from_partial(inputs)
|
||||
} else {
|
||||
hash_n_to_hash(inputs, false)
|
||||
}
|
||||
}
|
||||
|
||||
/// A one-way compression function which takes two ~256 bit inputs and returns a ~256 bit output.
|
||||
pub fn compress<F: Field>(x: Hash<F>, y: Hash<F>) -> Hash<F> {
|
||||
let mut inputs = Vec::with_capacity(8);
|
||||
inputs.extend(&x.elements);
|
||||
inputs.extend(&y.elements);
|
||||
hash_n_to_hash(inputs, false)
|
||||
}
|
||||
|
||||
/// If `pad` is enabled, the message is padded using the pad10*1 rule. In general this is required
|
||||
/// for the hash to be secure, but it can safely be disabled in certain cases, like if the input
|
||||
/// length is fixed.
|
||||
@ -56,3 +78,28 @@ pub fn hash_n_to_hash<F: Field>(inputs: Vec<F>, pad: bool) -> Hash<F> {
|
||||
pub fn hash_n_to_1<F: Field>(inputs: Vec<F>, pad: bool) -> F {
|
||||
hash_n_to_m(inputs, 1, pad)[0]
|
||||
}
|
||||
|
||||
/// Like `merkle_root`, but first reorders each vector so that `new[i] = old[i.reverse_bits()]`.
|
||||
pub(crate) fn merkle_root_bit_rev_order<F: Field>(vecs: Vec<Vec<F>>) -> Hash<F> {
|
||||
let vecs_reordered = vecs.into_par_iter()
|
||||
.map(reverse_index_bits)
|
||||
.collect();
|
||||
merkle_root(vecs_reordered)
|
||||
}
|
||||
|
||||
/// Given `n` vectors, each of length `l`, constructs a Merkle tree with `l` leaves, where each leaf
|
||||
/// is a hash obtained by hashing a "leaf set" consisting of `n` elements. If `n <= 4`, this hashing
|
||||
/// is skipped, as there is no need to compress leaf data.
|
||||
pub(crate) fn merkle_root<F: Field>(vecs: Vec<Vec<F>>) -> Hash<F> {
|
||||
// TODO: Parallelize.
|
||||
let mut vecs_t = transpose(&vecs);
|
||||
let mut hashes = vecs_t.into_iter()
|
||||
.map(|leaf_set| hash_or_noop(leaf_set))
|
||||
.collect::<Vec<_>>();
|
||||
while hashes.len() > 1 {
|
||||
hashes = hashes.chunks(2)
|
||||
.map(|pair| compress(pair[0], pair[1]))
|
||||
.collect();
|
||||
}
|
||||
hashes[0]
|
||||
}
|
||||
|
||||
62
src/main.rs
62
src/main.rs
@ -11,6 +11,14 @@ use field::fft::fft_precompute;
|
||||
|
||||
use crate::field::field::Field;
|
||||
use crate::util::log2_ceil;
|
||||
use crate::circuit_builder::CircuitBuilder;
|
||||
use crate::circuit_data::CircuitConfig;
|
||||
use crate::witness::PartialWitness;
|
||||
use crate::gates::fri_consistency_gate::FriConsistencyGate;
|
||||
use env_logger::Env;
|
||||
use crate::gates::gmimc::GMiMCGate;
|
||||
use std::sync::Arc;
|
||||
use std::convert::TryInto;
|
||||
|
||||
mod circuit_builder;
|
||||
mod circuit_data;
|
||||
@ -36,11 +44,19 @@ mod hash;
|
||||
const PROVER_POLYS: usize = 113 + 3 + 4;
|
||||
|
||||
fn main() {
|
||||
// Set the default log filter. This can be overridden using the `RUST_LOG` environment variable,
|
||||
// e.g. `RUST_LOG=debug`.
|
||||
// We default to debug for now, since there aren't many logs anyway, but we should probably
|
||||
// change this to info or warn later.
|
||||
env_logger::Builder::from_env(Env::default().default_filter_or("debug")).init();
|
||||
|
||||
let overall_start = Instant::now();
|
||||
|
||||
bench_prove::<CrandallField>();
|
||||
|
||||
// bench_fft();
|
||||
println!();
|
||||
bench_gmimc::<CrandallField>();
|
||||
// bench_gmimc::<CrandallField>();
|
||||
|
||||
let overall_duration = overall_start.elapsed();
|
||||
println!("Overall time: {:?}", overall_duration);
|
||||
@ -48,15 +64,42 @@ fn main() {
|
||||
// field_search()
|
||||
}
|
||||
|
||||
fn bench_prove<F: Field>() {
|
||||
let mut gmimc_constants = [F::ZERO; GMIMC_ROUNDS];
|
||||
for i in 0..GMIMC_ROUNDS {
|
||||
gmimc_constants[i] = F::from_canonical_u64(GMIMC_CONSTANTS[i]);
|
||||
}
|
||||
let gmimc_gate = GMiMCGate::<F, 12, GMIMC_ROUNDS>::with_constants(
|
||||
Arc::new(gmimc_constants));
|
||||
|
||||
let config = CircuitConfig {
|
||||
num_wires: 120,
|
||||
num_routed_wires: 12,
|
||||
security_bits: 128,
|
||||
rate_bits: 3,
|
||||
};
|
||||
|
||||
let mut builder = CircuitBuilder::<F>::new(config);
|
||||
|
||||
for _ in 0..5000 {
|
||||
builder.add_gate_no_constants(gmimc_gate.clone());
|
||||
}
|
||||
|
||||
for _ in 0..(40 * 5) {
|
||||
builder.add_gate(
|
||||
FriConsistencyGate::new(2, 3, 13),
|
||||
vec![F::primitive_root_of_unity(13)]);
|
||||
}
|
||||
|
||||
let prover = builder.build_prover();
|
||||
let inputs = PartialWitness::new();
|
||||
prover.prove(inputs);
|
||||
}
|
||||
|
||||
const GMIMC_ROUNDS: usize = 101;
|
||||
const GMIMC_CONSTANTS: [u64; GMIMC_ROUNDS] = [11875528958976719239, 6107683892976199900, 7756999550758271958, 14819109722912164804, 9716579428412441110, 13627117528901194436, 16260683900833506663, 5942251937084147420, 3340009544523273897, 5103423085715007461, 17051583366444092101, 11122892258227244197, 16564300648907092407, 978667924592675864, 17676416205210517593, 1938246372790494499, 8857737698008340728, 1616088456497468086, 15961521580811621978, 17427220057097673602, 14693961562064090188, 694121596646283736, 554241305747273747, 5783347729647881086, 14933083198980931734, 2600898787591841337, 9178797321043036456, 18068112389665928586, 14493389459750307626, 1650694762687203587, 12538946551586403559, 10144328970401184255, 4215161528137084719, 17559540991336287827, 1632269449854444901, 986434918028205468, 14921385763379308253, 4345141219277982730, 2645897826751167170, 9815223670029373528, 7687983869685434132, 13956100321958014639, 519639453142393369, 15617837024229225911, 1557446238053329052, 8130006133842942201, 864716631341688017, 2860289738131495304, 16723700803638270299, 8363528906277648001, 13196016034228493087, 2514677332206134618, 15626342185220554936, 466271571343554681, 17490024028988898434, 6454235936129380878, 15187752952940298536, 18043495619660620405, 17118101079533798167, 13420382916440963101, 535472393366793763, 1071152303676936161, 6351382326603870931, 12029593435043638097, 9983185196487342247, 414304527840226604, 1578977347398530191, 13594880016528059526, 13219707576179925776, 6596253305527634647, 17708788597914990288, 7005038999589109658, 10171979740390484633, 1791376803510914239, 2405996319967739434, 12383033218117026776, 17648019043455213923, 6600216741450137683, 5359884112225925883, 1501497388400572107, 11860887439428904719, 64080876483307031, 11909038931518362287, 14166132102057826906, 14172584203466994499, 593515702472765471, 3423583343794830614, 10041710997716717966, 13434212189787960052, 9943803922749087030, 3216887087479209126, 17385898166602921353, 617799950397934255, 9245115057096506938, 13290383521064450731, 10193883853810413351, 14648839921475785656, 14635698366607946133, 9134302981480720532, 10045888297267997632, 10752096344939765738];
|
||||
|
||||
fn bench_gmimc<F: Field>() {
|
||||
let mut constants: [F; GMIMC_ROUNDS] = [F::ZERO; GMIMC_ROUNDS];
|
||||
for i in 0..GMIMC_ROUNDS {
|
||||
constants[i] = F::from_canonical_u64(GMIMC_CONSTANTS[i]);
|
||||
}
|
||||
|
||||
const THREADS: usize = 12;
|
||||
const LDE_BITS: i32 = 3;
|
||||
const W: usize = 13;
|
||||
@ -86,10 +129,9 @@ fn bench_gmimc<F: Field>() {
|
||||
}
|
||||
|
||||
fn bench_fft() {
|
||||
let degree = 1 << log2_ceil(77916);
|
||||
let lde_bits = 4;
|
||||
let degree = 1 << 13;
|
||||
let lde_bits = 3;
|
||||
let lde_size = degree << lde_bits;
|
||||
let precomputation = fft_precompute(lde_size);
|
||||
println!("{} << {} = {}", degree, lde_bits, lde_size);
|
||||
|
||||
let start = Instant::now();
|
||||
@ -100,7 +142,7 @@ fn bench_fft() {
|
||||
}
|
||||
|
||||
let start = Instant::now();
|
||||
let result = fft::fft_with_precomputation_power_of_2(coeffs, &precomputation);
|
||||
let result = fft::fft(coeffs);
|
||||
let duration = start.elapsed();
|
||||
println!("FFT took {:?}", duration);
|
||||
println!("FFT result: {:?}", result[0]);
|
||||
|
||||
14
src/proof.rs
14
src/proof.rs
@ -1,8 +1,20 @@
|
||||
use crate::field::field::Field;
|
||||
use crate::target::Target;
|
||||
|
||||
/// Represents a ~256 bit hash output.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Hash<F: Field> {
|
||||
pub(crate) elements: Vec<F>,
|
||||
pub(crate) elements: [F; 4],
|
||||
}
|
||||
|
||||
impl<F: Field> Hash<F> {
|
||||
pub(crate) fn from_partial(mut elements: Vec<F>) -> Self {
|
||||
debug_assert!(elements.len() <= 4);
|
||||
while elements.len() < 4 {
|
||||
elements.push(F::ZERO);
|
||||
}
|
||||
Self { elements: [elements[0], elements[1], elements[2], elements[3]] }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HashTarget {
|
||||
|
||||
@ -1,12 +1,17 @@
|
||||
use std::time::Instant;
|
||||
|
||||
use log::info;
|
||||
|
||||
use crate::circuit_data::{CommonCircuitData, ProverOnlyCircuitData};
|
||||
use crate::field::fft::{fft, ifft};
|
||||
use crate::field::fft::{fft, ifft, lde};
|
||||
use crate::field::field::Field;
|
||||
use crate::generator::generate_partial_witness;
|
||||
use crate::proof::{Proof2, Hash};
|
||||
use crate::util::{log2_ceil, transpose};
|
||||
use crate::hash::{compress, hash_n_to_hash, hash_n_to_m, hash_or_noop, merkle_root_bit_rev_order};
|
||||
use crate::proof::{Hash, Proof2};
|
||||
use crate::util::{log2_ceil, reverse_index_bits};
|
||||
use crate::wire::Wire;
|
||||
use crate::witness::PartialWitness;
|
||||
use crate::hash::{hash_n_to_hash, hash_n_to_m};
|
||||
use rayon::prelude::*;
|
||||
|
||||
pub(crate) fn prove<F: Field>(
|
||||
prover_data: &ProverOnlyCircuitData<F>,
|
||||
@ -14,22 +19,33 @@ pub(crate) fn prove<F: Field>(
|
||||
inputs: PartialWitness<F>,
|
||||
) -> Proof2<F> {
|
||||
let mut witness = inputs;
|
||||
let start_witness = Instant::now();
|
||||
info!("Running {} generators", prover_data.generators.len());
|
||||
generate_partial_witness(&mut witness, &prover_data.generators);
|
||||
info!("Witness generation took {}s", start_witness.elapsed().as_secs_f32());
|
||||
|
||||
let config = common_data.config;
|
||||
let constraint_degree = 1 << log2_ceil(common_data.constraint_degree(config));
|
||||
let lde_size = constraint_degree * common_data.degree;
|
||||
|
||||
let num_wires = config.num_wires;
|
||||
|
||||
let start_wire_ldes = Instant::now();
|
||||
// TODO: Simplify using lde_multiple.
|
||||
// TODO: Parallelize.
|
||||
let wire_ldes = (0..num_wires)
|
||||
.map(|i| compute_wire_lde(i, &witness, common_data.degree, lde_size))
|
||||
.map(|i| compute_wire_lde(i, &witness, common_data.degree, config.rate_bits))
|
||||
.collect::<Vec<_>>();
|
||||
let wires_root = merkle_root(wire_ldes);
|
||||
info!("Computing wire LDEs took {}s", start_wire_ldes.elapsed().as_secs_f32());
|
||||
|
||||
let z_ldes = todo!();
|
||||
let plonk_z_root = merkle_root(z_ldes);
|
||||
let start_wires_root = Instant::now();
|
||||
let wires_root = merkle_root_bit_rev_order(wire_ldes);
|
||||
info!("Merklizing wire LDEs took {}s", start_wires_root.elapsed().as_secs_f32());
|
||||
|
||||
let plonk_t_root = todo!();
|
||||
let plonk_z_vecs = todo!();
|
||||
let plonk_z_ldes = todo!();
|
||||
let plonk_z_root = merkle_root_bit_rev_order(plonk_z_ldes);
|
||||
|
||||
let plonk_t_vecs = todo!();
|
||||
let plonk_t_ldes = todo!();
|
||||
let plonk_t_root = merkle_root_bit_rev_order(plonk_t_ldes);
|
||||
|
||||
let openings = todo!();
|
||||
|
||||
@ -41,37 +57,18 @@ pub(crate) fn prove<F: Field>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Given `n` vectors, each of length `l`, constructs a Merkle tree with `l` leaves, where each leaf
|
||||
/// is a hash obtained by hashing a "leaf set" consisting of `n` elements. If `n <= 4`, this hashing
|
||||
/// is skipped, as there is no need to compress leaf data.
|
||||
fn merkle_root<F: Field>(vecs: Vec<Vec<F>>) -> Hash<F> {
|
||||
let n = vecs.len();
|
||||
let mut vecs_t = transpose(&vecs);
|
||||
let l = vecs_t.len();
|
||||
if n > 4 {
|
||||
vecs_t = vecs_t.into_iter()
|
||||
.map(|leaf_set| hash_n_to_hash(leaf_set, false).elements)
|
||||
.collect();
|
||||
}
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn compute_wire_lde<F: Field>(
|
||||
input: usize,
|
||||
witness: &PartialWitness<F>,
|
||||
degree: usize,
|
||||
lde_size: usize,
|
||||
rate_bits: usize,
|
||||
) -> Vec<F> {
|
||||
let wire = (0..degree)
|
||||
let wire_values = (0..degree)
|
||||
// Some gates do not use all wires, and we do not require that generators populate unused
|
||||
// wires, so some wire values will not be set. We can set these to any value; here we
|
||||
// arbitrary pick zero. Ideally we would verify that no constraints operate on these unset
|
||||
// wires, but that isn't trivial.
|
||||
.map(|gate| witness.try_get_wire(Wire { gate, input }).unwrap_or(F::ZERO))
|
||||
.collect();
|
||||
let mut coeffs = ifft(wire);
|
||||
for _ in 0..(lde_size - degree) {
|
||||
coeffs.push(F::ZERO);
|
||||
}
|
||||
fft(coeffs)
|
||||
lde(wire_values, rate_bits)
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::circuit_builder::CircuitBuilder2;
|
||||
use crate::circuit_builder::CircuitBuilder;
|
||||
use crate::field::field::Field;
|
||||
|
||||
pub fn add_recursive_verifier<F: Field>(builder: &mut CircuitBuilder2<F>) {
|
||||
pub fn add_recursive_verifier<F: Field>(builder: &mut CircuitBuilder<F>) {
|
||||
}
|
||||
|
||||
46
src/util.rs
46
src/util.rs
@ -1,4 +1,3 @@
|
||||
// TODO: Can this impl usize?
|
||||
pub(crate) fn ceil_div_usize(a: usize, b: usize) -> usize {
|
||||
(a + b - 1) / b
|
||||
}
|
||||
@ -29,3 +28,48 @@ pub(crate) fn transpose<T: Clone>(matrix: &[Vec<T>]) -> Vec<Vec<T>> {
|
||||
}
|
||||
transposed
|
||||
}
|
||||
|
||||
/// Permutes `arr` such that each index is mapped to its reverse in binary.
|
||||
pub(crate) fn reverse_index_bits<T: Copy>(arr: Vec<T>) -> Vec<T> {
|
||||
let n = arr.len();
|
||||
let n_power = log2_strict(n);
|
||||
|
||||
let mut result = Vec::with_capacity(n);
|
||||
for i in 0..n {
|
||||
result.push(arr[reverse_bits(i, n_power)]);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn reverse_bits(n: usize, num_bits: usize) -> usize {
|
||||
let mut result = 0;
|
||||
for i in 0..num_bits {
|
||||
let i_rev = num_bits - i - 1;
|
||||
result |= (n >> i & 1) << i_rev;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::util::{reverse_bits, reverse_index_bits};
|
||||
|
||||
#[test]
|
||||
fn test_reverse_bits() {
|
||||
assert_eq!(reverse_bits(0b0000000000, 10), 0b0000000000);
|
||||
assert_eq!(reverse_bits(0b0000000001, 10), 0b1000000000);
|
||||
assert_eq!(reverse_bits(0b1000000000, 10), 0b0000000001);
|
||||
assert_eq!(reverse_bits(0b00000, 5), 0b00000);
|
||||
assert_eq!(reverse_bits(0b01011, 5), 0b11010);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reverse_index_bits() {
|
||||
assert_eq!(
|
||||
reverse_index_bits(vec![10, 20, 30, 40]),
|
||||
vec![10, 30, 20, 40]);
|
||||
assert_eq!(
|
||||
reverse_index_bits(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]),
|
||||
vec![0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user