Skip to content

Commit

Permalink
refactor: decouple assignment from definition (#78)
Browse files Browse the repository at this point in the history
* add primitive type trait

* make Visibility public

* add StaticValueType bound to PrimitiveType

* decouple value definition from assignment in Memory trait

* replace with todo! and fix tests

* delete ValueIdConfig and ValueConfig

* move value module to mpz-garble

* add ArrayRef type

* memory rewrite

* fix tests

* restore memory test

* Update garble/mpz-garble/src/protocol/deap/mod.rs

* array_from_values method

* use operation id for otp ids

* Apply suggestions from code review

Co-authored-by: dan <themighty1@users.noreply.github.com>

---------

Co-authored-by: dan <themighty1@users.noreply.github.com>
  • Loading branch information
sinui0 and themighty1 authored Oct 24, 2023
1 parent 4736ae0 commit 5171baa
Show file tree
Hide file tree
Showing 19 changed files with 1,104 additions and 1,235 deletions.
1 change: 1 addition & 0 deletions garble/mpz-garble/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ aes = { workspace = true }
rayon = { workspace = true }
derive_builder.workspace = true
itybity.workspace = true
opaque-debug.workspace = true

[dev-dependencies]
mpz-ot = { workspace = true, features = ["mock"] }
Expand Down
29 changes: 15 additions & 14 deletions garble/mpz-garble/benches/deap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@ async fn bench_deap() {
let msg = [0u8; 16];

let leader_fut = {
let key_ref = leader_thread
.new_private_input::<[u8; 16]>("key", Some(key))
.unwrap();
let msg_ref = leader_thread
.new_private_input::<[u8; 16]>("msg", None)
.unwrap();
let key_ref = leader_thread.new_private_input::<[u8; 16]>("key").unwrap();
let msg_ref = leader_thread.new_blind_input::<[u8; 16]>("msg").unwrap();
let ciphertext_ref = leader_thread.new_output::<[u8; 16]>("ciphertext").unwrap();

leader_thread.assign(&key_ref, key).unwrap();

async {
leader_thread
.execute(
Expand All @@ -41,16 +39,16 @@ async fn bench_deap() {
};

let follower_fut = {
let key_ref = follower_thread
.new_private_input::<[u8; 16]>("key", None)
.unwrap();
let key_ref = follower_thread.new_blind_input::<[u8; 16]>("key").unwrap();
let msg_ref = follower_thread
.new_private_input::<[u8; 16]>("msg", Some(msg))
.new_private_input::<[u8; 16]>("msg")
.unwrap();
let ciphertext_ref = follower_thread
.new_output::<[u8; 16]>("ciphertext")
.unwrap();

follower_thread.assign(&msg_ref, msg).unwrap();

async {
follower_thread
.execute(
Expand All @@ -75,10 +73,13 @@ fn bench_aes_leader<T: Thread + Execute + Decode + Send>(
block: usize,
) -> Pin<Box<dyn Future<Output = Result<[u8; 16], VmError>> + Send + '_>> {
Box::pin(async move {
let key = thread.new_private_input(&format!("key/{block}"), Some([0u8; 16]))?;
let msg = thread.new_private_input(&format!("msg/{block}"), Some([0u8; 16]))?;
let key = thread.new_private_input::<[u8; 16]>(&format!("key/{block}"))?;
let msg = thread.new_private_input::<[u8; 16]>(&format!("msg/{block}"))?;
let ciphertext = thread.new_output::<[u8; 16]>(&format!("ciphertext/{block}"))?;

thread.assign(&key, [0u8; 16])?;
thread.assign(&msg, [0u8; 16])?;

thread
.execute(AES128.clone(), &[key, msg], &[ciphertext.clone()])
.await?;
Expand All @@ -94,8 +95,8 @@ fn bench_aes_follower<T: Thread + Execute + Decode + Send>(
block: usize,
) -> Pin<Box<dyn Future<Output = Result<[u8; 16], VmError>> + Send + '_>> {
Box::pin(async move {
let key = thread.new_private_input::<[u8; 16]>(&format!("key/{block}"), None)?;
let msg = thread.new_private_input::<[u8; 16]>(&format!("msg/{block}"), None)?;
let key = thread.new_blind_input::<[u8; 16]>(&format!("key/{block}"))?;
let msg = thread.new_blind_input::<[u8; 16]>(&format!("msg/{block}"))?;
let ciphertext = thread.new_output::<[u8; 16]>(&format!("ciphertext/{block}"))?;

thread
Expand Down
226 changes: 6 additions & 220 deletions garble/mpz-garble/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
//! Various configuration used in the protocol
use mpz_circuits::types::{StaticValueType, Value, ValueType};
use mpz_core::value::{ValueId, ValueRef};

/// Role in 2PC.
#[derive(Debug, Clone, Copy, PartialEq)]
#[allow(missing_docs)]
Expand All @@ -11,224 +8,13 @@ pub enum Role {
Follower,
}

#[derive(Debug)]
#[allow(missing_docs)]
#[allow(dead_code)]
pub struct ValueConfigError {
value_ref: ValueRef,
ty: ValueType,
value: Option<Value>,
visibility: Visibility,
}

/// Visibility of a value
#[derive(Debug, Clone, Copy)]
pub(crate) enum Visibility {
pub enum Visibility {
/// A value known to all parties
Public,
/// A private value known to this party.
Private,
}

/// Configuration of a value
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub enum ValueConfig {
/// A value known to all parties
Public {
value_ref: ValueRef,
ty: ValueType,
value: Value,
},
/// A private value
Private {
value_ref: ValueRef,
ty: ValueType,
value: Option<Value>,
},
}

/// Configuration of a value
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub enum ValueIdConfig {
/// A value known to all parties
Public {
id: ValueId,
ty: ValueType,
value: Value,
},
/// A private value
Private {
id: ValueId,
ty: ValueType,
value: Option<Value>,
},
}

impl ValueConfig {
/// Creates a new public value config
pub fn new_public<T: StaticValueType>(
value_ref: ValueRef,
value: impl Into<Value>,
) -> Result<Self, ValueConfigError> {
let value = value.into();
let ty = value.value_type();
Self::new(value_ref, ty, Some(value), Visibility::Public)
}

/// Creates a new public array value config
pub fn new_public_array<T: StaticValueType>(
value_ref: ValueRef,
value: Vec<T>,
) -> Result<Self, ValueConfigError>
where
Vec<T>: Into<Value>,
{
let value = value.into();
let ty = value.value_type();
Self::new(value_ref, ty, Some(value), Visibility::Public)
}

/// Creates a new private value config
pub fn new_private<T: StaticValueType>(
value_ref: ValueRef,
value: Option<T>,
) -> Result<Self, ValueConfigError> {
let ty = T::value_type();
let value = value.map(|value| value.into());
Self::new(value_ref, ty, value, Visibility::Private)
}

/// Creates a new private array value config
pub fn new_private_array<T: StaticValueType>(
value_ref: ValueRef,
value: Option<Vec<T>>,
len: usize,
) -> Result<Self, ValueConfigError>
where
Vec<T>: Into<Value>,
{
let ty = ValueType::new_array::<T>(len);
let value = value.map(|value| value.into());
Self::new(value_ref, ty, value, Visibility::Private)
}

/// Creates a new value config
pub(crate) fn new(
value_ref: ValueRef,
ty: ValueType,
value: Option<Value>,
visibility: Visibility,
) -> Result<Self, ValueConfigError> {
// invariants:
// - public values are always set
// - types and lengths are consistent across `value_ref`, `ty`, and `value`
//
// the outer context must ensure that the provided `ty` is correct for the
// provided `value_ref`.
let is_ok = if !value_ref.is_array() && !ty.is_array() {
true
} else if let (ValueRef::Array(ids), ValueType::Array(_, len)) = (&value_ref, &ty) {
ids.len() == *len
} else {
false
};

match visibility {
Visibility::Public if is_ok && value.is_some() => Ok(Self::Public {
value_ref,
ty,
value: value.unwrap(),
}),
Visibility::Private if is_ok => Ok(Self::Private {
value_ref,
ty,
value,
}),
_ => Err(ValueConfigError {
value_ref,
ty,
value,
visibility,
}),
}
}

/// Flattens to a vector of `ValueIdConfig`
pub fn flatten(self) -> Vec<ValueIdConfig> {
match self {
ValueConfig::Public {
value_ref,
ty,
value,
} => match value_ref {
ValueRef::Value { id } => {
vec![ValueIdConfig::Public { id, ty, value }]
}
ValueRef::Array(ids) => {
let ValueType::Array(elem_ty, _) = ty else {
panic!("expected array type");
};

let elem_ty = *elem_ty;

let Value::Array(value) = value else {
panic!("expected array value");
};

ids.into_iter()
.zip(value)
.map(|(id, value)| ValueIdConfig::Public {
id,
ty: elem_ty.clone(),
value,
})
.collect()
}
},
ValueConfig::Private {
value_ref,
ty,
value,
} => match value_ref {
ValueRef::Value { id } => {
vec![ValueIdConfig::Private { id, ty, value }]
}
ValueRef::Array(ids) => {
let ValueType::Array(elem_ty, _) = ty else {
panic!("expected array type");
};

let elem_ty = *elem_ty;

let values = if let Some(value) = value {
let Value::Array(value) = value else {
panic!("expected array value");
};

value.into_iter().map(Option::Some).collect()
} else {
vec![None; ids.len()]
};

ids.into_iter()
.zip(values)
.map(|(id, value)| ValueIdConfig::Private {
id,
ty: elem_ty.clone(),
value,
})
.collect()
}
},
}
}
}

impl ValueIdConfig {
/// Returns the ID of the value
pub(crate) fn id(&self) -> &ValueId {
match self {
ValueIdConfig::Public { id, .. } => id,
ValueIdConfig::Private { id, .. } => id,
}
}
/// A private value not known to this party.
Blind,
}
4 changes: 2 additions & 2 deletions garble/mpz-garble/src/evaluator/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use mpz_core::value::{ValueId, ValueRef};
use crate::value::{ValueId, ValueRef};

/// Errors that can occur while performing the role of an evaluator
#[derive(Debug, thiserror::Error)]
Expand All @@ -18,7 +18,7 @@ pub enum EvaluatorError {
#[error(transparent)]
ValueError(#[from] mpz_garble_core::ValueError),
#[error(transparent)]
EncodingRegistryError(#[from] crate::registry::EncodingRegistryError),
EncodingRegistryError(#[from] crate::memory::EncodingMemoryError),
#[error("missing active encoding for value")]
MissingEncoding(ValueRef),
#[error("duplicate decoding for value: {0:?}")]
Expand Down
Loading

0 comments on commit 5171baa

Please sign in to comment.