Works everywhere except Waksman

This commit is contained in:
wborgeaud 2022-02-02 16:02:22 +01:00
parent cdea0d9f96
commit ff949f40bc
11 changed files with 424 additions and 371 deletions

View File

@ -4,6 +4,7 @@ use plonky2_field::extension_field::Extendable;
use plonky2_field::field_types::PrimeField; use plonky2_field::field_types::PrimeField;
use crate::gates::arithmetic_base::ArithmeticGate; use crate::gates::arithmetic_base::ArithmeticGate;
use crate::gates::batchable::GateRef;
use crate::gates::exponentiation::ExponentiationGate; use crate::gates::exponentiation::ExponentiationGate;
use crate::hash::hash_types::RichField; use crate::hash::hash_types::RichField;
use crate::iop::target::{BoolTarget, Target}; use crate::iop::target::{BoolTarget, Target};
@ -78,7 +79,8 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
} }
fn add_base_arithmetic_operation(&mut self, operation: BaseArithmeticOperation<F>) -> Target { fn add_base_arithmetic_operation(&mut self, operation: BaseArithmeticOperation<F>) -> Target {
let (gate, i) = self.find_base_arithmetic_gate(operation.const_0, operation.const_1); let gate = ArithmeticGate::new_from_config(&self.config);
let (gate, i) = self.find_slot(gate, vec![operation.const_0, operation.const_1]);
let wires_multiplicand_0 = Target::wire(gate, ArithmeticGate::wire_ith_multiplicand_0(i)); let wires_multiplicand_0 = Target::wire(gate, ArithmeticGate::wire_ith_multiplicand_0(i));
let wires_multiplicand_1 = Target::wire(gate, ArithmeticGate::wire_ith_multiplicand_1(i)); let wires_multiplicand_1 = Target::wire(gate, ArithmeticGate::wire_ith_multiplicand_1(i));
let wires_addend = Target::wire(gate, ArithmeticGate::wire_ith_addend(i)); let wires_addend = Target::wire(gate, ArithmeticGate::wire_ith_addend(i));

View File

@ -4,6 +4,7 @@ use plonky2_field::field_types::{Field, PrimeField};
use plonky2_util::bits_u64; use plonky2_util::bits_u64;
use crate::gates::arithmetic_extension::ArithmeticExtensionGate; use crate::gates::arithmetic_extension::ArithmeticExtensionGate;
use crate::gates::batchable::GateRef;
use crate::gates::multiplication_extension::MulExtensionGate; use crate::gates::multiplication_extension::MulExtensionGate;
use crate::hash::hash_types::RichField; use crate::hash::hash_types::RichField;
use crate::iop::ext_target::{ExtensionAlgebraTarget, ExtensionTarget}; use crate::iop::ext_target::{ExtensionAlgebraTarget, ExtensionTarget};
@ -60,7 +61,8 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
&mut self, &mut self,
operation: ExtensionArithmeticOperation<F, D>, operation: ExtensionArithmeticOperation<F, D>,
) -> ExtensionTarget<D> { ) -> ExtensionTarget<D> {
let (gate, i) = self.find_arithmetic_gate(operation.const_0, operation.const_1); let gate = ArithmeticExtensionGate::new_from_config(&self.config);
let (gate, i) = self.find_slot(gate, vec![operation.const_0, operation.const_1]);
let wires_multiplicand_0 = ExtensionTarget::from_range( let wires_multiplicand_0 = ExtensionTarget::from_range(
gate, gate,
ArithmeticExtensionGate::<D>::wires_ith_multiplicand_0(i), ArithmeticExtensionGate::<D>::wires_ith_multiplicand_0(i),
@ -83,7 +85,8 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
&mut self, &mut self,
operation: ExtensionArithmeticOperation<F, D>, operation: ExtensionArithmeticOperation<F, D>,
) -> ExtensionTarget<D> { ) -> ExtensionTarget<D> {
let (gate, i) = self.find_mul_gate(operation.const_0); let gate = MulExtensionGate::new_from_config(&self.config);
let (gate, i) = self.find_slot(gate, vec![operation.const_0]);
let wires_multiplicand_0 = let wires_multiplicand_0 =
ExtensionTarget::from_range(gate, MulExtensionGate::<D>::wires_ith_multiplicand_0(i)); ExtensionTarget::from_range(gate, MulExtensionGate::<D>::wires_ith_multiplicand_0(i));
let wires_multiplicand_1 = let wires_multiplicand_1 =

View File

@ -78,7 +78,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
} }
let gate = U32ArithmeticGate::<F, D>::new_from_config(&self.config); let gate = U32ArithmeticGate::<F, D>::new_from_config(&self.config);
let (gate_index, copy) = self.find_u32_arithmetic_gate(); let (gate_index, copy) = self.find_slot(gate, vec![]);
self.connect( self.connect(
Target::wire(gate_index, gate.wire_ith_multiplicand_0(copy)), Target::wire(gate_index, gate.wire_ith_multiplicand_0(copy)),
@ -138,7 +138,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
borrow: U32Target, borrow: U32Target,
) -> (U32Target, U32Target) { ) -> (U32Target, U32Target) {
let gate = U32SubtractionGate::<F, D>::new_from_config(&self.config); let gate = U32SubtractionGate::<F, D>::new_from_config(&self.config);
let (gate_index, copy) = self.find_u32_subtraction_gate(); let (gate_index, copy) = self.find_slot(gate, vec![]);
self.connect(Target::wire(gate_index, gate.wire_ith_input_x(copy)), x.0); self.connect(Target::wire(gate_index, gate.wire_ith_input_x(copy)), x.0);
self.connect(Target::wire(gate_index, gate.wire_ith_input_y(copy)), y.0); self.connect(Target::wire(gate_index, gate.wire_ith_input_y(copy)), y.0);

View File

@ -17,8 +17,8 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
if vec_size == 1 { if vec_size == 1 {
return self.connect(claimed_element, v[0]); return self.connect(claimed_element, v[0]);
} }
let (gate_index, copy) = self.find_random_access_gate(bits);
let dummy_gate = RandomAccessGate::<F, D>::new_from_config(&self.config, bits); let dummy_gate = RandomAccessGate::<F, D>::new_from_config(&self.config, bits);
let (gate_index, copy) = self.find_slot(dummy_gate, vec![]);
v.iter().enumerate().for_each(|(i, &val)| { v.iter().enumerate().for_each(|(i, &val)| {
self.connect( self.connect(

View File

@ -19,7 +19,7 @@ use crate::plonk::vars::{
/// A gate which can perform a weighted multiply-add, i.e. `result = c0 x y + c1 z`. If the config /// A gate which can perform a weighted multiply-add, i.e. `result = c0 x y + c1 z`. If the config
/// supports enough routed wires, it can support several such operations in one gate. /// supports enough routed wires, it can support several such operations in one gate.
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct ArithmeticGate { pub struct ArithmeticGate {
/// Number of arithmetic operations performed by an arithmetic gate. /// Number of arithmetic operations performed by an arithmetic gate.
pub num_ops: usize, pub num_ops: usize,

View File

@ -17,7 +17,7 @@ use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase};
/// A gate which can perform a weighted multiply-add, i.e. `result = c0 x y + c1 z`. If the config /// A gate which can perform a weighted multiply-add, i.e. `result = c0 x y + c1 z`. If the config
/// supports enough routed wires, it can support several such operations in one gate. /// supports enough routed wires, it can support several such operations in one gate.
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct ArithmeticExtensionGate<const D: usize> { pub struct ArithmeticExtensionGate<const D: usize> {
/// Number of arithmetic operations performed by an arithmetic gate. /// Number of arithmetic operations performed by an arithmetic gate.
pub num_ops: usize, pub num_ops: usize,

View File

@ -12,6 +12,8 @@ use crate::iop::target::Target;
use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_builder::CircuitBuilder;
pub trait BatchableGate<F: RichField + Extendable<D>, const D: usize>: Gate<F, D> { pub trait BatchableGate<F: RichField + Extendable<D>, const D: usize>: Gate<F, D> {
fn num_ops(&self) -> usize;
// TODO: It would be nice to have a `Parameters` associated type. // TODO: It would be nice to have a `Parameters` associated type.
fn fill_gate( fn fill_gate(
&self, &self,
@ -21,8 +23,9 @@ pub trait BatchableGate<F: RichField + Extendable<D>, const D: usize>: Gate<F, D
); );
} }
#[derive(Clone)]
pub struct CurrentSlot<F: RichField + Extendable<D>, const D: usize> { pub struct CurrentSlot<F: RichField + Extendable<D>, const D: usize> {
current_slot: HashMap<Vec<F>, (usize, usize)>, pub current_slot: HashMap<Vec<F>, (usize, usize)>,
} }
#[derive(Clone)] #[derive(Clone)]
@ -76,6 +79,10 @@ pub trait MultiOpsGate<F: RichField + Extendable<D>, const D: usize>: Gate<F, D>
impl<F: RichField + Extendable<D>, G: MultiOpsGate<F, D>, const D: usize> BatchableGate<F, D> impl<F: RichField + Extendable<D>, G: MultiOpsGate<F, D>, const D: usize> BatchableGate<F, D>
for G for G
{ {
fn num_ops(&self) -> usize {
self.num_ops()
}
fn fill_gate( fn fill_gate(
&self, &self,
params: &[F], params: &[F],

View File

@ -173,6 +173,7 @@ pub trait Gate<F: RichField + Extendable<D>, const D: usize>: 'static + Send + S
// } // }
/// A gate along with any constants used to configure it. /// A gate along with any constants used to configure it.
#[derive(Clone)]
pub struct GateInstance<F: RichField + Extendable<D>, const D: usize> { pub struct GateInstance<F: RichField + Extendable<D>, const D: usize> {
pub gate_ref: GateRef<F, D>, pub gate_ref: GateRef<F, D>,
pub constants: Vec<F>, pub constants: Vec<F>,

View File

@ -17,7 +17,7 @@ use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase};
/// A gate which can perform a weighted multiplication, i.e. `result = c0 x y`. If the config /// A gate which can perform a weighted multiplication, i.e. `result = c0 x y`. If the config
/// supports enough routed wires, it can support several such operations in one gate. /// supports enough routed wires, it can support several such operations in one gate.
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct MulExtensionGate<const D: usize> { pub struct MulExtensionGate<const D: usize> {
/// Number of multiplications performed by the gate. /// Number of multiplications performed by the gate.
pub num_ops: usize, pub num_ops: usize,

View File

@ -84,9 +84,6 @@ pub struct CircuitBuilder<F: RichField + Extendable<D>, const D: usize> {
/// Memoized results of `arithmetic_extension` calls. /// Memoized results of `arithmetic_extension` calls.
pub(crate) arithmetic_results: HashMap<ExtensionArithmeticOperation<F, D>, ExtensionTarget<D>>, pub(crate) arithmetic_results: HashMap<ExtensionArithmeticOperation<F, D>, ExtensionTarget<D>>,
// yo: Vec<Yo<F, D, dyn Copy>>,
batched_gates: BatchedGates<F, D>,
current_slots: HashMap<GateRef<F, D>, CurrentSlot<F, D>>, current_slots: HashMap<GateRef<F, D>, CurrentSlot<F, D>>,
} }
@ -106,7 +103,6 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
base_arithmetic_results: HashMap::new(), base_arithmetic_results: HashMap::new(),
arithmetic_results: HashMap::new(), arithmetic_results: HashMap::new(),
targets_to_constants: HashMap::new(), targets_to_constants: HashMap::new(),
batched_gates: BatchedGates::new(),
current_slots: HashMap::new(), current_slots: HashMap::new(),
}; };
builder.check_config(); builder.check_config();
@ -193,6 +189,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
/// Adds a gate to the circuit, and returns its index. /// Adds a gate to the circuit, and returns its index.
pub fn add_gate<G: BatchableGate<F, D>>(&mut self, gate_type: G, constants: Vec<F>) -> usize { pub fn add_gate<G: BatchableGate<F, D>>(&mut self, gate_type: G, constants: Vec<F>) -> usize {
// println!("{} {}", self.num_gates(), gate_type.id());
self.check_gate_compatibility(&gate_type); self.check_gate_compatibility(&gate_type);
assert_eq!( assert_eq!(
gate_type.num_constants(), gate_type.num_constants(),
@ -307,7 +304,11 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
return target; return target;
} }
let (gate, instance) = self.constant_gate_instance(); 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 = ConstantGate { num_consts };
let (gate, instance) = self.find_slot(gate, vec![F::ZERO; num_consts]);
let target = Target::wire(gate, instance); let target = Target::wire(gate, instance);
self.gate_instances[gate].constants[instance] = c; self.gate_instances[gate].constants[instance] = c;
@ -373,6 +374,44 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
}) })
} }
pub fn find_slot<G: BatchableGate<F, D> + Clone>(
&mut self,
gate: G,
params: Vec<F>,
) -> (usize, usize) {
let num_gates = self.num_gates();
let num_ops = gate.num_ops();
let gate_ref = GateRef::new(gate.clone());
let gate_slot = self
.current_slots
.entry(gate_ref.clone())
.or_insert(CurrentSlot {
current_slot: HashMap::new(),
});
let slot = gate_slot.current_slot.get(&params);
let res = if let Some(&s) = slot {
s
} else {
self.add_gate(gate, params.clone());
(num_gates, 0)
};
if res.1 == num_ops - 1 {
self.current_slots
.get_mut(&gate_ref)
.unwrap()
.current_slot
.remove(&params);
} else {
self.current_slots
.get_mut(&gate_ref)
.unwrap()
.current_slot
.insert(params, (res.0, res.1 + 1));
}
res
}
fn fri_params(&self, degree_bits: usize) -> FriParams { fn fri_params(&self, degree_bits: usize) -> FriParams {
let fri_config = &self.config.fri_config; let fri_config = &self.config.fri_config;
let reduction_arity_bits = fri_config.reduction_strategy.reduction_arity_bits( let reduction_arity_bits = fri_config.reduction_strategy.reduction_arity_bits(
@ -815,337 +854,337 @@ impl<F: RichField + Extendable<D>, const D: usize> BatchedGates<F, D> {
} }
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> { 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. // /// 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 // /// 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. // /// `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) { // pub(crate) fn find_base_arithmetic_gate(&mut self, const_0: F, const_1: F) -> (usize, usize) {
let (gate, i) = self // let (gate, i) = self
.batched_gates // .batched_gates
.free_base_arithmetic // .free_base_arithmetic
.get(&(const_0, const_1)) // .get(&(const_0, const_1))
.copied() // .copied()
.unwrap_or_else(|| { // .unwrap_or_else(|| {
let gate = self.add_gate( // let gate = self.add_gate(
ArithmeticGate::new_from_config(&self.config), // ArithmeticGate::new_from_config(&self.config),
vec![const_0, const_1], // vec![const_0, const_1],
); // );
(gate, 0) // (gate, 0)
}); // });
//
// Update `free_arithmetic` with new values. // // Update `free_arithmetic` with new values.
if i < ArithmeticGate::num_ops(&self.config) - 1 { // if i < ArithmeticGate::num_ops(&self.config) - 1 {
self.batched_gates // self.batched_gates
.free_base_arithmetic // .free_base_arithmetic
.insert((const_0, const_1), (gate, i + 1)); // .insert((const_0, const_1), (gate, i + 1));
} else { // } else {
self.batched_gates // self.batched_gates
.free_base_arithmetic // .free_base_arithmetic
.remove(&(const_0, const_1)); // .remove(&(const_0, const_1));
} // }
//
(gate, i) // (gate, i)
} // }
//
/// Finds the last available arithmetic gate with the given constants or add one if there aren't any. // /// 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 // /// 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. // /// `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) { // pub(crate) fn find_arithmetic_gate(&mut self, const_0: F, const_1: F) -> (usize, usize) {
let (gate, i) = self // let (gate, i) = self
.batched_gates // .batched_gates
.free_arithmetic // .free_arithmetic
.get(&(const_0, const_1)) // .get(&(const_0, const_1))
.copied() // .copied()
.unwrap_or_else(|| { // .unwrap_or_else(|| {
let gate = self.add_gate( // let gate = self.add_gate(
ArithmeticExtensionGate::new_from_config(&self.config), // ArithmeticExtensionGate::new_from_config(&self.config),
vec![const_0, const_1], // vec![const_0, const_1],
); // );
(gate, 0) // (gate, 0)
}); // });
//
// Update `free_arithmetic` with new values. // // Update `free_arithmetic` with new values.
if i < ArithmeticExtensionGate::<D>::num_ops(&self.config) - 1 { // if i < ArithmeticExtensionGate::<D>::num_ops(&self.config) - 1 {
self.batched_gates // self.batched_gates
.free_arithmetic // .free_arithmetic
.insert((const_0, const_1), (gate, i + 1)); // .insert((const_0, const_1), (gate, i + 1));
} else { // } else {
self.batched_gates // self.batched_gates
.free_arithmetic // .free_arithmetic
.remove(&(const_0, const_1)); // .remove(&(const_0, const_1));
} // }
//
(gate, i) // (gate, i)
} // }
//
/// Finds the last available arithmetic gate with the given constants or add one if there aren't any. // /// 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 // /// 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. // /// `g` and the gate's `i`-th operation is available.
pub(crate) fn find_mul_gate(&mut self, const_0: F) -> (usize, usize) { // pub(crate) fn find_mul_gate(&mut self, const_0: F) -> (usize, usize) {
let (gate, i) = self // let (gate, i) = self
.batched_gates // .batched_gates
.free_mul // .free_mul
.get(&const_0) // .get(&const_0)
.copied() // .copied()
.unwrap_or_else(|| { // .unwrap_or_else(|| {
let gate = self.add_gate( // let gate = self.add_gate(
MulExtensionGate::new_from_config(&self.config), // MulExtensionGate::new_from_config(&self.config),
vec![const_0], // vec![const_0],
); // );
(gate, 0) // (gate, 0)
}); // });
//
// Update `free_arithmetic` with new values. // // Update `free_arithmetic` with new values.
if i < MulExtensionGate::<D>::num_ops(&self.config) - 1 { // if i < MulExtensionGate::<D>::num_ops(&self.config) - 1 {
self.batched_gates.free_mul.insert(const_0, (gate, i + 1)); // self.batched_gates.free_mul.insert(const_0, (gate, i + 1));
} else { // } else {
self.batched_gates.free_mul.remove(&const_0); // self.batched_gates.free_mul.remove(&const_0);
} // }
//
(gate, i) // (gate, i)
} // }
//
/// Finds the last available random access gate with the given `vec_size` or add one if there aren't any. // /// Finds the last available random access gate with the given `vec_size` or add one if there aren't any.
/// Returns `(g,i)` such that there is a random access gate with the given `vec_size` at index // /// Returns `(g,i)` such that there is a random access gate with the given `vec_size` at index
/// `g` and the gate's `i`-th random access is available. // /// `g` and the gate's `i`-th random access is available.
pub(crate) fn find_random_access_gate(&mut self, bits: usize) -> (usize, usize) { // pub(crate) fn find_random_access_gate(&mut self, bits: usize) -> (usize, usize) {
let (gate, i) = self // let (gate, i) = self
.batched_gates // .batched_gates
.free_random_access // .free_random_access
.get(&bits) // .get(&bits)
.copied() // .copied()
.unwrap_or_else(|| { // .unwrap_or_else(|| {
let gate = self.add_gate( // let gate = self.add_gate(
RandomAccessGate::new_from_config(&self.config, bits), // RandomAccessGate::new_from_config(&self.config, bits),
vec![], // vec![],
); // );
(gate, 0) // (gate, 0)
}); // });
//
// Update `free_random_access` with new values. // // Update `free_random_access` with new values.
if i + 1 < RandomAccessGate::<F, D>::new_from_config(&self.config, bits).num_copies { // if i + 1 < RandomAccessGate::<F, D>::new_from_config(&self.config, bits).num_copies {
self.batched_gates // self.batched_gates
.free_random_access // .free_random_access
.insert(bits, (gate, i + 1)); // .insert(bits, (gate, i + 1));
} else { // } else {
self.batched_gates.free_random_access.remove(&bits); // self.batched_gates.free_random_access.remove(&bits);
} // }
//
(gate, i) // (gate, i)
} // }
//
pub fn find_switch_gate(&mut self, chunk_size: usize) -> (SwitchGate<F, D>, usize, usize) { // 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 { // if self.batched_gates.current_switch_gates.len() < chunk_size {
self.batched_gates.current_switch_gates.extend(vec![ // self.batched_gates.current_switch_gates.extend(vec![
None; // None;
chunk_size // chunk_size
- self // - self
.batched_gates // .batched_gates
.current_switch_gates // .current_switch_gates
.len() // .len()
]); // ]);
} // }
//
let (gate, gate_index, next_copy) = // let (gate, gate_index, next_copy) =
match self.batched_gates.current_switch_gates[chunk_size - 1].clone() { // match self.batched_gates.current_switch_gates[chunk_size - 1].clone() {
None => { // None => {
let gate = SwitchGate::<F, D>::new_from_config(&self.config, chunk_size); // let gate = SwitchGate::<F, D>::new_from_config(&self.config, chunk_size);
let gate_index = self.add_gate(gate.clone(), vec![]); // let gate_index = self.add_gate(gate.clone(), vec![]);
(gate, gate_index, 0) // (gate, gate_index, 0)
} // }
Some((gate, idx, next_copy)) => (gate, idx, next_copy), // Some((gate, idx, next_copy)) => (gate, idx, next_copy),
}; // };
//
let num_copies = gate.num_copies; // let num_copies = gate.num_copies;
//
if next_copy == num_copies - 1 { // if next_copy == num_copies - 1 {
self.batched_gates.current_switch_gates[chunk_size - 1] = None; // self.batched_gates.current_switch_gates[chunk_size - 1] = None;
} else { // } else {
self.batched_gates.current_switch_gates[chunk_size - 1] = // self.batched_gates.current_switch_gates[chunk_size - 1] =
Some((gate.clone(), gate_index, next_copy + 1)); // Some((gate.clone(), gate_index, next_copy + 1));
} // }
//
(gate, gate_index, next_copy) // (gate, gate_index, next_copy)
} // }
//
pub(crate) fn find_u32_arithmetic_gate(&mut self) -> (usize, usize) { // pub(crate) fn find_u32_arithmetic_gate(&mut self) -> (usize, usize) {
let (gate_index, copy) = match self.batched_gates.current_u32_arithmetic_gate { // let (gate_index, copy) = match self.batched_gates.current_u32_arithmetic_gate {
None => { // None => {
let gate = U32ArithmeticGate::new_from_config(&self.config); // let gate = U32ArithmeticGate::new_from_config(&self.config);
let gate_index = self.add_gate(gate, vec![]); // let gate_index = self.add_gate(gate, vec![]);
(gate_index, 0) // (gate_index, 0)
} // }
Some((gate_index, copy)) => (gate_index, copy), // Some((gate_index, copy)) => (gate_index, copy),
}; // };
//
if copy == U32ArithmeticGate::<F, D>::num_ops(&self.config) - 1 { // if copy == U32ArithmeticGate::<F, D>::num_ops(&self.config) - 1 {
self.batched_gates.current_u32_arithmetic_gate = None; // self.batched_gates.current_u32_arithmetic_gate = None;
} else { // } else {
self.batched_gates.current_u32_arithmetic_gate = Some((gate_index, copy + 1)); // self.batched_gates.current_u32_arithmetic_gate = Some((gate_index, copy + 1));
} // }
//
(gate_index, copy) // (gate_index, copy)
} // }
//
pub(crate) fn find_u32_subtraction_gate(&mut self) -> (usize, usize) { // pub(crate) fn find_u32_subtraction_gate(&mut self) -> (usize, usize) {
let (gate_index, copy) = match self.batched_gates.current_u32_subtraction_gate { // let (gate_index, copy) = match self.batched_gates.current_u32_subtraction_gate {
None => { // None => {
let gate = U32SubtractionGate::new_from_config(&self.config); // let gate = U32SubtractionGate::new_from_config(&self.config);
let gate_index = self.add_gate(gate, vec![]); // let gate_index = self.add_gate(gate, vec![]);
(gate_index, 0) // (gate_index, 0)
} // }
Some((gate_index, copy)) => (gate_index, copy), // Some((gate_index, copy)) => (gate_index, copy),
}; // };
//
if copy == U32SubtractionGate::<F, D>::num_ops(&self.config) - 1 { // if copy == U32SubtractionGate::<F, D>::num_ops(&self.config) - 1 {
self.batched_gates.current_u32_subtraction_gate = None; // self.batched_gates.current_u32_subtraction_gate = None;
} else { // } else {
self.batched_gates.current_u32_subtraction_gate = Some((gate_index, copy + 1)); // self.batched_gates.current_u32_subtraction_gate = Some((gate_index, copy + 1));
} // }
//
(gate_index, copy) // (gate_index, copy)
} // }
//
/// Returns the gate index and copy index of a free `ConstantGate` slot, potentially adding a // /// Returns the gate index and copy index of a free `ConstantGate` slot, potentially adding a
/// new `ConstantGate` if needed. // /// new `ConstantGate` if needed.
fn constant_gate_instance(&mut self) -> (usize, usize) { // fn constant_gate_instance(&mut self) -> (usize, usize) {
if self.batched_gates.free_constant.is_none() { // if self.batched_gates.free_constant.is_none() {
let num_consts = self.config.constant_gate_size; // let num_consts = self.config.constant_gate_size;
// We will fill this `ConstantGate` with zero constants initially. // // We will fill this `ConstantGate` with zero constants initially.
// These will be overwritten by `constant` as the gate instances are filled. // // 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]); // let gate = self.add_gate(ConstantGate { num_consts }, vec![F::ZERO; num_consts]);
self.batched_gates.free_constant = Some((gate, 0)); // self.batched_gates.free_constant = Some((gate, 0));
} // }
//
let (gate, instance) = self.batched_gates.free_constant.unwrap(); // let (gate, instance) = self.batched_gates.free_constant.unwrap();
if instance + 1 < self.config.constant_gate_size { // if instance + 1 < self.config.constant_gate_size {
self.batched_gates.free_constant = Some((gate, instance + 1)); // self.batched_gates.free_constant = Some((gate, instance + 1));
} else { // } else {
self.batched_gates.free_constant = None; // self.batched_gates.free_constant = None;
} // }
(gate, instance) // (gate, instance)
} // }
//
/// Fill the remaining unused arithmetic operations with zeros, so that all // /// Fill the remaining unused arithmetic operations with zeros, so that all
/// `ArithmeticGate` are run. // /// `ArithmeticGate` are run.
fn fill_base_arithmetic_gates(&mut self) { // fn fill_base_arithmetic_gates(&mut self) {
let zero = self.zero(); // let zero = self.zero();
for ((c0, c1), (_gate, i)) in self.batched_gates.free_base_arithmetic.clone() { // for ((c0, c1), (_gate, i)) in self.batched_gates.free_base_arithmetic.clone() {
for _ in i..ArithmeticGate::num_ops(&self.config) { // for _ in i..ArithmeticGate::num_ops(&self.config) {
// If we directly wire in zero, an optimization will skip doing anything and return // // 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. // // zero. So we pass in a virtual target and connect it to zero afterward.
let dummy = self.add_virtual_target(); // let dummy = self.add_virtual_target();
self.arithmetic(c0, c1, dummy, dummy, dummy); // self.arithmetic(c0, c1, dummy, dummy, dummy);
self.connect(dummy, zero); // self.connect(dummy, zero);
} // }
} // }
assert!(self.batched_gates.free_base_arithmetic.is_empty()); // assert!(self.batched_gates.free_base_arithmetic.is_empty());
} // }
//
/// Fill the remaining unused arithmetic operations with zeros, so that all // /// Fill the remaining unused arithmetic operations with zeros, so that all
/// `ArithmeticExtensionGenerator`s are run. // /// `ArithmeticExtensionGenerator`s are run.
fn fill_arithmetic_gates(&mut self) { // fn fill_arithmetic_gates(&mut self) {
let zero = self.zero_extension(); // let zero = self.zero_extension();
for ((c0, c1), (_gate, i)) in self.batched_gates.free_arithmetic.clone() { // for ((c0, c1), (_gate, i)) in self.batched_gates.free_arithmetic.clone() {
for _ in i..ArithmeticExtensionGate::<D>::num_ops(&self.config) { // for _ in i..ArithmeticExtensionGate::<D>::num_ops(&self.config) {
// If we directly wire in zero, an optimization will skip doing anything and return // // 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. // // zero. So we pass in a virtual target and connect it to zero afterward.
let dummy = self.add_virtual_extension_target(); // let dummy = self.add_virtual_extension_target();
self.arithmetic_extension(c0, c1, dummy, dummy, dummy); // self.arithmetic_extension(c0, c1, dummy, dummy, dummy);
self.connect_extension(dummy, zero); // self.connect_extension(dummy, zero);
} // }
} // }
assert!(self.batched_gates.free_arithmetic.is_empty()); // assert!(self.batched_gates.free_arithmetic.is_empty());
} // }
//
/// Fill the remaining unused arithmetic operations with zeros, so that all // /// Fill the remaining unused arithmetic operations with zeros, so that all
/// `ArithmeticExtensionGenerator`s are run. // /// `ArithmeticExtensionGenerator`s are run.
fn fill_mul_gates(&mut self) { // fn fill_mul_gates(&mut self) {
let zero = self.zero_extension(); // let zero = self.zero_extension();
for (c0, (_gate, i)) in self.batched_gates.free_mul.clone() { // for (c0, (_gate, i)) in self.batched_gates.free_mul.clone() {
for _ in i..MulExtensionGate::<D>::num_ops(&self.config) { // for _ in i..MulExtensionGate::<D>::num_ops(&self.config) {
// If we directly wire in zero, an optimization will skip doing anything and return // // 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. // // zero. So we pass in a virtual target and connect it to zero afterward.
let dummy = self.add_virtual_extension_target(); // let dummy = self.add_virtual_extension_target();
self.arithmetic_extension(c0, F::ZERO, dummy, dummy, zero); // self.arithmetic_extension(c0, F::ZERO, dummy, dummy, zero);
self.connect_extension(dummy, zero); // self.connect_extension(dummy, zero);
} // }
} // }
assert!(self.batched_gates.free_mul.is_empty()); // assert!(self.batched_gates.free_mul.is_empty());
} // }
//
/// Fill the remaining unused random access operations with zeros, so that all // /// Fill the remaining unused random access operations with zeros, so that all
/// `RandomAccessGenerator`s are run. // /// `RandomAccessGenerator`s are run.
fn fill_random_access_gates(&mut self) { // fn fill_random_access_gates(&mut self) {
let zero = self.zero(); // let zero = self.zero();
for (bits, (_, i)) in self.batched_gates.free_random_access.clone() { // for (bits, (_, i)) in self.batched_gates.free_random_access.clone() {
let max_copies = // let max_copies =
RandomAccessGate::<F, D>::new_from_config(&self.config, bits).num_copies; // RandomAccessGate::<F, D>::new_from_config(&self.config, bits).num_copies;
for _ in i..max_copies { // for _ in i..max_copies {
self.random_access(zero, zero, vec![zero; 1 << bits]); // self.random_access(zero, zero, vec![zero; 1 << bits]);
} // }
} // }
} // }
//
/// Fill the remaining unused switch gates with dummy values, so that all // /// Fill the remaining unused switch gates with dummy values, so that all
/// `SwitchGenerator`s are run. // /// `SwitchGenerator`s are run.
fn fill_switch_gates(&mut self) { // fn fill_switch_gates(&mut self) {
let zero = self.zero(); // let zero = self.zero();
//
for chunk_size in 1..=self.batched_gates.current_switch_gates.len() { // for chunk_size in 1..=self.batched_gates.current_switch_gates.len() {
if let Some((gate, gate_index, mut copy)) = // if let Some((gate, gate_index, mut copy)) =
self.batched_gates.current_switch_gates[chunk_size - 1].clone() // self.batched_gates.current_switch_gates[chunk_size - 1].clone()
{ // {
while copy < gate.num_copies { // while copy < gate.num_copies {
for element in 0..chunk_size { // for element in 0..chunk_size {
let wire_first_input = // let wire_first_input =
Target::wire(gate_index, gate.wire_first_input(copy, element)); // Target::wire(gate_index, gate.wire_first_input(copy, element));
let wire_second_input = // let wire_second_input =
Target::wire(gate_index, gate.wire_second_input(copy, element)); // Target::wire(gate_index, gate.wire_second_input(copy, element));
let wire_switch_bool = // let wire_switch_bool =
Target::wire(gate_index, gate.wire_switch_bool(copy)); // Target::wire(gate_index, gate.wire_switch_bool(copy));
self.connect(zero, wire_first_input); // self.connect(zero, wire_first_input);
self.connect(zero, wire_second_input); // self.connect(zero, wire_second_input);
self.connect(zero, wire_switch_bool); // self.connect(zero, wire_switch_bool);
} // }
copy += 1; // copy += 1;
} // }
} // }
} // }
} // }
//
/// Fill the remaining unused U32 arithmetic operations with zeros, so that all // /// Fill the remaining unused U32 arithmetic operations with zeros, so that all
/// `U32ArithmeticGenerator`s are run. // /// `U32ArithmeticGenerator`s are run.
fn fill_u32_arithmetic_gates(&mut self) { // fn fill_u32_arithmetic_gates(&mut self) {
let zero = self.zero_u32(); // let zero = self.zero_u32();
if let Some((_gate_index, copy)) = self.batched_gates.current_u32_arithmetic_gate { // if let Some((_gate_index, copy)) = self.batched_gates.current_u32_arithmetic_gate {
for _ in copy..U32ArithmeticGate::<F, D>::num_ops(&self.config) { // for _ in copy..U32ArithmeticGate::<F, D>::num_ops(&self.config) {
let dummy = self.add_virtual_u32_target(); // let dummy = self.add_virtual_u32_target();
self.mul_add_u32(dummy, dummy, dummy); // self.mul_add_u32(dummy, dummy, dummy);
self.connect_u32(dummy, zero); // self.connect_u32(dummy, zero);
} // }
} // }
} // }
//
/// Fill the remaining unused U32 subtraction operations with zeros, so that all // /// Fill the remaining unused U32 subtraction operations with zeros, so that all
/// `U32SubtractionGenerator`s are run. // /// `U32SubtractionGenerator`s are run.
fn fill_u32_subtraction_gates(&mut self) { // fn fill_u32_subtraction_gates(&mut self) {
let zero = self.zero_u32(); // let zero = self.zero_u32();
if let Some((_gate_index, copy)) = self.batched_gates.current_u32_subtraction_gate { // if let Some((_gate_index, copy)) = self.batched_gates.current_u32_subtraction_gate {
for _i in copy..U32SubtractionGate::<F, D>::num_ops(&self.config) { // for _i in copy..U32SubtractionGate::<F, D>::num_ops(&self.config) {
let dummy = self.add_virtual_u32_target(); // let dummy = self.add_virtual_u32_target();
self.sub_u32(dummy, dummy, dummy); // self.sub_u32(dummy, dummy, dummy);
self.connect_u32(dummy, zero); // self.connect_u32(dummy, zero);
} // }
} // }
} // }
//
fn fill_batched_gates(&mut self) { fn fill_batched_gates(&mut self) {
self.fill_arithmetic_gates(); let instances = self.gate_instances.clone();
self.fill_base_arithmetic_gates(); for gate in instances {
self.fill_mul_gates(); if let Some(slot) = self.current_slots.get(&gate.gate_ref) {
self.fill_random_access_gates(); let cloned = slot.clone();
self.fill_switch_gates(); gate.gate_ref.0.fill_gate(&gate.constants, &cloned, self);
self.fill_u32_arithmetic_gates(); }
self.fill_u32_subtraction_gates(); }
} }
} }

View File

@ -79,32 +79,33 @@ fn create_switch<F: RichField + Extendable<D>, const D: usize>(
let chunk_size = a1.len(); let chunk_size = a1.len();
let (gate, gate_index, next_copy) = builder.find_switch_gate(chunk_size); todo!()
// let (gate, gate_index, next_copy) = builder.find_switch_gate(chunk_size);
//
// let mut c = Vec::new();
// let mut d = Vec::new();
// for e in 0..chunk_size {
// builder.connect(
// a1[e],
// Target::wire(gate_index, gate.wire_first_input(next_copy, e)),
// );
// builder.connect(
// a2[e],
// Target::wire(gate_index, gate.wire_second_input(next_copy, e)),
// );
// c.push(Target::wire(
// gate_index,
// gate.wire_first_output(next_copy, e),
// ));
// d.push(Target::wire(
// gate_index,
// gate.wire_second_output(next_copy, e),
// ));
// }
let mut c = Vec::new(); // let switch = Target::wire(gate_index, gate.wire_switch_bool(next_copy));
let mut d = Vec::new(); //
for e in 0..chunk_size { // (switch, c, d)
builder.connect(
a1[e],
Target::wire(gate_index, gate.wire_first_input(next_copy, e)),
);
builder.connect(
a2[e],
Target::wire(gate_index, gate.wire_second_input(next_copy, e)),
);
c.push(Target::wire(
gate_index,
gate.wire_first_output(next_copy, e),
));
d.push(Target::wire(
gate_index,
gate.wire_second_output(next_copy, e),
));
}
let switch = Target::wire(gate_index, gate.wire_switch_bool(next_copy));
(switch, c, d)
} }
fn assert_permutation_recursive<F: RichField + Extendable<D>, const D: usize>( fn assert_permutation_recursive<F: RichField + Extendable<D>, const D: usize>(