Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
robinhundt committed Mar 25, 2024
1 parent e9c1497 commit b54443b
Show file tree
Hide file tree
Showing 5 changed files with 259 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions crates/rec-sc-exp/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "rec-sc-exp"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
118 changes: 118 additions & 0 deletions crates/rec-sc-exp/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
use std::collections::{hash_map, HashMap};
use std::sync::Arc;

struct BaseCircuit;

struct Circuit {
base_circuits: Vec<BaseCircuit>,
main: SubCircuit,
}

struct SubCircuit(Arc<SubCircInner>);

struct SubCircInner {
base_circ_id: CircId, // this corresponds to the position in Circuits.base_circuits Vec
sub_circuits: Vec<SubCircuit>, // position in this Vec is CallId
call_map: CallMap,
}

struct CallId(u32);
struct CircId(u32);
struct GateId(u32);

struct CallGateId {
call: CallId,
gate: GateId,
}
struct CircGateId {
circ: CircId,
gate: GateId,
}

struct CallMap {
map: HashMap<GateId, CallGateId>,
}

struct Storage<T> {
own: Vec<T>,
sub_circuits: Vec<Storage<T>>, // indexed by the call Id
}

impl Storage<()> {
// clear storage and free associated memory. Should be called
// once a sub-circuit is evaluated
fn free() {}
}

struct CircuitLayer<'a, G> {
call_id: CallId,
gates: Vec<G>,
gate_ids: Vec<GateId>,
sub_circ_iter: &'a mut SubCircIter,
}

impl<'a, G> CircuitLayer<'a, G> {
fn sub_layer_iter(&mut self) -> SubLayerIter<'_> {
SubLayerIter {
sub_circ_iter: self.sub_circ_iter.sub_circ_iters.iter_mut(),
}
}
}

struct SubLayerIter<'a> {
sub_circ_iter: hash_map::IterMut<'a, CallId, SubCircIter>,
}

fn handle_layer<'a>(mut layer: CircuitLayer<'a, ()>, storage: &mut Storage<()>) {
// do stuff with layer.gates
// how do I associate a CircuitLayer with its correct storage destination?
// Storage also needs to be a recursive datastructure
let iter = layer.sub_layer_iter();
for layer in iter {
let storage = &mut storage.sub_circuits[layer.call_id.0 as usize];
handle_layer(layer, storage);
}
}

struct SubCircIter {
own_base_iter: BaseIter,
sub_circ_iters: HashMap<CallId, SubCircIter>,
sub_circ: SubCircuit,
}

impl SubCircIter {
fn next(&mut self) -> Option<CircuitLayer<'_, ()>> {
// drive own base iter to get gates for this base circuit
// check own gates in self.sub_circ call_map to see if they are outgoing
// if yes, add new SubCircIter to self.sub_circ_iters or update iter state
// with connected to gates
Some(CircuitLayer {
call_id: CallId(0),
gates: vec![],
gate_ids: vec![],
sub_circ_iter: self,
})
}
}

impl<'a> Iterator for SubLayerIter<'a> {
type Item = CircuitLayer<'a, ()>;
fn next(&mut self) -> Option<Self::Item> {
self.sub_circ_iter
.next()
.map(|(call_id, sc_iter)| sc_iter.next().map(|layer| layer))
.flatten()
}
}

struct BaseIter {
// the same?
}

impl BaseIter {
// mhhh, these methods are only needed if we can have a sub-circuit call directly from an
// interactive gate. If we add a SubCircuitCall gate, which **must** be the from gate of a
// call map, then we only need add to current layer.
fn add_to_current_layer(&mut self, gate_id: GateId) {}
fn add_to_next_layer(&mut self, gate_id: GateId) {}
}
1 change: 1 addition & 0 deletions crates/seec/src/circuit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub mod builder;
pub(crate) mod circuit_connections;
pub mod dyn_layers;
pub mod static_layers;
mod sub_circuit;

pub use crate::protocols::boolean_gmw::BooleanGate;
use crate::protocols::Gate;
Expand Down
128 changes: 128 additions & 0 deletions crates/seec/src/circuit/sub_circuit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
use crate::circuit::circuit_connections::CrossCircuitConnections;
use crate::circuit::{base_circuit, BaseCircuit, GateIdx};
use crate::protocols::Gate;
use crate::GateId;
use ahash::HashMap;
use std::collections::hash_map;
use std::slice;
use std::sync::Arc;

#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct CallId(u32);
#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct CircId(u32);

