-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #22 from alexandrainst/typed-verification
Typed Verification
- Loading branch information
Showing
15 changed files
with
622 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
use crate::net::Communicate; | ||
use std::{ | ||
collections::BTreeMap, | ||
ops::AsyncFn, | ||
sync::{ | ||
atomic::{AtomicU32, Ordering::SeqCst}, | ||
Mutex, | ||
}, | ||
}; | ||
#[derive(Clone)] | ||
pub enum Status<T> { | ||
Verified, | ||
Unverified { | ||
parents: (u32, u32), | ||
data: Option<T>, | ||
}, | ||
Failure, | ||
} | ||
|
||
pub struct ExpTree<T> { | ||
tree: Mutex<BTreeMap<u32, Status<T>>>, | ||
issuer: AtomicU32, | ||
} | ||
|
||
impl<T: Clone> ExpTree<T> { | ||
fn issue(&self) -> u32 { | ||
let curr = self.issuer.fetch_update(SeqCst, SeqCst, |n| Some(n + 1)); | ||
curr.expect("Never fails since lambda always returns Some") | ||
} | ||
|
||
pub fn add_dependent(&self, a: u32, b: u32) -> u32 { | ||
let new = self.issue(); | ||
let status: Status<T> = Status::Unverified { | ||
parents: (a, b), | ||
data: None, | ||
}; | ||
{ | ||
let mut tree = self.tree.lock().unwrap(); | ||
tree.insert(new, status); | ||
} | ||
new | ||
} | ||
|
||
pub fn add_dependent_with(&self, a: u32, b: u32, data: T) -> u32 { | ||
let new = self.issue(); | ||
let data = Some(data); | ||
let status = Status::Unverified { | ||
parents: (a, b), | ||
data, | ||
}; | ||
{ | ||
let mut tree = self.tree.lock().unwrap(); | ||
tree.insert(new, status); | ||
} | ||
new | ||
} | ||
|
||
pub fn add_root(&self) -> u32 { | ||
let new = self.issue(); | ||
let status = Status::Verified; | ||
{ | ||
let mut tree = self.tree.lock().unwrap(); | ||
tree.insert(new, status); | ||
} | ||
new | ||
} | ||
|
||
pub async fn verify<F, C>(&mut self, id: u32, verify_fn: F, coms: C) -> Option<bool> | ||
where | ||
F: AsyncFn(Vec<T>, C) -> Option<bool>, | ||
C: Communicate, | ||
{ | ||
let mut to_check = vec![]; | ||
let mut datas: Vec<T> = vec![]; | ||
let mut checking = vec![]; | ||
checking.push(id); | ||
|
||
let tree = self.tree.get_mut().unwrap(); | ||
|
||
while let Some(id) = checking.pop() { | ||
let t = tree.get(&id)?; | ||
match t { | ||
Status::Failure => todo!("Taint dependent values -or- crash and burn"), | ||
Status::Verified => (), | ||
Status::Unverified { parents, data } => { | ||
checking.push(parents.0); | ||
checking.push(parents.1); | ||
if let Some(data) = data { | ||
datas.push(data.clone()); | ||
} | ||
to_check.push(id); | ||
} | ||
} | ||
} | ||
|
||
let res = verify_fn.async_call((datas, coms)).await?; | ||
let status = if res { | ||
Status::Verified | ||
} else { | ||
Status::Failure | ||
}; | ||
|
||
for id in to_check { | ||
tree.insert(id, status.clone()); | ||
} | ||
|
||
Some(res) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
mod exptree; | ||
|
||
use rand::RngCore; | ||
use serde::{de::DeserializeOwned, Deserialize, Serialize}; | ||
|
||
use crate::{ | ||
net::Communicate, | ||
schemes::{interactive::InteractiveShared, Shared, Verify}, | ||
}; | ||
|
||
#[repr(transparent)] | ||
#[derive(Serialize, Debug, Clone)] | ||
pub struct Verified<S>(S); | ||
|
||
#[repr(transparent)] | ||
#[derive(Serialize, Debug, Clone)] | ||
pub struct Unverified<S>(S); | ||
|
||
impl<'de, S: Shared + DeserializeOwned> Deserialize<'de> for Unverified<S> { | ||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | ||
where | ||
D: serde::Deserializer<'de>, | ||
{ | ||
Deserialize::deserialize(deserializer).map(|s| Unverified(s)) | ||
} | ||
} | ||
|
||
impl<S: Verify> Unverified<S> { | ||
pub async fn verify(self, coms: impl Communicate, args: S::Args) -> Option<Verified<S>> { | ||
if self.0.verify(coms, args).await { | ||
Some(Verified(self.0)) | ||
} else { | ||
None | ||
} | ||
} | ||
} | ||
|
||
impl<S> Unverified<S> { | ||
pub fn assume_verified(self) -> Verified<S> { | ||
Verified(self.0) | ||
} | ||
} | ||
|
||
impl<S: InteractiveShared> Verified<S> { | ||
pub async fn open( | ||
self, | ||
ctx: &S::Context, | ||
coms: impl Communicate, | ||
) -> Result<S::Value, S::Error> { | ||
S::recombine(ctx, self.0, coms).await | ||
} | ||
|
||
pub async fn share( | ||
val: S::Value, | ||
ctx: &S::Context, | ||
rng: impl RngCore + Send, | ||
coms: impl Communicate, | ||
) -> Result<Self, S::Error> { | ||
let s = S::share(ctx, val, rng, coms).await?; | ||
Ok(Self(s)) | ||
} | ||
} | ||
|
||
impl<S: InteractiveShared> Unverified<S> { | ||
pub async fn share_symmetric( | ||
val: S::Value, | ||
ctx: &S::Context, | ||
rng: impl RngCore + Send, | ||
coms: impl Communicate, | ||
) -> Result<Vec<Self>, S::Error> { | ||
let s = S::symmetric_share(ctx, val, rng, coms).await?; | ||
Ok(s.into_iter().map(Self).collect()) | ||
} | ||
|
||
pub async fn receive_share( | ||
ctx: &S::Context, | ||
coms: impl Communicate, | ||
from: usize, | ||
) -> Result<Self, S::Error> { | ||
let s = S::receive_share(ctx, coms, from).await?; | ||
Ok(Self(s)) | ||
} | ||
} | ||
|
||
impl<T> From<Unverified<Vec<T>>> for Vec<Unverified<T>> { | ||
fn from(value: Unverified<Vec<T>>) -> Self { | ||
value.0.into_iter().map(|t| Unverified(t)).collect() | ||
} | ||
} | ||
|
||
impl<T> From<Verified<Vec<T>>> for Vec<Verified<T>> { | ||
fn from(value: Verified<Vec<T>>) -> Self { | ||
value.0.into_iter().map(|t| Verified(t)).collect() | ||
} | ||
} | ||
|
||
impl<S: Verify> Unverified<Vec<S>> { | ||
pub async fn verify_all( | ||
self, | ||
coms: impl Communicate, | ||
args: S::Args, | ||
) -> Verified<Vec<Option<S>>> { | ||
let res = S::verify_many(&self.0, coms, args).await; | ||
let res = res | ||
.into_iter() | ||
.zip(self.0) | ||
.map(|(verified, t)| verified.then_some(t)) | ||
.collect(); | ||
Verified(res) | ||
} | ||
} | ||
|
||
// Pure boring manual operator implementations | ||
// Could be done with some macros instead. | ||
mod ops { | ||
use crate::schemes::Shared; | ||
use std::ops::{Add, Mul, Sub}; | ||
|
||
use super::*; | ||
|
||
impl<S: Shared> Add for Verified<S> { | ||
type Output = Self; | ||
|
||
fn add(self, rhs: Self) -> Self::Output { | ||
Self(self.0 + rhs.0) | ||
} | ||
} | ||
|
||
impl<S: Shared> Sub for Verified<S> { | ||
type Output = Self; | ||
|
||
fn sub(self, rhs: Self) -> Self::Output { | ||
Self(self.0 - rhs.0) | ||
} | ||
} | ||
|
||
impl<S: Shared> Add<Unverified<S>> for Verified<S> { | ||
type Output = Unverified<S>; | ||
|
||
fn add(self, rhs: Unverified<S>) -> Self::Output { | ||
Unverified(self.0 + rhs.0) | ||
} | ||
} | ||
|
||
impl<S: Shared> Sub<Unverified<S>> for Verified<S> { | ||
type Output = Unverified<S>; | ||
|
||
fn sub(self, rhs: Unverified<S>) -> Self::Output { | ||
Unverified(self.0 - rhs.0) | ||
} | ||
} | ||
|
||
impl<S: Shared> Add for Unverified<S> { | ||
type Output = Self; | ||
|
||
fn add(self, rhs: Self) -> Self::Output { | ||
Self(self.0 + rhs.0) | ||
} | ||
} | ||
|
||
impl<S: Shared> Sub for Unverified<S> { | ||
type Output = Self; | ||
|
||
fn sub(self, rhs: Self) -> Self::Output { | ||
Self(self.0 - rhs.0) | ||
} | ||
} | ||
|
||
impl<S: Shared> Mul<S::Value> for Verified<S> | ||
where | ||
S: Mul<S::Value, Output = S>, | ||
{ | ||
type Output = Self; | ||
|
||
fn mul(self, rhs: S::Value) -> Self::Output { | ||
Self(self.0 * rhs) | ||
} | ||
} | ||
|
||
impl<S: Shared> Mul<S::Value> for Unverified<S> | ||
where | ||
S: Mul<S::Value, Output = S>, | ||
{ | ||
type Output = Self; | ||
|
||
fn mul(self, rhs: S::Value) -> Self::Output { | ||
Self(self.0 * rhs) | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use super::*; | ||
|
||
use rand::rngs; | ||
|
||
use crate::{ | ||
algebra::element::Mod11, | ||
testing::mock::{self, Share}, | ||
}; | ||
|
||
#[test] | ||
fn serdede() { | ||
let ctx = mock::Context { | ||
all_parties: 1, | ||
me: 0, | ||
}; | ||
let mut rng = rngs::mock::StepRng::new(0, 0); | ||
let s = <mock::Share<Mod11> as Shared>::share(&ctx, Mod11(3), &mut rng); | ||
let s = Verified(s[0]); | ||
let s0 = s.clone(); | ||
let s = s0 + s; | ||
|
||
let to_send = bincode::serialize(&s).unwrap(); | ||
// sending... | ||
let back_again: Unverified<Share<Mod11>> = bincode::deserialize(&to_send).unwrap(); | ||
|
||
println!("Hello again {back_again:?}"); | ||
} | ||
} |
Oops, something went wrong.