use crate::arithmetic::py::group_elements::PyGroupElement;
use crate::core::py::elgamal::PyElGamal;
use crate::data::padding::Padded;
use crate::data::simple::*;
use derive_more::{Deref, From, Into};
use pyo3::prelude::*;
use pyo3::types::{PyAny, PyBytes};
use pyo3::Py;
#[pyclass(name = "Pseudonym", from_py_object)]
#[derive(Copy, Clone, Eq, PartialEq, Debug, From, Into, Deref)]
pub struct PyPseudonym(pub(crate) Pseudonym);
#[pymethods]
#[allow(clippy::wrong_self_convention)]
impl PyPseudonym {
#[new]
fn new(x: PyGroupElement) -> Self {
Self(Pseudonym::from_point(x.0))
}
#[pyo3(name = "to_point")]
fn to_point(&self) -> PyGroupElement {
self.0.value.into()
}
#[staticmethod]
#[pyo3(name = "random")]
fn random() -> Self {
let mut rng = rand::rng();
Self(Pseudonym::random(&mut rng))
}
#[pyo3(name = "to_bytes")]
fn encode(&self, py: Python) -> Py<PyAny> {
PyBytes::new(py, &self.0.to_bytes()).into()
}
#[pyo3(name = "to_hex")]
fn as_hex(&self) -> String {
self.0.to_hex()
}
#[staticmethod]
#[pyo3(name = "from_bytes")]
fn decode(bytes: &[u8]) -> Option<Self> {
Pseudonym::from_slice(bytes).map(Self)
}
#[staticmethod]
#[pyo3(name = "from_hex")]
fn from_hex(hex: &str) -> Option<Self> {
Pseudonym::from_hex(hex).map(Self)
}
#[staticmethod]
#[pyo3(name = "from_hash")]
fn from_hash(v: &[u8]) -> PyResult<Self> {
if v.len() != 64 {
return Err(pyo3::exceptions::PyValueError::new_err(
"Hash must be 64 bytes",
));
}
let mut arr = [0u8; 64];
arr.copy_from_slice(v);
Ok(Pseudonym::from_hash(&arr).into())
}
#[staticmethod]
#[pyo3(name = "from_lizard")]
fn from_lizard(data: &[u8]) -> PyResult<Self> {
if data.len() != 16 {
return Err(pyo3::exceptions::PyValueError::new_err(
"Data must be 16 bytes",
));
}
let mut arr = [0u8; 16];
arr.copy_from_slice(data);
Ok(Self(Pseudonym::from_lizard(&arr)))
}
#[pyo3(name = "to_lizard")]
fn to_lizard(&self, py: Python) -> Option<Py<PyAny>> {
self.0.to_lizard().map(|x| PyBytes::new(py, &x).into())
}
#[staticmethod]
#[pyo3(name = "from_bytes_padded")]
fn from_bytes_padded(data: &[u8]) -> PyResult<Self> {
Pseudonym::from_bytes_padded(data)
.map(Self)
.map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("Encoding failed: {e}")))
}
#[staticmethod]
#[pyo3(name = "from_string_padded")]
fn from_string_padded(text: &str) -> PyResult<Self> {
Pseudonym::from_string_padded(text)
.map(Self)
.map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("Encoding failed: {e}")))
}
#[pyo3(name = "to_string_padded")]
fn to_string_padded(&self) -> PyResult<String> {
self.0
.to_string_padded()
.map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("Decoding failed: {e}")))
}
#[pyo3(name = "to_bytes_padded")]
fn to_bytes_padded(&self, py: Python) -> PyResult<Py<PyAny>> {
let result = self.0.to_bytes_padded().map_err(|e| {
pyo3::exceptions::PyValueError::new_err(format!("Decoding failed: {e}"))
})?;
Ok(PyBytes::new(py, &result).into())
}
fn __repr__(&self) -> String {
format!("Pseudonym({})", self.as_hex())
}
fn __str__(&self) -> String {
self.as_hex()
}
fn __eq__(&self, other: &PyPseudonym) -> bool {
self.0 == other.0
}
}
#[pyclass(name = "Attribute", from_py_object)]
#[derive(Copy, Clone, Eq, PartialEq, Debug, From, Into, Deref)]
pub struct PyAttribute(pub(crate) Attribute);
#[pymethods]
#[allow(clippy::wrong_self_convention)]
impl PyAttribute {
#[new]
fn new(x: PyGroupElement) -> Self {
Self(Attribute::from_point(x.0))
}
#[pyo3(name = "to_point")]
fn to_point(&self) -> PyGroupElement {
self.0.value.into()
}
#[staticmethod]
#[pyo3(name = "random")]
fn random() -> Self {
let mut rng = rand::rng();
Self(Attribute::random(&mut rng))
}
#[pyo3(name = "to_bytes")]
fn encode(&self, py: Python) -> Py<PyAny> {
PyBytes::new(py, &self.0.to_bytes()).into()
}
#[pyo3(name = "to_hex")]
fn as_hex(&self) -> String {
self.0.to_hex()
}
#[staticmethod]
#[pyo3(name = "from_bytes")]
fn decode(bytes: &[u8]) -> Option<Self> {
Attribute::from_slice(bytes).map(Self)
}
#[staticmethod]
#[pyo3(name = "from_hex")]
fn from_hex(hex: &str) -> Option<Self> {
Attribute::from_hex(hex).map(Self)
}
#[staticmethod]
#[pyo3(name = "from_hash")]
fn from_hash(v: &[u8]) -> PyResult<Self> {
if v.len() != 64 {
return Err(pyo3::exceptions::PyValueError::new_err(
"Hash must be 64 bytes",
));
}
let mut arr = [0u8; 64];
arr.copy_from_slice(v);
Ok(Attribute::from_hash(&arr).into())
}
#[staticmethod]
#[pyo3(name = "from_lizard")]
fn from_lizard(data: &[u8]) -> PyResult<Self> {
if data.len() != 16 {
return Err(pyo3::exceptions::PyValueError::new_err(
"Data must be 16 bytes",
));
}
let mut arr = [0u8; 16];
arr.copy_from_slice(data);
Ok(Self(Attribute::from_lizard(&arr)))
}
#[pyo3(name = "to_lizard")]
fn to_lizard(&self, py: Python) -> Option<Py<PyAny>> {
self.0.to_lizard().map(|x| PyBytes::new(py, &x).into())
}
#[staticmethod]
#[pyo3(name = "from_bytes_padded")]
fn from_bytes_padded(data: &[u8]) -> PyResult<Self> {
Attribute::from_bytes_padded(data)
.map(Self)
.map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("Encoding failed: {e}")))
}
#[staticmethod]
#[pyo3(name = "from_string_padded")]
fn from_string_padded(text: &str) -> PyResult<Self> {
Attribute::from_string_padded(text)
.map(Self)
.map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("Encoding failed: {e}")))
}
#[pyo3(name = "to_string_padded")]
fn to_string_padded(&self) -> PyResult<String> {
self.0
.to_string_padded()
.map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("Decoding failed: {e}")))
}
#[pyo3(name = "to_bytes_padded")]
fn to_bytes_padded(&self, py: Python) -> PyResult<Py<PyAny>> {
let result = self.0.to_bytes_padded().map_err(|e| {
pyo3::exceptions::PyValueError::new_err(format!("Decoding failed: {e}"))
})?;
Ok(PyBytes::new(py, &result).into())
}
fn __repr__(&self) -> String {
format!("Attribute({})", self.as_hex())
}
fn __str__(&self) -> String {
self.as_hex()
}
fn __eq__(&self, other: &PyAttribute) -> bool {
self.0 == other.0
}
}
#[pyclass(name = "EncryptedPseudonym", from_py_object)]
#[derive(Copy, Clone, Eq, PartialEq, Debug, From, Into, Deref)]
pub struct PyEncryptedPseudonym(pub(crate) EncryptedPseudonym);
#[pymethods]
impl PyEncryptedPseudonym {
#[new]
fn new(x: PyElGamal) -> Self {
Self(EncryptedPseudonym::from(x.0))
}
#[pyo3(name = "to_bytes")]
fn encode(&self, py: Python) -> Py<PyAny> {
PyBytes::new(py, &self.0.to_bytes()).into()
}
#[staticmethod]
#[pyo3(name = "from_bytes")]
fn decode(v: &[u8]) -> Option<Self> {
use crate::core::elgamal::ElGamal;
ElGamal::from_slice(v).map(|eg| Self(EncryptedPseudonym::from(eg)))
}
#[pyo3(name = "to_base64")]
fn as_base64(&self) -> String {
self.to_base64()
}
#[staticmethod]
#[pyo3(name = "from_base64")]
fn from_base64(s: &str) -> Option<Self> {
EncryptedPseudonym::from_base64(s).map(Self)
}
fn __repr__(&self) -> String {
format!("EncryptedPseudonym({})", self.to_base64())
}
fn __str__(&self) -> String {
self.to_base64()
}
fn __eq__(&self, other: &PyEncryptedPseudonym) -> bool {
self.0 == other.0
}
}
#[pyclass(name = "EncryptedAttribute", from_py_object)]
#[derive(Copy, Clone, Eq, PartialEq, Debug, From, Into, Deref)]
pub struct PyEncryptedAttribute(pub(crate) EncryptedAttribute);
#[pymethods]
impl PyEncryptedAttribute {
#[new]
fn new(x: PyElGamal) -> Self {
Self(EncryptedAttribute::from(x.0))
}
#[pyo3(name = "to_bytes")]
fn encode(&self, py: Python) -> Py<PyAny> {
PyBytes::new(py, &self.0.to_bytes()).into()
}
#[staticmethod]
#[pyo3(name = "from_bytes")]
fn decode(v: &[u8]) -> Option<Self> {
use crate::core::elgamal::ElGamal;
ElGamal::from_slice(v).map(|eg| Self(EncryptedAttribute::from(eg)))
}
#[pyo3(name = "to_base64")]
fn as_base64(&self) -> String {
self.to_base64()
}
#[staticmethod]
#[pyo3(name = "from_base64")]
fn from_base64(s: &str) -> Option<Self> {
EncryptedAttribute::from_base64(s).map(Self)
}
fn __repr__(&self) -> String {
format!("EncryptedAttribute({})", self.to_base64())
}
fn __str__(&self) -> String {
self.to_base64()
}
fn __eq__(&self, other: &PyEncryptedAttribute) -> bool {
self.0 == other.0
}
}
pub fn register(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<PyPseudonym>()?;
m.add_class::<PyAttribute>()?;
m.add_class::<PyEncryptedPseudonym>()?;
m.add_class::<PyEncryptedAttribute>()?;
Ok(())
}