This commit is contained in:
wborgeaud 2021-06-07 11:19:54 +02:00
parent f5dfe95b2e
commit 6f2275bc6d
5 changed files with 262 additions and 25 deletions

View File

@ -157,16 +157,20 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
let evals = [0, 1, 4]
.iter()
.flat_map(|&i| proof.unsalted_evals(i, config))
.map(|&e| F::Extension::from_basefield(e));
.map(|&e| self.convert_to_ext(e));
let openings = os
.constants
.iter()
.chain(&os.plonk_sigmas)
.chain(&os.quotient_polys);
let numerator = izip!(evals, openings, &mut alpha_powers)
.map(|(e, &o, a)| a * (e - o))
.sum::<F::Extension>();
let denominator = subgroup_x - zeta;
let mut numerator = self.zero_extension();
for (e, &o) in izip!(evals, openings) {
let a = alpha_powers.next(self);
let diff = self.sub_extension(e, o);
numerator = self.mul_add_extension(a, diff, numerator);
}
let denominator = self.sub_extension(subgroup_x, zeta);
// let quotient = self.div_unsafe()
sum += numerator / denominator;
let ev: F::Extension = proof

View File

@ -225,29 +225,40 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
q
}
}
/// An iterator over the powers of a certain base element `b`: `b^0, b^1, b^2, ...`.
#[derive(Clone)]
pub struct PowersTarget<const D: usize> {
base: ExtensionTarget<D>,
current: ExtensionTarget<D>,
}
/// Computes `q = x / y` by witnessing `q` and requiring that `q * y = x`. This can be unsafe in
/// some cases, as it allows `0 / 0 = <anything>`.
pub fn div_unsafe_extension(
&mut self,
x: ExtensionTarget<D>,
y: ExtensionTarget<D>,
) -> ExtensionTarget<D> {
// Add an `ArithmeticGate` to compute `q * y`.
let gate = self.add_gate(ArithmeticGate::new(), vec![F::ONE, F::ZERO]);
impl<F: Extendable<D>, const D: usize> PowersTarget<D> {
fn next(&mut self, builder: &mut CircuitBuilder<F, D>) -> Option<ExtensionTarget<D>> {
let result = self.current;
self.current = builder.mul_extension(self.base, self.current);
Some(result)
}
}
let wire_multiplicand_0 = Wire {
gate,
input: ArithmeticGate::WIRE_MULTIPLICAND_0,
};
let wire_multiplicand_1 = Wire {
gate,
input: ArithmeticGate::WIRE_MULTIPLICAND_1,
};
let wire_addend = Wire {
gate,
input: ArithmeticGate::WIRE_ADDEND,
};
let wire_output = Wire {
gate,
input: ArithmeticGate::WIRE_OUTPUT,
};
impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
pub fn powers(&mut self, base: ExtensionTarget<D>) -> PowersTarget<D> {
PowersTarget {
base,
current: self.one_extension(),
}
let q = Target::Wire(wire_multiplicand_0);
self.add_generator(QuotientGeneratorExtension {
numerator: x,
denominator: ExtensionTarget(),
quotient: ExtensionTarget(),
})
}
}
@ -268,3 +279,53 @@ impl<F: Field> SimpleGenerator<F> for QuotientGenerator {
PartialWitness::singleton_target(self.quotient, num / den)
}
}
struct QuotientGeneratorExtension<const D: usize> {
numerator: ExtensionTarget<D>,
denominator: ExtensionTarget<D>,
quotient: ExtensionTarget<D>,
}
impl<F: Field, const D: usize> SimpleGenerator<F> for QuotientGeneratorExtension<D> {
fn dependencies(&self) -> Vec<Target> {
let mut deps = self.numerator.to_target_array().to_vec();
deps.extend(&self.denominator.to_target_array());
deps
}
fn run_once(&self, witness: &PartialWitness<F>) -> PartialWitness<F> {
let num = witness.get_extension_target(self.numerator);
let dem = witness.get_extension_target(self.denominator);
let quotient = num / dem;
let mut pw = PartialWitness::new();
pw.set_ext_wires(self.quotient.to_target_array(), quotient);
pw
}
}
/// An iterator over the powers of a certain base element `b`: `b^0, b^1, b^2, ...`.
#[derive(Clone)]
pub struct PowersTarget<const D: usize> {
base: ExtensionTarget<D>,
current: ExtensionTarget<D>,
}
impl<const D: usize> PowersTarget<D> {
pub fn next<F: Extendable<D>>(
&mut self,
builder: &mut CircuitBuilder<F, D>,
) -> ExtensionTarget<D> {
let result = self.current;
self.current = builder.mul_extension(self.base, self.current);
result
}
}
impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
pub fn powers(&mut self, base: ExtensionTarget<D>) -> PowersTarget<D> {
PowersTarget {
base,
current: self.one_extension(),
}
}
}

View File

@ -8,3 +8,4 @@ pub(crate) mod noop;
#[cfg(test)]
mod gate_testing;
mod mul_extension;

160
src/gates/mul_extension.rs Normal file
View File

