use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use pyo3::types::{PyBytes, PyList};
use synta_mtc::crypto::{MtcProof, MtcSignature};
#[pyclass(frozen, name = "HashAlgorithm")]
#[derive(Clone)]
pub struct PyHashAlgorithm {
pub(super) inner: synta_mtc::crypto::HashAlgorithm,
}
#[pymethods]
impl PyHashAlgorithm {
#[classattr]
#[allow(non_snake_case)]
fn Sha256() -> Self {
PyHashAlgorithm {
inner: synta_mtc::crypto::HashAlgorithm::Sha256,
}
}
#[classattr]
#[allow(non_snake_case)]
fn Sha384() -> Self {
PyHashAlgorithm {
inner: synta_mtc::crypto::HashAlgorithm::Sha384,
}
}
#[classattr]
#[allow(non_snake_case)]
fn Sha512() -> Self {
PyHashAlgorithm {
inner: synta_mtc::crypto::HashAlgorithm::Sha512,
}
}
#[classattr]
#[allow(non_snake_case)]
fn Sha3_256() -> Self {
PyHashAlgorithm {
inner: synta_mtc::crypto::HashAlgorithm::Sha3_256,
}
}
#[classattr]
#[allow(non_snake_case)]
fn Sha3_384() -> Self {
PyHashAlgorithm {
inner: synta_mtc::crypto::HashAlgorithm::Sha3_384,
}
}
#[classattr]
#[allow(non_snake_case)]
fn Sha3_512() -> Self {
PyHashAlgorithm {
inner: synta_mtc::crypto::HashAlgorithm::Sha3_512,
}
}
fn output_size(&self) -> usize {
self.inner.output_size()
}
fn name(&self) -> &'static str {
self.inner.name()
}
fn oid(&self) -> String {
self.inner.to_oid().to_string()
}
fn __repr__(&self) -> String {
format!(
"HashAlgorithm.{:?}(name='{}', output_size={})",
self.inner,
self.inner.name(),
self.inner.output_size(),
)
}
fn __str__(&self) -> &'static str {
self.inner.name()
}
fn __eq__(&self, other: &Self) -> bool {
self.inner == other.inner
}
fn __hash__(&self) -> u64 {
use std::hash::{Hash, Hasher};
let mut h = std::collections::hash_map::DefaultHasher::new();
self.inner.hash(&mut h);
h.finish()
}
}
#[pyclass(frozen, name = "MtcSignature")]
pub struct PyMtcSignature {
pub(super) cosigner_id: Vec<u8>,
pub(super) signature_value: Vec<u8>,
}
fn make_mtc_signature(py: Python<'_>, s: MtcSignature) -> PyResult<Py<PyMtcSignature>> {
Py::new(
py,
PyMtcSignature {
cosigner_id: s.cosigner_id,
signature_value: s.signature_value,
},
)
}
#[pymethods]
impl PyMtcSignature {
#[getter]
fn cosigner_id<'py>(&self, py: Python<'py>) -> Bound<'py, PyBytes> {
PyBytes::new(py, &self.cosigner_id)
}
#[getter]
fn signature_value<'py>(&self, py: Python<'py>) -> Bound<'py, PyBytes> {
PyBytes::new(py, &self.signature_value)
}
fn __repr__(&self) -> String {
format!(
"MtcSignature(cosigner_id_len={}, signature_value_len={})",
self.cosigner_id.len(),
self.signature_value.len()
)
}
fn __eq__(&self, other: &Self) -> bool {
self.cosigner_id == other.cosigner_id && self.signature_value == other.signature_value
}
}
#[pyclass(frozen, name = "MtcProof")]
pub struct PyMtcProof {
pub(super) extensions: Vec<u8>,
pub(super) start: u64,
pub(super) end: u64,
pub(super) inclusion_proof: Vec<u8>,
pub(super) signatures: Vec<Py<PyMtcSignature>>,
}
#[pymethods]
impl PyMtcProof {
#[staticmethod]
fn decode(py: Python<'_>, data: &[u8]) -> PyResult<Self> {
let proof = MtcProof::decode(data).map_err(|e| PyValueError::new_err(e.to_string()))?;
let signatures = proof
.signatures
.into_iter()
.map(|s| make_mtc_signature(py, s))
.collect::<PyResult<Vec<_>>>()?;
Ok(PyMtcProof {
extensions: proof.extensions,
start: proof.start,
end: proof.end,
inclusion_proof: proof.inclusion_proof,
signatures,
})
}
fn encode<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
let signatures: Vec<MtcSignature> = self
.signatures
.iter()
.map(|s| {
let s = s.get();
MtcSignature {
cosigner_id: s.cosigner_id.clone(),
signature_value: s.signature_value.clone(),
}
})
.collect();
let proof = MtcProof {
extensions: self.extensions.clone(),
start: self.start,
end: self.end,
inclusion_proof: self.inclusion_proof.clone(),
signatures,
};
let bytes = proof
.encode()
.map_err(|e| PyValueError::new_err(e.to_string()))?;
Ok(PyBytes::new(py, &bytes))
}
#[getter]
fn extensions<'py>(&self, py: Python<'py>) -> Bound<'py, PyBytes> {
PyBytes::new(py, &self.extensions)
}
#[getter]
fn start(&self) -> u64 {
self.start
}
#[getter]
fn end(&self) -> u64 {
self.end
}
#[getter]
fn inclusion_proof<'py>(&self, py: Python<'py>) -> Bound<'py, PyBytes> {
PyBytes::new(py, &self.inclusion_proof)
}
#[getter]
fn signatures<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyList>> {
let elems: Vec<Bound<'_, PyMtcSignature>> = self
.signatures
.iter()
.map(|x| x.clone_ref(py).into_bound(py))
.collect();
PyList::new(py, elems)
}
fn __repr__(&self) -> String {
format!(
"MtcProof(start={}, end={}, inclusion_proof_len={}, signatures={})",
self.start,
self.end,
self.inclusion_proof.len(),
self.signatures.len()
)
}
fn __eq__(&self, other: &Self) -> bool {
self.extensions == other.extensions
&& self.start == other.start
&& self.end == other.end
&& self.inclusion_proof == other.inclusion_proof
&& self.signatures.len() == other.signatures.len()
}
}