Skip to main content

nym_compact_ecash/
traits.rs

1// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::common_types::{BlindedSignature, Signature};
5use crate::proofs::proof_spend::{SpendInstance, SpendProof};
6use crate::proofs::proof_withdrawal::{WithdrawalReqInstance, WithdrawalReqProof};
7use crate::scheme::withdrawal::RequestInfo;
8use crate::scheme::{Payment, WalletSignatures};
9use crate::{Attribute, CompactEcashError, PartialWallet, WithdrawalRequest};
10use group::GroupEncoding;
11use nym_bls12_381_fork::{G1Affine, G1Projective};
12
13#[macro_export]
14macro_rules! impl_byteable_bs58 {
15    ($typ:ident) => {
16        impl $crate::traits::Bytable for $typ {
17            fn to_byte_vec(&self) -> Vec<u8> {
18                self.to_bytes().to_vec()
19            }
20
21            fn try_from_byte_slice(slice: &[u8]) -> $crate::error::Result<Self> {
22                Self::from_bytes(slice)
23            }
24        }
25
26        impl $crate::traits::Base58 for $typ {}
27
28        impl TryFrom<&[u8]> for $typ {
29            type Error = CompactEcashError;
30
31            fn try_from(bytes: &[u8]) -> $crate::error::Result<Self> {
32                Self::from_bytes(bytes)
33            }
34        }
35    };
36}
37
38macro_rules! impl_complex_binary_bytable {
39    ($typ:ident) => {
40        impl $typ {
41            pub fn to_bytes(&self) -> Vec<u8> {
42                use bincode::Options;
43
44                // all of our manually derived types correctly serialise into bincode
45                #[allow(clippy::unwrap_used)]
46                crate::binary_serialiser().serialize(self).unwrap()
47            }
48
49            pub fn from_bytes(bytes: &[u8]) -> crate::error::Result<Self> {
50                use bincode::Options;
51                crate::binary_serialiser()
52                    .deserialize(bytes)
53                    .map_err(|source| CompactEcashError::BinaryDeserialisationFailure {
54                        type_name: std::any::type_name::<$typ>().to_string(),
55                        source,
56                    })
57            }
58        }
59
60        impl_byteable_bs58!($typ);
61    };
62}
63
64pub trait Bytable
65where
66    Self: Sized,
67{
68    fn to_byte_vec(&self) -> Vec<u8>;
69
70    fn try_from_byte_slice(slice: &[u8]) -> Result<Self, CompactEcashError>;
71}
72
73pub trait Base58
74where
75    Self: Bytable,
76{
77    fn try_from_bs58<S: AsRef<str>>(x: S) -> Result<Self, CompactEcashError> {
78        Self::try_from_byte_slice(&bs58::decode(x.as_ref()).into_vec()?)
79    }
80    fn to_bs58(&self) -> String {
81        bs58::encode(self.to_byte_vec()).into_string()
82    }
83}
84
85impl Bytable for G1Projective {
86    fn to_byte_vec(&self) -> Vec<u8> {
87        self.to_bytes().as_ref().to_vec()
88    }
89
90    fn try_from_byte_slice(slice: &[u8]) -> Result<Self, CompactEcashError> {
91        let bytes = slice
92            .try_into()
93            .map_err(|_| CompactEcashError::G1ProjectiveDeserializationFailure)?;
94
95        let maybe_g1 = G1Affine::from_compressed(&bytes);
96        if maybe_g1.is_none().into() {
97            Err(CompactEcashError::G1ProjectiveDeserializationFailure)
98        } else {
99            // safety: this unwrap is fine as we've just checked the element is not none
100            #[allow(clippy::unwrap_used)]
101            Ok(maybe_g1.unwrap().into())
102        }
103    }
104}
105
106impl Base58 for G1Projective {}
107
108impl Bytable for Attribute {
109    fn to_byte_vec(&self) -> Vec<u8> {
110        self.to_bytes().to_vec()
111    }
112
113    fn try_from_byte_slice(slice: &[u8]) -> Result<Self, CompactEcashError> {
114        let maybe_attribute = Attribute::from_bytes(
115            slice
116                .try_into()
117                .map_err(|_| CompactEcashError::ScalarDeserializationFailure)?,
118        );
119        if maybe_attribute.is_none().into() {
120            Err(CompactEcashError::ScalarDeserializationFailure)
121        } else {
122            // safety: this unwrap is fine as we've just checked the element is not none
123            #[allow(clippy::unwrap_used)]
124            Ok(maybe_attribute.unwrap())
125        }
126    }
127}
128
129impl_byteable_bs58!(Signature);
130impl_byteable_bs58!(BlindedSignature);
131impl_byteable_bs58!(WalletSignatures);
132impl_byteable_bs58!(PartialWallet);
133
134impl_complex_binary_bytable!(SpendProof);
135impl_complex_binary_bytable!(SpendInstance);
136impl_complex_binary_bytable!(WithdrawalReqProof);
137impl_complex_binary_bytable!(WithdrawalReqInstance);
138impl_complex_binary_bytable!(Payment);
139impl_complex_binary_bytable!(WithdrawalRequest);
140impl_complex_binary_bytable!(RequestInfo);