use crate::{FBError, FBObj, FBObjTrait};
use base64::{prelude::BASE64_STANDARD, Engine};
use crypto_bigint::{generic_array::GenericArray, ArrayEncoding, Bounded};
use std::sync::Mutex;
pub trait Encode<T>
where
Self: FBObjTrait<T>,
T: ArrayEncoding + Bounded,
{
fn to_bytes(&self) -> (Vec<u8>, Vec<u8>) {
let c = self.cipher().lock().unwrap()
.iter()
.flat_map(|bigint| bigint.to_le_byte_array())
.collect();
let r = self.keybase().iter()
.flat_map(|bigint| bigint.to_le_byte_array())
.collect();
(c, r)
}
fn export(&self) -> (String, String) {
let (c, r) = self.to_bytes();
(BASE64_STANDARD.encode(c), BASE64_STANDARD.encode(r))
}
fn from_bytes(cipher: &[u8], keybase: &[u8]) -> Result<FBObj<T>, FBError> {
let chunk_to_uint = |chunk| T::from_le_byte_array(GenericArray::clone_from_slice(chunk));
let c_vec: Vec<T> = cipher.chunks_exact(T::BYTES).map(chunk_to_uint).collect();
let r: Vec<T> = keybase.chunks_exact(T::BYTES).map(chunk_to_uint).collect();
if r.len() > c_vec.len() || r.len() < 2 {
return Err(FBError::InvalidParams);
}
let c = Mutex::new(c_vec);
Ok(FBObj { c, r })
}
fn import(cipher: &str, keybase: &str) -> Result<FBObj<T>, FBError> {
let c_bytes = BASE64_STANDARD
.decode(cipher)
.map_err(|_| FBError::DecodeError)?;
let r_bytes = BASE64_STANDARD
.decode(keybase)
.map_err(|_| FBError::DecodeError)?;
Self::from_bytes(&c_bytes, &r_bytes)
}
}