From 60cad202a2bf62cec27ecfd5cd1a81effe1e4e37 Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Mon, 3 Jul 2023 15:46:30 +0200
Subject: [PATCH] feat: expose ferveo variant in bindings
---
ferveo-python/ferveo/__init__.py | 2 ++
ferveo-python/ferveo/__init__.pyi | 14 ++++++++
ferveo-python/test/test_serialization.py | 7 +++-
ferveo/src/api.rs | 32 +++++++++++++++++-
ferveo/src/bindings_python.rs | 43 +++++++++++++++++++++++-
ferveo/src/bindings_wasm.rs | 37 ++++++++++++++++++++
ferveo/src/lib.rs | 3 ++
7 files changed, 135 insertions(+), 3 deletions(-)
diff --git a/ferveo-python/ferveo/__init__.py b/ferveo-python/ferveo/__init__.py
index fbaab504..869f3a18 100644
--- a/ferveo-python/ferveo/__init__.py
+++ b/ferveo-python/ferveo/__init__.py
@@ -15,6 +15,7 @@
DkgPublicKey,
SharedSecret,
ValidatorMessage,
+ FerveoVariant,
ThresholdEncryptionError,
InvalidShareNumberParameter,
InvalidDkgStateToDeal,
@@ -32,4 +33,5 @@
ValidatorsNotSorted,
ValidatorPublicKeyMismatch,
SerializationError,
+ InvalidVariant,
)
diff --git a/ferveo-python/ferveo/__init__.pyi b/ferveo-python/ferveo/__init__.pyi
index 170e98b0..b31a7b6c 100644
--- a/ferveo-python/ferveo/__init__.pyi
+++ b/ferveo-python/ferveo/__init__.pyi
@@ -170,6 +170,16 @@ class SharedSecret:
...
+# TODO: Figure out how to make this a proper enum or expose a plain class
+class FerveoVariant:
+
+ def from_string(self, variant: str) -> FerveoVariant:
+ ...
+
+ def __str__(self) -> str:
+ ...
+
+
def encrypt(message: bytes, add: bytes, dkg_public_key: DkgPublicKey) -> Ciphertext:
...
@@ -260,3 +270,7 @@ class ValidatorPublicKeyMismatch(Exception):
class SerializationError(Exception):
pass
+
+
+class InvalidVariant(Exception):
+ pass
diff --git a/ferveo-python/test/test_serialization.py b/ferveo-python/test/test_serialization.py
index e5de35f0..da776f1e 100644
--- a/ferveo-python/test/test_serialization.py
+++ b/ferveo-python/test/test_serialization.py
@@ -4,6 +4,7 @@
Dkg,
DkgPublicKey,
FerveoPublicKey,
+ FerveoVariant,
)
@@ -64,7 +65,11 @@ def test_dkg_public_key_serialization():
assert len(serialized) == DkgPublicKey.serialized_size()
-def test_dkg_public_key_serialization():
+def test_public_key_serialization():
pk = make_pk()
serialized = bytes(pk)
assert len(serialized) == FerveoPublicKey.serialized_size()
+
+# TODO: Consider different API, FerveoVariant.Precomputed etc.
+def test_ferveo_variant_serialization():
+ variant = FerveoVariant('FerveoVariant::Precomputed')
diff --git a/ferveo/src/api.rs b/ferveo/src/api.rs
index 99c5af02..1c3bfe35 100644
--- a/ferveo/src/api.rs
+++ b/ferveo/src/api.rs
@@ -1,4 +1,4 @@
-use std::io;
+use std::{fmt, io};
use ark_poly::{EvaluationDomain, Radix2EvaluationDomain};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
@@ -69,6 +69,36 @@ pub fn decrypt_with_shared_secret(
.map_err(Error::from)
}
+#[serde_as]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
+pub enum FerveoVariant {
+ Simple = 0_isize,
+ Precomputed = 1_isize,
+}
+
+impl fmt::Display for FerveoVariant {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", self.as_str())
+ }
+}
+
+impl FerveoVariant {
+ pub fn as_str(&self) -> &'static str {
+ match self {
+ FerveoVariant::Simple => "FerveoVariant::Simple",
+ FerveoVariant::Precomputed => "FerveoVariant::Precomputed",
+ }
+ }
+
+ pub fn from_string(s: &str) -> Result {
+ match s {
+ "FerveoVariant::Simple" => Ok(FerveoVariant::Simple),
+ "FerveoVariant::Precomputed" => Ok(FerveoVariant::Precomputed),
+ _ => Err(Error::InvalidVariant(s.to_string())),
+ }
+ }
+}
+
#[serde_as]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct DkgPublicKey(
diff --git a/ferveo/src/bindings_python.rs b/ferveo/src/bindings_python.rs
index 05756164..408a4164 100644
--- a/ferveo/src/bindings_python.rs
+++ b/ferveo/src/bindings_python.rs
@@ -6,7 +6,7 @@ use pyo3::{
create_exception,
exceptions::{PyException, PyRuntimeError, PyValueError},
prelude::*,
- types::{PyBytes, PyUnicode},
+ types::{PyBytes, PyString, PyUnicode},
PyClass,
};
use rand::thread_rng;
@@ -94,6 +94,9 @@ impl From for PyErr {
expected, actual
))
}
+ Error::InvalidVariant(variant) => {
+ InvalidVariant::new_err(variant.to_string())
+ }
},
_ => default(),
}
@@ -128,6 +131,7 @@ create_exception!(exceptions, ValidatorsNotSorted, PyValueError);
create_exception!(exceptions, ValidatorPublicKeyMismatch, PyValueError);
create_exception!(exceptions, SerializationError, PyValueError);
create_exception!(exceptions, InvalidByteLength, PyValueError);
+create_exception!(exceptions, InvalidVariant, PyValueError);
fn from_py_bytes(bytes: &[u8]) -> PyResult {
T::from_bytes(bytes)
@@ -278,6 +282,41 @@ pub fn decrypt_with_shared_secret(
.map_err(|err| FerveoPythonError::FerveoError(err).into())
}
+#[pyclass(module = "ferveo")]
+pub enum FerveoVariant {
+ Simple = api::FerveoVariant::Simple as isize,
+ Precomputed = api::FerveoVariant::Precomputed as isize,
+}
+
+impl From for FerveoVariant {
+ fn from(variant: api::FerveoVariant) -> Self {
+ match variant {
+ api::FerveoVariant::Simple => FerveoVariant::Simple,
+ api::FerveoVariant::Precomputed => FerveoVariant::Precomputed,
+ }
+ }
+}
+
+#[pymethods]
+impl FerveoVariant {
+ #[new]
+ pub fn new(s: &PyString) -> PyResult {
+ api::FerveoVariant::from_string(s.to_string().as_str())
+ .map_err(|err| FerveoPythonError::FerveoError(err).into())
+ .map(|variant| variant.into())
+ }
+
+ #[getter]
+ pub fn __str__(&self) -> String {
+ match self {
+ FerveoVariant::Simple => api::FerveoVariant::Simple.to_string(),
+ FerveoVariant::Precomputed => {
+ api::FerveoVariant::Precomputed.to_string()
+ }
+ }
+ }
+}
+
#[pyclass(module = "ferveo")]
#[derive(derive_more::AsRef)]
pub struct SharedSecret(api::SharedSecret);
@@ -600,6 +639,7 @@ pub fn make_ferveo_py_module(py: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_class::()?;
m.add_class::()?;
m.add_class::()?;
+ m.add_class::()?;
// Exceptions
m.add(
@@ -655,6 +695,7 @@ pub fn make_ferveo_py_module(py: Python<'_>, m: &PyModule) -> PyResult<()> {
py.get_type::(),
)?;
m.add("SerializationError", py.get_type::())?;
+ m.add("InvalidVariant", py.get_type::())?;
Ok(())
}
diff --git a/ferveo/src/bindings_wasm.rs b/ferveo/src/bindings_wasm.rs
index 8e071564..5f23596a 100644
--- a/ferveo/src/bindings_wasm.rs
+++ b/ferveo/src/bindings_wasm.rs
@@ -161,6 +161,43 @@ macro_rules! generate_common_methods {
};
}
+#[derive(TryFromJsValue)]
+#[wasm_bindgen]
+#[derive(Clone, Debug, derive_more::AsRef, derive_more::From)]
+pub struct FerveoVariant {
+ variant: api::FerveoVariant,
+}
+
+#[wasm_bindgen]
+impl FerveoVariant {
+ #[wasm_bindgen(js_name = "fromString")]
+ pub fn from_string(s: &str) -> JsResult {
+ let variant = api::FerveoVariant::from_string(s).map_err(map_js_err)?;
+ Ok(Self { variant })
+ }
+
+ // Allow `to_string` here because we want to expose it to bindings
+ #[allow(clippy::inherent_to_string)]
+ #[wasm_bindgen(js_name = "toString")]
+ pub fn to_string(&self) -> String {
+ self.variant.to_string()
+ }
+
+ #[wasm_bindgen(js_name = "Precomputed", getter)]
+ pub fn precomputed() -> FerveoVariant {
+ Self {
+ variant: api::FerveoVariant::Precomputed,
+ }
+ }
+
+ #[wasm_bindgen(js_name = "Simple", getter)]
+ pub fn simple() -> FerveoVariant {
+ Self {
+ variant: api::FerveoVariant::Simple,
+ }
+ }
+}
+
#[derive(TryFromJsValue)]
#[wasm_bindgen]
#[derive(Clone, Debug, derive_more::AsRef, derive_more::From)]
diff --git a/ferveo/src/lib.rs b/ferveo/src/lib.rs
index 7e1b3657..036e2fca 100644
--- a/ferveo/src/lib.rs
+++ b/ferveo/src/lib.rs
@@ -101,6 +101,9 @@ pub enum Error {
#[error("Invalid byte length. Expected {0}, got {1}")]
InvalidByteLength(usize, usize),
+
+ #[error("Invalid variant: {0}")]
+ InvalidVariant(String),
}
pub type Result = std::result::Result;