This commit is contained in:
Nicholas Ward 2021-08-24 18:35:30 -07:00
parent a574fecc4d
commit 2ab37e688f
3 changed files with 143 additions and 74 deletions

View File

@ -3,7 +3,7 @@ use std::convert::TryInto;
use crate::field::{extension_field::Extendable, field_types::Field};
use crate::gates::switch::SwitchGate;
use crate::iop::generator::{GeneratedValues, SimpleGenerator};
use crate::iop::target::Target;
use crate::iop::target::{BoolTarget, Target};
use crate::iop::witness::PartialWitness;
use crate::plonk::circuit_builder::CircuitBuilder;
@ -45,7 +45,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
c: [Target; CHUNK_SIZE],
d: [Target; CHUNK_SIZE],
) {
let (_, _, gate_c, gate_d) = self.create_switch(a, b);
let (_, gate_c, gate_d) = self.create_switch(a, b);
for e in 0..CHUNK_SIZE {
self.route(c[e], gate_c[e]);
self.route(d[e], gate_d[e]);
@ -56,28 +56,64 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
&mut self,
a: [Target; CHUNK_SIZE],
b: [Target; CHUNK_SIZE],
) -> (
SwitchGate<F, D, CHUNK_SIZE>,
usize,
[Target; CHUNK_SIZE],
[Target; CHUNK_SIZE],
) {
let gate = SwitchGate::<F, D, CHUNK_SIZE>::new(1);
let gate_index = self.add_gate(gate.clone(), vec![]);
) -> (usize, [Target; CHUNK_SIZE], [Target; CHUNK_SIZE]) {
if self.current_switch_gates.len() < CHUNK_SIZE {
self.current_switch_gates
.extend(vec![None; CHUNK_SIZE - self.current_switch_gates.len()]);
}
let (gate_index, mut next_copy) = match self.current_switch_gates[CHUNK_SIZE - 1] {
None => {
let gate = SwitchGate::<F, D, CHUNK_SIZE>::new_from_config(self.config.clone());
let gate_index = self.add_gate(gate.clone(), vec![]);
(gate_index, 0)
}
Some((idx, next_copy)) => (idx, next_copy),
};
let num_copies =
SwitchGate::<F, D, CHUNK_SIZE>::max_num_copies(self.config.num_routed_wires);
let mut c = Vec::new();
let mut d = Vec::new();
for e in 0..CHUNK_SIZE {
self.route(a[e], Target::wire(gate_index, gate.wire_first_input(0, e)));
self.route(b[e], Target::wire(gate_index, gate.wire_second_input(0, e)));
c.push(Target::wire(gate_index, gate.wire_first_output(0, e)));
d.push(Target::wire(gate_index, gate.wire_second_output(0, e)));
self.route(
a[e],
Target::wire(
gate_index,
SwitchGate::<F, D, CHUNK_SIZE>::wire_first_input(0, e),
),
);
self.route(
b[e],
Target::wire(
gate_index,
SwitchGate::<F, D, CHUNK_SIZE>::wire_second_input(0, e),
),
);
c.push(Target::wire(
gate_index,
SwitchGate::<F, D, CHUNK_SIZE>::wire_first_output(0, e),
));
d.push(Target::wire(
gate_index,
SwitchGate::<F, D, CHUNK_SIZE>::wire_second_output(0, e),
));
}
let c_arr: [Target; CHUNK_SIZE] = c.try_into().unwrap();
let d_arr: [Target; CHUNK_SIZE] = d.try_into().unwrap();
(gate, gate_index, c_arr, d_arr)
next_copy += 1;
if next_copy == num_copies {
let new_gate = SwitchGate::<F, D, CHUNK_SIZE>::new_from_config(self.config.clone());
let new_gate_index = self.add_gate(new_gate.clone(), vec![]);
self.current_switch_gates[CHUNK_SIZE - 1] = Some((new_gate_index, 0));
} else {
self.current_switch_gates[CHUNK_SIZE - 1] = Some((gate_index, next_copy));
}
(gate_index, c_arr, d_arr)
}
fn assert_permutation_recursive<const CHUNK_SIZE: usize>(
@ -102,12 +138,12 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
};
for i in 0..a_num_switches {
let (_, _, out_1, out_2) = self.create_switch(a[i * 2], a[i * 2 + 1]);
let (_, out_1, out_2) = self.create_switch(a[i * 2], a[i * 2 + 1]);
child_1_a.push(out_1);
child_2_a.push(out_2);
}
for i in 0..b_num_switches {
let (_, _, out_1, out_2) = self.create_switch(b[i * 2], b[i * 2 + 1]);
let (_, out_1, out_2) = self.create_switch(b[i * 2], b[i * 2 + 1]);
child_1_b.push(out_1);
child_2_b.push(out_2);
}
@ -126,13 +162,30 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
}
}
struct PermutationGenerator<const CHUNK_SIZE: usize> {
gate_index: usize,
fn route_one_layer<F: Field, const CHUNK_SIZE: usize>(
a_values: Vec<F>,
b_values: Vec<F>,
a_wires: Vec<[Target; CHUNK_SIZE]>,
b_wires: Vec<[Target; CHUNK_SIZE]>,
) {
todo!()
}
impl<F: Field, const CHUNK_SIZE: usize> SimpleGenerator<F> for PermutationGenerator<CHUNK_SIZE> {
struct PermutationGenerator<F: Field, const CHUNK_SIZE: usize> {
a_values: Vec<F>,
b_values: Vec<F>,
a_wires: Vec<[Target; CHUNK_SIZE]>,
b_wires: Vec<[Target; CHUNK_SIZE]>,
}
impl<F: Field, const CHUNK_SIZE: usize> SimpleGenerator<F> for PermutationGenerator<F, CHUNK_SIZE> {
fn dependencies(&self) -> Vec<Target> {
todo!()
self.a_wires
.iter()
.map(|arr| arr.to_vec())
.flatten()
.collect()
//.chain(self.b_wires.iter()).collect()
}
fn run_once(&self, witness: &PartialWitness<F>, out_buffer: &mut GeneratedValues<F>) {

View File

@ -32,37 +32,32 @@ impl<F: Extendable<D>, const D: usize, const CHUNK_SIZE: usize> SwitchGate<F, D,
Self::new(num_copies)
}
fn max_num_copies(num_routed_wires: usize) -> usize {
pub fn max_num_copies(num_routed_wires: usize) -> usize {
num_routed_wires / (4 * CHUNK_SIZE)
}
pub fn wire_first_input(&self, copy: usize, element: usize) -> usize {
debug_assert!(copy < self.num_copies);
pub fn wire_first_input(copy: usize, element: usize) -> usize {
debug_assert!(element < CHUNK_SIZE);
copy * (4 * CHUNK_SIZE) + element
}
pub fn wire_second_input(&self, copy: usize, element: usize) -> usize {
debug_assert!(copy < self.num_copies);
pub fn wire_second_input(copy: usize, element: usize) -> usize {
debug_assert!(element < CHUNK_SIZE);
copy * (4 * CHUNK_SIZE) + CHUNK_SIZE + element
}
pub fn wire_first_output(&self, copy: usize, element: usize) -> usize {
debug_assert!(copy < self.num_copies);
pub fn wire_first_output(copy: usize, element: usize) -> usize {
debug_assert!(element < CHUNK_SIZE);
copy * (4 * CHUNK_SIZE) + 2 * CHUNK_SIZE + element
}
pub fn wire_second_output(&self, copy: usize, element: usize) -> usize {
debug_assert!(copy < self.num_copies);
pub fn wire_second_output(copy: usize, element: usize) -> usize {
debug_assert!(element < CHUNK_SIZE);
copy * (4 * CHUNK_SIZE) + 3 * CHUNK_SIZE + element
}
pub fn wire_switch_bool(&self, copy: usize) -> usize {
debug_assert!(copy < self.num_copies);
self.num_copies * (4 * CHUNK_SIZE) + copy
pub fn wire_switch_bool(num_copies: usize, copy: usize) -> usize {
num_copies * (4 * CHUNK_SIZE) + copy
}
}
@ -77,14 +72,14 @@ impl<F: Extendable<D>, const D: usize, const CHUNK_SIZE: usize> Gate<F, D>
let mut constraints = Vec::with_capacity(self.num_constraints());
for c in 0..self.num_copies {
let switch_bool = vars.local_wires[self.wire_switch_bool(c)];
let switch_bool = vars.local_wires[Self::wire_switch_bool(self.num_wires(), c)];
let not_switch = F::Extension::ONE - switch_bool;
for e in 0..CHUNK_SIZE {
let first_input = vars.local_wires[self.wire_first_input(c, e)];
let second_input = vars.local_wires[self.wire_second_input(c, e)];
let first_output = vars.local_wires[self.wire_first_output(c, e)];
let second_output = vars.local_wires[self.wire_second_output(c, e)];
let first_input = vars.local_wires[Self::wire_first_input(c, e)];
let second_input = vars.local_wires[Self::wire_second_input(c, e)];
let first_output = vars.local_wires[Self::wire_first_output(c, e)];
let second_output = vars.local_wires[Self::wire_second_output(c, e)];
constraints.push(switch_bool * (first_input - second_output));
constraints.push(switch_bool * (second_input - first_output));
@ -100,14 +95,14 @@ impl<F: Extendable<D>, const D: usize, const CHUNK_SIZE: usize> Gate<F, D>
let mut constraints = Vec::with_capacity(self.num_constraints());
for c in 0..self.num_copies {
let switch_bool = vars.local_wires[self.wire_switch_bool(c)];
let switch_bool = vars.local_wires[Self::wire_switch_bool(self.num_copies, c)];
let not_switch = F::ONE - switch_bool;
for e in 0..CHUNK_SIZE {
let first_input = vars.local_wires[self.wire_first_input(c, e)];
let second_input = vars.local_wires[self.wire_second_input(c, e)];
let first_output = vars.local_wires[self.wire_first_output(c, e)];
let second_output = vars.local_wires[self.wire_second_output(c, e)];
let first_input = vars.local_wires[Self::wire_first_input(c, e)];
let second_input = vars.local_wires[Self::wire_second_input(c, e)];
let first_output = vars.local_wires[Self::wire_first_output(c, e)];
let second_output = vars.local_wires[Self::wire_second_output(c, e)];
constraints.push(switch_bool * (first_input - second_output));
constraints.push(switch_bool * (second_input - first_output));
@ -128,14 +123,14 @@ impl<F: Extendable<D>, const D: usize, const CHUNK_SIZE: usize> Gate<F, D>
let one = builder.one_extension();
for c in 0..self.num_copies {
let switch_bool = vars.local_wires[self.wire_switch_bool(c)];
let switch_bool = vars.local_wires[Self::wire_switch_bool(self.num_copies, c)];
let not_switch = builder.sub_extension(one, switch_bool);
for e in 0..CHUNK_SIZE {
let first_input = vars.local_wires[self.wire_first_input(c, e)];
let second_input = vars.local_wires[self.wire_second_input(c, e)];
let first_output = vars.local_wires[self.wire_first_output(c, e)];
let second_output = vars.local_wires[self.wire_second_output(c, e)];
let first_input = vars.local_wires[Self::wire_first_input(c, e)];
let second_input = vars.local_wires[Self::wire_second_input(c, e)];
let first_output = vars.local_wires[Self::wire_first_output(c, e)];
let second_output = vars.local_wires[Self::wire_second_output(c, e)];
let first_switched = builder.sub_extension(first_input, second_output);
let first_switched_constraint = builder.mul_extension(switch_bool, first_switched);
@ -174,7 +169,7 @@ impl<F: Extendable<D>, const D: usize, const CHUNK_SIZE: usize> Gate<F, D>
}
fn num_wires(&self) -> usize {
self.wire_second_output(self.num_copies - 1, CHUNK_SIZE - 1) + 1
Self::wire_second_output(self.num_copies - 1, CHUNK_SIZE - 1) + 1
}
fn num_constants(&self) -> usize {
@ -205,10 +200,18 @@ impl<F: Extendable<D>, const D: usize, const CHUNK_SIZE: usize> SimpleGenerator<
let mut deps = Vec::new();
for c in 0..self.gate.num_copies {
for e in 0..CHUNK_SIZE {
deps.push(local_target(self.gate.wire_first_input(c, e)));
deps.push(local_target(self.gate.wire_second_input(c, e)));
deps.push(local_target(self.gate.wire_first_output(c, e)));
deps.push(local_target(self.gate.wire_second_output(c, e)));
deps.push(local_target(
SwitchGate::<F, D, CHUNK_SIZE>::wire_first_input(c, e),
));
deps.push(local_target(
SwitchGate::<F, D, CHUNK_SIZE>::wire_second_input(c, e),
));
deps.push(local_target(
SwitchGate::<F, D, CHUNK_SIZE>::wire_first_output(c, e),
));
deps.push(local_target(
SwitchGate::<F, D, CHUNK_SIZE>::wire_second_output(c, e),
));
}
}
@ -224,12 +227,19 @@ impl<F: Extendable<D>, const D: usize, const CHUNK_SIZE: usize> SimpleGenerator<
let get_local_wire = |input| witness.get_wire(local_wire(input));
for c in 0..self.gate.num_copies {
let switch_bool_wire = local_wire(self.gate.wire_switch_bool(c));
let switch_bool_wire = local_wire(SwitchGate::<F, D, CHUNK_SIZE>::wire_switch_bool(
self.gate.num_copies,
c,
));
for e in 0..CHUNK_SIZE {
let first_input = get_local_wire(self.gate.wire_first_input(c, e));
let second_input = get_local_wire(self.gate.wire_second_input(c, e));
let first_output = get_local_wire(self.gate.wire_first_output(c, e));
let second_output = get_local_wire(self.gate.wire_second_output(c, e));
let first_input =
get_local_wire(SwitchGate::<F, D, CHUNK_SIZE>::wire_first_input(c, e));
let second_input =
get_local_wire(SwitchGate::<F, D, CHUNK_SIZE>::wire_second_input(c, e));
let first_output =
get_local_wire(SwitchGate::<F, D, CHUNK_SIZE>::wire_first_output(c, e));
let second_output =
get_local_wire(SwitchGate::<F, D, CHUNK_SIZE>::wire_second_output(c, e));
if first_input == first_output {
out_buffer.set_wire(switch_bool_wire, F::ONE);
@ -259,24 +269,27 @@ mod tests {
#[test]
fn wire_indices() {
let gate = SwitchGate::<CrandallField, 4, 3> {
num_copies: 3,
type SG = SwitchGate<CrandallField, 4, 3>;
let num_copies = 3;
let gate = SG {
num_copies,
_phantom: PhantomData,
};
assert_eq!(gate.wire_first_input(0, 0), 0);
assert_eq!(gate.wire_first_input(0, 2), 2);
assert_eq!(gate.wire_second_input(0, 0), 3);
assert_eq!(gate.wire_second_input(0, 2), 5);
assert_eq!(gate.wire_first_output(0, 0), 6);
assert_eq!(gate.wire_second_output(0, 2), 11);
assert_eq!(gate.wire_first_input(1, 0), 12);
assert_eq!(gate.wire_second_output(1, 2), 23);
assert_eq!(gate.wire_first_input(2, 0), 24);
assert_eq!(gate.wire_second_output(2, 2), 35);
assert_eq!(gate.wire_switch_bool(0), 36);
assert_eq!(gate.wire_switch_bool(1), 37);
assert_eq!(gate.wire_switch_bool(2), 38);
assert_eq!(SG::wire_first_input(0, 0), 0);
assert_eq!(SG::wire_first_input(0, 2), 2);
assert_eq!(SG::wire_second_input(0, 0), 3);
assert_eq!(SG::wire_second_input(0, 2), 5);
assert_eq!(SG::wire_first_output(0, 0), 6);
assert_eq!(SG::wire_second_output(0, 2), 11);
assert_eq!(SG::wire_first_input(1, 0), 12);
assert_eq!(SG::wire_second_output(1, 2), 23);
assert_eq!(SG::wire_first_input(2, 0), 24);
assert_eq!(SG::wire_second_output(2, 2), 35);
assert_eq!(SG::wire_switch_bool(num_copies, 0), 36);
assert_eq!(SG::wire_switch_bool(num_copies, 1), 37);
assert_eq!(SG::wire_switch_bool(num_copies, 2), 38);
}
#[test]

View File

@ -40,7 +40,7 @@ pub struct CircuitBuilder<F: Extendable<D>, const D: usize> {
gates: HashSet<GateRef<F, D>>,
/// The concrete placement of each gate.
gate_instances: Vec<GateInstance<F, D>>,
pub(crate) gate_instances: Vec<GateInstance<F, D>>,
/// Targets to be made public.
public_inputs: Vec<Target>,
@ -65,6 +65,8 @@ pub struct CircuitBuilder<F: 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) current_switch_gates: Vec<Option<(usize, usize)>>,
}
impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
@ -82,6 +84,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
constants_to_targets: HashMap::new(),
targets_to_constants: HashMap::new(),
free_arithmetic: HashMap::new(),
current_switch_gates: Vec::new(),
}
}