From ff949f40bcfe3cd07c1bf11f480b39a2cdfef0c9 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 2 Feb 2022 16:02:22 +0100 Subject: [PATCH] Works everywhere except Waksman --- plonky2/src/gadgets/arithmetic.rs | 4 +- plonky2/src/gadgets/arithmetic_extension.rs | 7 +- plonky2/src/gadgets/arithmetic_u32.rs | 4 +- plonky2/src/gadgets/random_access.rs | 2 +- plonky2/src/gates/arithmetic_base.rs | 2 +- plonky2/src/gates/arithmetic_extension.rs | 2 +- plonky2/src/gates/batchable.rs | 9 +- plonky2/src/gates/gate.rs | 1 + plonky2/src/gates/multiplication_extension.rs | 2 +- plonky2/src/plonk/circuit_builder.rs | 711 +++++++++--------- waksman/src/permutation.rs | 51 +- 11 files changed, 424 insertions(+), 371 deletions(-) diff --git a/plonky2/src/gadgets/arithmetic.rs b/plonky2/src/gadgets/arithmetic.rs index e280fa5e..0d844af9 100644 --- a/plonky2/src/gadgets/arithmetic.rs +++ b/plonky2/src/gadgets/arithmetic.rs @@ -4,6 +4,7 @@ use plonky2_field::extension_field::Extendable; use plonky2_field::field_types::PrimeField; use crate::gates::arithmetic_base::ArithmeticGate; +use crate::gates::batchable::GateRef; use crate::gates::exponentiation::ExponentiationGate; use crate::hash::hash_types::RichField; use crate::iop::target::{BoolTarget, Target}; @@ -78,7 +79,8 @@ impl, const D: usize> CircuitBuilder { } fn add_base_arithmetic_operation(&mut self, operation: BaseArithmeticOperation) -> 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_1 = Target::wire(gate, ArithmeticGate::wire_ith_multiplicand_1(i)); let wires_addend = Target::wire(gate, ArithmeticGate::wire_ith_addend(i)); diff --git a/plonky2/src/gadgets/arithmetic_extension.rs b/plonky2/src/gadgets/arithmetic_extension.rs index 125fb49a..1ccbb6bd 100644 --- a/plonky2/src/gadgets/arithmetic_extension.rs +++ b/plonky2/src/gadgets/arithmetic_extension.rs @@ -4,6 +4,7 @@ use plonky2_field::field_types::{Field, PrimeField}; use plonky2_util::bits_u64; use crate::gates::arithmetic_extension::ArithmeticExtensionGate; +use crate::gates::batchable::GateRef; use crate::gates::multiplication_extension::MulExtensionGate; use crate::hash::hash_types::RichField; use crate::iop::ext_target::{ExtensionAlgebraTarget, ExtensionTarget}; @@ -60,7 +61,8 @@ impl, const D: usize> CircuitBuilder { &mut self, operation: ExtensionArithmeticOperation, ) -> ExtensionTarget { - 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( gate, ArithmeticExtensionGate::::wires_ith_multiplicand_0(i), @@ -83,7 +85,8 @@ impl, const D: usize> CircuitBuilder { &mut self, operation: ExtensionArithmeticOperation, ) -> ExtensionTarget { - 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 = ExtensionTarget::from_range(gate, MulExtensionGate::::wires_ith_multiplicand_0(i)); let wires_multiplicand_1 = diff --git a/plonky2/src/gadgets/arithmetic_u32.rs b/plonky2/src/gadgets/arithmetic_u32.rs index 6116f61b..1c8df3b6 100644 --- a/plonky2/src/gadgets/arithmetic_u32.rs +++ b/plonky2/src/gadgets/arithmetic_u32.rs @@ -78,7 +78,7 @@ impl, const D: usize> CircuitBuilder { } let gate = U32ArithmeticGate::::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( Target::wire(gate_index, gate.wire_ith_multiplicand_0(copy)), @@ -138,7 +138,7 @@ impl, const D: usize> CircuitBuilder { borrow: U32Target, ) -> (U32Target, U32Target) { let gate = U32SubtractionGate::::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_y(copy)), y.0); diff --git a/plonky2/src/gadgets/random_access.rs b/plonky2/src/gadgets/random_access.rs index a688292d..1a142844 100644 --- a/plonky2/src/gadgets/random_access.rs +++ b/plonky2/src/gadgets/random_access.rs @@ -17,8 +17,8 @@ impl, const D: usize> CircuitBuilder { if vec_size == 1 { return self.connect(claimed_element, v[0]); } - let (gate_index, copy) = self.find_random_access_gate(bits); let dummy_gate = RandomAccessGate::::new_from_config(&self.config, bits); + let (gate_index, copy) = self.find_slot(dummy_gate, vec![]); v.iter().enumerate().for_each(|(i, &val)| { self.connect( diff --git a/plonky2/src/gates/arithmetic_base.rs b/plonky2/src/gates/arithmetic_base.rs index ca308923..455dbc81 100644 --- a/plonky2/src/gates/arithmetic_base.rs +++ b/plonky2/src/gates/arithmetic_base.rs @@ -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 /// supports enough routed wires, it can support several such operations in one gate. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ArithmeticGate { /// Number of arithmetic operations performed by an arithmetic gate. pub num_ops: usize, diff --git a/plonky2/src/gates/arithmetic_extension.rs b/plonky2/src/gates/arithmetic_extension.rs index bd575272..530b030c 100644 --- a/plonky2/src/gates/arithmetic_extension.rs +++ b/plonky2/src/gates/arithmetic_extension.rs @@ -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 /// supports enough routed wires, it can support several such operations in one gate. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ArithmeticExtensionGate { /// Number of arithmetic operations performed by an arithmetic gate. pub num_ops: usize, diff --git a/plonky2/src/gates/batchable.rs b/plonky2/src/gates/batchable.rs index a2daef6f..6bae6a88 100644 --- a/plonky2/src/gates/batchable.rs +++ b/plonky2/src/gates/batchable.rs @@ -12,6 +12,8 @@ use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; pub trait BatchableGate, const D: usize>: Gate { + fn num_ops(&self) -> usize; + // TODO: It would be nice to have a `Parameters` associated type. fn fill_gate( &self, @@ -21,8 +23,9 @@ pub trait BatchableGate, const D: usize>: Gate, const D: usize> { - current_slot: HashMap, (usize, usize)>, + pub current_slot: HashMap, (usize, usize)>, } #[derive(Clone)] @@ -76,6 +79,10 @@ pub trait MultiOpsGate, const D: usize>: Gate impl, G: MultiOpsGate, const D: usize> BatchableGate for G { + fn num_ops(&self) -> usize { + self.num_ops() + } + fn fill_gate( &self, params: &[F], diff --git a/plonky2/src/gates/gate.rs b/plonky2/src/gates/gate.rs index 5cc15216..db73f6ce 100644 --- a/plonky2/src/gates/gate.rs +++ b/plonky2/src/gates/gate.rs @@ -173,6 +173,7 @@ pub trait Gate, const D: usize>: 'static + Send + S // } /// A gate along with any constants used to configure it. +#[derive(Clone)] pub struct GateInstance, const D: usize> { pub gate_ref: GateRef, pub constants: Vec, diff --git a/plonky2/src/gates/multiplication_extension.rs b/plonky2/src/gates/multiplication_extension.rs index 031edfdc..0b93359d 100644 --- a/plonky2/src/gates/multiplication_extension.rs +++ b/plonky2/src/gates/multiplication_extension.rs @@ -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 /// supports enough routed wires, it can support several such operations in one gate. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct MulExtensionGate { /// Number of multiplications performed by the gate. pub num_ops: usize, diff --git a/plonky2/src/plonk/circuit_builder.rs b/plonky2/src/plonk/circuit_builder.rs index cdd169ff..bfe5ee3a 100644 --- a/plonky2/src/plonk/circuit_builder.rs +++ b/plonky2/src/plonk/circuit_builder.rs @@ -84,9 +84,6 @@ pub struct CircuitBuilder, const D: usize> { /// Memoized results of `arithmetic_extension` calls. pub(crate) arithmetic_results: HashMap, ExtensionTarget>, - // yo: Vec>, - batched_gates: BatchedGates, - current_slots: HashMap, CurrentSlot>, } @@ -106,7 +103,6 @@ impl, const D: usize> CircuitBuilder { base_arithmetic_results: HashMap::new(), arithmetic_results: HashMap::new(), targets_to_constants: HashMap::new(), - batched_gates: BatchedGates::new(), current_slots: HashMap::new(), }; builder.check_config(); @@ -193,6 +189,7 @@ impl, const D: usize> CircuitBuilder { /// Adds a gate to the circuit, and returns its index. pub fn add_gate>(&mut self, gate_type: G, constants: Vec) -> usize { + // println!("{} {}", self.num_gates(), gate_type.id()); self.check_gate_compatibility(&gate_type); assert_eq!( gate_type.num_constants(), @@ -307,7 +304,11 @@ impl, const D: usize> CircuitBuilder { 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); self.gate_instances[gate].constants[instance] = c; @@ -373,6 +374,44 @@ impl, const D: usize> CircuitBuilder { }) } + pub fn find_slot + Clone>( + &mut self, + gate: G, + params: Vec, + ) -> (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(¶ms); + 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(¶ms); + } 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 { let fri_config = &self.config.fri_config; let reduction_arity_bits = fri_config.reduction_strategy.reduction_arity_bits( @@ -815,337 +854,337 @@ impl, const D: usize> BatchedGates { } impl, const D: usize> CircuitBuilder { - /// 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::::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::::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 `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 - /// `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::::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, 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::::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) - } - - 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::::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::::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::::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::::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::::new_from_config(&self.config, bits).num_copies; - for _ in i..max_copies { - self.random_access(zero, zero, vec![zero; 1 << bits]); - } - } - } - - /// 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 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::::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::::num_ops(&self.config) { - let dummy = self.add_virtual_u32_target(); - self.sub_u32(dummy, dummy, dummy); - self.connect_u32(dummy, zero); - } - } - } - + // /// 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::::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::::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 `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 + // /// `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::::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, 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::::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) + // } + // + // 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::::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::::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::::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::::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::::new_from_config(&self.config, bits).num_copies; + // for _ in i..max_copies { + // self.random_access(zero, zero, vec![zero; 1 << bits]); + // } + // } + // } + // + // /// 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 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::::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::::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_arithmetic_gates(); - self.fill_u32_subtraction_gates(); + let instances = self.gate_instances.clone(); + for gate in instances { + if let Some(slot) = self.current_slots.get(&gate.gate_ref) { + let cloned = slot.clone(); + gate.gate_ref.0.fill_gate(&gate.constants, &cloned, self); + } + } } } diff --git a/waksman/src/permutation.rs b/waksman/src/permutation.rs index 666342d7..877038dd 100644 --- a/waksman/src/permutation.rs +++ b/waksman/src/permutation.rs @@ -79,32 +79,33 @@ fn create_switch, const D: usize>( 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 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 switch = Target::wire(gate_index, gate.wire_switch_bool(next_copy)); - - (switch, c, d) + // let switch = Target::wire(gate_index, gate.wire_switch_bool(next_copy)); + // + // (switch, c, d) } fn assert_permutation_recursive, const D: usize>(