mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-07 08:13:11 +00:00
Progress
This commit is contained in:
parent
f5dfe95b2e
commit
6f2275bc6d
@ -157,16 +157,20 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
let evals = [0, 1, 4]
|
let evals = [0, 1, 4]
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|&i| proof.unsalted_evals(i, config))
|
.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
|
let openings = os
|
||||||
.constants
|
.constants
|
||||||
.iter()
|
.iter()
|
||||||
.chain(&os.plonk_sigmas)
|
.chain(&os.plonk_sigmas)
|
||||||
.chain(&os.quotient_polys);
|
.chain(&os.quotient_polys);
|
||||||
let numerator = izip!(evals, openings, &mut alpha_powers)
|
let mut numerator = self.zero_extension();
|
||||||
.map(|(e, &o, a)| a * (e - o))
|
for (e, &o) in izip!(evals, openings) {
|
||||||
.sum::<F::Extension>();
|
let a = alpha_powers.next(self);
|
||||||
let denominator = subgroup_x - zeta;
|
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;
|
sum += numerator / denominator;
|
||||||
|
|
||||||
let ev: F::Extension = proof
|
let ev: F::Extension = proof
|
||||||
|
|||||||
@ -225,29 +225,40 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
|
|
||||||
q
|
q
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// An iterator over the powers of a certain base element `b`: `b^0, b^1, b^2, ...`.
|
/// Computes `q = x / y` by witnessing `q` and requiring that `q * y = x`. This can be unsafe in
|
||||||
#[derive(Clone)]
|
/// some cases, as it allows `0 / 0 = <anything>`.
|
||||||
pub struct PowersTarget<const D: usize> {
|
pub fn div_unsafe_extension(
|
||||||
base: ExtensionTarget<D>,
|
&mut self,
|
||||||
current: ExtensionTarget<D>,
|
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> {
|
let wire_multiplicand_0 = Wire {
|
||||||
fn next(&mut self, builder: &mut CircuitBuilder<F, D>) -> Option<ExtensionTarget<D>> {
|
gate,
|
||||||
let result = self.current;
|
input: ArithmeticGate::WIRE_MULTIPLICAND_0,
|
||||||
self.current = builder.mul_extension(self.base, self.current);
|
};
|
||||||
Some(result)
|
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> {
|
let q = Target::Wire(wire_multiplicand_0);
|
||||||
pub fn powers(&mut self, base: ExtensionTarget<D>) -> PowersTarget<D> {
|
self.add_generator(QuotientGeneratorExtension {
|
||||||
PowersTarget {
|
numerator: x,
|
||||||
base,
|
denominator: ExtensionTarget(),
|
||||||
current: self.one_extension(),
|
quotient: ExtensionTarget(),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,3 +279,53 @@ impl<F: Field> SimpleGenerator<F> for QuotientGenerator {
|
|||||||
PartialWitness::singleton_target(self.quotient, num / den)
|
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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -8,3 +8,4 @@ pub(crate) mod noop;
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod gate_testing;
|
mod gate_testing;
|
||||||
|
mod mul_extension;
|
||||||
|
|||||||
160
src/gates/mul_extension.rs
Normal file
160
src/gates/mul_extension.rs
Normal 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>())
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,9 +1,11 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::field::extension_field::target::ExtensionTarget;
|
||||||
use crate::field::extension_field::{Extendable, FieldExtension};
|
use crate::field::extension_field::{Extendable, FieldExtension};
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
use crate::wire::Wire;
|
use crate::wire::Wire;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PartialWitness<F: Field> {
|
pub struct PartialWitness<F: Field> {
|
||||||
@ -39,6 +41,15 @@ impl<F: Field> PartialWitness<F> {
|
|||||||
targets.iter().map(|&t| self.get_target(t)).collect()
|
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> {
|
pub fn try_get_target(&self, target: Target) -> Option<F> {
|
||||||
self.target_values.get(&target).cloned()
|
self.target_values.get(&target).cloned()
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user