Redesign mpc-garble (#220)

* mpc-garble

* move semihonest test to integration, expose some more types

* value config doc

* reenable all mpc crates

* rename msg type

* simplify config a bit

* typo

* add bound to StaticValueType

* clean up setup_inputs

* appease clippy

* add more flexible methods to memory trait

* add getter for value type

* comments and tweaks

* rename append -> append_string

* fix registry corruption

* drain filter

* finalize bug

* use matches!

* use as_ref

* remove default

* make decode public

* lower visibility for evaluator fn

* eval doc fix

* update buffering to be per value id

* input buffer methods

* move memory impl into separate module

* encapsulate finalized state

* flatten logic in value config

* fixes in utils

* docs
This commit is contained in:
sinu.eth
2023-05-08 08:48:18 -07:00
parent 4b081ca915
commit 949e3ff84e
3 changed files with 242 additions and 1 deletions

166
utils/utils/src/id.rs Normal file
View File

@@ -0,0 +1,166 @@
use std::sync::Arc;
/// A nested ID.
///
/// # Example
///
/// ```
/// # use utils::id::NestedId;
/// let id = NestedId::new("foo");
/// let id = id.append_string("bar");
/// assert_eq!(id.to_string(), "foo/bar");
/// let mut id = id.append_counter();
/// assert_eq!(id.to_string(), "foo/bar/0");
/// let new_id = id.increment();
/// assert_eq!(new_id.to_string(), "foo/bar/1");
/// assert!(new_id > id);
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum NestedId {
String {
id: String,
root: Option<Arc<NestedId>>,
},
Counter {
value: usize,
root: Option<Arc<NestedId>>,
},
}
impl NestedId {
/// Create a new nested ID.
pub fn new(id: &str) -> Self {
NestedId::String {
id: id.to_string(),
root: None,
}
}
/// Returns the root of this ID.
pub fn root(&self) -> Option<&NestedId> {
match self {
NestedId::String { root, .. } => root,
NestedId::Counter { root, .. } => root,
}
.as_ref()
.map(|id| id.as_ref())
}
/// Returns whether this ID is a counter ID.
pub fn is_counter(&self) -> bool {
match self {
NestedId::String { .. } => false,
NestedId::Counter { .. } => true,
}
}
/// Returns whether this ID is a string ID.
pub fn is_string(&self) -> bool {
!self.is_counter()
}
/// Creates a new ID with `self` as the root.
pub fn append_string(&self, id: &str) -> NestedId {
Self::String {
id: id.to_string(),
root: Some(Arc::new(self.clone())),
}
}
/// Creates a new counter ID with `self` as the root.
pub fn append_counter(&self) -> NestedId {
Self::Counter {
value: 0,
root: Some(Arc::new(self.clone())),
}
}
/// Returns a new ID with the counter incremented.
///
/// # Panics
///
/// Panics if this ID is not a counter ID.
pub fn increment(&self) -> Self {
let mut id = self.clone();
id.increment_in_place();
id
}
/// Increments the counter of this ID, returning the previous value.
///
/// # Panics
///
/// Panics if this ID is not a counter ID.
pub fn increment_in_place(&mut self) -> Self {
let prev = self.clone();
match self {
NestedId::String { .. } => panic!("cannot increment a string ID"),
NestedId::Counter { value, .. } => *value += 1,
}
prev
}
}
impl ToString for NestedId {
fn to_string(&self) -> String {
match self {
NestedId::String { id, root } => match root {
Some(root) => format!("{}/{}", root.to_string(), id),
None => id.to_string(),
},
NestedId::Counter { value, root } => match root {
Some(root) => format!("{}/{}", root.to_string(), value),
None => value.to_string(),
},
}
}
}
impl PartialOrd for NestedId {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.to_string().cmp(&other.to_string()))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_nested_id() {
let id = NestedId::new("foo");
assert_eq!(id.to_string(), "foo");
assert_eq!(id.root(), None);
let id = id.append_string("bar");
assert_eq!(id.to_string(), "foo/bar");
assert_eq!(id.root().unwrap().to_string(), "foo");
assert!(id.is_string());
let id = id.append_string("baz");
assert_eq!(id.to_string(), "foo/bar/baz");
assert_eq!(id.root().unwrap().to_string(), "foo/bar");
assert!(id.is_string());
let mut id = id.append_counter();
assert_eq!(id.to_string(), "foo/bar/baz/0");
assert_eq!(id.root().unwrap().to_string(), "foo/bar/baz");
assert!(id.is_counter());
id.increment_in_place();
assert_eq!(id.to_string(), "foo/bar/baz/1");
assert_eq!(id.root().unwrap().to_string(), "foo/bar/baz");
assert!(id.is_counter());
let new_id = id.increment();
assert_eq!(new_id.to_string(), "foo/bar/baz/2");
assert_eq!(new_id.root().unwrap().to_string(), "foo/bar/baz");
assert!(new_id.is_counter());
assert!(new_id > id);
let root = id.root().unwrap().root().unwrap().root().unwrap();
assert_eq!(root.to_string(), "foo");
}
}

View File

@@ -93,6 +93,68 @@ where
{
}
pub struct FilterDrainIter<'a, F, T> {
vec: &'a mut Vec<T>,
pos: usize,
pred: F,
}
impl<'a, F, T> Iterator for FilterDrainIter<'a, F, T>
where
F: Fn(&T) -> bool,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.pos >= self.vec.len() {
return None;
}
if (self.pred)(&self.vec[self.pos]) {
Some(self.vec.swap_remove(self.pos))
} else {
self.pos += 1;
self.next()
}
}
}
/// Helper trait that implements `drain_filter` which is not stable yet.
///
/// See [tracking issue](https://github.com/rust-lang/rust/issues/43244)
///
/// We call this `FilterDrain` to avoid the naming conflict with the standard library.
///
/// # Note
///
/// The order of the elements is not preserved.
pub trait FilterDrain<'a, F, T>
where
F: Fn(&T) -> bool,
{
type Item;
type Iter: Iterator<Item = Self::Item> + 'a;
fn filter_drain(&'a mut self, pred: F) -> Self::Iter;
}
impl<'a, F, T> FilterDrain<'a, F, T> for Vec<T>
where
F: Fn(&T) -> bool + 'a,
T: 'a,
{
type Item = T;
type Iter = FilterDrainIter<'a, F, T>;
fn filter_drain(&'a mut self, pred: F) -> FilterDrainIter<'a, F, T> {
FilterDrainIter {
vec: self,
pos: 0,
pred,
}
}
}
#[cfg(test)]
mod test {
use super::*;
@@ -100,11 +162,23 @@ mod test {
struct Container<T>(T);
impl<T> Container<T> {
fn get<'a>(&'a self) -> &'a T {
fn get(&self) -> &T {
&self.0
}
}
#[test]
fn test_filter_drain() {
let mut v = vec![1, 2, 3, 4, 5, 6, 7, 8];
let mut even = v.filter_drain(|x| *x % 2 == 0).collect::<Vec<_>>();
v.sort();
even.sort();
assert_eq!(even, vec![2, 4, 6, 8]);
assert_eq!(v, vec![1, 3, 5, 7]);
}
#[test]
fn duplicate_check_contains_dups() {
let x = [0, 1, 1];

View File

@@ -1,2 +1,3 @@
pub mod bits;
pub mod id;
pub mod iter;