mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-08 08:43:06 +00:00
windowed multiplication in circuit
This commit is contained in:
parent
dc44baa592
commit
53a2a92258
@ -332,7 +332,8 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
let x_index_within_coset = self.le_sum(x_index_within_coset_bits.iter());
|
||||
|
||||
// Check consistency with our old evaluation from the previous round.
|
||||
self.random_access_extension(x_index_within_coset, old_eval, evals.clone());
|
||||
let new_eval = self.random_access_extension(x_index_within_coset, evals.clone());
|
||||
self.connect_extension(new_eval, old_eval);
|
||||
|
||||
// Infer P(y) from {P(x)}_{x^arity=y}.
|
||||
old_eval = with_context!(
|
||||
|
||||
@ -1,11 +1,18 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use plonky2_field::extension_field::Extendable;
|
||||
use plonky2_field::field_types::Field;
|
||||
|
||||
use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar};
|
||||
use crate::gadgets::arithmetic_u32::U32Target;
|
||||
use crate::gadgets::biguint::BigUintTarget;
|
||||
use crate::gadgets::nonnative::NonNativeTarget;
|
||||
use crate::hash::hash_types::RichField;
|
||||
use crate::iop::target::Target;
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
|
||||
const WINDOW_SIZE: usize = 4;
|
||||
|
||||
/// A Target representing an affine point on the curve `C`. We use incomplete arithmetic for efficiency,
|
||||
/// so we assume these points are not zero.
|
||||
#[derive(Clone, Debug)]
|
||||
@ -157,6 +164,82 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn precompute_window<C: Curve>(
|
||||
&mut self,
|
||||
p: &AffinePointTarget<C>,
|
||||
) -> Vec<AffinePointTarget<C>> {
|
||||
let mut multiples = Vec::new();
|
||||
multiples.push(self.constant_affine_point(C::GENERATOR_AFFINE));
|
||||
let mut cur = p.clone();
|
||||
for _pow in 1..WINDOW_SIZE {
|
||||
for existing in multiples.clone() {
|
||||
multiples.push(self.curve_add(&cur, &existing));
|
||||
}
|
||||
cur = self.curve_double(&cur);
|
||||
}
|
||||
|
||||
multiples
|
||||
}
|
||||
|
||||
pub fn random_access_curve_points<C: Curve>(
|
||||
&mut self,
|
||||
access_index: Target,
|
||||
v: Vec<AffinePointTarget<C>>,
|
||||
) -> AffinePointTarget<C> {
|
||||
let num_limbs = v[0].x.value.num_limbs();
|
||||
let x_limbs: Vec<Vec<_>> = (0..num_limbs)
|
||||
.map(|i| v.iter().map(|p| p.x.value.limbs[i].0).collect())
|
||||
.collect();
|
||||
let y_limbs: Vec<Vec<_>> = (0..num_limbs)
|
||||
.map(|i| v.iter().map(|p| p.y.value.limbs[i].0).collect())
|
||||
.collect();
|
||||
|
||||
let selected_x_limbs: Vec<_> = x_limbs
|
||||
.iter()
|
||||
.map(|limbs| U32Target(self.random_access(access_index, limbs.clone())))
|
||||
.collect();
|
||||
let selected_y_limbs: Vec<_> = y_limbs
|
||||
.iter()
|
||||
.map(|limbs| U32Target(self.random_access(access_index, limbs.clone())))
|
||||
.collect();
|
||||
|
||||
let x = NonNativeTarget {
|
||||
value: BigUintTarget {
|
||||
limbs: selected_x_limbs,
|
||||
},
|
||||
_phantom: PhantomData,
|
||||
};
|
||||
let y = NonNativeTarget {
|
||||
value: BigUintTarget {
|
||||
limbs: selected_y_limbs,
|
||||
},
|
||||
_phantom: PhantomData,
|
||||
};
|
||||
AffinePointTarget { x, y }
|
||||
}
|
||||
|
||||
pub fn curve_scalar_mul_windowed<C: Curve>(
|
||||
&mut self,
|
||||
p: &AffinePointTarget<C>,
|
||||
n: &NonNativeTarget<C::ScalarField>,
|
||||
) -> AffinePointTarget<C> {
|
||||
let mut result = self.constant_affine_point(C::GENERATOR_AFFINE);
|
||||
|
||||
let precomputation = self.precompute_window(p);
|
||||
|
||||
let windows = self.split_nonnative_to_4_bit_limbs(n);
|
||||
let m = C::ScalarField::BITS / WINDOW_SIZE;
|
||||
for i in m..0 {
|
||||
result = self.curve_double(&result);
|
||||
let window = windows[i];
|
||||
|
||||
let to_add = self.random_access_curve_points(window, precomputation.clone());
|
||||
result = self.curve_add(&result, &to_add);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@ -16,3 +16,4 @@ pub mod range_check;
|
||||
pub mod select;
|
||||
pub mod split_base;
|
||||
pub(crate) mod split_join;
|
||||
pub mod split_nonnative;
|
||||
|
||||
@ -10,13 +10,15 @@ use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
/// Checks that a `Target` matches a vector at a non-deterministic index.
|
||||
/// Note: `access_index` is not range-checked.
|
||||
pub fn random_access(&mut self, access_index: Target, claimed_element: Target, v: Vec<Target>) {
|
||||
pub fn random_access(&mut self, access_index: Target, v: Vec<Target>) -> Target {
|
||||
let vec_size = v.len();
|
||||
let bits = log2_strict(vec_size);
|
||||
debug_assert!(vec_size > 0);
|
||||
if vec_size == 1 {
|
||||
return self.connect(claimed_element, v[0]);
|
||||
return v[0];
|
||||
}
|
||||
let claimed_element = self.add_virtual_target();
|
||||
|
||||
let dummy_gate = RandomAccessGate::<F, D>::new_from_config(&self.config, bits);
|
||||
let (gate_index, copy) = self.find_slot(dummy_gate, &[], &[]);
|
||||
|
||||
@ -34,6 +36,8 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
claimed_element,
|
||||
Target::wire(gate_index, dummy_gate.wire_claimed_element(copy)),
|
||||
);
|
||||
|
||||
claimed_element
|
||||
}
|
||||
|
||||
/// Checks that an `ExtensionTarget` matches a vector at a non-deterministic index.
|
||||
@ -41,16 +45,13 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
pub fn random_access_extension(
|
||||
&mut self,
|
||||
access_index: Target,
|
||||
claimed_element: ExtensionTarget<D>,
|
||||
v: Vec<ExtensionTarget<D>>,
|
||||
) {
|
||||
for i in 0..D {
|
||||
self.random_access(
|
||||
access_index,
|
||||
claimed_element.0[i],
|
||||
v.iter().map(|et| et.0[i]).collect(),
|
||||
);
|
||||
}
|
||||
) -> ExtensionTarget<D> {
|
||||
let v: Vec<_> = (0..D)
|
||||
.map(|i| self.random_access(access_index, v.iter().map(|et| et.0[i]).collect()))
|
||||
.collect();
|
||||
|
||||
ExtensionTarget(v.try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,7 +81,8 @@ mod tests {
|
||||
for i in 0..len {
|
||||
let it = builder.constant(F::from_canonical_usize(i));
|
||||
let elem = builder.constant_extension(vec[i]);
|
||||
builder.random_access_extension(it, elem, v.clone());
|
||||
let res = builder.random_access_extension(it, v.clone());
|
||||
builder.connect_extension(elem, res);
|
||||
}
|
||||
|
||||
let data = builder.build::<C>();
|
||||
|
||||
34
plonky2/src/gadgets/split_nonnative.rs
Normal file
34
plonky2/src/gadgets/split_nonnative.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use itertools::Itertools;
|
||||
use plonky2_field::extension_field::Extendable;
|
||||
use plonky2_field::field_types::Field;
|
||||
|
||||
use crate::gadgets::arithmetic_u32::U32Target;
|
||||
use crate::gadgets::nonnative::NonNativeTarget;
|
||||
use crate::hash::hash_types::RichField;
|
||||
use crate::iop::target::Target;
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
pub fn split_u32_to_4_bit_limbs(&mut self, val: U32Target) -> Vec<Target> {
|
||||
let two_bit_limbs = self.split_le_base::<2>(val.0, 16);
|
||||
let four = self.constant(F::from_canonical_usize(4));
|
||||
let combined_limbs = two_bit_limbs
|
||||
.iter()
|
||||
.tuples()
|
||||
.map(|(&a, &b)| self.mul_add(b, four, a))
|
||||
.collect();
|
||||
|
||||
combined_limbs
|
||||
}
|
||||
|
||||
pub fn split_nonnative_to_4_bit_limbs<FF: Field>(
|
||||
&mut self,
|
||||
val: &NonNativeTarget<FF>,
|
||||
) -> Vec<Target> {
|
||||
val.value
|
||||
.limbs
|
||||
.iter()
|
||||
.flat_map(|&l| self.split_u32_to_4_bit_limbs(l))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
@ -78,11 +78,9 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
let index = self.le_sum(leaf_index_bits[proof.siblings.len()..].iter().copied());
|
||||
|
||||
for i in 0..4 {
|
||||
self.random_access(
|
||||
index,
|
||||
state.elements[i],
|
||||
merkle_cap.0.iter().map(|h| h.elements[i]).collect(),
|
||||
);
|
||||
let result =
|
||||
self.random_access(index, merkle_cap.0.iter().map(|h| h.elements[i]).collect());
|
||||
self.connect(result, state.elements[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,11 +108,11 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
}
|
||||
|
||||
for i in 0..4 {
|
||||
self.random_access(
|
||||
let result = self.random_access(
|
||||
cap_index,
|
||||
state.elements[i],
|
||||
merkle_cap.0.iter().map(|h| h.elements[i]).collect(),
|
||||
);
|
||||
self.connect(result, state.elements[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -846,3 +846,443 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
}
|
||||
}
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
|
||||
/// Various gate types can contain multiple copies in a single Gate. This helper struct lets a
|
||||
/// CircuitBuilder track such gates that are currently being "filled up."
|
||||
pub struct BatchedGates<F: RichField + Extendable<D>, const D: usize> {
|
||||
/// A map `(c0, c1) -> (g, i)` from constants `(c0,c1)` to an available arithmetic gate using
|
||||
/// these constants with gate index `g` and already using `i` arithmetic operations.
|
||||
pub(crate) free_arithmetic: HashMap<(F, F), (usize, usize)>,
|
||||
pub(crate) free_base_arithmetic: HashMap<(F, F), (usize, usize)>,
|
||||
|
||||
pub(crate) free_mul: HashMap<F, (usize, usize)>,
|
||||
|
||||
/// A map `b -> (g, i)` from `b` bits to an available random access gate of that size with gate
|
||||
/// index `g` and already using `i` random accesses.
|
||||
pub(crate) free_random_access: HashMap<usize, (usize, usize)>,
|
||||
|
||||
/// `current_switch_gates[chunk_size - 1]` contains None if we have no switch gates with the value
|
||||
/// chunk_size, and contains `(g, i, c)`, if the gate `g`, at index `i`, already contains `c` copies
|
||||
/// of switches
|
||||
pub(crate) current_switch_gates: Vec<Option<(SwitchGate<F, D>, usize, usize)>>,
|
||||
|
||||
/// A map `n -> (g, i)` from `n` number of addends to an available `U32AddManyGate` of that size with gate
|
||||
/// index `g` and already using `i` random accesses.
|
||||
pub(crate) free_u32_add_many: HashMap<usize, (usize, usize)>,
|
||||
|
||||
/// The `U32ArithmeticGate` currently being filled (so new u32 arithmetic operations will be added to this gate before creating a new one)
|
||||
pub(crate) current_u32_arithmetic_gate: Option<(usize, usize)>,
|
||||
/// The `U32SubtractionGate` currently being filled (so new u32 subtraction operations will be added to this gate before creating a new one)
|
||||
pub(crate) current_u32_subtraction_gate: Option<(usize, usize)>,
|
||||
|
||||
/// An available `ConstantGate` instance, if any.
|
||||
pub(crate) free_constant: Option<(usize, usize)>,
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> BatchedGates<F, D> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
free_arithmetic: HashMap::new(),
|
||||
free_base_arithmetic: HashMap::new(),
|
||||
free_mul: HashMap::new(),
|
||||
free_random_access: HashMap::new(),
|
||||
current_switch_gates: Vec::new(),
|
||||
free_u32_add_many: HashMap::new(),
|
||||
current_u32_arithmetic_gate: None,
|
||||
current_u32_subtraction_gate: None,
|
||||
free_constant: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
/// Finds the last available arithmetic gate with the given constants or add one if there aren't any.
|
||||
/// Returns `(g,i)` such that there is an arithmetic gate with the given constants at index
|
||||
/// `g` and the gate's `i`-th operation is available.
|
||||
pub(crate) fn find_base_arithmetic_gate(&mut self, const_0: F, const_1: F) -> (usize, usize) {
|
||||
let (gate, i) = self
|
||||
.batched_gates
|
||||
.free_base_arithmetic
|
||||
.get(&(const_0, const_1))
|
||||
.copied()
|
||||
.unwrap_or_else(|| {
|
||||
let gate = self.add_gate(
|
||||
ArithmeticGate::new_from_config(&self.config),
|
||||
vec![const_0, const_1],
|
||||
);
|
||||
(gate, 0)
|
||||
});
|
||||
|
||||
// Update `free_arithmetic` with new values.
|
||||
if i < ArithmeticGate::num_ops(&self.config) - 1 {
|
||||
self.batched_gates
|
||||
.free_base_arithmetic
|
||||
.insert((const_0, const_1), (gate, i + 1));
|
||||
} else {
|
||||
self.batched_gates
|
||||
.free_base_arithmetic
|
||||
.remove(&(const_0, const_1));
|
||||
}
|
||||
|
||||
(gate, i)
|
||||
}
|
||||
|
||||
/// Finds the last available arithmetic gate with the given constants or add one if there aren't any.
|
||||
/// Returns `(g,i)` such that there is an arithmetic gate with the given constants at index
|
||||
/// `g` and the gate's `i`-th operation is available.
|
||||
pub(crate) fn find_arithmetic_gate(&mut self, const_0: F, const_1: F) -> (usize, usize) {
|
||||
let (gate, i) = self
|
||||
.batched_gates
|
||||
.free_arithmetic
|
||||
.get(&(const_0, const_1))
|
||||
.copied()
|
||||
.unwrap_or_else(|| {
|
||||
let gate = self.add_gate(
|
||||
ArithmeticExtensionGate::new_from_config(&self.config),
|
||||
vec![const_0, const_1],
|
||||
);
|
||||
(gate, 0)
|
||||
});
|
||||
|
||||
// Update `free_arithmetic` with new values.
|
||||
if i < ArithmeticExtensionGate::<D>::num_ops(&self.config) - 1 {
|
||||
self.batched_gates
|
||||
.free_arithmetic
|
||||
.insert((const_0, const_1), (gate, i + 1));
|
||||
} else {
|
||||
self.batched_gates
|
||||
.free_arithmetic
|
||||
.remove(&(const_0, const_1));
|
||||
}
|
||||
|
||||
(gate, i)
|
||||
}
|
||||
|
||||
/// Finds the last available arithmetic gate with the given constants or add one if there aren't any.
|
||||
/// Returns `(g,i)` such that there is an arithmetic gate with the given constants at index
|
||||
/// `g` and the gate's `i`-th operation is available.
|
||||
pub(crate) fn find_mul_gate(&mut self, const_0: F) -> (usize, usize) {
|
||||
let (gate, i) = self
|
||||
.batched_gates
|
||||
.free_mul
|
||||
.get(&const_0)
|
||||
.copied()
|
||||
.unwrap_or_else(|| {
|
||||
let gate = self.add_gate(
|
||||
MulExtensionGate::new_from_config(&self.config),
|
||||
vec![const_0],
|
||||
);
|
||||
(gate, 0)
|
||||
});
|
||||
|
||||
// Update `free_arithmetic` with new values.
|
||||
if i < MulExtensionGate::<D>::num_ops(&self.config) - 1 {
|
||||
self.batched_gates.free_mul.insert(const_0, (gate, i + 1));
|
||||
} else {
|
||||
self.batched_gates.free_mul.remove(&const_0);
|
||||
}
|
||||
|
||||
(gate, i)
|
||||
}
|
||||
|
||||
/// Finds the last available random access gate with the given `bits` or adds one if there aren't any.
|
||||
/// Returns `(g,i)` such that there is a random access gate for the given `bits` at index
|
||||
/// `g` and the gate's `i`-th random access is available.
|
||||
pub(crate) fn find_random_access_gate(&mut self, bits: usize) -> (usize, usize) {
|
||||
let (gate, i) = self
|
||||
.batched_gates
|
||||
.free_random_access
|
||||
.get(&bits)
|
||||
.copied()
|
||||
.unwrap_or_else(|| {
|
||||
let gate = self.add_gate(
|
||||
RandomAccessGate::new_from_config(&self.config, bits),
|
||||
vec![],
|
||||
);
|
||||
(gate, 0)
|
||||
});
|
||||
|
||||
// Update `free_random_access` with new values.
|
||||
if i + 1 < RandomAccessGate::<F, D>::new_from_config(&self.config, bits).num_copies {
|
||||
self.batched_gates
|
||||
.free_random_access
|
||||
.insert(bits, (gate, i + 1));
|
||||
} else {
|
||||
self.batched_gates.free_random_access.remove(&bits);
|
||||
}
|
||||
|
||||
(gate, i)
|
||||
}
|
||||
|
||||
pub fn find_switch_gate(&mut self, chunk_size: usize) -> (SwitchGate<F, D>, usize, usize) {
|
||||
if self.batched_gates.current_switch_gates.len() < chunk_size {
|
||||
self.batched_gates.current_switch_gates.extend(vec![
|
||||
None;
|
||||
chunk_size
|
||||
- self
|
||||
.batched_gates
|
||||
.current_switch_gates
|
||||
.len()
|
||||
]);
|
||||
}
|
||||
|
||||
let (gate, gate_index, next_copy) =
|
||||
match self.batched_gates.current_switch_gates[chunk_size - 1].clone() {
|
||||
None => {
|
||||
let gate = SwitchGate::<F, D>::new_from_config(&self.config, chunk_size);
|
||||
let gate_index = self.add_gate(gate.clone(), vec![]);
|
||||
(gate, gate_index, 0)
|
||||
}
|
||||
Some((gate, idx, next_copy)) => (gate, idx, next_copy),
|
||||
};
|
||||
|
||||
let num_copies = gate.num_copies;
|
||||
|
||||
if next_copy == num_copies - 1 {
|
||||
self.batched_gates.current_switch_gates[chunk_size - 1] = None;
|
||||
} else {
|
||||
self.batched_gates.current_switch_gates[chunk_size - 1] =
|
||||
Some((gate.clone(), gate_index, next_copy + 1));
|
||||
}
|
||||
|
||||
(gate, gate_index, next_copy)
|
||||
}
|
||||
|
||||
/// Finds the last available U32 add-many gate with the given `num_addends` or adds one if there aren't any.
|
||||
/// Returns `(g,i)` such that there is a `U32AddManyGate` for the given `num_addends` at index
|
||||
/// `g` and the gate's `i`-th copy is available.
|
||||
pub(crate) fn find_u32_add_many_gate(&mut self, num_addends: usize) -> (usize, usize) {
|
||||
let (gate, i) = self
|
||||
.batched_gates
|
||||
.free_u32_add_many
|
||||
.get(&num_addends)
|
||||
.copied()
|
||||
.unwrap_or_else(|| {
|
||||
let gate = self.add_gate(
|
||||
U32AddManyGate::new_from_config(&self.config, num_addends),
|
||||
vec![],
|
||||
);
|
||||
(gate, 0)
|
||||
});
|
||||
|
||||
// Update `free_u32_add_many` with new values.
|
||||
if i + 1 < U32AddManyGate::<F, D>::new_from_config(&self.config, num_addends).num_ops {
|
||||
self.batched_gates
|
||||
.free_u32_add_many
|
||||
.insert(num_addends, (gate, i + 1));
|
||||
} else {
|
||||
self.batched_gates.free_u32_add_many.remove(&num_addends);
|
||||
}
|
||||
|
||||
(gate, i)
|
||||
}
|
||||
|
||||
pub(crate) fn find_u32_arithmetic_gate(&mut self) -> (usize, usize) {
|
||||
let (gate_index, copy) = match self.batched_gates.current_u32_arithmetic_gate {
|
||||
None => {
|
||||
let gate = U32ArithmeticGate::new_from_config(&self.config);
|
||||
let gate_index = self.add_gate(gate, vec![]);
|
||||
(gate_index, 0)
|
||||
}
|
||||
Some((gate_index, copy)) => (gate_index, copy),
|
||||
};
|
||||
|
||||
if copy == U32ArithmeticGate::<F, D>::num_ops(&self.config) - 1 {
|
||||
self.batched_gates.current_u32_arithmetic_gate = None;
|
||||
} else {
|
||||
self.batched_gates.current_u32_arithmetic_gate = Some((gate_index, copy + 1));
|
||||
}
|
||||
|
||||
(gate_index, copy)
|
||||
}
|
||||
|
||||
pub(crate) fn find_u32_subtraction_gate(&mut self) -> (usize, usize) {
|
||||
let (gate_index, copy) = match self.batched_gates.current_u32_subtraction_gate {
|
||||
None => {
|
||||
let gate = U32SubtractionGate::new_from_config(&self.config);
|
||||
let gate_index = self.add_gate(gate, vec![]);
|
||||
(gate_index, 0)
|
||||
}
|
||||
Some((gate_index, copy)) => (gate_index, copy),
|
||||
};
|
||||
|
||||
if copy == U32SubtractionGate::<F, D>::num_ops(&self.config) - 1 {
|
||||
self.batched_gates.current_u32_subtraction_gate = None;
|
||||
} else {
|
||||
self.batched_gates.current_u32_subtraction_gate = Some((gate_index, copy + 1));
|
||||
}
|
||||
|
||||
(gate_index, copy)
|
||||
}
|
||||
|
||||
/// Returns the gate index and copy index of a free `ConstantGate` slot, potentially adding a
|
||||
/// new `ConstantGate` if needed.
|
||||
fn constant_gate_instance(&mut self) -> (usize, usize) {
|
||||
if self.batched_gates.free_constant.is_none() {
|
||||
let num_consts = self.config.constant_gate_size;
|
||||
// We will fill this `ConstantGate` with zero constants initially.
|
||||
// These will be overwritten by `constant` as the gate instances are filled.
|
||||
let gate = self.add_gate(ConstantGate { num_consts }, vec![F::ZERO; num_consts]);
|
||||
self.batched_gates.free_constant = Some((gate, 0));
|
||||
}
|
||||
|
||||
let (gate, instance) = self.batched_gates.free_constant.unwrap();
|
||||
if instance + 1 < self.config.constant_gate_size {
|
||||
self.batched_gates.free_constant = Some((gate, instance + 1));
|
||||
} else {
|
||||
self.batched_gates.free_constant = None;
|
||||
}
|
||||
(gate, instance)
|
||||
}
|
||||
|
||||
/// Fill the remaining unused arithmetic operations with zeros, so that all
|
||||
/// `ArithmeticGate` are run.
|
||||
fn fill_base_arithmetic_gates(&mut self) {
|
||||
let zero = self.zero();
|
||||
for ((c0, c1), (_gate, i)) in self.batched_gates.free_base_arithmetic.clone() {
|
||||
for _ in i..ArithmeticGate::num_ops(&self.config) {
|
||||
// If we directly wire in zero, an optimization will skip doing anything and return
|
||||
// zero. So we pass in a virtual target and connect it to zero afterward.
|
||||
let dummy = self.add_virtual_target();
|
||||
self.arithmetic(c0, c1, dummy, dummy, dummy);
|
||||
self.connect(dummy, zero);
|
||||
}
|
||||
}
|
||||
assert!(self.batched_gates.free_base_arithmetic.is_empty());
|
||||
}
|
||||
|
||||
/// Fill the remaining unused arithmetic operations with zeros, so that all
|
||||
/// `ArithmeticExtensionGenerator`s are run.
|
||||
fn fill_arithmetic_gates(&mut self) {
|
||||
let zero = self.zero_extension();
|
||||
for ((c0, c1), (_gate, i)) in self.batched_gates.free_arithmetic.clone() {
|
||||
for _ in i..ArithmeticExtensionGate::<D>::num_ops(&self.config) {
|
||||
// If we directly wire in zero, an optimization will skip doing anything and return
|
||||
// zero. So we pass in a virtual target and connect it to zero afterward.
|
||||
let dummy = self.add_virtual_extension_target();
|
||||
self.arithmetic_extension(c0, c1, dummy, dummy, dummy);
|
||||
self.connect_extension(dummy, zero);
|
||||
}
|
||||
}
|
||||
assert!(self.batched_gates.free_arithmetic.is_empty());
|
||||
}
|
||||
|
||||
/// Fill the remaining unused arithmetic operations with zeros, so that all
|
||||
/// `ArithmeticExtensionGenerator`s are run.
|
||||
fn fill_mul_gates(&mut self) {
|
||||
let zero = self.zero_extension();
|
||||
for (c0, (_gate, i)) in self.batched_gates.free_mul.clone() {
|
||||
for _ in i..MulExtensionGate::<D>::num_ops(&self.config) {
|
||||
// If we directly wire in zero, an optimization will skip doing anything and return
|
||||
// zero. So we pass in a virtual target and connect it to zero afterward.
|
||||
let dummy = self.add_virtual_extension_target();
|
||||
self.arithmetic_extension(c0, F::ZERO, dummy, dummy, zero);
|
||||
self.connect_extension(dummy, zero);
|
||||
}
|
||||
}
|
||||
assert!(self.batched_gates.free_mul.is_empty());
|
||||
}
|
||||
|
||||
/// Fill the remaining unused random access operations with zeros, so that all
|
||||
/// `RandomAccessGenerator`s are run.
|
||||
fn fill_random_access_gates(&mut self) {
|
||||
let zero = self.zero();
|
||||
for (bits, (_, i)) in self.batched_gates.free_random_access.clone() {
|
||||
let max_copies =
|
||||
RandomAccessGate::<F, D>::new_from_config(&self.config, bits).num_copies;
|
||||
for _ in i..max_copies {
|
||||
let result = self.random_access(zero, vec![zero; 1 << bits]);
|
||||
self.connect(result, zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fill the remaining unused switch gates with dummy values, so that all
|
||||
/// `SwitchGenerator`s are run.
|
||||
fn fill_switch_gates(&mut self) {
|
||||
let zero = self.zero();
|
||||
|
||||
for chunk_size in 1..=self.batched_gates.current_switch_gates.len() {
|
||||
if let Some((gate, gate_index, mut copy)) =
|
||||
self.batched_gates.current_switch_gates[chunk_size - 1].clone()
|
||||
{
|
||||
while copy < gate.num_copies {
|
||||
for element in 0..chunk_size {
|
||||
let wire_first_input =
|
||||
Target::wire(gate_index, gate.wire_first_input(copy, element));
|
||||
let wire_second_input =
|
||||
Target::wire(gate_index, gate.wire_second_input(copy, element));
|
||||
let wire_switch_bool =
|
||||
Target::wire(gate_index, gate.wire_switch_bool(copy));
|
||||
self.connect(zero, wire_first_input);
|
||||
self.connect(zero, wire_second_input);
|
||||
self.connect(zero, wire_switch_bool);
|
||||
}
|
||||
copy += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fill the remaining unused u32 add-many operations with zeros, so that all
|
||||
/// `U32AddManyGenerator`s are run.
|
||||
fn fill_u32_add_many_gates(&mut self) {
|
||||
let zero = self.zero_u32();
|
||||
for (num_addends, (_, i)) in self.batched_gates.free_u32_add_many.clone() {
|
||||
let max_copies =
|
||||
U32AddManyGate::<F, D>::new_from_config(&self.config, num_addends).num_ops;
|
||||
for _ in i..max_copies {
|
||||
let gate = U32AddManyGate::<F, D>::new_from_config(&self.config, num_addends);
|
||||
let (gate_index, copy) = self.find_u32_add_many_gate(num_addends);
|
||||
|
||||
for j in 0..num_addends {
|
||||
self.connect(
|
||||
Target::wire(gate_index, gate.wire_ith_op_jth_addend(copy, j)),
|
||||
zero.0,
|
||||
);
|
||||
}
|
||||
self.connect(Target::wire(gate_index, gate.wire_ith_carry(copy)), zero.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fill the remaining unused U32 arithmetic operations with zeros, so that all
|
||||
/// `U32ArithmeticGenerator`s are run.
|
||||
fn fill_u32_arithmetic_gates(&mut self) {
|
||||
let zero = self.zero_u32();
|
||||
if let Some((_gate_index, copy)) = self.batched_gates.current_u32_arithmetic_gate {
|
||||
for _ in copy..U32ArithmeticGate::<F, D>::num_ops(&self.config) {
|
||||
let dummy = self.add_virtual_u32_target();
|
||||
self.mul_add_u32(dummy, dummy, dummy);
|
||||
self.connect_u32(dummy, zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fill the remaining unused U32 subtraction operations with zeros, so that all
|
||||
/// `U32SubtractionGenerator`s are run.
|
||||
fn fill_u32_subtraction_gates(&mut self) {
|
||||
let zero = self.zero_u32();
|
||||
if let Some((_gate_index, copy)) = self.batched_gates.current_u32_subtraction_gate {
|
||||
for _i in copy..U32SubtractionGate::<F, D>::num_ops(&self.config) {
|
||||
let dummy = self.add_virtual_u32_target();
|
||||
self.sub_u32(dummy, dummy, dummy);
|
||||
self.connect_u32(dummy, zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_batched_gates(&mut self) {
|
||||
self.fill_arithmetic_gates();
|
||||
self.fill_base_arithmetic_gates();
|
||||
self.fill_mul_gates();
|
||||
self.fill_random_access_gates();
|
||||
self.fill_switch_gates();
|
||||
self.fill_u32_add_many_gates();
|
||||
self.fill_u32_arithmetic_gates();
|
||||
self.fill_u32_subtraction_gates();
|
||||
}
|
||||
}
|
||||
>>>>>>> aa48021 (windowed multiplication in circuit)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user