diff --git a/src/garble_classic.rs b/src/garble_classic.rs index 5eea199..2594044 100644 --- a/src/garble_classic.rs +++ b/src/garble_classic.rs @@ -38,24 +38,49 @@ fn decrypt(key_a: [u8; 16], key_b: [u8; 16], encrypted: [u8; 32]) -> Option<[u8; struct Wire { sym: Option, keys: [[u8; 16]; 2], - secret: bool, + evaluator: bool, } #[derive(Clone, Debug)] -struct Circuit { - left: Box, - right: Box, +struct Gate { + left: Box, + right: Box, out: Wire, table: [[[u8; 32]; 2]; 2], sym: String, } #[derive(Clone, Debug)] -enum CircOption { - Circuit(Circuit), +enum Circuit { + Gate(Gate), Wire(Wire), } +#[derive(Clone, Debug)] +struct HiddenWire { + sym: Option, +} + +#[derive(Clone, Debug)] +struct HiddenGate { + left: Box, + right: Box, + table: [[[u8; 32]; 2]; 2], + sym: String, +} + +#[derive(Clone, Debug)] +enum HiddenCircuit { + Gate(HiddenGate), + Wire(HiddenWire), +} + +#[derive(Clone, Debug)] +struct FullyHiddenCircuit { + table: [[u8; 32]; 2], + circuit: HiddenCircuit, +} + impl Display for Wire { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match &self.sym { @@ -65,39 +90,39 @@ impl Display for Wire { } } -impl Display for CircOption { +impl Display for Circuit { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - CircOption::Wire(w) => write!(f, "{}", w), - CircOption::Circuit(c) => write!(f, "{}", c), + Circuit::Wire(w) => write!(f, "{}", w), + Circuit::Gate(c) => write!(f, "{}", c), } } } -impl Display for Circuit { +impl Display for Gate { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{} {} {}", self.left, self.sym, self.right) } } impl Wire { - fn new_rng(sym: String, secret: bool, rng: &mut (impl RngCore + CryptoRng)) -> Self { + fn new_rng(sym: String, evaluator: bool, rng: &mut (impl RngCore + CryptoRng)) -> Self { let mut keys = [[0; 16]; 2]; rng.fill_bytes(&mut keys[0]); rng.fill_bytes(&mut keys[1]); Self { sym: Some(sym), keys, - secret, + evaluator, } } - fn new(sym: String, secret: bool) -> Self { - Self::new_rng(sym, secret, &mut OsRng) + fn new(sym: String, evaluator: bool) -> Self { + Self::new_rng(sym, evaluator, &mut OsRng) } - fn to_circ(&self) -> CircOption { - CircOption::Wire(self.clone()) + fn to_circ(&self) -> Circuit { + Circuit::Wire(self.clone()) } fn empty(rng: &mut (impl RngCore + CryptoRng)) -> Self { @@ -107,27 +132,27 @@ impl Wire { Self { sym: None, keys, - secret: false, + evaluator: false, } } } -impl Circuit { +impl Gate { fn new( - left: CircOption, - right: CircOption, + left: Circuit, + right: Circuit, value: [[bool; 2]; 2], sym: String, rng: &mut (impl RngCore + CryptoRng), ) -> Self { let linp_keys = match left { - CircOption::Wire(ref w) => w.keys, - CircOption::Circuit(ref c) => c.out.keys, + Circuit::Wire(ref w) => w.keys, + Circuit::Gate(ref c) => c.out.keys, }; let rinp_keys = match right { - CircOption::Wire(ref w) => w.keys, - CircOption::Circuit(ref c) => c.out.keys, + Circuit::Wire(ref w) => w.keys, + Circuit::Gate(ref c) => c.out.keys, }; let out = Wire::empty(rng); @@ -157,15 +182,15 @@ impl Circuit { } } - fn to_circ(&self) -> CircOption { - CircOption::Circuit(self.clone()) + fn to_circ(&self) -> Circuit { + Circuit::Gate(self.clone()) } } -impl CircOption { +impl Circuit { fn evaluate_re(&self, vals: HashMap) -> [u8; 16] { match self { - CircOption::Circuit(c) => { + Circuit::Gate(c) => { let lv = c.left.evaluate_re(vals.clone()); let rv = c.right.evaluate_re(vals); let mut out = [0; 16]; @@ -178,8 +203,8 @@ impl CircOption { } out } - CircOption::Wire(w) => match &w.sym { - // Errr OT? hello? + Circuit::Wire(w) => match &w.sym { + // No OT Some(c) => w.keys[(vals[c]) as usize], None => panic!("This should not happen."), }, @@ -190,7 +215,7 @@ impl CircOption { let out_label = self.evaluate_re(vals); match self { - CircOption::Circuit(c) => { + Circuit::Gate(c) => { if out_label == c.out.keys[0] { false } else if out_label == c.out.keys[1] { @@ -199,7 +224,7 @@ impl CircOption { panic!("Error!"); } } - CircOption::Wire(w) => { + Circuit::Wire(w) => { if out_label == w.keys[0] { false } else if out_label == w.keys[1] { @@ -210,13 +235,111 @@ impl CircOption { } } } + + pub fn to_hidden( + &self, + ) -> ( + FullyHiddenCircuit, + HashMap, + HashMap, + ) { + let (circ, map1, map2) = self.to_hidden_re(); + match self { + Circuit::Gate(c) => { + let out_keys = c.out.keys; + let mut table = [[0; 32]; 2]; + + let i = OsRng.gen::() as usize; + + for bit in [i, 1 - i] { + let enc = encrypt(out_keys[bit], [0; 16], [bit as u8; 16]); + table[bit] = enc; + } + ( + FullyHiddenCircuit { + table, + circuit: circ, + }, + map1, + map2, + ) + } + Circuit::Wire(w) => { + let out_keys = w.keys; + let mut table = [[0; 32]; 2]; + let i = OsRng.gen::() as usize; + for bit in [i, 1 - i] { + let enc = encrypt(out_keys[bit], [0; 16], [bit as u8; 16]); + table[bit] = enc; + } + ( + FullyHiddenCircuit { + table, + circuit: circ, + }, + map1, + map2, + ) + } + } + } + + fn to_hidden_re( + &self, + ) -> ( + HiddenCircuit, + HashMap, + HashMap, + ) { + match self { + Circuit::Gate(c) => { + let (c1, sender1, eval1) = c.left.to_hidden_re(); + let (c2, sender2, eval2) = c.right.to_hidden_re(); + ( + HiddenCircuit::Gate(HiddenGate { + left: Box::new(c1), + right: Box::new(c2), + table: c.table, + sym: c.sym.clone(), + }), + sender1.into_iter().chain(sender2).collect(), + eval1.into_iter().chain(eval2).collect(), + ) + } + Circuit::Wire(w) => { + let out = match w.sym.clone() { + Some(s) => s, + None => panic!("Need wire description."), + }; + if w.evaluator { + let sender = HashMap::new(); + let mut eval = HashMap::new(); + eval.insert(out, w.keys); + ( + HiddenCircuit::Wire(HiddenWire { sym: w.sym.clone() }), + sender, + eval, + ) + } else { + let mut sender = HashMap::new(); + let eval = HashMap::new(); + sender.insert(out, w.keys); + ( + HiddenCircuit::Wire(HiddenWire { sym: w.sym.clone() }), + sender, + eval, + ) + } + } + } + } } -impl BitAnd for CircOption { - type Output = CircOption; +impl BitAnd for Circuit { + type Output = Circuit; fn bitand(self, rhs: Self) -> Self::Output { - CircOption::Circuit(Circuit::new( + Circuit::Gate(Gate::new( self, rhs, [[false, false], [false, true]], @@ -226,11 +349,11 @@ impl BitAnd for CircOption { } } -impl BitOr for CircOption { - type Output = CircOption; +impl BitOr for Circuit { + type Output = Circuit; fn bitor(self, rhs: Self) -> Self::Output { - CircOption::Circuit(Circuit::new( + Circuit::Gate(Gate::new( self, rhs, [[false, true], [true, true]], @@ -240,11 +363,11 @@ impl BitOr for CircOption { } } -impl BitXor for CircOption { - type Output = CircOption; +impl BitXor for Circuit { + type Output = Circuit; fn bitxor(self, rhs: Self) -> Self::Output { - CircOption::Circuit(Circuit::new( + Circuit::Gate(Gate::new( self, rhs, [[false, true], [true, false]], @@ -254,11 +377,95 @@ impl BitXor for CircOption { } } +impl From for HiddenWire { + fn from(value: Wire) -> Self { + Self { sym: value.sym } + } +} + +impl From for HiddenGate { + fn from(value: Gate) -> Self { + Self { + left: Box::new((*value.left).into()), + right: Box::new((*value.right).into()), + table: value.table, + sym: value.sym, + } + } +} + +impl From for HiddenCircuit { + fn from(value: Circuit) -> Self { + match value { + Circuit::Gate(c) => Self::Gate(c.into()), + Circuit::Wire(w) => Self::Wire(w.into()), + } + } +} + +impl HiddenCircuit { + fn evaluate_re(&self, vals: HashMap) -> [u8; 16] { + match self { + HiddenCircuit::Gate(c) => { + let lv = c.left.evaluate_re(vals.clone()); + let rv = c.right.evaluate_re(vals); + let mut out = [0; 16]; + for i in [0, 1] { + for j in [0, 1] { + if let Some(x) = decrypt(lv, rv, c.table[i][j]) { + out = x; + } + } + } + out + } + HiddenCircuit::Wire(w) => match &w.sym { + Some(c) => vals[c], + None => panic!("This should not happen."), + }, + } + } +} + +impl FullyHiddenCircuit { + pub fn evaluate( + &self, + sender: HashMap, + eval: HashMap, + ) -> bool { + let out_label = self + .circuit + .evaluate_re(sender.into_iter().chain(eval).collect()); + + let mut out = false; + for i in [0, 1] { + if let Some(x) = decrypt(out_label, [0; 16], self.table[i]) { + out = x[0] != 0; + } + } + out + } +} + +pub fn map_values_to_keys( + keys: HashMap, + values: Vec<(String, bool)>, +) -> HashMap { + let mut ret = HashMap::new(); + for i in values { + match keys.get(&i.0) { + Some(v) => ret.insert(i.0, v[i.1 as usize]), + None => continue, + }; + } + ret +} + #[cfg(test)] mod test { use crate::garble_classic::Wire; - use crate::garble_classic::{decrypt, encrypt}; + use crate::garble_classic::{decrypt, encrypt, map_values_to_keys}; use std::collections::HashMap; #[test] @@ -268,7 +475,7 @@ mod test { } #[test] - fn circuit() { + fn public_circuit() { let a = Wire::new("a".to_string(), true).to_circ(); let b = Wire::new("b".to_string(), false).to_circ(); let c = Wire::new("c".to_string(), false).to_circ(); @@ -278,7 +485,29 @@ mod test { h.insert("a".to_string(), false); h.insert("b".to_string(), false); h.insert("c".to_string(), true); + let out = circ.evaluate(h); assert!(out == false); } + + #[test] + fn garbled_circuit() { + let a = Wire::new("a".to_string(), true).to_circ(); + let b = Wire::new("b".to_string(), false).to_circ(); + let c = Wire::new("c".to_string(), false).to_circ(); + let circ = (a | b) & c; + + let (hidden_circ, sender, eval) = circ.to_hidden(); + + let values_sender = map_values_to_keys( + sender, + vec![("b".to_string(), false), ("c".to_string(), true)], + ); + + let values_eval = map_values_to_keys(eval, vec![("a".to_string(), true)]); + + let out = hidden_circ.evaluate(values_sender, values_eval); + + assert!(out == true); + } }