1use crate::{FbError, FbObj};
3use crypto_bigint::{ArrayEncoding, generic_array::GenericArray, Uint};
4use std::sync::RwLock;
5
6#[cfg(feature = "base64")]
7#[cfg_attr(docsrs, doc(cfg(feature = "base64")))]
8use base64::{prelude::BASE64_STANDARD, Engine};
9
10pub trait Encode {
12 fn to_bytes(&self) -> (Vec<u8>, Vec<u8>);
14
15 fn from_bytes(cipher: &[u8], keybase: &[u8]) -> Result<Self, FbError>
20 where
21 Self: Sized;
22
23 #[cfg(feature = "base64")]
26 #[cfg_attr(docsrs, doc(cfg(feature = "base64")))]
27 fn to_base64(&self) -> (String, String);
28
29 #[cfg(feature = "base64")]
36 #[cfg_attr(docsrs, doc(cfg(feature = "base64")))]
37 fn from_base64(cipher: &str, keybase: &str) -> Result<Self, FbError>
38 where
39 Self: Sized;
40}
41
42impl<const LIMBS: usize> Encode for FbObj<Uint<LIMBS>>
43where
44 Uint<LIMBS>: ArrayEncoding,
45{
46 fn to_bytes(&self) -> (Vec<u8>, Vec<u8>) {
47 let c = self.c.read().unwrap()
48 .iter()
49 .flat_map(|bigint| bigint.to_le_byte_array())
50 .collect();
51 let r = self.r.iter()
52 .flat_map(|bigint| bigint.to_le_byte_array())
53 .collect();
54
55 (c, r)
56 }
57
58 fn from_bytes(cipher: &[u8], keybase: &[u8]) -> Result<Self, FbError> {
59 let to_uint = |chunk| Uint::<LIMBS>::from_le_byte_array(GenericArray::clone_from_slice(chunk));
60 let c_vec: Vec<_> = cipher.chunks_exact(Uint::<LIMBS>::BYTES)
61 .map(to_uint)
62 .collect();
63 let r: Vec<_> = keybase.chunks_exact(Uint::<LIMBS>::BYTES)
64 .map(to_uint)
65 .collect();
66 if r.len() > c_vec.len() || r.len() < 2 {
67 return Err(FbError::InvalidParams);
68 }
69 let c = RwLock::new(c_vec);
70
71 Ok(FbObj {c, r})
72 }
73
74 #[cfg(feature = "base64")]
75 #[cfg_attr(docsrs, doc(cfg(feature = "base64")))]
76 fn to_base64(&self) -> (String, String) {
77 let (c, r) = self.to_bytes();
78
79 (BASE64_STANDARD.encode(c), BASE64_STANDARD.encode(r))
80 }
81
82 #[cfg(feature = "base64")]
83 #[cfg_attr(docsrs, doc(cfg(feature = "base64")))]
84 fn from_base64(cipher: &str, keybase: &str) -> Result<Self, FbError> {
85 let c_bytes = BASE64_STANDARD.decode(cipher)
86 .map_err(|_| FbError::DecodeError)?;
87 let r_bytes = BASE64_STANDARD.decode(keybase)
88 .map_err(|_| FbError::DecodeError)?;
89
90 Self::from_bytes(&c_bytes, &r_bytes)
91 }
92}