use crate::{FBError, FBObj, FBObjTrait}; use crypto_bigint::{ArrayEncoding, Bounded, generic_array::GenericArray}; use base64::{prelude::BASE64_STANDARD, Engine}; pub trait Encode where Self: FBObjTrait, T: ArrayEncoding + Bounded, { /// Returns the byte representation of the ciphertext and keybase. fn to_bytes(&self) -> (Vec, Vec) { let c = self.cipher().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) } /// Returns the base64 encoded representation of the ciphertext and keybase. fn export(&self) -> (String, String) { let (c, r) = self.to_bytes(); (BASE64_STANDARD.encode(c), BASE64_STANDARD.encode(r)) } /// Constructs the [`FBObj`] from the provided byte representations of /// ciphertext and keybase. /// # Errors /// - [InvalidParams](FBError::InvalidParams) - Are the parameters in the wrong order? fn from_bytes(cipher: &[u8], keybase: &[u8]) -> Result, FBError> { let chunk_to_uint = |chunk| { T::from_le_byte_array( GenericArray::clone_from_slice(chunk) )}; let c: Vec = cipher.chunks_exact(T::BYTES) .map(chunk_to_uint) .collect(); let r: Vec = keybase.chunks_exact(T::BYTES) .map(chunk_to_uint) .collect(); if r.len() > c.len() || r.len() < 2 { return Err(FBError::InvalidParams); } Ok(FBObj {c, r}) } /// Constructs the [`FBObj`] from the provided base64 encoded forms of /// ciphertext and keybase. /// # Errors /// - [DecodeError](FBError::DecodeError) /// - [InvalidParams](FBError::InvalidParams) - Are the parameters in the wrong order? fn import(cipher: &str, keybase: &str) -> Result, 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) } }