@ -0,0 +1,160 @@
use crate::circuit_builder::CircuitBuilder;
use crate::field::extension_field::target::ExtensionTarget;
use crate::field::extension_field::Extendable;
use crate::field::field::Field;
use crate::gates::gate::{Gate, GateRef};
use crate::generator::{SimpleGenerator, WitnessGenerator};
use crate::target::Target;
use crate::vars::{EvaluationTargets, EvaluationVars};
use crate::wire::Wire;
use crate::witness::PartialWitness;
use std::ops::Range;
/// A gate which can multiply to field extension elements.
/// TODO: Add an addend if `NUM_ROUTED_WIRES` is large enough.
#[derive(Debug)]
pub struct MulExtensionGate<const D: usize>;
impl<const D: usize> MulExtensionGate<D> {
pub fn new<F: Extendable<D>>() -> GateRef<F, D> {
GateRef::new(MulExtensionGate)
}
pub fn wires_multiplicand_0() -> Range<usize> {
0..D
}
pub fn wires_multiplicand_1() -> Range<usize> {
D..2 * D
}
pub fn wires_output() -> Range<usize> {
2 * D..3 * D
}
}
impl<F: Extendable<D>, const D: usize> Gate<F, D> for MulExtensionGate<D> {
fn id(&self) -> String {
format!("{:?}", self)
}
fn eval_unfiltered(&self, vars: EvaluationVars<F, D>) -> Vec<F::Extension> {
let const_0 = vars.local_constants[0];
let const_1 = vars.local_constants[1];
let multiplicand_0 = vars.local_wires[Self::WIRE_MULTIPLICAND_0];
let multiplicand_1 = vars.local_wires[Self::WIRE_MULTIPLICAND_1];
let addend = vars.local_wires[Self::WIRE_ADDEND];
let output = vars.local_wires[Self::WIRE_OUTPUT];
let computed_output = const_0 * multiplicand_0 * multiplicand_1 + const_1 * addend;
vec![computed_output - output]
}
fn eval_unfiltered_recursively(
&self,
builder: &mut CircuitBuilder<F, D>,
vars: EvaluationTargets<D>,
) -> Vec<ExtensionTarget<D>> {
let const_0 = vars.local_constants[0];
let const_1 = vars.local_constants[1];
let multiplicand_0 = vars.local_wires[Self::WIRE_MULTIPLICAND_0];
let multiplicand_1 = vars.local_wires[Self::WIRE_MULTIPLICAND_1];
let addend = vars.local_wires[Self::WIRE_ADDEND];
let output = vars.local_wires[Self::WIRE_OUTPUT];
let product_term = builder.mul_many_extension(&[const_0, multiplicand_0, multiplicand_1]);
let addend_term = builder.mul_extension(const_1, addend);
let computed_output = builder.add_many_extension(&[product_term, addend_term]);
vec![builder.sub_extension(computed_output, output)]
}
fn generators(
&self,
gate_index: usize,
local_constants: &[F],
) -> Vec<Box<dyn WitnessGenerator<F>>> {
let gen = ArithmeticGenerator {
gate_index,
const_0: local_constants[0],
const_1: local_constants[1],
};
vec![Box::new(gen)]
}
fn num_wires(&self) -> usize {
4
}
fn num_constants(&self) -> usize {
2
}
fn degree(&self) -> usize {
3
}
fn num_constraints(&self) -> usize {
1
}
}
struct ArithmeticGenerator<F: Field> {
gate_index: usize,
const_0: F,
const_1: F,
}
impl<F: Field> SimpleGenerator<F> for ArithmeticGenerator<F> {
fn dependencies(&self) -> Vec<Target> {
vec![
Target::Wire(Wire {
gate: self.gate_index,
input: ArithmeticGate::WIRE_MULTIPLICAND_0,
}),
Target::Wire(Wire {
gate: self.gate_index,
input: ArithmeticGate::WIRE_MULTIPLICAND_1,
}),
Target::Wire(Wire {
gate: self.gate_index,
input: ArithmeticGate::WIRE_ADDEND,
}),
]
}
fn run_once(&self, witness: &PartialWitness<F>) -> PartialWitness<F> {
let multiplicand_0_target = Wire {
gate: self.gate_index,
input: ArithmeticGate::WIRE_MULTIPLICAND_0,
};
let multiplicand_1_target = Wire {
gate: self.gate_index,
input: ArithmeticGate::WIRE_MULTIPLICAND_1,
};
let addend_target = Wire {
gate: self.gate_index,
input: ArithmeticGate::WIRE_ADDEND,
};
let output_target = Wire {
gate: self.gate_index,
input: ArithmeticGate::WIRE_OUTPUT,
};
let multiplicand_0 = witness.get_wire(multiplicand_0_target);
let multiplicand_1 = witness.get_wire(multiplicand_1_target);
let addend = witness.get_wire(addend_target);
let output = self.const_0 * multiplicand_0 * multiplicand_1 + self.const_1 * addend;
PartialWitness::singleton_wire(output_target, output)
}
}
#[cfg(test)]
mod tests {
use crate::field::crandall_field::CrandallField;
use crate::gates::arithmetic::ArithmeticGate;
use crate::gates::gate_testing::test_low_degree;
#[test]
fn low_degree() {
test_low_degree(ArithmeticGate::new::<CrandallField, 4>())
}
}

View File

@ -1,9 +1,11 @@
use std::collections::HashMap;
use crate::field::extension_field::target::ExtensionTarget;
use crate::field::extension_field::{Extendable, FieldExtension};
use crate::field::field::Field;
use crate::target::Target;
use crate::wire::Wire;
use std::convert::TryInto;
#[derive(Clone, Debug)]
pub struct PartialWitness<F: Field> {
@ -39,6 +41,15 @@ impl<F: Field> PartialWitness<F> {
targets.iter().map(|&t| self.get_target(t)).collect()
}
pub fn get_extension_target<const D: usize>(&self, et: ExtensionTarget<D>) -> F::Extension
where
F: Extendable<D>,
{
F::Extension::from_basefield_array(
self.get_targets(&et.to_target_array()).try_into().unwrap(),
)
}
pub fn try_get_target(&self, target: Target) -> Option<F> {
self.target_values.get(&target).cloned()
}