diff --git a/Cargo.lock b/Cargo.lock index 36c795a..65b878d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -225,6 +225,7 @@ dependencies = [ "rand_chacha", "rayon", "serde", + "serde_json", "sha2", "tempfile", "thiserror", @@ -672,6 +673,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "lazy_static" version = "1.4.0" @@ -1058,6 +1065,12 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + [[package]] name = "scoped-tls" version = "1.0.1" @@ -1096,6 +1109,18 @@ dependencies = [ "syn 2.0.59", ] +[[package]] +name = "serde_json" +version = "1.0.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + [[package]] name = "sha2" version = "0.10.8" diff --git a/Cargo.toml b/Cargo.toml index a61037d..6052155 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ tokio-util = { version = "0.7.9", features = ["io", "net", "io-util", "codec", " tracing = "0.1.40" [dev-dependencies] +serde_json = "1.0.121" tempfile = "3.10.1" tokio-test = "0.4.4" curve25519-dalek = { version = "4.1.3", features = ["group", "serde"] } @@ -38,6 +39,7 @@ sha2 = "0.10.8" [features] rayon = [] +test = [] [profile.release] lto = true diff --git a/pycare/Cargo.lock b/pycare/Cargo.lock index daf4bc3..869d4d8 100644 --- a/pycare/Cargo.lock +++ b/pycare/Cargo.lock @@ -408,9 +408,9 @@ checksum = "c007b1ae3abe1cb6f85a16305acd418b7ca6343b953633fee2b76d8f108b830f" [[package]] name = "fixed" -version = "2.0.0-alpha.27.0" +version = "2.0.0-alpha.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1bf398c70463a217e213bc751669e4c8509c5676df2444d7a5177722f8ddeaa" +checksum = "8276713fe97d959ae66a91bdac60a9a1b9e39d25513ccca4555fe1cf2571567f" dependencies = [ "az", "bytemuck", @@ -614,9 +614,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -895,15 +895,15 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.21.2" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e00b96a521718e08e03b1a622f01c8a8deb50719335de3f60b3b3950f069d8" +checksum = "831e8e819a138c36e212f3af3fd9eeffed6bf1510a805af35b0edee5ffa59433" dependencies = [ "cfg-if", "indoc", "libc", "memoffset", - "parking_lot", + "once_cell", "portable-atomic", "pyo3-build-config", "pyo3-ffi", @@ -913,9 +913,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.21.2" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7883df5835fafdad87c0d888b266c8ec0f4c9ca48a5bed6bbb592e8dedee1b50" +checksum = "1e8730e591b14492a8945cdff32f089250b05f5accecf74aeddf9e8272ce1fa8" dependencies = [ "once_cell", "python3-dll-a", @@ -924,9 +924,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.21.2" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01be5843dc60b916ab4dad1dca6d20b9b4e6ddc8e15f50c47fe6d85f1fb97403" +checksum = "5e97e919d2df92eb88ca80a037969f44e5e70356559654962cbb3316d00300c6" dependencies = [ "libc", "pyo3-build-config", @@ -934,9 +934,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.21.2" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77b34069fc0682e11b31dbd10321cbf94808394c56fd996796ce45217dfac53c" +checksum = "eb57983022ad41f9e683a599f2fd13c3664d7063a3ac5714cae4b7bee7d3f206" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -946,9 +946,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.21.2" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08260721f32db5e1a5beae69a55553f56b99bd0e1c3e6e0a5e8851a9d0f5a85c" +checksum = "ec480c0c51ddec81019531705acac51bcdbeae563557c982aa8263bb96880372" dependencies = [ "heck", "proc-macro2", @@ -1424,8 +1424,10 @@ name = "wecare" version = "0.1.0" dependencies = [ "caring", + "castaway", "curve25519-dalek", "enum_dispatch", + "ff", "fixed", "rand", "tokio", diff --git a/pycare/Cargo.toml b/pycare/Cargo.toml index 2da0a53..c93c2a4 100644 --- a/pycare/Cargo.toml +++ b/pycare/Cargo.toml @@ -9,5 +9,5 @@ name = "caring" crate-type = ["cdylib"] [dependencies] -pyo3 = { version = "0.21", features = ["abi3-py37", "generate-import-lib", "extension-module"]} +pyo3 = { version = "0.22", features = ["abi3-py37", "generate-import-lib", "extension-module"]} wecare = { path = "../wecare" } diff --git a/pycare/caring.pyi b/pycare/caring.pyi index 124df1c..6edbfeb 100644 --- a/pycare/caring.pyi +++ b/pycare/caring.pyi @@ -1,4 +1,58 @@ +# TODO: Add documentation + +class Id: + ... + +class Opened: + ... + +class Computed: + def as_float(self) -> list[float]: ... + def as_integer(self) -> list[int]: ... + + +class Expr: + @staticmethod + def share(num: float | int | list[float] | list[int]) -> Expr: ... + + @staticmethod + def recv(id: Id) -> Expr: ... + + @staticmethod + def symmetric_share(num: float | int | list[float] | list[int], id: Id, size: int) -> list[Expr]: ... + + def open(self) -> Opened: ... + + def __add__(self, other: Expr) -> Expr: ... + def __sub__(self, other: Expr) -> Expr: ... + def __mul__(self, other: Expr) -> Expr: ... + def __iadd__(self, other: Expr) -> None: ... + def __isub__(self, other: Expr) -> None: ... + def __imul__(self, other: Expr) -> None: ... + class Engine: + def __init__( + self, + scheme: str, + address: str, + peers: list[str], + multithreaded: bool = False, + threshold: int | None = None, + preprocessed: str | None = None, + ) -> None: ... + + def execute(self, script: Opened) -> Computed: ... + + def id(self) -> Id: ... + + def peers(self) -> list[Id]: ... + + +# +# Old stuff +# + +class OldEngine: """ Performs a summation with the connected parties. Returns the sum of all the numbers. @@ -18,7 +72,7 @@ class Engine: """ Takedown the MPC Engine, releasing the resources and dropping connections. """ - def takedown(self): ... + def takedown(self) -> None: ... """ diff --git a/pycare/examples/vm1.py b/pycare/examples/vm1.py new file mode 100644 index 0000000..e9d9518 --- /dev/null +++ b/pycare/examples/vm1.py @@ -0,0 +1,13 @@ +from caring import Expr, Engine + +engine = Engine(scheme="shamir-25519", address="localhost:1234", peers=["localhost:1235"], threshold=1) + +[a, b] = Expr.symmetric_share(23, id=engine.id(), size=2) + +c = a + b; + +script = c.open() + +res = engine.execute(script).as_float() + +print(res) diff --git a/pycare/examples/vm2.py b/pycare/examples/vm2.py new file mode 100644 index 0000000..0d48653 --- /dev/null +++ b/pycare/examples/vm2.py @@ -0,0 +1,13 @@ +from caring import Expr, Engine + +engine = Engine(scheme="shamir-25519", address="localhost:1235", peers=["localhost:1234"], threshold=1) + +[a, b] = Expr.symmetric_share(7, id=engine.id(), size=2) + +c = a + b; + +script = c.open() + +res = engine.execute(script).as_float() + +print(res) diff --git a/pycare/src/expr.rs b/pycare/src/expr.rs new file mode 100644 index 0000000..ef1dd6a --- /dev/null +++ b/pycare/src/expr.rs @@ -0,0 +1,106 @@ +use pyo3::{exceptions::PyTypeError, prelude::*}; +use wecare::vm; + +#[pyclass] +pub struct Expr(vm::Expr); + +#[pyclass(frozen)] +pub struct Opened(pub(crate) vm::Opened); + +#[pyclass(frozen)] +#[derive(Debug, Clone, Copy)] +pub struct Id(pub(crate) vm::Id); + +#[pymethods] +impl Expr { + /// Construct a new share expression + #[staticmethod] + fn share(num: &Bound<'_, PyAny>) -> PyResult { + let res = if let Ok(num) = num.extract::() { + let num = vm::Number::Float(num); + vm::Expr::share(num) + } else if let Ok(num) = num.extract::() { + // TODO: Consider signedness + let num = vm::Number::Integer(num); + vm::Expr::share(num) + } else if let Ok(num) = num.extract::>() { + let num: Vec<_> = num.into_iter().map(vm::Number::Float).collect(); + vm::Expr::share_vec(num) + } else if let Ok(num) = num.extract::>() { + // TODO: Consider signedness + let num: Vec<_> = num.into_iter().map(vm::Number::Integer).collect(); + vm::Expr::share_vec(num) + } else { + return Err(PyTypeError::new_err("num is not a number")); + }; + Ok(Self(res)) + } + + #[staticmethod] + fn symmetric_share(num: &Bound<'_, PyAny>, id: Id, size: usize) -> PyResult> { + let res = if let Ok(num) = num.extract::() { + let num = vm::Number::Float(num); + vm::Expr::symmetric_share(num) + } else if let Ok(num) = num.extract::() { + // TODO: Consider signedness + let num = vm::Number::Integer(num); + vm::Expr::symmetric_share(num) + } else if let Ok(num) = num.extract::>() { + let num: Vec<_> = num.into_iter().map(vm::Number::Float).collect(); + vm::Expr::symmetric_share_vec(num) + } else if let Ok(num) = num.extract::>() { + // TODO: Consider signedness + let num: Vec<_> = num.into_iter().map(vm::Number::Integer).collect(); + vm::Expr::symmetric_share_vec(num) + } else { + return Err(PyTypeError::new_err("num is not a number")); + }; + + let res = res.concrete(id.0 .0, size); + let res = res.into_iter().map(Expr).collect(); + Ok(res) + } + + /// recv from a given party + #[staticmethod] + fn recv(id: &Id) -> Self { + Self(vm::Expr::receive_input(id.0)) + } + + fn open(&self) -> Opened { + Opened(self.0.clone().open()) + } + + fn __iadd__(&mut self, other: &Self) { + let rhs: vm::Expr = other.0.clone(); + self.0 += rhs; + } + + fn __add__(&self, other: &Self) -> Self { + let lhs: vm::Expr = self.0.clone(); + let rhs: vm::Expr = other.0.clone(); + Self(lhs + rhs) + } + + fn __sub__(&self, other: &Self) -> Self { + let lhs: vm::Expr = self.0.clone(); + let rhs: vm::Expr = other.0.clone(); + Self(lhs - rhs) + } + + fn __isub__(&mut self, other: &Self) { + let rhs: vm::Expr = other.0.clone(); + self.0 -= rhs; + } + + fn __mul__(&self, other: &Self) -> Self { + let lhs: vm::Expr = self.0.clone(); + let rhs: vm::Expr = other.0.clone(); + Self(lhs * rhs) + } + + fn __imul__(&mut self, other: &Self) { + let rhs: vm::Expr = other.0.clone(); + self.0 *= rhs; + } +} diff --git a/pycare/src/lib.rs b/pycare/src/lib.rs index 0356ce2..33623da 100644 --- a/pycare/src/lib.rs +++ b/pycare/src/lib.rs @@ -1,15 +1,18 @@ use pyo3::{exceptions::PyIOError, prelude::*, types::PyTuple}; +pub mod expr; +pub mod vm; + use std::fs::File; use wecare::*; #[pyclass] -struct Engine(Option); +struct OldEngine(Option); /// Setup a MPC addition engine connected to the given sockets using SPDZ. #[pyfunction] #[pyo3(signature = (path_to_pre, my_addr, *others))] -fn spdz(path_to_pre: &str, my_addr: &str, others: &Bound<'_, PyTuple>) -> PyResult { +fn spdz(path_to_pre: &str, my_addr: &str, others: &Bound<'_, PyTuple>) -> PyResult { let others: Vec<_> = others .iter() .map(|x| x.extract::().unwrap().clone()) @@ -18,17 +21,17 @@ fn spdz(path_to_pre: &str, my_addr: &str, others: &Bound<'_, PyTuple>) -> PyResu match wecare::Engine::setup(my_addr) .add_participants(&others) .file_to_preprocessed(&mut file) - .build_spdz() { - Ok(e) => Ok(Engine(Some(e))), + .build_spdz() + { + Ok(e) => Ok(OldEngine(Some(e))), Err(e) => Err(PyIOError::new_err(e.0)), } } - /// Setup a MPC addition engine connected to the given sockets using shamir secret sharing. #[pyfunction] #[pyo3(signature = (threshold, my_addr, *others))] -fn shamir(threshold: u32, my_addr: &str, others: &Bound<'_, PyTuple>) -> PyResult { +fn shamir(threshold: u32, my_addr: &str, others: &Bound<'_, PyTuple>) -> PyResult { let others: Vec<_> = others .iter() .map(|x| x.extract::().unwrap().clone()) @@ -36,17 +39,17 @@ fn shamir(threshold: u32, my_addr: &str, others: &Bound<'_, PyTuple>) -> PyResul match wecare::Engine::setup(my_addr) .add_participants(&others) .threshold(threshold as u64) - .build_shamir() { - Ok(e) => Ok(Engine(Some(e))), + .build_shamir() + { + Ok(e) => Ok(OldEngine(Some(e))), Err(e) => Err(PyIOError::new_err(e.0)), } } - /// Setup a MPC addition engine connected to the given sockets using shamir secret sharing. #[pyfunction] #[pyo3(signature = (threshold, my_addr, *others))] -fn feldman(threshold: u32, my_addr: &str, others: &Bound<'_, PyTuple>) -> PyResult { +fn feldman(threshold: u32, my_addr: &str, others: &Bound<'_, PyTuple>) -> PyResult { let others: Vec<_> = others .iter() .map(|x| x.extract::().unwrap().clone()) @@ -54,8 +57,9 @@ fn feldman(threshold: u32, my_addr: &str, others: &Bound<'_, PyTuple>) -> PyResu match wecare::Engine::setup(my_addr) .add_participants(&others) .threshold(threshold as u64) - .build_feldman() { - Ok(e) => Ok(Engine(Some(e))), + .build_feldman() + { + Ok(e) => Ok(OldEngine(Some(e))), Err(e) => Err(PyIOError::new_err(e.0)), } } @@ -69,11 +73,11 @@ fn preproc(number_of_shares: usize, paths_to_pre: &Bound<'_, PyTuple>) { .map(|x| x.extract::().unwrap()) .map(|p| File::create(p).unwrap()) .collect(); - do_preproc(&mut files, vec![number_of_shares, number_of_shares], false); + do_preproc(&mut files, &[number_of_shares, number_of_shares], false); } #[pymethods] -impl Engine { +impl OldEngine { /// Run a sum procedure in which each party supplies a double floating point fn sum(&mut self, a: f64) -> f64 { self.0.as_mut().unwrap().mpc_sum(&[a]).unwrap()[0] @@ -98,6 +102,11 @@ fn caring(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(shamir, m)?)?; m.add_function(wrap_pyfunction!(feldman, m)?)?; m.add_function(wrap_pyfunction!(preproc, m)?)?; - m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; Ok(()) } diff --git a/pycare/src/vm.rs b/pycare/src/vm.rs new file mode 100644 index 0000000..4b776a8 --- /dev/null +++ b/pycare/src/vm.rs @@ -0,0 +1,104 @@ +use std::sync::Mutex; + +use crate::expr::{Id, Opened}; +use pyo3::{exceptions::PyValueError, prelude::*, types::PyList}; +use wecare::vm; + +#[pyclass(frozen)] +pub struct Engine(Mutex); + +#[pyclass(frozen)] +pub struct Computed(vm::Value); + +#[pymethods] +impl Computed { + /// Parse the computed result as a float + fn as_float(&self) -> Vec { + self.0.clone().map(|s| s.to_f64()).to_vec() + } + + /// Parse the computed result as an integer + fn as_integer(&self) -> Vec { + self.0.clone().map(|s| s.to_u64()).to_vec() + } +} + +#[pymethods] +impl Engine { + /// Construct a new engine connected to the other parties + /// + /// * `scheme`: one of {'spdz-25519', 'shamir-25519', 'feldman-25519', 'spdz-32', 'shamir-32'} + /// * `address`: the address to bind to + /// * `peers`: the adresses of the other peers to connect to + /// * `multithreaded`: use a multithreaded runtime + /// * `threshold`: (optional) threshold if using a threshold scheme + /// * `preprocessed`: (optional) path to preprocessed material + #[new] + #[pyo3(signature = (scheme, address, peers, multithreaded=false, threshold=None, preprocessed=None))] + fn new( + scheme: &str, + address: &str, + peers: &Bound<'_, PyList>, + multithreaded: bool, + threshold: Option, + preprocessed: Option<&str>, + ) -> PyResult { + let peers = peers.iter().map(|x| x.extract::().unwrap().clone()); + + let (scheme, field) = match scheme { + "spdz-25519" => (vm::SchemeKind::Spdz, vm::FieldKind::Curve25519), + "shamir-25519" => (vm::SchemeKind::Shamir, vm::FieldKind::Curve25519), + "feldman-25519" => (vm::SchemeKind::Shamir, vm::FieldKind::Curve25519), + "spdz-32" => (vm::SchemeKind::Spdz, vm::FieldKind::Element32), + "shamir-32" => (vm::SchemeKind::Shamir, vm::FieldKind::Element32), + _ => return Err(PyValueError::new_err("Unknown scheme")), + }; + + let builder = vm::Engine::builder() + .address(address) + .participants_from(peers) + .scheme(scheme) + .field(field); + + let builder = builder.threshold(threshold.unwrap_or_default()); + let builder = match preprocessed { + Some(path) => { + let file = std::fs::File::open(path)?; + builder.preprocessed(file) + } + None => builder, + }; + + let builder = if multithreaded { + builder.multi_threaded_runtime() + } else { + builder.single_threaded_runtime() + }; + + let builder = builder.connect_blocking().unwrap(); + let engine = builder.build(); + Ok(Self(Mutex::new(engine))) + } + + /// Execute a script + /// + /// * `script`: list of expressions to evaluate + fn execute(&self, script: &Opened) -> Computed { + let res = { + let mut engine = self.0.lock().expect("Lock poisoned"); + let script: vm::Opened = script.0.clone(); + engine.execute(script) + }; + Computed(res) + } + + /// Your own Id + fn id(&self) -> Id { + Id(self.0.lock().unwrap().id()) + } + + /// Your own Id + fn peers(&self) -> Vec { + self.0.lock().unwrap().peers().into_iter().map(Id).collect() + } +} diff --git a/rust-toolchain b/rust-toolchain index 1eb34f8..bc20060 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ # vim: ft=toml [toolchain] -channel = "nightly-2024-05-15" +channel = "nightly-2024-08-21" diff --git a/src/lib.rs b/src/lib.rs index 7971429..888fb78 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,17 +1,18 @@ #![deny(unsafe_code)] #![allow(refining_impl_trait)] #![allow(dead_code)] -#![feature(async_fn_traits)] #![allow(clippy::cast_possible_truncation)] +#![feature(async_fn_traits)] +#![feature(async_closure)] pub mod algebra; +mod help; +pub mod marker; pub mod net; pub mod ot; mod protocols; pub mod schemes; +pub mod vm; -mod help; -pub mod marker; - -#[cfg(test)] -mod testing; +#[cfg(any(test, feature = "test"))] +pub mod testing; diff --git a/src/marker/mod.rs b/src/marker/mod.rs index 6b03e13..e6afeed 100644 --- a/src/marker/mod.rs +++ b/src/marker/mod.rs @@ -6,7 +6,7 @@ use rand::RngCore; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use crate::{ - net::Communicate, + net::{Communicate, Id}, schemes::{interactive::InteractiveShared, Shared, Verify}, }; @@ -77,7 +77,7 @@ impl Unverified { pub async fn receive_share( ctx: &mut S::Context, coms: impl Communicate, - from: usize, + from: Id, ) -> Result { let s = S::receive_share(ctx, coms, from).await?; Ok(Self(s)) @@ -206,7 +206,7 @@ mod test { fn serdede() { let ctx = mock::Context { all_parties: 1, - me: 0, + me: Id(0), }; let mut rng = rngs::mock::StepRng::new(0, 0); let s = as Shared>::share(&ctx, Mod11(3), &mut rng); diff --git a/src/net/agency.rs b/src/net/agency.rs index d1ae6c2..889465e 100644 --- a/src/net/agency.rs +++ b/src/net/agency.rs @@ -59,7 +59,7 @@ pub trait Broadcast: Send { /// Returns: a message from the given party or an error fn recv_from( &mut self, - idx: usize, + id: Id, ) -> impl Future> + Send; /// Size of the broadcasting network including yourself, @@ -89,9 +89,9 @@ impl<'a, B: Broadcast> Broadcast for &'a mut B { fn recv_from( &mut self, - idx: usize, + id: Id, ) -> impl Future> + Send { - (**self).recv_from(idx) + (**self).recv_from(id) } fn size(&self) -> usize { @@ -176,6 +176,8 @@ impl<'a, U: Unicast> Unicast for &'a mut U { use digest::Digest; use tracing::{event, Level}; +use crate::net::Id; + pub struct VerifiedBroadcast(B, PhantomData); impl VerifiedBroadcast { @@ -292,7 +294,7 @@ impl VerifiedBroadcast { #[tracing::instrument(skip_all)] pub async fn recv_from( &mut self, - party: usize, + party: Id, ) -> Result> where T: serde::de::DeserializeOwned, @@ -369,9 +371,9 @@ impl Broadcast for VerifiedBroadcast { fn recv_from( &mut self, - idx: usize, + id: Id, ) -> impl Future> + Send { - self.recv_from(idx) + self.recv_from(id) } fn size(&self) -> usize { @@ -451,12 +453,12 @@ mod test { let t2 = async { let mut vb = VerifiedBroadcast::<_, sha2::Sha256>::new(n2); - let resp: String = vb.recv_from(0).await.unwrap(); + let resp: String = vb.recv_from(Id(0)).await.unwrap(); assert_eq!(resp, "Hello everyone!"); }; let t3 = async { let mut vb = VerifiedBroadcast::<_, sha2::Sha256>::new(n3); - let resp: String = vb.recv_from(0).await.unwrap(); + let resp: String = vb.recv_from(Id(0)).await.unwrap(); assert_eq!(resp, "Hello everyone!"); }; @@ -473,12 +475,12 @@ mod test { let t1 = async { let mut vb = VerifiedBroadcast::<_, sha2::Sha256>::new(n1); - vb.recv_from::(2).await + vb.recv_from::(Id(2)).await }; let t2 = async { let mut vb = VerifiedBroadcast::<_, sha2::Sha256>::new(n2); - vb.recv_from::(2).await + vb.recv_from::(Id(2)).await }; let t3 = async { let vb = VerifiedBroadcast::<_, sha2::Sha256>::new(n3); @@ -493,8 +495,8 @@ mod test { net.broadcast(&hash).await.unwrap(); net.symmetric_broadcast(hash).await.unwrap(); // fake broadcast - net.send_to(0, &s0).await.unwrap(); - net.send_to(1, &s1).await.unwrap(); + net.send_to(Id(0), &s0).await.unwrap(); + net.send_to(Id(1), &s1).await.unwrap(); let _ = net.symmetric_broadcast(true).await.unwrap(); }; diff --git a/src/net/connection.rs b/src/net/connection.rs index 41d3ffb..2721a5f 100644 --- a/src/net/connection.rs +++ b/src/net/connection.rs @@ -40,8 +40,8 @@ use crate::net::{ }; pub struct Connection { - sender: Sending, - receiver: Receiving, + pub(crate) sender: Sending, + pub(crate) receiver: Receiving, } #[derive(Error, Debug)] diff --git a/src/net/mod.rs b/src/net/mod.rs index c6ea036..3e35454 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -1,6 +1,6 @@ use std::{error::Error, future::Future}; -use serde::{de::DeserializeOwned, Serialize}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; use thiserror::Error; use tokio_util::bytes::{Bytes, BytesMut}; @@ -58,7 +58,7 @@ pub trait RecvBytes: Send { ) -> impl Future>> + Send { async { let msg = self.recv_bytes().await?; - bincode::deserialize(&msg).map_err(|e| ReceiverError::BadSerialization(e)) + bincode::deserialize(&msg).map_err(ReceiverError::BadSerialization) } } } @@ -99,20 +99,23 @@ impl<'a, C: SplitChannel> SplitChannel for &'a mut C { } } +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize, Deserialize)] +pub struct Id(pub usize); + /// Tune to a specific channel pub trait Tuneable { type TuningError: Error + Send + 'static; - fn id(&self) -> usize; + fn id(&self) -> Id; fn recv_from( &mut self, - idx: usize, + id: Id, ) -> impl Future> + Send; fn send_to( &mut self, - idx: usize, + id: Id, msg: &T, ) -> impl Future> + Send; } @@ -120,23 +123,23 @@ pub trait Tuneable { impl<'a, R: Tuneable + ?Sized> Tuneable for &'a mut R { type TuningError = R::TuningError; - fn id(&self) -> usize { + fn id(&self) -> Id { (**self).id() } fn recv_from( &mut self, - idx: usize, + id: Id, ) -> impl Future> + Send { - (**self).recv_from(idx) + (**self).recv_from(id) } fn send_to( &mut self, - idx: usize, + id: Id, msg: &T, ) -> impl Future> + Send { - (**self).send_to(idx, msg) + (**self).send_to(id, msg) } } diff --git a/src/net/network.rs b/src/net/network.rs index dd98691..d974ebb 100644 --- a/src/net/network.rs +++ b/src/net/network.rs @@ -1,4 +1,4 @@ -use crate::net::{Channel, Communicate, ReceiverError, RecvBytes, SendBytes}; +use crate::net::{Channel, Communicate, Id, ReceiverError, RecvBytes, SendBytes}; use std::{collections::BTreeMap, net::SocketAddr, ops::Range, time::Duration}; use futures::future::join_all; @@ -33,12 +33,13 @@ use crate::net::{ /// /// * `connections`: Connections, one for each peer, sorted by their index, skipping our own index. /// * `index`: My own index +#[derive(Debug)] pub struct Network { // NOTE: // We could also insert a 'fake' Connection into the set for the representation of ourselves. // However that is probably a less efficient, if nicer, abstraction. - pub(super) connections: Vec, - pub index: usize, + pub(crate) connections: Vec, + pub(crate) index: usize, } #[derive(thiserror::Error, Debug)] @@ -53,21 +54,50 @@ type NetResult = std::result::Result Network { - pub(crate) fn id_to_index(&self, index: usize) -> usize { + pub(crate) fn id_to_index(&self, Id(id): Id) -> usize { let n = self.connections.len() + 1; - if index < self.index { - index - } else if index == self.index { + if id < self.index { + id + } else if id == self.index { // You probably didn't mean to do that. - panic!("Trying to reference self connection, id = {index}") - } else if index < n { - index - 1 + panic!("Trying to reference self connection, id = {id}") + } else if id < n { + id - 1 } else { // Out of bounds - panic!("Only {n} in network, but referenced id = {index}") + panic!("Only {n} in network, but referenced id = {id}") } } + pub fn id(&self) -> Id { + Id(self.index) + } + + pub fn prev_neighbour(&self) -> Id { + let n = self.connections.len(); + Id((self.index + n - 1) % n) + } + + pub fn next_neighbour(&self) -> Id { + let n = self.connections.len(); + Id((self.index + n + 1) % n) + } + + pub fn peers(&self) -> Vec { + let n = self.connections.len(); + (0..=n) + .map(|i| Id(i)) + .filter(|id| *id != self.id()) + .collect_vec() + } + + /// Returns a range for representing the participants. + pub fn participants(&self) -> Range { + let n = self.connections.len() as u32; + let n = n + 1; // We need to count ourselves. + 0..n + } + /// Broadcast a message to all other parties. /// /// Asymmetric, non-waiting @@ -297,13 +327,6 @@ impl Network { Ok(()) } - /// Returns a range for representing the participants. - pub fn participants(&self) -> Range { - let n = self.connections.len() as u32; - let n = n + 1; // We need to count ourselves. - 0..n - } - async fn drop_party(_id: usize) -> Result<(), ()> { todo!("Initiate a drop vote"); } @@ -398,9 +421,9 @@ impl Broadcast for Network { fn recv_from( &mut self, - idx: usize, + id: Id, ) -> impl Future> + Send { - Tuneable::recv_from(self, idx) + Tuneable::recv_from(self, id) } fn size(&self) -> usize { @@ -411,15 +434,15 @@ impl Broadcast for Network { impl Tuneable for Network { type TuningError = NetworkError; - fn id(&self) -> usize { - self.index + fn id(&self) -> Id { + self.id() } async fn recv_from( &mut self, - idx: usize, + id: Id, ) -> Result { - let idx = self.id_to_index(idx); + let idx = self.id_to_index(id); self.connections[idx] .recv() .await @@ -431,10 +454,10 @@ impl Tuneable for Network { async fn send_to( &mut self, - idx: usize, + id: Id, msg: &T, ) -> Result<(), Self::TuningError> { - let idx = self.id_to_index(idx); + let idx = self.id_to_index(id); self.connections[idx] .send(msg) .await diff --git a/src/protocols/beaver.rs b/src/protocols/beaver.rs index e23a7c4..672783e 100644 --- a/src/protocols/beaver.rs +++ b/src/protocols/beaver.rs @@ -6,16 +6,19 @@ use rand::RngCore; use crate::{ algebra::field::Field, net::{agency::Broadcast, Communicate}, - schemes::{interactive::InteractiveShared, Shared}, + schemes::{ + interactive::{InteractiveShared, InteractiveSharedMany}, + Shared, + }, }; /// Beaver (Multiplication) Triple -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct BeaverTriple { pub shares: (S, S, S), } -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct BeaverPower { val: S, powers: Vec, @@ -135,26 +138,19 @@ pub async fn beaver_multiply_many< Some(zs) } -//pub async fn beaver_multiply_many2< -// C, -// F: Field, -// S: Shared + Copy + std::ops::Mul, -//>( -// ctx: &C, -// xs: &[S], -// ys: &[S], -// triples: &[BeaverTriple], -// agent: Network, -//) -> Option> { -// let n = xs.len(); -// let (gateway, mut muxes) = NetworkGateway::multiplex(agent, n); -// let iter = multizip((xs, ys, triples, muxes.iter_mut())).map(|(x, y, triple, net)| { -// beaver_multiply(ctx, *x, *y, triple.clone(), net) -// }); -// let zs : Option> = join_all(iter).await.into_iter().collect(); -// let _ = gateway.takedown().await; -// zs -//} +pub async fn beaver_multiply_vector< + C, + F: Field, + S: InteractiveSharedMany + std::ops::Mul, +>( + _ctx: &mut S::Context, + _x: S::VectorShare, + _y: S::VectorShare, + _triples: &[BeaverTriple], + _coms: impl Communicate, +) { + todo!() +} #[derive(Clone)] pub struct BeaverSquare { @@ -222,10 +218,27 @@ mod test { use super::*; use crate::{ algebra::element::Element32, - net::network::InMemoryNetwork, + net::{network::InMemoryNetwork, Id}, schemes::shamir::{self, ShamirParams}, + testing::mock, }; + #[test] + fn fake_shares() { + type Share = mock::Share; + let ctx = Share::new_context(Id(1), 3); + let mut rng = rand::rngs::mock::StepRng::new(7, 32); + let triples_set = BeaverTriple::::fake_many(&ctx, &mut rng, 7); + for (i, triples) in triples_set.into_iter().enumerate() { + for triple in triples { + let i = Id(i); + assert_eq!(triple.shares.0.issued_to, i); + assert_eq!(triple.shares.1.issued_to, i); + assert_eq!(triple.shares.2.issued_to, i); + } + } + } + #[tokio::test] async fn beaver_mult() { let mut rng = rand::rngs::mock::StepRng::new(0, 7); diff --git a/src/protocols/commitments.rs b/src/protocols/commitments.rs index 4117cc4..acecb32 100644 --- a/src/protocols/commitments.rs +++ b/src/protocols/commitments.rs @@ -6,6 +6,8 @@ use rand::Rng; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; +// TODO: refactor rng and bincode away + // TODO: Find a hashing algorithm of cryptograpic standart to use in commitments // TODO: Consider whether we need a "real" commitment scheme #[derive(PartialEq, serde::Serialize, serde::Deserialize)] diff --git a/src/protocols/voting.rs b/src/protocols/voting.rs index 1584c2f..0f168d1 100644 --- a/src/protocols/voting.rs +++ b/src/protocols/voting.rs @@ -2,12 +2,12 @@ use std::env::Args; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use crate::net::Communicate; +use crate::net::{Communicate, Id}; #[derive(Clone, Serialize, Deserialize)] pub struct Proposal { initative: T, - creator: usize, + creator: Id, } pub trait Initiative: Serialize + DeserializeOwned + Sync { diff --git a/src/schemes/feldman.rs b/src/schemes/feldman.rs index d504722..43f3e70 100644 --- a/src/schemes/feldman.rs +++ b/src/schemes/feldman.rs @@ -15,13 +15,16 @@ use std::{ borrow::Borrow, iter, - ops::{self, Mul}, + ops::{self, Mul, MulAssign}, }; use crate::{ algebra::math::Vector, net::agency::Unicast, - schemes::{shamir, SharedMany}, + schemes::{ + shamir::{self}, + SharedMany, + }, }; use crate::{algebra::poly::Polynomial, schemes::shamir::ShamirParams}; @@ -142,7 +145,11 @@ where impl< F: ff::Field + serde::Serialize + serde::de::DeserializeOwned, - G: Group + serde::Serialize + serde::de::DeserializeOwned + std::ops::Mul, + G: Group + + serde::Serialize + + serde::de::DeserializeOwned + + std::ops::Mul + + for<'a> std::ops::MulAssign<&'a F>, > super::Shared for VerifiableShare { type Context = ShamirParams; @@ -193,6 +200,19 @@ impl ops::Sub for VerifiableShare { } } +impl ops::Mul for VerifiableShare +where + Vector: for<'a> MulAssign<&'a F>, +{ + type Output = Self; + + fn mul(mut self, rhs: F) -> Self::Output { + self.poly.0 *= &rhs; + self.share.y *= rhs; + self + } +} + impl std::iter::Sum for VerifiableShare { fn sum>(mut iter: I) -> Self { let fst = iter.next().unwrap(); @@ -210,14 +230,16 @@ impl std::iter::Sum for VerifiableShare { pub struct VecVerifiableShare { shares: shamir::VecShare, polys: Box<[Polynomial]>, - pub x: F, } impl SharedMany for VerifiableShare where F: Field + serde::Serialize + serde::de::DeserializeOwned, - G: Group + serde::Serialize + serde::de::DeserializeOwned + std::ops::Mul, - G: std::ops::Mul, + G: Group + + serde::Serialize + + serde::de::DeserializeOwned + + for<'a> std::ops::MulAssign<&'a F> + + std::ops::Mul, F: ops::Mul, Box<[G]>: FromIterator<>::Output>, { @@ -239,6 +261,18 @@ where } } +impl FromIterator> for VecVerifiableShare { + fn from_iter>>(iter: T) -> Self { + let (shares, polys): (Vec<_>, Vec<_>) = iter + .into_iter() + .map(|VerifiableShare { share, poly }| (share, poly)) + .unzip(); + let shares = shares.into(); + let polys = polys.into(); + Self { shares, polys } + } +} + impl<'a, F: Field, G: Group> std::ops::Add<&'a Self> for VecVerifiableShare { type Output = VecVerifiableShare; @@ -274,7 +308,6 @@ impl<'a, F: Field, G: Group> std::ops::Sub<&'a Self> for VecVerifiableShare std::iter::Sum for VecVerifiableShare { fn sum>(mut iter: I) -> Self { let fst = iter.next().unwrap(); - let x = fst.x; let mut shares = fst.shares; let mut polys = fst.polys.iter().cloned().collect_vec(); @@ -285,7 +318,7 @@ impl std::iter::Sum for VecVerifiableShare { } } let polys: Box<[_]> = polys.into(); - VecVerifiableShare { shares, polys, x } + VecVerifiableShare { shares, polys } } } @@ -293,8 +326,8 @@ impl VecVerifiableShare where G: Group + std::ops::Mul, { - pub fn verify(&self) -> bool { - let VecVerifiableShare { shares, polys, x } = self; + pub fn verify(&self, x: F) -> bool { + let VecVerifiableShare { shares, polys } = self; let ys = &shares.ys; for (&y, poly) in ys.iter().zip(polys.iter()) { let mut check = G::identity(); @@ -364,7 +397,7 @@ where ys: Vector::from_vec(vecshare), }; let polys = macs.clone(); - vshares.push(VecVerifiableShare { shares, polys, x }) + vshares.push(VecVerifiableShare { shares, polys }) } vshares @@ -377,8 +410,8 @@ where G: Group, T: Borrow>, { - for shares in vec_shares { - if !(shares.borrow().verify()) { + for (shares, x) in vec_shares.iter().zip(ctx.ids.iter()) { + if !(shares.borrow().verify(*x)) { return None; }; } @@ -421,8 +454,8 @@ mod test { let v: Vec<_> = a.clone().into_iter().map(to_scalar).collect(); share_many::(&v, &ctx.ids, 4, &mut rng) }; - for share in &vs1 { - assert!(share.verify()); + for (share, x) in vs1.iter().zip(ctx.ids.iter()) { + assert!(share.verify(*x)); } let vsum = reconstruct_many(&ctx, &vs1).unwrap(); let v: Vec = vsum @@ -481,17 +514,18 @@ mod test { let v: Vec<_> = b.clone().into_iter().map(to_scalar).collect(); share_many::(&v, &ctx.ids, 4, &mut rng) }; - for share in &vs1 { - assert!(share.verify()); + + for (share, x) in vs1.iter().zip(ctx.ids.iter()) { + assert!(share.verify(*x)); } - for share in &vs2 { - assert!(share.verify()); + for (share, x) in vs2.iter().zip(ctx.ids.iter()) { + assert!(share.verify(*x)); } let shares: Vec> = vs1.into_iter().zip(vs2).map(|(s1, s2)| s1 + &s2).collect(); - for share in &shares { - assert!(share.verify()); + for (share, x) in shares.iter().zip(ctx.ids.iter()) { + assert!(share.verify(*x)); } let vsum = reconstruct_many(&ctx, &shares).unwrap(); diff --git a/src/schemes/mod.rs b/src/schemes/mod.rs index 131b90c..2b798f0 100644 --- a/src/schemes/mod.rs +++ b/src/schemes/mod.rs @@ -28,7 +28,7 @@ pub mod spdz; use std::{ error::Error, future::Future, - ops::{Add, Sub}, + ops::{Add, Mul, Sub}, }; use rand::RngCore; @@ -53,6 +53,7 @@ pub trait Shared: Sized + Add + Sub + + Mul + serde::Serialize + serde::de::DeserializeOwned + Clone @@ -120,6 +121,7 @@ pub trait Shared: pub trait SharedMany: Shared { type Vectorized: Sized + + FromIterator + for<'a> Add<&'a Self::Vectorized, Output = Self::Vectorized> + for<'b> Sub<&'b Self::Vectorized, Output = Self::Vectorized> + serde::Serialize @@ -152,11 +154,13 @@ pub trait SharedMany: Shared { } pub mod interactive { + use std::ops::Mul; + use thiserror::Error; use crate::{ algebra::math::Vector, - net::{Communicate, Tuneable}, + net::{Communicate, Id, Tuneable}, }; #[derive(Debug, Error)] @@ -193,8 +197,8 @@ pub mod interactive { rng: impl RngCore + Send, mut coms: impl Communicate, ) -> Result { - let shares = S::share(ctx, secret, rng); - let my_share = shares[coms.id()].clone(); + let mut shares = S::share(ctx, secret, rng); + let my_share = shares.remove(coms.id().0); coms.unicast(&shares) .await .map_err(CommunicationError::new)?; @@ -230,7 +234,7 @@ pub mod interactive { async fn receive_share( _ctx: &mut Self::Context, mut coms: impl Communicate, - from: usize, + from: Id, ) -> Result { let s = Tuneable::recv_from(&mut coms, from).await; let s = s.map_err(CommunicationError::new)?; @@ -242,6 +246,7 @@ pub mod interactive { Sized + Add + Sub + + Mul + serde::Serialize + serde::de::DeserializeOwned + Clone @@ -268,7 +273,7 @@ pub mod interactive { fn receive_share( ctx: &mut Self::Context, coms: impl Communicate, - from: usize, + from: Id, ) -> impl std::future::Future> + Send; fn recombine( @@ -279,7 +284,15 @@ pub mod interactive { } pub trait InteractiveSharedMany: InteractiveShared { - type VectorShare; + type VectorShare: Sized + + FromIterator + + for<'a> Add<&'a Self::VectorShare, Output = Self::VectorShare> + + for<'b> Sub<&'b Self::VectorShare, Output = Self::VectorShare> + + serde::Serialize + + serde::de::DeserializeOwned + + Clone + + Send + + Sync; fn share_many( ctx: &mut Self::Context, @@ -298,7 +311,7 @@ pub mod interactive { fn receive_share_many( ctx: &mut Self::Context, coms: impl Communicate, - from: usize, + from: Id, ) -> impl std::future::Future> + Send; fn recombine_many( @@ -325,7 +338,7 @@ pub mod interactive { mut coms: impl Communicate, ) -> Result { let shares = S::share_many(&*ctx, secrets, rng); - let my_share = shares[coms.id()].clone(); + let my_share = shares[coms.id().0].clone(); coms.unicast(&shares) .await .map_err(CommunicationError::new)?; @@ -349,7 +362,7 @@ pub mod interactive { async fn receive_share_many( _ctx: &mut Self::Context, mut coms: impl Communicate, - from: usize, + from: Id, ) -> Result { let s = Tuneable::recv_from(&mut coms, from).await; let s = s.map_err(CommunicationError::new)?; diff --git a/src/schemes/pedersen.rs b/src/schemes/pedersen.rs index 9275a4f..457142f 100644 --- a/src/schemes/pedersen.rs +++ b/src/schemes/pedersen.rs @@ -106,7 +106,11 @@ pub struct PedersenContext { impl Shared for VerifiableShare where F: Field + Serialize + DeserializeOwned, - G: Group + Serialize + DeserializeOwned + std::ops::Mul, + G: Group + + Serialize + + DeserializeOwned + + std::ops::Mul + + for<'a> std::ops::MulAssign<&'a F>, { type Context = PedersenContext; diff --git a/src/schemes/rep3.rs b/src/schemes/rep3.rs index 3f3a1c2..e118dac 100644 --- a/src/schemes/rep3.rs +++ b/src/schemes/rep3.rs @@ -10,7 +10,10 @@ use rand::RngCore; use derive_more::{Add, Sub}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use crate::{net::Tuneable, schemes::interactive::InteractiveMult}; +use crate::{ + net::{Id, Tuneable}, + schemes::interactive::InteractiveMult, +}; #[derive(Debug, Clone, Copy, Add, Sub, Serialize, Deserialize)] pub struct Share(F, F); @@ -41,17 +44,29 @@ impl super::Shared for Share { } } +impl std::ops::Mul for Share { + type Output = Self; + + fn mul(self, rhs: F) -> Self::Output { + let x = self.0 * rhs; + let y = self.1 * rhs; + Share(x, y) + } +} + pub async fn multiplication( a: Share, b: Share, cx: &mut impl Tuneable, ) -> Share { - let (prev_id, next_id) = match cx.id() { + let (prev_id, next_id) = match cx.id().0 { 0 => (2, 1), 1 => (0, 2), 2 => (1, 0), _ => panic!("ID higher than 3"), }; + let next_id = Id(next_id); + let prev_id = Id(prev_id); let c0 = (a.0 * b.0) + (a.0 * b.1) + (a.1 * b.0); diff --git a/src/schemes/shamir.rs b/src/schemes/shamir.rs index 05e76e0..f634129 100644 --- a/src/schemes/shamir.rs +++ b/src/schemes/shamir.rs @@ -303,7 +303,6 @@ impl SharedMany for Share { /// A secret shared vector /// -/// * `x`: the id /// * `ys`: share values #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct VecShare { @@ -311,6 +310,13 @@ pub struct VecShare { pub(crate) ys: Vector, } +impl FromIterator> for VecShare { + fn from_iter>>(iter: T) -> Self { + let ys = iter.into_iter().map(|s| s.y).collect(); + Self { ys } + } +} + impl super::Shared for VecShare { type Context = ShamirParams; @@ -369,6 +375,15 @@ impl std::ops::Sub<&Self> for VecShare { } } +impl std::ops::Mul> for VecShare { + type Output = Self; + + fn mul(self, rhs: Vec) -> Self::Output { + let ys = self.ys.into_iter().zip(rhs).map(|(a, c)| a * c).collect(); + VecShare { ys } + } +} + impl From>> for VecShare { fn from(value: Vec>) -> Self { // let x = value[0].x; diff --git a/src/schemes/spdz/mod.rs b/src/schemes/spdz/mod.rs index bbec8a2..76d98e6 100644 --- a/src/schemes/spdz/mod.rs +++ b/src/schemes/spdz/mod.rs @@ -9,7 +9,7 @@ // TODO: make costum errors. use crate::{ algebra::math::Vector, - net::agency::Broadcast, + net::{agency::Broadcast, Id}, protocols::commitments::{commit, verify_commit}, schemes::interactive::InteractiveSharedMany, }; @@ -115,7 +115,7 @@ where Ok(tri) => tri, Err(e) => return Err(e), }; - let is_chosen_party = params.who_am_i == 0; + let is_chosen_party = params.who_am_i == Id(0); let e = s1 - triplet.a; let d = s2 - triplet.b; @@ -155,9 +155,10 @@ where mut coms: impl Communicate, ) -> Result, Self::Error> { let number_of_parties = Broadcast::size(&coms); - let me = ctx.params.who_am_i(); + let me = ctx.params.who_am_i; let mut shares: Vec> = vec![]; for turn in 0..number_of_parties { + let turn = Id(turn); // TODO: Concurrency. if turn == me { let s = send_shares( @@ -187,7 +188,7 @@ where async fn receive_share( ctx: &mut Self::Context, mut coms: impl Communicate, - from: usize, + from: Id, ) -> Result { let params = &ctx.params; let for_sharing = &mut ctx.preprocessed.for_sharing; @@ -234,9 +235,10 @@ where ) -> Result, Self::Error> { let number_of_parties = Broadcast::size(&coms); let nums: Vec<_> = secret.into(); - let me = ctx.params.who_am_i(); + let me = ctx.params.who_am_i; let mut shares: Vec>> = vec![]; for turn in 0..number_of_parties { + let turn = Id(turn); // TODO: Concurrency. if turn == me { let s = send_shares( @@ -266,7 +268,7 @@ where async fn receive_share_many( ctx: &mut Self::Context, mut coms: impl Communicate, - from: usize, + from: Id, ) -> Result { let params = &ctx.params; let for_sharing = &mut ctx.preprocessed.for_sharing; @@ -300,7 +302,7 @@ pub async fn share>, // TODO: remove option. for_sharing: &mut ForSharing, params: &SpdzParams, - who_is_sending: usize, + who_is_sending: Id, network: &mut impl Broadcast, ) -> Result>, Box> { let is_chosen_one = params.who_am_i == who_is_sending; @@ -313,7 +315,7 @@ pub async fn share( network: &mut impl Broadcast, - who_is_sending: usize, + who_is_sending: Id, for_sharing: &mut ForSharing, params: &SpdzParams, ) -> Result>, Box> { @@ -359,11 +361,11 @@ fn create_shares( let Some(r) = for_sharing.rand_known_to_me.vals.pop() else { return Err(preprocessing::PreProcError::MissingForSharingElement); }; - let Some(r_share) = for_sharing.rand_known_to_i.shares[params.who_am_i].pop() else { + let Some(r_share) = for_sharing.rand_known_to_i.shares[params.who_am_i.0].pop() else { return Err(preprocessing::PreProcError::MissingForSharingElement); }; let correction = *val - r; - let share = r_share.add_public(correction, params.who_am_i == 0, params); + let share = r_share.add_public(correction, params.who_am_i == Id(0), params); res_share.push(share); res_correction.push(correction); } @@ -374,21 +376,21 @@ fn create_shares( fn create_shares_from( corrections: &[F], for_sharing: &mut ForSharing, - who_is_sending: usize, + who_is_sending: Id, params: &SpdzParams, ) -> Result>, preprocessing::PreProcError> { - let prep_rand_len = for_sharing.rand_known_to_i.shares[who_is_sending].len(); + let prep_rand_len = for_sharing.rand_known_to_i.shares[who_is_sending.0].len(); let n = corrections.len(); - if n > for_sharing.rand_known_to_i.shares[who_is_sending].len() { + if n > for_sharing.rand_known_to_i.shares[who_is_sending.0].len() { return Err(preprocessing::PreProcError::MissingForSharingElement); } let mut randoms = - for_sharing.rand_known_to_i.shares[who_is_sending].split_off(prep_rand_len - n); + for_sharing.rand_known_to_i.shares[who_is_sending.0].split_off(prep_rand_len - n); // TODO consider changing send_shares to also use split_off instead of pop, so we don't need to reverse. randoms.reverse(); let rc = randoms.iter().zip(corrections); let shares: Vec> = rc - .map(|(&r, &c)| r.add_public(c, params.who_am_i() == 0, params)) + .map(|(&r, &c)| r.add_public(c, params.who_am_i == Id(0), params)) .collect(); Ok(shares) } @@ -412,13 +414,7 @@ async fn partial_opening { mac_key_share: F, - pub who_am_i: usize, -} - -impl SpdzParams { - pub fn who_am_i(&self) -> usize { - self.who_am_i - } + pub who_am_i: Id, } // The SPDZ context needs to be public atleast to some degree, as it is needed for many operations that we would like to call publicly. @@ -703,8 +699,8 @@ mod test { fn test_sharing_using_send_and_resive() { type F = Element32; let (p1_context, p2_context, secret_values) = dummie_preproc(); - assert!(p1_context.params.who_am_i == 0); - assert!(p2_context.params.who_am_i == 1); + assert!(p1_context.params.who_am_i == Id(0)); + assert!(p2_context.params.who_am_i == Id(1)); // P1 shares an element let mut p1_prepros = p1_context.preprocessed; let elm1 = F::from_u128(56u128); @@ -717,7 +713,7 @@ mod test { let elm1_2 = create_shares_from( &[correction], &mut p2_prepros.for_sharing, - 0, + Id(0), &p2_context.params, ) .expect("Something went wrong while P2 was receiving the share.")[0]; @@ -734,7 +730,7 @@ mod test { let elm2_1 = create_shares_from( &[correction], &mut p1_prepros.for_sharing, - 1, + Id(1), &p1_context.params, ) .expect("Something went wrong while P1 was receiving the share")[0]; @@ -770,7 +766,7 @@ mod test { elm, &mut context.preprocessed.for_sharing, &context.params, - 0, + Id(0), &mut network, ) .await; @@ -824,7 +820,7 @@ mod test { let elm1_2 = create_shares_from( &[correction], &mut (p2_context.preprocessed.for_sharing), - 0, + Id(0), &p2_context.params, ) .expect("Something went worng when P2 was receiving the element")[0]; @@ -844,7 +840,7 @@ mod test { let elm2_1 = create_shares_from( &[correction], &mut p1_context.preprocessed.for_sharing, - 1, + Id(1), &p1_context.params, ) .expect("Something went worng when P1 was receiving the element")[0]; @@ -920,7 +916,7 @@ mod test { let elm1_2 = create_shares_from( &[correction], &mut (p2_context.preprocessed.for_sharing), - 0, + Id(0), &p2_context.params, ) .expect("Something went worng when P2 was receiving the element")[0]; @@ -940,7 +936,7 @@ mod test { let elm2_1 = create_shares_from( &[correction], &mut p1_context.preprocessed.for_sharing, - 1, + Id(1), &p1_context.params, ) .expect("Something went worng when P1 was receiving the element")[0]; @@ -1007,7 +1003,7 @@ mod test { let elm1_2 = create_shares_from( &[correction], &mut p2_prepros.for_sharing, - 0, + Id(0), &p2_context.params, ) .expect("Something went wrong when P2 was receiving the element.")[0]; @@ -1024,7 +1020,7 @@ mod test { let elm2_1 = create_shares_from( &[correction], &mut p1_prepros.for_sharing, - 1, + Id(1), &p1_context.params, ) .expect("Something went wrong when P1 was receiving the element.")[0]; @@ -1058,7 +1054,7 @@ mod test { let elm1_2 = match create_shares_from( &[correction], &mut p2_prepros.for_sharing, - 0, + Id(0), &p2_context.params, ) { Ok(s) => s[0], @@ -1078,7 +1074,7 @@ mod test { let elm2_1 = match create_shares_from( &[correction], &mut p1_prepros.for_sharing, - 1, + Id(1), &p1_context.params, ) { Ok(s) => s[0], @@ -1117,7 +1113,7 @@ mod test { let elm1_2 = match create_shares_from( &[correction], &mut p2_prepros.for_sharing, - 0, + Id(0), &p2_context.params, ) { Ok(s) => s[0], @@ -1153,7 +1149,7 @@ mod test { let elm1_2 = match create_shares_from( &[correction], &mut p2_prepros.for_sharing, - 0, + Id(0), &p2_context.params, ) { Ok(s) => s[0], @@ -1173,7 +1169,7 @@ mod test { let elm2_1 = match create_shares_from( &[correction], &mut p1_prepros.for_sharing, - 1, + Id(1), &p1_context.params, ) { Ok(s) => s[0], @@ -1268,7 +1264,7 @@ mod test { let elm1_2 = match create_shares_from( &[correction], &mut p2_prepros.for_sharing, - 0, + Id(0), &p2_context.params, ) { Ok(s) => s[0], @@ -1280,13 +1276,13 @@ mod test { // Adding with pub_constant let elm3_1 = elm1_1.add_public( pub_constant, - 0 == p1_context.params.who_am_i, + Id(0) == p1_context.params.who_am_i, &p1_context.params, ); let elm3_2 = elm1_2.add_public( pub_constant, - 0 == p2_context.params.who_am_i, + Id(0) == p2_context.params.who_am_i, &p2_context.params, ); @@ -1312,7 +1308,7 @@ mod test { let elm1_2 = create_shares_from( &[correction], &mut p2_prepros.for_sharing, - 0, + Id(0), &p2_context.params, ) .unwrap()[0]; @@ -1322,13 +1318,13 @@ mod test { // Adding with pub_constant let elm3_1 = elm1_1.sub_public( pub_constant, - 0 == p1_context.params.who_am_i, + Id(0) == p1_context.params.who_am_i, &p1_context.params, ); let elm3_2 = elm1_2.sub_public( pub_constant, - 0 == p2_context.params.who_am_i, + Id(0) == p2_context.params.who_am_i, &p2_context.params, ); @@ -1384,7 +1380,7 @@ mod test { values[0].clone(), &mut context.preprocessed.for_sharing, &context.params, - 0, + Id(0), &mut network, ) .await; @@ -1395,7 +1391,7 @@ mod test { values[1].clone(), &mut context.preprocessed.for_sharing, &context.params, - 1, + Id(1), &mut network, ) .await; @@ -1419,7 +1415,7 @@ mod test { values[2].clone(), &mut context.preprocessed.for_sharing, &context.params, - 0, + Id(0), &mut network, ) .await; @@ -1430,7 +1426,8 @@ mod test { // Adding val_4 with public constant const_1: val_5 let const_1 = constant; - let val_5 = val_4.add_public(const_1, context.params.who_am_i == 0, &context.params); + let val_5 = + val_4.add_public(const_1, context.params.who_am_i == Id(0), &context.params); // Checking all partially opened values let mut rng = rand_chacha::ChaCha20Rng::from_entropy(); let random_element = F::random(&mut rng); @@ -1490,7 +1487,7 @@ mod test { values.clone(), &mut context.preprocessed.for_sharing, &context.params, - 0, + Id(0), &mut network, ) .await @@ -1560,7 +1557,7 @@ mod test { values_1, &mut context.preprocessed.for_sharing, &context.params, - 0, + Id(0), &mut network, ) .await @@ -1593,7 +1590,7 @@ mod test { values_2, &mut context.preprocessed.for_sharing, &context.params, - 1, + Id(1), &mut network, ) .await; @@ -1644,7 +1641,7 @@ mod test { let mut files = [tempfile::tempfile().unwrap(), tempfile::tempfile().unwrap()]; let known_to_each = vec![1, 2]; let number_of_triplets = 2; - preprocessing::write_preproc_to_file( + preprocessing::write_context( &mut files, known_to_each, number_of_triplets, @@ -1653,8 +1650,8 @@ mod test { .unwrap(); files[0].rewind().unwrap(); files[1].rewind().unwrap(); - let p1_context: SpdzContext = preprocessing::read_preproc_from_file(&mut files[0]); - let p2_context: SpdzContext = preprocessing::read_preproc_from_file(&mut files[1]); + let p1_context: SpdzContext = preprocessing::load_context(&mut files[0]); + let p2_context: SpdzContext = preprocessing::load_context(&mut files[1]); // unpacking let p1_params = p1_context.params; let p2_params = p2_context.params; diff --git a/src/schemes/spdz/preprocessing.rs b/src/schemes/spdz/preprocessing.rs index 15581a9..7f510e8 100644 --- a/src/schemes/spdz/preprocessing.rs +++ b/src/schemes/spdz/preprocessing.rs @@ -1,14 +1,19 @@ // Preprocessing -use crate::schemes::spdz::{self, SpdzContext}; +use crate::{ + net::Id, + schemes::spdz::{self, SpdzContext}, +}; use bincode; use ff::PrimeField; use rand::SeedableRng; +use serde::{de::DeserializeOwned, Serialize}; use std::{ error::Error, fmt, fs::File, io::{self, Write}, + path::Path, }; #[derive(Debug, Clone, PartialEq)] @@ -25,9 +30,7 @@ impl fmt::Display for PreProcError { } PreProcError::MissingForSharingElement => { write!(f, "Not enough pre shared random elements.") - } // _ => { - // write!(f, "Not enough preprocessing available") - // } + } } } } @@ -90,7 +93,7 @@ pub struct SecretValues { pub mac_key: F, } -pub fn write_preproc_to_file( +pub fn write_context( files: &mut [File], known_to_each: Vec, number_of_triplets: usize, @@ -110,14 +113,23 @@ pub fn write_preproc_to_file( +pub fn load_context( file: &mut File, ) -> SpdzContext { // TODO: return Result instead. - bincode::deserialize_from(file).unwrap() + let buffered = std::io::BufReader::new(file); + bincode::deserialize_from(buffered).unwrap() +} + +pub async fn load_context_async( + file: &Path, +) -> SpdzContext { + let contents = tokio::fs::read(file).await.unwrap(); + // TODO: return Result instead. + bincode::deserialize_from(&*contents).unwrap() } -pub fn dealer_preproc( +pub fn dealer_preproc( mut rng: impl rand::Rng, known_to_each: Vec, number_of_triplets: usize, @@ -128,7 +140,7 @@ pub fn dealer_preproc> = (0..number_of_parties) - .map(|i| SpdzContext::empty(number_of_parties, mac_keys[i], i)) + .map(|i| SpdzContext::empty(number_of_parties, mac_keys[i], Id(i))) .collect(); let mac_key = mac_keys.into_iter().sum(); @@ -244,20 +256,20 @@ pub fn dealer_preproc SpdzContext { - fn empty(number_of_parties: usize, mac_key_share: F, who_am_i: usize) -> Self { +impl SpdzContext { + fn empty(number_of_parties: usize, mac_key_share: F, who_am_i: Id) -> Self { generate_empty_context(number_of_parties, mac_key_share, who_am_i) } pub fn from_file(mut file: File) -> Result { - Ok(read_preproc_from_file(&mut file)) + Ok(load_context(&mut file)) } } fn generate_empty_context( number_of_parties: usize, mac_key_share: F, - who_am_i: usize, + who_am_i: Id, ) -> SpdzContext { let rand_known_to_i = RandomKnownToPi { shares: vec![vec![]; number_of_parties], diff --git a/src/testing/mock.rs b/src/testing/mock.rs index 5c56d97..9665ba0 100644 --- a/src/testing/mock.rs +++ b/src/testing/mock.rs @@ -1,13 +1,19 @@ +use std::ops::{AddAssign, SubAssign}; + use itertools::Itertools; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use crate::{algebra::field::Field, schemes::Shared}; +use crate::{ + algebra::{field::Field, math::Vector}, + net::Id, + schemes::{Shared, SharedMany}, +}; #[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub struct Share { - value: F, - issued_to: usize, - issued_by: Option, + pub value: F, + pub issued_to: Id, + pub issued_by: Option, } impl std::ops::Add for Share { @@ -23,6 +29,12 @@ impl std::ops::Add for Share { } } +impl AddAssign<&Self> for Share { + fn add_assign(&mut self, rhs: &Self) { + *self = *self + *rhs; + } +} + impl std::ops::Sub for Share { type Output = Self; @@ -36,6 +48,12 @@ impl std::ops::Sub for Share { } } +impl SubAssign<&Self> for Share { + fn sub_assign(&mut self, rhs: &Self) { + *self = *self - *rhs; + } +} + impl std::ops::Mul for Share { type Output = Self; @@ -47,10 +65,19 @@ impl std::ops::Mul for Share { } } +impl Share { + pub fn new_context(id: Id, total_parties: usize) -> Context { + Context { + all_parties: total_parties, + me: id, + } + } +} + #[derive(Clone, Copy)] pub struct Context { pub all_parties: usize, - pub me: usize, + pub me: Id, } impl Context { @@ -66,13 +93,13 @@ pub fn assert_holding_same(shares: &[Share]) { ); } -pub fn assert_holded_by(shares: impl IntoIterator>, party: usize) { +pub fn assert_holded_by(shares: impl IntoIterator>, party: Id) { let val = shares .into_iter() .map(|s| s.issued_to) .all_equal_value() .expect("Not all values were the same"); - assert_eq!(val, party, "Shares not issued to party {party}"); + assert_eq!(val, party, "Shares not issued to party {party:?}"); } impl Shared for Share { @@ -88,15 +115,21 @@ impl Shared f (0..ctx.all_parties) .map(|i| Share { value: secret, - issued_to: i, + issued_to: Id(i), issued_by: Some(ctx.me), }) .collect() } fn recombine(_ctx: &Self::Context, shares: &[Self]) -> Option { + let mut all_is_well = true; for (i, share) in shares.iter().enumerate() { - assert_eq!(share.issued_to, i, "Mismatch in issued_to and order"); + all_is_well &= share.issued_to.0 == i + } + + if !all_is_well { + let ids: Vec<_> = shares.iter().map(|s| s.issued_to).collect(); + panic!("Mismatch in issued shares and order. Received them as:\n {ids:#?}"); } assert!( @@ -107,3 +140,27 @@ impl Shared f Some(shares[0].value) } } + +impl SharedMany for Share { + type Vectorized = Vector>; + + fn share_many( + ctx: &Self::Context, + secrets: &[Self::Value], + rng: impl rand::RngCore, + ) -> Vec { + Share::share_many_naive(ctx, secrets, rng) + .into_iter() + .map(Vector::from_vec) + .collect() + } + + fn recombine_many( + ctx: &Self::Context, + many_shares: &[Self::Vectorized], + ) -> Option> { + Share::recombine_many_naive(ctx, many_shares) + .into_iter() + .collect() + } +} diff --git a/src/testing/mod.rs b/src/testing/mod.rs index eb47998..4f392a7 100644 --- a/src/testing/mod.rs +++ b/src/testing/mod.rs @@ -1,7 +1,13 @@ //! This module documents various tools which can be used to test or benchmark schemes. pub mod mock; -use crate::net::network::InMemoryNetwork; +use crate::{ + algebra::element::Element32, + net::{agency::Broadcast, network::InMemoryNetwork}, + protocols::beaver, + vm::{Engine, Script}, +}; +use rand::rngs::mock::StepRng; use std::future::Future; use tokio::task::JoinError; @@ -60,7 +66,15 @@ impl Cluster { } } -impl Cluster { +impl Cluster { + pub fn more_args(self, args: impl Into>) -> Cluster<(Arg, B)> { + let args: Vec<_> = self.args.into_iter().zip(args.into()).collect(); + Cluster { + players: self.players, + args, + } + } + /// Run a cluster with arguments /// /// # Example @@ -96,6 +110,25 @@ impl Cluster { } } +impl Cluster> { + pub async fn execute_mock(self) -> Result, JoinError> { + self.run_with_args(|network, script| async move { + type S = mock::Share; + let context = mock::Context { + all_parties: network.size(), + me: network.id(), + }; + let private_rng = StepRng::new(42, 7 + network.id().0 as u64); + let shared_rng = StepRng::new(3, 14); + let mut fueltanks = beaver::BeaverTriple::fake_many(&context, shared_rng, 2000); + let mut engine = Engine::<_, S, _>::new(context, network, private_rng); + engine.add_fuel(&mut fueltanks[context.me.0]); + engine.execute(&script).await.unwrap_single() + }) + .await + } +} + #[cfg(test)] mod test { use crate::testing::Cluster; diff --git a/src/testing/tapping.rs b/src/testing/tapping.rs deleted file mode 100644 index e5cd78f..0000000 --- a/src/testing/tapping.rs +++ /dev/null @@ -1,131 +0,0 @@ -use std::io::Write; - -use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt, DuplexStream}; -use tokio::io::{ReadHalf, WriteHalf}; - -use crate::net::{ - connection::{Connection, ConnectionError, Receiving, Sending}, - network::{InMemoryNetwork, Network}, - Channel, RecvBytes, SendBytes, SplitChannel, -}; - -pub struct TappedConnection(TapSending, TapReceiving); - -impl Connection { - pub fn tap(self, name: String) -> TappedConnection { - let r = TapReceiving { - name: name.clone(), - inner: self.receiver, - buf: Vec::new(), - }; - let s = TapSending { - name, - inner: self.sender, - buf: Vec::new(), - }; - TappedConnection(s, r) - } -} - -impl SendBytes - for TappedConnection -{ - type SendError = ConnectionError; - - async fn send_bytes(&mut self, bytes: tokio_util::bytes::Bytes) -> Result<(), Self::SendError> { - self.0.send_bytes(bytes).await - } - - async fn send(&mut self, msg: &T) -> Result<(), Self::SendError> { - self.0.send(msg).await - } -} - -impl RecvBytes - for TappedConnection -{ - type RecvError = ConnectionError; - - async fn recv_bytes(&mut self) -> Result { - self.1.recv_bytes().await - } - - async fn recv(&mut self) -> Result { - self.1.recv().await - } -} - -pub struct TapSending { - inner: Sending, - name: String, - buf: Vec, -} - -impl SendBytes for TapSending { - type SendError = ConnectionError; - - async fn send_bytes(&mut self, bytes: tokio_util::bytes::Bytes) -> Result<(), Self::SendError> { - self.inner.send_bytes(bytes).await - } - - async fn send(&mut self, msg: &T) -> Result<(), Self::SendError> { - let pretty = serde_json::to_string(msg).unwrap(); - let msg = bincode::serialize(msg).unwrap(); - let name = &self.name; - let _ = writeln!(self.buf, "[{name}] Sending: {pretty}"); - let mut stdout = tokio::io::stdout(); - let _ = stdout.write_all(&self.buf).await; - self.buf.clear(); - self.send_bytes(msg.into()).await - } -} - -impl RecvBytes for TapReceiving { - type RecvError = ConnectionError; - - async fn recv_bytes(&mut self) -> Result { - self.inner.recv_bytes().await - } -} - -pub struct TapReceiving { - inner: Receiving, - name: String, - buf: Vec, -} - -impl Channel for TappedConnection { - type Error = ConnectionError; -} - -impl SplitChannel - for TappedConnection -{ - type Sender = TapSending; - type Receiver = TapReceiving; - - fn split(&mut self) -> (&mut Self::Sender, &mut Self::Receiver) { - (&mut self.0, &mut self.1) - } -} - -pub type TappedDuplexConnection = TappedConnection, WriteHalf>; -pub type TappedInMemoryNetwork = Network; - -impl InMemoryNetwork { - pub fn tap(self, name: impl AsRef) -> TappedInMemoryNetwork { - let name = name.as_ref(); - let index = self.index; - let connections: Vec<_> = self - .connections - .into_iter() - .enumerate() - .map(|(id, c)| { - let id = if id >= index { id + 1 } else { id }; - let name = format!("{name} | Channel {id}"); - c.tap(name) - }) - .collect(); - TappedInMemoryNetwork { index, connections } - } -} diff --git a/src/vm/mod.rs b/src/vm/mod.rs new file mode 100644 index 0000000..d7181d4 --- /dev/null +++ b/src/vm/mod.rs @@ -0,0 +1,471 @@ +pub mod parsing; + +use ff::Field; +use itertools::{Either, Itertools}; +use rand::RngCore; + +use crate::{ + algebra::math::Vector, + net::{agency::Broadcast, connection::TcpConnection, network::Network, Id, SplitChannel}, + protocols::beaver::{beaver_multiply, BeaverTriple}, + schemes::interactive::{InteractiveShared, InteractiveSharedMany}, +}; + +#[derive(Debug, Clone)] +pub enum Value { + Single(F), + Vector(Vector), +} + +impl Value { + pub fn unwrap_single(self) -> F { + match self { + Value::Single(v) => v, + _ => panic!("Was vector and not a single!"), + } + } + + pub fn unwrap_vector(self) -> Vector { + match self { + Value::Vector(v) => v, + _ => panic!("Was single and not a vector!"), + } + } + + pub fn map(self, func: impl Fn(F) -> U) -> Value { + match self { + Value::Single(a) => Value::Single(func(a)), + Value::Vector(a) => Value::Vector(a.into_iter().map(func).collect()), + } + } + + pub fn to_vec(self) -> Vec { + match self { + Value::Single(s) => vec![s], + Value::Vector(v) => v.into(), + } + } +} + +impl From for Value { + fn from(value: F) -> Self { + Value::Single(value) + } +} +impl From> for Value { + fn from(value: Vector) -> Self { + Value::Vector(value) + } +} + +impl Value { + pub fn convert(self) -> Value + where + F: Into, + { + match self { + Value::Single(v) => Value::Single(v.into()), + Value::Vector(v) => Value::Vector(v.into_iter().map(|v| v.into()).collect()), + } + } + + pub fn try_convert(self) -> Result, F::Error> + where + F: TryInto, + { + match self { + Value::Single(v) => Ok(Value::Single(v.try_into()?)), + Value::Vector(v) => { + let bs: Vector = v.into_iter().map(|v| v.try_into()).try_collect()?; + Ok(Value::Vector(bs)) + } + } + } +} + +#[derive(Debug, Clone, Copy)] +pub struct Const(u16); + +#[derive(Debug, Clone, Copy)] +pub enum Instruction { + Share(Const), + SymShare(Const), + MulCon(Const), + Recv(Id), + RecvVec(Id), + Recombine, + Add, + Mul, + Sub, + Sum(usize), +} + +#[derive(Clone, Debug)] +enum SharedValue { + Single(S), + Vector(S::VectorShare), +} + +pub struct Script { + constants: Vec>, + instructions: Vec, +} + +#[derive(Debug)] +pub struct Engine { + network: Network, + context: S::Context, + fueltank: Vec>, + rng: R, +} + +struct Stack { + stack: Vec>, +} + +impl Stack { + pub fn new() -> Self { + Self { stack: vec![] } + } + + pub fn push(&mut self, val: SharedValue) { + self.stack.push(val) + } + + pub fn push_single(&mut self, single: S) { + self.stack.push(SharedValue::Single(single)) + } + + pub fn push_vector(&mut self, vector: S::VectorShare) { + self.stack.push(SharedValue::Vector(vector)) + } + + pub fn pop(&mut self) -> SharedValue { + self.stack.pop().expect("No value found") + } + + pub fn pop_single(&mut self) -> S { + match self.stack.pop() { + Some(SharedValue::Single(single)) => single, + _ => panic!("no valid value found"), + } + } + + pub fn pop_vector(&mut self) -> S::VectorShare { + match self.stack.pop() { + Some(SharedValue::Vector(vector)) => vector, + _ => panic!("no valid value found"), + } + } + + pub fn take_singles(&mut self, n: usize) -> impl Iterator + '_ { + self.stack.drain(0..n).map(|v| match v { + SharedValue::Single(v) => v, + _ => panic!(), + }) + } + + pub fn take_vectors(&mut self, n: usize) -> impl Iterator + '_ { + self.stack.drain(0..n).map(|v| match v { + SharedValue::Vector(v) => v, + _ => panic!(), + }) + } + + pub fn take( + &mut self, + n: usize, + ) -> Either + '_, impl Iterator + '_> { + match self.stack.last() { + Some(SharedValue::Single(_)) => Either::Left(self.take_singles(n)), + Some(SharedValue::Vector(_)) => Either::Right(self.take_vectors(n)), + None => panic!(), + } + } +} + +impl Engine +where + C: SplitChannel, + S: InteractiveSharedMany + 'static, + R: RngCore + Send, + F: Field, +{ + pub fn new(context: S::Context, network: Network, rng: R) -> Self { + Self { + network, + context, + fueltank: vec![], + rng, + } + } + + pub fn id(&self) -> Id { + self.network.id() + } + + pub fn peers(&self) -> Vec { + self.network.peers() + } + + pub fn add_fuel(&mut self, fuel: &mut Vec>) { + self.fueltank.append(fuel); + } + + // TODO: Superscalar execution when awaiting. + + pub async fn execute(&mut self, script: &Script) -> Value { + let mut stack = Stack::new(); + let mut results: Vec> = vec![]; + let constants = &script.constants; + + for opcode in script.instructions.iter() { + self.step(&mut stack, &mut results, constants, opcode) + .await + .unwrap(); + } + + results.pop().unwrap() + } + + async fn step( + &mut self, + stack: &mut Stack, + results: &mut Vec>, + constants: &[Value], + opcode: &Instruction, + ) -> Result<(), S::Error> { + let ctx = &mut self.context; + let mut coms = &mut self.network; + let mut rng = &mut self.rng; + let fueltank = &mut self.fueltank; + match opcode { + Instruction::Share(addr) => { + let f = &constants[addr.0 as usize]; + match f { + Value::Single(f) => { + let share = S::share(ctx, *f, &mut rng, &mut coms).await?; + stack.push_single(share) + } + Value::Vector(fs) => { + let share = S::share_many(ctx, fs, &mut rng, &mut coms).await?; + stack.push_vector(share) + } + } + } + Instruction::SymShare(addr) => { + let f = &constants[addr.0 as usize]; + match f { + Value::Single(f) => { + let shares = S::symmetric_share(ctx, *f, &mut rng, &mut coms).await?; + let shares = shares.into_iter().map(|s| SharedValue::Single(s)); + stack.stack.extend(shares) // dirty hack + } + Value::Vector(f) => { + let shares = S::symmetric_share_many(ctx, f, &mut rng, &mut coms).await?; + let shares = shares.into_iter().map(|s| SharedValue::Vector(s)); + stack.stack.extend(shares) // dirty hack + } + } + } + Instruction::Recv(id) => { + let share = S::receive_share(ctx, &mut coms, *id).await?; + stack.push_single(share) + } + Instruction::RecvVec(id) => { + let share = S::receive_share_many(ctx, &mut coms, *id).await?; + stack.push_vector(share) + } + Instruction::Recombine => { + match stack.pop() { + SharedValue::Single(share) => { + let f = S::recombine(ctx, share, &mut coms).await?; + results.push(Value::Single(f)); + } + SharedValue::Vector(share) => { + let f = S::recombine_many(ctx, share, &mut coms).await?; + results.push(Value::Vector(f)); + } + }; + } + Instruction::Add => { + let a = stack.pop(); + let b = stack.pop(); + match (a, b) { + (SharedValue::Single(a), SharedValue::Single(b)) => stack.push_single(a + b), + (SharedValue::Vector(a), SharedValue::Vector(b)) => stack.push_vector(a + &b), + _ => panic!("Unsupported operation"), + } + } + Instruction::Sub => { + let a = stack.pop(); + let b = stack.pop(); + match (a, b) { + (SharedValue::Single(a), SharedValue::Single(b)) => stack.push_single(a - b), + (SharedValue::Vector(a), SharedValue::Vector(b)) => stack.push_vector(a - &b), + _ => panic!("Unsupported operation"), + } + } + Instruction::MulCon(addr) => { + let constant = &constants[addr.0 as usize]; + match (stack.pop(), constant) { + (SharedValue::Single(a), Value::Single(constant)) => { + stack.push_single(a * *constant) + } + (SharedValue::Vector(_a), Value::Vector(_constant)) => { + todo!("vector mult") + //stack.push_vector(a * &constant) + } + (SharedValue::Single(_), Value::Vector(_)) => todo!(), + (SharedValue::Vector(_), Value::Single(_)) => todo!(), + } + } + Instruction::Mul => { + let x = stack.pop(); + let y = stack.pop(); + match (x, y) { + (SharedValue::Single(x), SharedValue::Single(y)) => { + let triple = fueltank.pop().unwrap(); + let z = beaver_multiply(ctx, x, y, triple, &mut coms).await?; + stack.push_single(z) + } + (SharedValue::Vector(_x), SharedValue::Vector(_y)) => { + todo!() + } + (SharedValue::Vector(_), SharedValue::Single(_y)) => { + todo!() + } + (SharedValue::Single(_), SharedValue::Vector(_)) => todo!(), + }; + } + Instruction::Sum(size) => { + // Zero is a sentinal value that represents the party size. + let size = if *size == 0 { + self.network.size() + } else { + *size + }; + let res = match stack.take(size) { + Either::Left(iter) => { + let res = iter.reduce(|s, acc| acc + s).unwrap(); + SharedValue::Single(res) + } + Either::Right(iter) => { + let res = iter.reduce(|s, acc| acc + &s).unwrap(); + SharedValue::Vector(res) + } + }; + stack.push(res) + } + } + Ok(()) + } + + pub async fn raw(&mut self, routine: Func) -> Out + where + Func: async Fn(&mut Network, &mut S::Context, &mut R) -> Out, + { + // TODO: Add other resources. + routine(&mut self.network, &mut self.context, &mut self.rng).await + } +} + +impl Engine { + pub async fn shutdown(self) -> Result<(), std::io::Error> { + self.network.shutdown().await + } +} + +#[cfg(test)] +mod tests { + use rand::rngs::mock::StepRng; + + use crate::{ + algebra::{self, element::Element32}, + net::{agency::Broadcast, connection::DuplexConnection, network::InMemoryNetwork, Id}, + testing::{self, mock}, + vm::{Const, Engine, Instruction, Value}, + }; + + pub fn dumb_engine( + network: InMemoryNetwork, + ) -> Engine, rand::rngs::mock::StepRng> + { + let context = mock::Context { + all_parties: network.size(), + me: network.id(), + }; + + let rng = StepRng::new(42, 7); + + Engine { + network, + context, + fueltank: vec![], + rng, + } + } + + #[tokio::test] + async fn add_two() { + let results = testing::Cluster::new(2) + .with_args([47, 52u32]) + .run_with_args(|net, val| async move { + let mut engine = dumb_engine(net); + use Instruction::{Add, Recombine, SymShare}; + let val = Element32::from(val); + let script = crate::vm::Script { + constants: vec![Value::Single(val)], + instructions: vec![ + SymShare(Const(0)), // add two to the stack. + Add, + Recombine, + ], + }; + let res: u32 = engine.execute(&script).await.unwrap_single().into(); + engine.network.shutdown().await.unwrap(); + res + }) + .await + .unwrap(); + + assert_eq!(results, vec![99, 99]); + } + + #[tokio::test] + async fn add_two_again() { + use Instruction::{Add, Recombine, Recv, Share}; + let a = Element32::from(42u32); + let a = crate::vm::Script { + constants: vec![Value::Single(a)], + instructions: vec![ + Share(Const(0)), // +1 + Recv(Id(1)), // +1 + Add, // -1 + Recombine, // -1 + ], + }; + let b = Element32::from(57u32); + let b = crate::vm::Script { + constants: vec![Value::Single(b)], + instructions: vec![ + Recv(Id(0)), // +1 + Share(Const(0)), // +1 + Add, // -1 + Recombine, // -1 + ], + }; + let results = testing::Cluster::new(2) + .with_args([a, b]) + .run_with_args(|net, script| async move { + let mut engine = dumb_engine(net); + let res: u32 = engine.execute(&script).await.unwrap_single().into(); + engine.network.shutdown().await.unwrap(); + res + }) + .await + .unwrap(); + + assert_eq!(results, vec![99, 99]); + } +} diff --git a/src/vm/parsing.rs b/src/vm/parsing.rs new file mode 100644 index 0000000..709a2a0 --- /dev/null +++ b/src/vm/parsing.rs @@ -0,0 +1,451 @@ +use itertools::Itertools; +/// Pseudo-parsing direct to an array-backed AST which just is a bytecode stack. +use std::{ + array, + iter::Sum, + ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign}, +}; + +use crate::{ + algebra::math::Vector, + net::Id, + vm::{Const, Instruction, Script, Value}, +}; + +/// An expression stack +#[derive(Clone, Debug)] +pub struct Exp { + constants: Vec>, + instructions: Vec, +} + +// A dynamicly sized list of expressions. +#[derive(Clone, Debug)] +pub struct ExpList { + constant: Value, +} + +// An opened expression (last step) +#[derive(Clone, Debug)] +pub struct Opened(Exp); + +impl Exp { + pub fn from_parts(constants: Vec>, instructions: Vec) -> Self { + Self { + constants, + instructions, + } + } + + fn empty() -> Self { + Self { + constants: vec![], + instructions: vec![], + } + } + + fn append_constant(&mut self, value: impl Into>) -> Const { + self.constants.push(value.into()); + Const(self.constants.len() as u16 - 1) + } + + fn constant_op(value: impl Into>, opcode: Instruction) -> Self { + let constants = vec![value.into()]; + Self { + instructions: vec![opcode], + constants, + } + } + + // This is slighty cursed. + pub fn symmetric_share(secret: impl Into) -> ExpList { + ExpList { + constant: Value::Single(secret.into()), + } + } + + // This is slighty cursed. + pub fn symmetric_share_vec(secret: impl Into>) -> ExpList { + ExpList { + constant: Value::Vector(secret.into()), + } + } + + /// Secret share into a field value + /// + /// * `secret`: value to secret share + pub fn share(secret: impl Into) -> Self { + Self::constant_op(secret.into(), Instruction::Share(Const(0))) + } + + /// Secret share a vector + /// + /// * `secret`: vector to secret share + pub fn share_vec(secret: impl Into>) -> Self { + Self::constant_op(secret.into(), Instruction::Share(Const(0))) + } + + /// Receive are share from a given party `id` + /// + /// * `id`: Id of party to receive from + pub fn receive_input(id: Id) -> Self { + Self { + constants: vec![], + instructions: vec![Instruction::Recv(id)], + } + } + + /// Share and receive based on your given Id + /// + /// * `input`: Your input to secret-share + /// * `me`: Your Id + pub fn share_and_receive(input: impl Into, me: Id) -> [Self; N] { + let mut input: Option = Some(input.into()); + array::from_fn(|i| { + let id = Id(i); + if id == me { + let f = input.take().expect("We only do this once."); + Self::share(f) + } else { + Self::receive_input(id) + } + }) + } + + /// Share and receive based on your given Id + /// + /// * `input`: Your input to secret-share + /// * `me`: Your Id + pub fn share_and_receive_n(input: impl Into, me: Id, n: usize) -> Vec { + let mut input: Option = Some(input.into()); + (0..n) + .map(|i| { + let id = Id(i); + if id == me { + let f = input.take().expect("We only do this once."); + Self::share(f) + } else { + Self::receive_input(id) + } + }) + .collect() + } + + /// Open the secret value + pub fn open(mut self) -> Opened { + self.instructions.push(Instruction::Recombine); + Opened(self) + } + + /// Helper function to manage changes in addreses when combining expressions + fn append(&mut self, mut other: Self) { + let n = self.constants.len() as u16; + self.constants.append(&mut other.constants); + for opcode in other.instructions.iter_mut() { + match opcode { + Instruction::Share(addr) => addr.0 += n, + Instruction::SymShare(addr) => addr.0 += n, + Instruction::MulCon(addr) => addr.0 += n, + Instruction::Recv(_) // Explicit do nothing here. + | Instruction::RecvVec(_) + | Instruction::Recombine + | Instruction::Add + | Instruction::Sum(_) + | Instruction::Mul + | Instruction::Sub => (), + } + } + self.instructions.append(&mut other.instructions); + } +} + +impl Opened { + pub fn finalize(self) -> Script + where + T: Into, + { + let Exp { + constants, + instructions, + } = self.0; + let constants = constants.into_iter().map(|v| v.convert()).collect(); + Script { + constants, + instructions, + } + } + + pub fn try_finalize(self) -> Result, T::Error> + where + T: TryInto, + { + let Exp { + constants, + instructions, + } = self.0; + let constants = constants + .into_iter() + .map(|v| v.try_convert()) + .try_collect()?; + Ok(Script { + constants, + instructions, + }) + } +} + +impl ExpList { + /// Promise that the explist is `size` long + /// + /// This will then assume that there a `size` on the stack when executing. + pub fn concrete(self, own: usize, size: usize) -> Vec> { + let mut me = Some(Exp { + constants: vec![self.constant], + instructions: vec![Instruction::SymShare(Const(0))], + }); + (0..size) + .map(|id| { + if id == own { + me.take().unwrap() + } else { + Exp::empty() + } + }) + .collect() + } + + pub fn sum(self) -> Exp { + use Instruction as I; + Exp { + constants: vec![self.constant], + instructions: vec![I::SymShare(Const(0)), I::Sum(0)], + } + } +} + +impl AddAssign for Exp { + fn add_assign(&mut self, rhs: Self) { + self.append(rhs); + self.instructions.push(Instruction::Add); + } +} + +impl SubAssign for Exp { + fn sub_assign(&mut self, rhs: Self) { + self.append(rhs); + self.instructions.push(Instruction::Sub); + } +} + +impl MulAssign for Exp { + fn mul_assign(&mut self, rhs: Self) { + self.append(rhs); + self.instructions.push(Instruction::Mul); + } +} + +impl Add for Exp { + type Output = Self; + + fn add(mut self, rhs: Self) -> Self::Output { + self.append(rhs); + self.instructions.push(Instruction::Add); + self + } +} + +impl Mul for Exp { + type Output = Self; + + fn mul(mut self, rhs: Self) -> Self::Output { + self.append(rhs); + self.instructions.push(Instruction::Mul); + self + } +} + +impl Mul for Exp { + type Output = Self; + + fn mul(mut self, rhs: F) -> Self::Output { + let addr = self.append_constant(rhs); + self.instructions.push(Instruction::MulCon(addr)); + self + } +} + +impl Sub for Exp { + type Output = Self; + + fn sub(mut self, rhs: Self) -> Self::Output { + self.append(rhs); + self.instructions.push(Instruction::Sub); + self + } +} + +impl Sum for Exp { + fn sum>(iter: I) -> Self { + let (mut exp, size) = iter.fold((Exp::empty(), 0usize), |(mut acc, count), exp| { + acc.append(exp); + (acc, count + 1) + }); + exp.instructions.push(Instruction::Sum(size)); + exp + } +} + +#[cfg(test)] +mod test { + use crate::{ + algebra::{self, element::Element32}, + net::Id, + testing::{self, Cluster}, + vm::parsing::Exp, + }; + + type F = algebra::element::Element32; + type Share = testing::mock::Share; + + #[tokio::test] + async fn addition() { + let inputs = [3, 7, 13u32]; + let res = Cluster::new(3) + .with_args( + (0..3) + .map(|id| { + let me = Id(id); + type E = Exp; + let [a, b, c] = E::share_and_receive(inputs[id], me); + let sum = a + b + c; + let res = sum.open(); + dbg!(&res); + res.finalize() + }) + .collect::>(), + ) + .execute_mock() + .await + .unwrap(); + + assert_eq!(res, vec![23u32.into(), 23u32.into(), 23u32.into()]); + } + + #[tokio::test] + async fn multiplication() { + let inputs = [1, 2, 3u32]; + let res = Cluster::new(3) + .with_args( + (0..3) + .map(|id| { + let me = Id(id); + type E = Exp; + let [a, b, c] = E::share_and_receive(inputs[id], me); + let sum = a * b * c; + let res = sum.open(); + res.finalize() + }) + .collect::>(), + ) + .execute_mock() + .await + .unwrap(); + + assert_eq!(res, vec![6u32.into(), 6u32.into(), 6u32.into()]); + } + + #[tokio::test] + async fn mult_add() { + let inputs = [1, 2, 3u32]; + let res = Cluster::new(3) + .with_args( + (0..3) + .map(|id| { + let me = Id(id); + type E = Exp; + let [a, b, c] = E::share_and_receive(inputs[id], me); + let sum = a + b * c; // no need to implement precedence! + let res = sum.open(); + res.finalize() + }) + .collect::>(), + ) + .execute_mock() + .await + .unwrap(); + + // 1 + 2 * 3 = 7 + assert_eq!(res, vec![7u32.into(), 7u32.into(), 7u32.into()]); + } + + #[tokio::test] + async fn explist() { + let inputs = [1, 2, 3u32]; + let res = Cluster::new(3) + .with_args( + (0..3) + .map(|id| { + type E = Exp; + let exp = E::symmetric_share(inputs[id]); + let [a, b, c]: [E; 3] = exp.concrete(id, 3).try_into().unwrap(); + let sum = a + b * c; // no need to implement precedence! + let res = sum.open(); + res.finalize() + }) + .collect::>(), + ) + .execute_mock() + .await + .unwrap(); + + // 1 + 2 * 3 = 7 + assert_eq!(res, vec![7u32.into(), 7u32.into(), 7u32.into()]); + } + + #[tokio::test] + async fn sum() { + let inputs = [1, 2, 3u32]; + let res = Cluster::new(3) + .with_args( + (0..3) + .map(|id| { + let me = Id(id); + type E = Exp; + let [a, b, c] = E::share_and_receive(inputs[id], me); + let sum: E = [a, b, c].into_iter().sum(); + let res = sum.open(); + res.finalize() + }) + .collect::>(), + ) + .execute_mock() + .await + .unwrap(); + + // 1 + 2 + 3 = 6 + assert_eq!(res, vec![6u32.into(), 6u32.into(), 6u32.into()]); + } + + #[tokio::test] + async fn sum_explist() { + let inputs = [1, 2, 3u32]; + let res = Cluster::new(3) + .with_args( + (0..3) + .map(|id| { + type E = Exp; + let exp = E::symmetric_share(inputs[id]); + let sum = exp.sum(); + let res = sum.open(); + res.finalize() + }) + .collect::>(), + ) + .execute_mock() + .await + .unwrap(); + + // 1 + 2 + 3 = 6 + assert_eq!(res, vec![6u32.into(), 6u32.into(), 6u32.into()]); + } +} diff --git a/wecare/Cargo.lock b/wecare/Cargo.lock index 2991f71..8e789a5 100644 --- a/wecare/Cargo.lock +++ b/wecare/Cargo.lock @@ -15,9 +15,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -55,6 +55,18 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + [[package]] name = "async-backtrace" version = "0.2.7" @@ -79,25 +91,47 @@ checksum = "affbba0d438add06462a0371997575927bc05052f7ec486e7a4ca405c956c3d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.76", +] + +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", ] [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.76", ] [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "az" @@ -107,9 +141,9 @@ checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", @@ -131,15 +165,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.3.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bitvec" @@ -162,11 +190,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + [[package]] name = "bytemuck" -version = "1.15.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" +checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31" [[package]] name = "byteorder" @@ -176,9 +210,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "caring" @@ -195,7 +229,7 @@ dependencies = [ "futures", "futures-concurrency", "group", - "itertools", + "itertools 0.13.0", "num-traits", "overload", "rand", @@ -208,6 +242,12 @@ dependencies = [ "tracing", ] +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "castaway" version = "0.2.3" @@ -219,9 +259,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.94" +version = "1.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7" +checksum = "50d2eb3cd3d1bf4529e31c215ee6f93ec5a3d536d9f578f93d9d33ee19562932" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -229,6 +272,58 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.5.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + [[package]] name = "convert_case" version = "0.4.0" @@ -237,13 +332,49 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools 0.10.5", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -265,9 +396,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -311,7 +442,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.76", ] [[package]] @@ -329,17 +460,23 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "convert_case", "proc-macro2", "quote", "rustc_version", - "syn 1.0.109", + "syn 2.0.76", ] +[[package]] +name = "diatomic-waker" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af873b6853650fb206431c52fa7bbf6917146b70a8a9979d6d141f5d5394086b" + [[package]] name = "digest" version = "0.10.7" @@ -352,9 +489,9 @@ dependencies = [ [[package]] name = "either" -version = "1.11.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "enum_dispatch" @@ -365,7 +502,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.76", ] [[package]] @@ -389,9 +526,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "ff" @@ -424,15 +561,15 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.7" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c007b1ae3abe1cb6f85a16305acd418b7ca6343b953633fee2b76d8f108b830f" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "fixed" -version = "2.0.0-alpha.27.0" +version = "2.0.0-alpha.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1bf398c70463a217e213bc751669e4c8509c5676df2444d7a5177722f8ddeaa" +checksum = "8276713fe97d959ae66a91bdac60a9a1b9e39d25513ccca4555fe1cf2571567f" dependencies = [ "az", "bytemuck", @@ -460,6 +597,17 @@ dependencies = [ "futures-util", ] +[[package]] +name = "futures-buffered" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91fa130f3777d0d4b0993653c20bc433026d3290627693c4ed1b18dd237357ab" +dependencies = [ + "diatomic-waker", + "futures-core", + "pin-project-lite", +] + [[package]] name = "futures-channel" version = "0.3.30" @@ -472,11 +620,12 @@ dependencies = [ [[package]] name = "futures-concurrency" -version = "7.6.0" +version = "7.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51ee14e256b9143bfafbf2fddeede6f396650bacf95d06fc1b3f2b503df129a0" +checksum = "4b14ac911e85d57c5ea6eef76d7b4d4a3177ecd15f4bea2e61927e9e3823e19f" dependencies = [ "bitvec", + "futures-buffered", "futures-core", "futures-lite", "pin-project", @@ -530,7 +679,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.76", ] [[package]] @@ -588,9 +737,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -599,9 +748,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "group" @@ -626,9 +775,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", @@ -640,15 +789,41 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] +[[package]] +name = "is-terminal" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +dependencies = [ + "hermit-abi 0.4.0", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.13.0" @@ -658,17 +833,32 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "linux-raw-sys" @@ -678,9 +868,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -688,9 +878,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "loom" @@ -716,28 +906,29 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi 0.3.9", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -772,28 +963,18 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "object" -version = "0.32.2" +version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" dependencies = [ "memchr", ] @@ -804,6 +985,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "oorandom" +version = "11.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" + [[package]] name = "overload" version = "0.1.1" @@ -818,9 +1005,9 @@ checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -828,15 +1015,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -856,7 +1043,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.76", ] [[package]] @@ -871,26 +1058,57 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "plotters" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" + +[[package]] +name = "plotters-svg" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" +dependencies = [ + "plotters-backend", +] + [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -953,23 +1171,23 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] name = "regex" -version = "1.10.4" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.6", - "regex-syntax 0.8.3", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -983,13 +1201,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.3", + "regex-syntax 0.8.4", ] [[package]] @@ -1000,15 +1218,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -1031,7 +1249,7 @@ version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.5.0", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -1040,9 +1258,24 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.16" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "ryu" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] [[package]] name = "scoped-tls" @@ -1058,28 +1291,40 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.198" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" +checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.198" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" +checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" dependencies = [ "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.76", +] + +[[package]] +name = "serde_json" +version = "1.0.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", ] [[package]] @@ -1091,11 +1336,17 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] @@ -1117,9 +1368,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", @@ -1133,9 +1384,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -1150,9 +1401,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.59" +version = "2.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a6531ffc7b071655e4ce2e04bd464c4830bb585a61cabb96cf808f05172615a" +checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" dependencies = [ "proc-macro2", "quote", @@ -1167,34 +1418,35 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.10.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", - "fastrand 2.1.0", + "fastrand 2.1.1", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.76", ] [[package]] @@ -1207,41 +1459,74 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tokio" -version = "1.37.0" +version = "1.39.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.76", +] + +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-test" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" +dependencies = [ + "async-stream", + "bytes", + "futures-core", + "tokio", + "tokio-stream", ] [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", @@ -1252,7 +1537,6 @@ dependencies = [ "pin-project-lite", "slab", "tokio", - "tracing", ] [[package]] @@ -1274,7 +1558,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.76", ] [[package]] @@ -1336,15 +1620,25 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "waker-fn" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] [[package]] name = "wasi" @@ -1352,17 +1646,86 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.76", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + +[[package]] +name = "web-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "wecare" version = "0.1.0" dependencies = [ "caring", + "castaway", + "criterion", "curve25519-dalek", "enum_dispatch", + "ff", "fixed", "rand", "tempfile", "tokio", + "tokio-test", ] [[package]] @@ -1381,6 +1744,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -1398,20 +1770,20 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] name = "windows-sys" -version = "0.52.0" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -1431,18 +1803,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -1453,9 +1825,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -1465,9 +1837,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -1477,15 +1849,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -1495,9 +1867,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -1507,9 +1879,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -1519,9 +1891,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -1531,9 +1903,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "wyz" @@ -1546,26 +1918,27 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.76", ] [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/wecare/Cargo.toml b/wecare/Cargo.toml index 396b3de..1aa21ef 100644 --- a/wecare/Cargo.toml +++ b/wecare/Cargo.toml @@ -10,8 +10,21 @@ caring = { path = ".." } tokio = { version = "1.33.0", features = ["full"] } curve25519-dalek = { version = "4.1.3", features = ["group", "serde"] } rand = "0.8.5" -fixed = "2.0.0-alpha.11" +fixed = "2.0.0-alpha.28.0" enum_dispatch = "0.3.13" +ff = "0.13.0" +castaway = "0.2.3" [dev-dependencies] +caring = { path = "..", features = ["test"]} +tokio-test = "0.4.4" +criterion = "0.5.1" tempfile = "3.10.1" + +[[bench]] +name = "spdz-25519" +harness = false + +[[bench]] +name = "shamir-25519" +harness = false diff --git a/wecare/benches/shamir-25519.rs b/wecare/benches/shamir-25519.rs new file mode 100644 index 0000000..586eb9a --- /dev/null +++ b/wecare/benches/shamir-25519.rs @@ -0,0 +1,112 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use std::{hint::black_box, thread}; +use std::{io::Write, time::Duration}; +use wecare::vm::{blocking, FieldKind}; +use wecare::{vm::Engine, vm::SchemeKind}; + +fn build_shamir_engines() -> (blocking::Engine, blocking::Engine) { + let clock = std::time::Instant::now(); + print!("Setting up engines..."); + let _ = std::io::stdout().flush(); + let (e1, e2) = thread::scope(|scope| { + let e2 = scope.spawn(|| { + Engine::builder() + .address("127.0.0.1:1234") + .participant("127.0.0.1:1235") + .scheme(SchemeKind::Shamir) + .field(FieldKind::Curve25519) + .single_threaded_runtime() + .connect_blocking() + .unwrap() + .build() + }); + let e1 = scope.spawn(|| { + thread::sleep(Duration::from_millis(200)); + Engine::builder() + .address("127.0.0.1:1235") + .participant("127.0.0.1:1234") + .scheme(SchemeKind::Shamir) + .field(FieldKind::Curve25519) + .single_threaded_runtime() + .connect_blocking() + .unwrap() + .build() + }); + (e1.join().unwrap(), e2.join().unwrap()) + }); + println!(" Complete! (took {:#?})", clock.elapsed()); + (e1, e2) +} + +fn criterion_benchmark(c: &mut Criterion) { + let (mut e1, mut e2) = build_shamir_engines(); + c.bench_function("shamir single", |b| { + let input1 = vec![7.0]; + let input2 = vec![3.0]; + b.iter(|| { + thread::scope(|scope| { + let t1 = scope.spawn(|| { + black_box(e1.sum(&input1)); + }); + let t2 = scope.spawn(|| { + black_box(e2.sum(&input2)); + }); + t1.join().unwrap(); + t2.join().unwrap(); + }); + }); + }); + c.bench_function("shamir vec32", |b| { + let input1 = vec![7.0; 32]; + let input2 = vec![3.0; 32]; + b.iter(|| { + thread::scope(|scope| { + let t1 = scope.spawn(|| { + black_box(e1.sum(&input1)); + }); + let t2 = scope.spawn(|| { + black_box(e2.sum(&input2)); + }); + t1.join().unwrap(); + t2.join().unwrap(); + }); + }); + }); + c.bench_function("shamir vec64", |b| { + let input1 = vec![7.0; 64]; + let input2 = vec![3.0; 64]; + b.iter(|| { + thread::scope(|scope| { + let t1 = scope.spawn(|| { + black_box(e1.sum(&input1)); + }); + let t2 = scope.spawn(|| { + black_box(e2.sum(&input2)); + }); + t1.join().unwrap(); + t2.join().unwrap(); + }); + }); + }); + c.bench_function("shamir vec128", |b| { + let input1 = vec![7.0; 128]; + let input2 = vec![3.0; 128]; + b.iter(|| { + thread::scope(|scope| { + let t1 = scope.spawn(|| { + black_box(e1.sum(&input1)); + }); + let t2 = scope.spawn(|| { + black_box(e2.sum(&input2)); + }); + t1.join().unwrap(); + t2.join().unwrap(); + }); + }); + }); + let _ = e1.shutdown(); + let _ = e2.shutdown(); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/wecare/benches/spdz-25519.rs b/wecare/benches/spdz-25519.rs new file mode 100644 index 0000000..37353c1 --- /dev/null +++ b/wecare/benches/spdz-25519.rs @@ -0,0 +1,133 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use std::time; +use std::{fs::File, hint::black_box, io::Seek, thread}; +use std::{io::Write, time::Duration}; +use wecare::{ + do_preproc, + vm::{blocking, Engine, FieldKind, SchemeKind}, +}; + +fn precompute(n: usize) -> (File, File) { + let clock = time::Instant::now(); + print!("\nPrecomputing..."); + let _ = std::io::stdout().flush(); + let ctx1 = tempfile::tempfile().unwrap(); + let ctx2 = tempfile::tempfile().unwrap(); + let mut files = [ctx1, ctx2]; + do_preproc(&mut files, &[n, n], false); + let [mut ctx1, mut ctx2] = files; + ctx1.rewind().unwrap(); + ctx2.rewind().unwrap(); + println!(" Complete! (took {:#?})", clock.elapsed()); + (ctx1, ctx2) +} + +fn build_spdz_engines() -> (blocking::Engine, blocking::Engine) { + let (mut ctx1, mut ctx2) = precompute(10000000); + let clock = time::Instant::now(); + print!("Setting up engines..."); + let _ = std::io::stdout().flush(); + let (e1, e2) = thread::scope(|scope| { + let e2 = scope.spawn(|| { + Engine::builder() + .address("127.0.0.1:1234") + .participant("127.0.0.1:1235") + .preprocessed(ctx1) + .scheme(SchemeKind::Spdz) + .field(FieldKind::Curve25519) + .single_threaded_runtime() + .connect_blocking() + .unwrap() + .build() + }); + let e1 = scope.spawn(|| { + thread::sleep(Duration::from_millis(200)); + Engine::builder() + .address("127.0.0.1:1235") + .participant("127.0.0.1:1234") + .preprocessed(ctx2) + .scheme(SchemeKind::Spdz) + .field(FieldKind::Curve25519) + .single_threaded_runtime() + .connect_blocking() + .unwrap() + .build() + }); + (e1.join().unwrap(), e2.join().unwrap()) + }); + println!(" Complete! (took {:#?})", clock.elapsed()); + (e1, e2) +} + +fn criterion_benchmark(c: &mut Criterion) { + let (mut e1, mut e2) = build_spdz_engines(); + c.bench_function("spdz single", |b| { + let input1 = vec![7.0]; + let input2 = vec![3.0]; + b.iter(|| { + thread::scope(|scope| { + let t1 = scope.spawn(|| { + black_box(e1.sum(&input1)); + }); + let t2 = scope.spawn(|| { + black_box(e2.sum(&input2)); + }); + t1.join().unwrap(); + t2.join().unwrap(); + }); + }); + }); + c.bench_function("spdz vec32", |b| { + let input1 = vec![7.0; 32]; + let input2 = vec![3.0; 32]; + b.iter(|| { + thread::scope(|scope| { + let t1 = scope.spawn(|| { + black_box(e1.sum(&input1)); + }); + let t2 = scope.spawn(|| { + black_box(e2.sum(&input2)); + }); + t1.join().unwrap(); + t2.join().unwrap(); + }); + }); + }); + c.bench_function("spdz vec64", |b| { + let input1 = vec![7.0; 64]; + let input2 = vec![3.0; 64]; + b.iter(|| { + thread::scope(|scope| { + let t1 = scope.spawn(|| { + black_box(e1.sum(&input1)); + }); + let t2 = scope.spawn(|| { + black_box(e2.sum(&input2)); + }); + t1.join().unwrap(); + t2.join().unwrap(); + }); + }); + }); + c.bench_function("spdz vec128", |b| { + let input1 = vec![7.0; 128]; + let input2 = vec![3.0; 128]; + b.iter(|| { + thread::scope(|scope| { + let t1 = scope.spawn(|| { + black_box(e1.sum(&input1)); + }); + let t2 = scope.spawn(|| { + black_box(e2.sum(&input2)); + }); + t1.join().unwrap(); + t2.join().unwrap(); + }); + }); + }); + let _ = e1.shutdown(); + let _ = e2.shutdown(); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/wecare/src/lib.rs b/wecare/src/lib.rs index f85deb6..c16f4a4 100644 --- a/wecare/src/lib.rs +++ b/wecare/src/lib.rs @@ -1,8 +1,15 @@ +#![feature(async_closure)] + +pub mod vm; + use caring::{ algebra::math::Vector, net::network::TcpNetwork, schemes::{ - feldman, interactive::InteractiveSharedMany, shamir, spdz::{self, preprocessing} + feldman, + interactive::InteractiveSharedMany, + shamir, + spdz::{self, preprocessing}, }, }; use curve25519_dalek::RistrettoPoint; @@ -44,18 +51,17 @@ impl Mapping for S25519 { impl Mapping for S32 { fn from_f64(val: f64) -> Self { - let num : i32 = FixedI32::<16>::from_num(val).to_bits(); + let num: i32 = FixedI32::<16>::from_num(val).to_bits(); S32::from(num as u32) } fn into_f64(val: Self) -> f64 { - let val : u32 = val.into(); - let val = FixedI32::<16>::from_bits(val as i32); + let val: u32 = val.into(); + let val = FixedI32::<16>::from_bits(val as i32); val.to_num() } } - pub struct AdderEngine { network: TcpNetwork, runtime: tokio::runtime::Runtime, @@ -64,7 +70,8 @@ pub struct AdderEngine { impl AdderEngine where - S: InteractiveSharedMany, F: Mapping + S: InteractiveSharedMany, + F: Mapping, { //pub fn setup_engine(my_addr: &str, others: &[impl AsRef], file_name: String) -> Result, MpcError> { fn new(network: TcpNetwork, runtime: Runtime, context: S::Context) -> Self { @@ -93,12 +100,7 @@ where context, } = self; - let nums: Vec<_> = nums - .iter() - .map(|&num| { - F::from_f64(num) - }) - .collect(); + let nums: Vec<_> = nums.iter().map(|&num| F::from_f64(num)).collect(); let rng = rand::rngs::StdRng::from_rng(thread_rng()).unwrap(); let res: Option<_> = runtime.block_on(async move { let ctx = context; @@ -111,10 +113,7 @@ where let sum: S::VectorShare = shares.into_iter().sum(); let res: Vector = S::recombine_many(ctx, sum, network).await.unwrap(); - let res = res - .into_iter() - .map(|x| F::into_f64(x)) - .collect(); + let res = res.into_iter().map(|x| F::into_f64(x)).collect(); Some(res) }); res @@ -139,28 +138,16 @@ impl std::fmt::Display for MpcError { impl std::error::Error for MpcError {} -pub fn do_preproc(files: &mut [File], number_of_shares: Vec, use_32: bool) { +pub fn do_preproc(files: &mut [File], number_of_shares: &[usize], use_32: bool) { assert_eq!(files.len(), number_of_shares.len()); let known_to_each = vec![number_of_shares[0], number_of_shares[1]]; let number_of_triplets = 0; if use_32 { let num = S32::from_f64(0.0); - preprocessing::write_preproc_to_file( - files, - known_to_each, - number_of_triplets, - num, - ) - .unwrap(); + preprocessing::write_context(files, known_to_each, number_of_triplets, num).unwrap(); } else { let num = S25519::from_f64(0.0); - preprocessing::write_preproc_to_file( - files, - known_to_each, - number_of_triplets, - num, - ) - .unwrap(); + preprocessing::write_context(files, known_to_each, number_of_triplets, num).unwrap(); } } @@ -187,18 +174,18 @@ mod generic { impl<'a> EngineBuilder<'a> { pub fn build_spdz(self) -> Result { - let (network, runtime) = self.semi_build()?; + let (network, runtime) = self.connect_network()?; let file = self .preprocessed .ok_or(MpcError("No proccesing file found"))?; if self.use_32bit_field { - let mut context = preprocessing::read_preproc_from_file(file); - context.params.who_am_i = network.index; + let mut context = preprocessing::load_context(file); + context.params.who_am_i = network.id(); let engine = SpdzEngine32::new(network, runtime, context); Ok(AdderEngine::Spdz32(engine)) } else { - let mut context = preprocessing::read_preproc_from_file(file); - context.params.who_am_i = network.index; + let mut context = preprocessing::load_context(file); + context.params.who_am_i = network.id(); let engine = SpdzEngine::new(network, runtime, context); Ok(AdderEngine::Spdz(engine)) } @@ -206,7 +193,7 @@ mod generic { pub fn build_shamir(self) -> Result { let threshold = self.threshold.ok_or(MpcError("No threshold found"))?; - let (network, runtime) = self.semi_build()?; + let (network, runtime) = self.connect_network()?; if self.use_32bit_field { let ids = network .participants() @@ -228,7 +215,7 @@ mod generic { pub fn build_feldman(self) -> Result { let threshold = self.threshold.ok_or(MpcError("No threshold found"))?; - let (network, runtime) = self.semi_build()?; + let (network, runtime) = self.connect_network()?; let ids = network .participants() .map(|id| (id + 1u32).into()) @@ -238,7 +225,7 @@ mod generic { Ok(AdderEngine::Feldman(engine)) } - fn semi_build(&self) -> Result<(TcpNetwork, Runtime), MpcError> { + fn connect_network(&self) -> Result<(TcpNetwork, Runtime), MpcError> { let my_addr: SocketAddr = self.my_addr.parse().unwrap(); let others: Vec = self.other_addr.iter().map(|s| s.parse().unwrap()).collect(); @@ -300,7 +287,7 @@ mod generic { AdderEngine::Spdz32(e) => e.mpc_sum(nums), AdderEngine::Shamir(e) => e.mpc_sum(nums), AdderEngine::Shamir32(e) => e.mpc_sum(nums), - AdderEngine::Feldman(e) => e.mpc_sum(nums) + AdderEngine::Feldman(e) => e.mpc_sum(nums), } } @@ -375,7 +362,7 @@ mod test { let ctx1 = tempfile::tempfile().unwrap(); let ctx2 = tempfile::tempfile().unwrap(); let mut files = [ctx1, ctx2]; - do_preproc(&mut files, vec![1, 1], false); + do_preproc(&mut files, &[1, 1], false); let [mut ctx1, mut ctx2] = files; ctx1.rewind().unwrap(); ctx2.rewind().unwrap(); @@ -420,7 +407,7 @@ mod test { let ctx1 = tempfile::tempfile().unwrap(); let ctx2 = tempfile::tempfile().unwrap(); let mut files = [ctx1, ctx2]; - do_preproc(&mut files, vec![2, 2], false); + do_preproc(&mut files, &[2, 2], false); let [mut ctx1, mut ctx2] = files; ctx1.rewind().unwrap(); ctx2.rewind().unwrap(); @@ -437,7 +424,7 @@ mod test { drop(engine); res }); - std::thread::sleep(Duration::from_millis(50)); + std::thread::sleep(Duration::from_millis(200)); let t2 = thread::spawn(move || { println!("[2] Setting up..."); let mut engine = Engine::setup("127.0.0.1:2235") diff --git a/wecare/src/vm.rs b/wecare/src/vm.rs new file mode 100644 index 0000000..f1154ce --- /dev/null +++ b/wecare/src/vm.rs @@ -0,0 +1,537 @@ +use std::{ + fs::File, + net::{SocketAddr, ToSocketAddrs}, +}; + +use curve25519_dalek::{RistrettoPoint, Scalar}; +use fixed::{FixedI128, FixedI32}; +use rand::{rngs::StdRng, SeedableRng}; + +use caring::{ + algebra::{element::Element32, math::Vector}, + net::{agency::Broadcast, connection::TcpConnection, network::TcpNetwork}, + schemes::{feldman, shamir, spdz}, + vm::{self, parsing::Exp}, +}; + +pub use caring::net::Id; +pub use caring::vm::Value; + +#[derive(Clone, Copy)] +pub enum Number { + Float(f64), + Integer(u64), + SignedInteger(i64), +} + +impl From for Number { + fn from(value: f64) -> Self { + Number::Float(value) + } +} + +impl From for Number { + fn from(value: u64) -> Self { + Number::Integer(value) + } +} + +impl From for Number { + fn from(value: i64) -> Self { + Number::SignedInteger(value) + } +} + +impl TryFrom for Element32 { + type Error = String; + fn try_from(value: Number) -> Result { + match value { + Number::Float(float) => { + let num: i32 = FixedI32::<16>::from_num(float).to_bits(); + Ok(Element32::from(num as u32)) + } + Number::Integer(uint) => { + let uint: u32 = uint + .try_into() + .map_err(|_| format!("Could not fit {uint} into an u32"))?; + Ok(Element32::from(uint)) + } + Number::SignedInteger(int) => { + let int: i32 = int + .try_into() + .map_err(|_| format!("Could not fit {int} into an u32"))?; + let uint: u32 = if int.is_negative() { + u32::MAX / 2 - int.unsigned_abs() + } else { + u32::MAX / 2 + int as u32 + }; + Ok(Element32::from(uint)) + } + } + } +} + +impl TryFrom for Scalar { + type Error = String; + fn try_from(value: Number) -> Result { + match value { + Number::Float(float) => { + let num: i128 = FixedI128::<64>::from_num(float).to_bits(); + Ok(Scalar::from(num as u128)) + } + Number::Integer(uint) => { + let uint: u128 = uint.into(); + Ok(Scalar::from(uint)) + } + Number::SignedInteger(int) => { + let int: i128 = int.into(); + let uint: u128 = if int.is_negative() { + u128::MAX / 2 - int.unsigned_abs() + } else { + u128::MAX / 2 + int as u128 + }; + Ok(Scalar::from(uint)) + } + } + } +} + +#[derive(Clone, Copy)] +pub enum UnknownNumber { + U32(u32), + U64(u64), + U128(u128), +} + +impl UnknownNumber { + pub fn to_u64(self) -> u64 { + match self { + UnknownNumber::U32(a) => a.into(), + UnknownNumber::U64(a) => a, + UnknownNumber::U128(a) => a as u64, + } + } + + pub fn to_i64(self) -> i64 { + todo!() + } + + pub fn to_f64(self) -> f64 { + match self { + UnknownNumber::U32(val) => { + let val = FixedI32::<16>::from_bits(val as i32); + val.to_num() + } + UnknownNumber::U64(_) => todo!(), + UnknownNumber::U128(val) => { + let num = FixedI128::<64>::from_bits(val as i128); + num.to_num() + } + } + } +} + +impl From for UnknownNumber { + fn from(value: Element32) -> Self { + let value: u32 = value.into(); + Self::U32(value) + } +} + +impl From for UnknownNumber { + fn from(value: Scalar) -> Self { + let val = u128::from_le_bytes(value.as_bytes()[0..128 / 8].try_into().unwrap()); + Self::U128(val) + } +} + +type ShamirEngine = vm::Engine, StdRng>; +type SpdzEngine = vm::Engine, StdRng>; +type FeldmanEngine = vm::Engine, StdRng>; + +type ShamirCurve25519Engine = ShamirEngine; +type ShamirElement32Engine = ShamirEngine; +type SpdzCurve25519Engine = SpdzEngine; +type SpdzElement32Engine = SpdzEngine; + +pub type Expr = Exp; +pub type Opened = vm::parsing::Opened; + +pub enum Engine { + Spdz25519(SpdzCurve25519Engine), + Spdz32(SpdzElement32Engine), + Shamir25519(ShamirCurve25519Engine), + Shamir32(ShamirElement32Engine), + Feldman25519(FeldmanEngine), +} + +macro_rules! delegate { + ($self:expr, $func:ident) => { + match $self { + Engine::Spdz25519(e) => e.$func().into(), + Engine::Spdz32(e) => e.$func().into(), + Engine::Shamir25519(e) => e.$func().into(), + Engine::Shamir32(e) => e.$func().into(), + Engine::Feldman25519(e) => e.$func().into(), + } + }; +} + +macro_rules! delegate_await { + ($self:expr, $func:ident) => { + match $self { + Engine::Spdz25519(e) => e.$func().await.into(), + Engine::Spdz32(e) => e.$func().await.into(), + Engine::Shamir25519(e) => e.$func().await.into(), + Engine::Shamir32(e) => e.$func().await.into(), + Engine::Feldman25519(e) => e.$func().await.into(), + } + }; +} + +impl Engine { + pub fn builder() -> EngineBuilder { + EngineBuilder::default() + } + + pub async fn execute(&mut self, expr: Opened) -> Value { + let res: Value = match self { + Engine::Spdz25519(engine) => { + let res = engine.execute(&expr.try_finalize().unwrap()).await; + res.map(|x| x.into()) + } + Engine::Shamir32(engine) => engine + .execute(&expr.try_finalize().unwrap()) + .await + .map(|x| x.into()), + Engine::Spdz32(engine) => { + let res = engine.execute(&expr.try_finalize().unwrap()).await; + res.map(|x| x.into()) + } + Engine::Shamir25519(engine) => { + let res = engine.execute(&expr.try_finalize().unwrap()).await; + res.map(|x| x.into()) + } + Engine::Feldman25519(engine) => { + let res = engine.execute(&expr.try_finalize().unwrap()).await; + res.map(|x| x.into()) + } + }; + res + } + + pub fn id(&self) -> Id { + delegate!(self, id) + } + + pub fn peers(&self) -> Vec { + delegate!(self, peers) + } + + pub async fn sum(&mut self, nums: &[f64]) -> Vec { + let nums: Vector<_> = nums.iter().map(|v| Number::Float(*v)).collect(); + let program = { + let explist = Expr::symmetric_share_vec(nums); + explist.sum().open() + }; + self.execute(program) + .await + .unwrap_vector() + .into_iter() + .map(|x| x.to_f64()) + .collect() + } + + pub async fn shutdown(self) -> Result<(), std::io::Error> { + delegate_await!(self, shutdown) + } +} + +pub enum FieldKind { + Curve25519, + Element32, +} + +pub enum SchemeKind { + Shamir, + Spdz, + Feldman, +} + +#[derive(Default)] +pub struct EngineBuilder { + own: Option, + peers: Vec, + network: Option, + threshold: Option, + preprocesing: Option, + field: Option, + scheme: Option, +} + +impl EngineBuilder { + pub fn address(mut self, addr: impl ToSocketAddrs) -> Self { + // TODO: Handle this better + self.own + .replace(addr.to_socket_addrs().unwrap().next().unwrap()); + self + } + + pub fn participant(mut self, addr: impl ToSocketAddrs) -> Self { + // TODO: Handle this better + self.peers + .push(addr.to_socket_addrs().unwrap().next().unwrap()); + self + } + + pub fn participants(mut self, addrs: impl ToSocketAddrs) -> Self { + let addrs = addrs.to_socket_addrs().unwrap(); + self.peers.extend(addrs); + self + } + + pub fn participants_from( + mut self, + addrs: impl IntoIterator, + ) -> Self { + let addrs = addrs + .into_iter() + .map(|a| a.to_socket_addrs().unwrap().next().unwrap()); + self.peers.extend(addrs); + self + } + + pub fn threshold(mut self, t: u64) -> Self { + self.threshold = Some(t); + self + } + + pub fn preprocessed(mut self, file: File) -> Self { + self.preprocesing = Some(file); + self + } + + pub fn scheme(mut self, scheme: SchemeKind) -> Self { + self.scheme = Some(scheme); + self + } + + pub fn field(mut self, field: FieldKind) -> Self { + self.field = Some(field); + self + } + + pub async fn connect(mut self) -> Result { + let network = TcpNetwork::connect(self.own.unwrap(), &self.peers) + .await + .map_err(|_| "Bad thing happened")?; + + self.network = Some(network); + Ok(self) + } + + pub fn build(self) -> Engine { + let network = self.network.expect("No network installed!"); + let party_count = network.size(); + let scheme = self.scheme.unwrap_or(SchemeKind::Shamir); + let threshold = self.threshold.unwrap_or(party_count as u64); + let field = self.field.unwrap_or(FieldKind::Curve25519); + let rng = rand::rngs::StdRng::from_entropy(); + + match (scheme, field) { + (SchemeKind::Shamir, FieldKind::Curve25519) => { + let ids = network + .participants() + .map(|id| (id + 1u32).into()) + .collect(); + let context = shamir::ShamirParams { threshold, ids }; + Engine::Shamir25519(vm::Engine::new(context, network, rng)) + } + (SchemeKind::Shamir, FieldKind::Element32) => { + let ids = network + .participants() + .map(|id| (id + 1u32).into()) + .collect(); + let context = shamir::ShamirParams { threshold, ids }; + Engine::Shamir32(vm::Engine::new(context, network, rng)) + } + (SchemeKind::Spdz, FieldKind::Curve25519) => { + let mut file = self.preprocesing.expect("Missing preproc!"); + let context = spdz::preprocessing::load_context(&mut file); + Engine::Spdz25519(vm::Engine::new(context, network, rng)) + } + (SchemeKind::Spdz, FieldKind::Element32) => { + let mut file = self.preprocesing.expect("Missing preproc!"); + let context = spdz::preprocessing::load_context(&mut file); + Engine::Spdz32(vm::Engine::new(context, network, rng)) + } + (SchemeKind::Feldman, FieldKind::Curve25519) => { + let ids = network + .participants() + .map(|id| (id + 1u32).into()) + .collect(); + let context = shamir::ShamirParams { threshold, ids }; + Engine::Feldman25519(vm::Engine::new(context, network, rng)) + } + (SchemeKind::Feldman, FieldKind::Element32) => { + panic!("Can't construct feldman from this field element. Missing group!") + } + } + } +} + +pub mod blocking { + use caring::{net::Id, vm::Value}; + + use crate::vm::UnknownNumber; + + pub struct Engine { + parent: super::Engine, + runtime: tokio::runtime::Runtime, + } + + pub struct EngineBuilder { + parent: super::EngineBuilder, + runtime: tokio::runtime::Runtime, + } + + impl super::EngineBuilder { + pub fn single_threaded_runtime(self) -> EngineBuilder { + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + EngineBuilder { + parent: self, + runtime, + } + } + pub fn multi_threaded_runtime(self) -> EngineBuilder { + let runtime = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap(); + EngineBuilder { + parent: self, + runtime, + } + } + } + + impl EngineBuilder { + pub fn connect_blocking(mut self) -> Result { + let runtime = &mut self.runtime; + let mut parent = self.parent; + parent = runtime.block_on(async move { parent.connect().await })?; + self.parent = parent; + Ok(self) + } + + pub fn build(self) -> Engine { + let parent = self.parent.build(); + Engine { + runtime: self.runtime, + parent, + } + } + } + + impl Engine { + pub fn execute(&mut self, expr: super::Opened) -> Value { + self.runtime.block_on(self.parent.execute(expr)) + } + + pub fn id(&self) -> Id { + self.parent.id() + } + + pub fn peers(&self) -> Vec { + self.parent.peers() + } + + pub fn sum(&mut self, nums: &[f64]) -> Vec { + self.runtime.block_on(self.parent.sum(nums)) + } + + pub fn shutdown(self) -> Result<(), std::io::Error> { + self.runtime.block_on(self.parent.shutdown()) + } + } +} + +#[cfg(test)] +mod test { + use std::{thread, time::Duration}; + + use crate::vm::{blocking, Engine, Expr, FieldKind, SchemeKind}; + + #[test] + fn addition() { + fn engine(addr: &str, peers: [&str; 2]) -> blocking::Engine { + Engine::builder() + .address(addr) + .participants_from(peers) + .scheme(SchemeKind::Shamir) + .field(FieldKind::Curve25519) + .single_threaded_runtime() + .connect_blocking() + .unwrap() + .build() + } + let addrs = ["127.0.0.1:3235", "127.0.0.1:3236", "127.0.0.1:3237"]; + let res = thread::scope(|scope| { + [ + scope.spawn(|| { + println!("Party 0: Starting"); + let mut engine = engine(addrs[0], [addrs[1], addrs[2]]); + let me = engine.id(); + + let num = 3.0; + let [a, b, c] = Expr::share_and_receive(num, me); + let sum = a + b + c; + let res = sum.open(); + let script = res; + + println!("Party 0: Executing"); + let res = engine.execute(script); + res.unwrap_single().to_f64() + }), + scope.spawn(|| { + std::thread::sleep(Duration::from_millis(50)); + println!("Party 1: Starting"); + let mut engine = engine(addrs[1], [addrs[0], addrs[2]]); + let me = engine.id(); + + let num = 7.0; + let [a, b, c] = Expr::share_and_receive(num, me); + let sum = a + b + c; + let res = sum.open(); + let script = res; + + println!("Party 1: Executing"); + let res = engine.execute(script); + res.unwrap_single().to_f64() + }), + scope.spawn(|| { + std::thread::sleep(Duration::from_millis(100)); + println!("Party 2: Starting"); + let mut engine = engine(addrs[2], [addrs[0], addrs[1]]); + let me = engine.id(); + + let num = 13.0; + let [a, b, c] = Expr::share_and_receive(num, me); + let sum = a + b + c; + let res = sum.open(); + let script = res; + + println!("Party 2: Executing"); + let res = engine.execute(script); + res.unwrap_single().to_f64() + }), + ] + .map(|t| t.join().unwrap()) + }); + + assert_eq!(&res, &[23.0, 23.0, 23.0]) + } +}