pub struct Circuit<G, Idx> {
base_circuits: Vec<BaseCircuit<G, Idx>>,
main: SubCircuit<Idx>,
}

#[derive(Clone)]
pub struct SubCircuit<Idx>(Arc<SubCircuitInner<Idx>>);

struct SubCircuitInner<Idx> {
base_circ_id: CircId, // this corresponds to the position in Circuits.base_circuits Vec
sub_circuits: Vec<SubCircuit<Idx>>, // position in this Vec is CallId
call_map: CallMap<Idx>,
}

struct CallMap<Idx> {
map: HashMap<GateId<Idx>, Vec<(CallId, GateId<Idx>)>>,
}

impl<Idx: GateIdx> CallMap<Idx> {
pub fn outgoing_gates(
&self,
g: GateId<Idx>,
) -> impl Iterator<Item = &(CallId, GateId<Idx>)> + '_ {
self.map.get(&g).map(|v| v.iter()).unwrap_or([].iter())
}
}

struct SubCircIter<'base, G, Idx: GateIdx> {
circ: &'base Circuit<G, Idx>,
base_iter: base_circuit::BaseLayerIter<'base, G, Idx, ()>,
sub_circ_iters: HashMap<CallId, Self>,
sub_circuit: SubCircuit<Idx>,
}

struct SubCircLayer<'sc_iter, 'base, G, Idx: GateIdx> {
call_id: CallId,
base_layer: base_circuit::CircuitLayer<G, Idx>,
sub_circ_iter: &'sc_iter mut SubCircIter<'base, G, Idx>,
}

impl<'base, G: Gate, Idx: GateIdx> SubCircIter<'base, G, Idx> {
fn next(&mut self) -> Option<SubCircLayer<'_, 'base, G, Idx>> {
let base_layer = self.base_iter.next().unwrap();
for gate_id in base_layer.iter_ids() {
for &(call_id, out_gate) in self.sub_circuit.0.call_map.outgoing_gates(gate_id) {
let sc_iter = self.sub_circ_iters.entry(call_id).or_insert_with(|| {
let called_sc = self.sub_circuit.0.sub_circuits[call_id.0 as usize].clone();
let called_circ_id = called_sc.0.base_circ_id;
let called_base_circ = &self.circ.base_circuits[called_circ_id.0 as usize];
let mut base_iter = base_circuit::BaseLayerIter::new_uninit(called_base_circ);
SubCircIter {
circ: self.circ,
base_iter,
sub_circ_iters: Default::default(),
sub_circuit: called_sc,
}
});
// TODO
sc_iter.base_iter.add_to_next_layer(out_gate.into());
}
}
// drive own base iter to get gates for this base circuit
// check own gates in self.sub_circ call_map to see if they are outgoing
// if yes, add new SubCircIter to self.sub_circ_iters or update iter state
// returns None when?? If own base_iter and all sub_circ_iters are exhausted?
todo!()
}
}

impl<'sc_iter, 'base, G, Idx: GateIdx> SubCircLayer<'sc_iter, 'base, G, Idx> {
fn sub_layer_iter(&mut self) -> SubLayerIter<'_, 'base, G, Idx> {
SubLayerIter {
iter: self.sub_circ_iter.sub_circ_iters.iter_mut(),
}
}
}

struct SubLayerIter<'a, 'base, G, Idx: GateIdx> {
iter: hash_map::IterMut<'a, CallId, SubCircIter<'base, G, Idx>>,
}


/// enum LayerExecutor {
/// BeforeInteractive {
/// layer: Layer
/// sub_executors: Vec<LayerExecutor>
/// },
/// AfterInteractive {
/// interactive_gates: InteractiveLayer
/// msg_range: Range<usize>
/// sub_executors: Vec<LayerExecutor>
/// }
/// }
///
///
/// impl LayerExecutor {
/// fn handle_before() {
/// handle_non_interactive(layer)
/// let msg_idx = handle_interactive(layer, &mut msg_buf)
/// for sub_layer in layer:
/// sub_executor = LayerExecutor::BeforeInteractive { layer: sub_layer, ... }
/// sub_executor.handle_before()
/// self.sub_executors.push(sub_executor)
/// }


// TODO: How is the interface for evaluating interactive gates?
// for layer in sc_iter:
// handle_non_interactive(layer)
// compute_msg(layer, &mut msg_buf)
// for sub_layer in layer:
// handle_layer(layer)
//

0 comments on commit b54443b

Please sign in to comment.