Merge pull request #80 from mir-protocol/blinding_factors

Blinding factors
This commit is contained in:
Nicholas Ward 2021-06-29 23:20:07 -07:00 committed by GitHub
commit 46ff079674
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 108 additions and 3 deletions

View File

@ -14,14 +14,14 @@ use crate::gates::constant::ConstantGate;
use crate::gates::gate::{GateInstance, GateRef, PrefixedGate};
use crate::gates::gate_tree::Tree;
use crate::gates::noop::NoopGate;
use crate::generator::{CopyGenerator, WitnessGenerator};
use crate::generator::{CopyGenerator, RandomValueGenerator, WitnessGenerator};
use crate::hash::hash_n_to_hash;
use crate::permutation_argument::TargetPartitions;
use crate::plonk_common::PlonkPolynomials;
use crate::polynomial::commitment::ListPolynomialCommitment;
use crate::polynomial::polynomial::PolynomialValues;
use crate::target::Target;
use crate::util::{log2_strict, transpose, transpose_poly_values};
use crate::util::{log2_ceil, log2_strict, transpose, transpose_poly_values};
use crate::wire::Wire;
pub struct CircuitBuilder<F: Extendable<D>, const D: usize> {
@ -223,8 +223,96 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
self.targets_to_constants.get(&target).cloned()
}
/// The number of polynomial values that will be revealed per opening, both for the "regular"
/// polynomials and for the Z polynomials. Because calculating these values involves a recursive
/// dependence (the amount of blinding depends on the degree, which depends on the blinding),
/// this function takes in an estimate of the degree.
fn num_blinding_gates(&self, degree_estimate: usize) -> (usize, usize) {
let fri_queries = self.config.fri_config.num_query_rounds;
let arities: Vec<usize> = self
.config
.fri_config
.reduction_arity_bits
.iter()
.map(|x| 1 << x)
.collect();
let total_fri_folding_points: usize = arities.iter().map(|x| x - 1).sum::<usize>();
let final_poly_coeffs: usize = degree_estimate / arities.iter().product::<usize>();
let fri_openings = fri_queries * (1 + D * total_fri_folding_points + D * final_poly_coeffs);
let regular_poly_openings = D + fri_openings;
let z_openings = 2 * D + fri_openings;
(regular_poly_openings, z_openings)
}
/// The number of polynomial values that will be revealed per opening, both for the "regular"
/// polynomials (which are opened at only one location) and for the Z polynomials (which are
/// opened at two).
fn blinding_counts(&self) -> (usize, usize) {
let num_gates = self.gates.len();
let mut degree_estimate = 1 << log2_ceil(num_gates);
loop {
let (regular_poly_openings, z_openings) = self.num_blinding_gates(degree_estimate);
// For most polynomials, we add one random element to offset each opened value.
// But blinding Z is separate. For that, we add two random elements with a copy
// constraint between them.
let total_blinding_count = regular_poly_openings + 2 * z_openings;
if num_gates + total_blinding_count <= degree_estimate {
return (regular_poly_openings, z_openings);
}
// The blinding gates do not fit within our estimated degree; increase our estimate.
degree_estimate *= 2;
}
}
fn blind_and_pad(&mut self) {
// TODO: Blind.
let (regular_poly_openings, z_openings) = self.blinding_counts();
let num_routed_wires = self.config.num_routed_wires;
let num_wires = self.config.num_wires;
// For each "regular" blinding factor, we simply add a no-op gate, and insert a random value
// for each wire.
for _ in 0..regular_poly_openings {
let gate = self.add_gate_no_constants(NoopGate::get());
for w in 0..num_wires {
self.add_generator(RandomValueGenerator {
target: Target::Wire(Wire { gate, input: w }),
});
}
}
// For each z poly blinding factor, we add two new gates with the same random value, and
// enforce a copy constraint between them.
// See https://mirprotocol.org/blog/Adding-zero-knowledge-to-Plonk-Halo
for _ in 0..z_openings {
let gate_1 = self.add_gate_no_constants(NoopGate::get());
let gate_2 = self.add_gate_no_constants(NoopGate::get());
for w in 0..num_routed_wires {
self.add_generator(RandomValueGenerator {
target: Target::Wire(Wire {
gate: gate_1,
input: w,
}),
});
self.add_generator(CopyGenerator {
src: Target::Wire(Wire {
gate: gate_1,
input: w,
}),
dst: Target::Wire(Wire {
gate: gate_2,
input: w,
}),
});
}
}
while !self.gate_instances.len().is_power_of_two() {
self.add_gate_no_constants(NoopGate::get());

View File

@ -113,3 +113,20 @@ impl<F: Field> SimpleGenerator<F> for CopyGenerator {
PartialWitness::singleton_target(self.dst, value)
}
}
/// A generator for including a random value
pub(crate) struct RandomValueGenerator {
pub(crate) target: Target,
}
impl<F: Field> SimpleGenerator<F> for RandomValueGenerator {
fn dependencies(&self) -> Vec<Target> {
Vec::new()
}
fn run_once(&self, _witness: &PartialWitness<F>) -> PartialWitness<F> {
let random_value = F::rand();
PartialWitness::singleton_target(self.target, random_value)
}
}