false-bottom 0.3.4

A deniable encryption scheme
Documentation
// SPDX-License-Identifier: GPL-3.0-or-later
use crate::{FbError, FbObj};
use crypto_bigint::{ArrayEncoding, generic_array::GenericArray, Uint};
use std::sync::RwLock;

#[cfg(feature = "base64")]
#[cfg_attr(docsrs, doc(cfg(feature = "base64")))]
use base64::{prelude::BASE64_STANDARD, Engine};

/// Provides methods to encode and decode data to and from several formats.
pub trait Encode {
	/// Returns the byte representation of the ciphertext and keybase.
	fn to_bytes(&self) -> (Vec<u8>, Vec<u8>);

	/// 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<Self, FbError>
	where
		Self: Sized;

	/// Returns the base64 encoded representation of the ciphertext and keybase.  
	/// Requires `base64` feature to be enabled.
    #[cfg(feature = "base64")]
	#[cfg_attr(docsrs, doc(cfg(feature = "base64")))]
	fn to_base64(&self) -> (String, String);

	/// Constructs the `FbObj` from the provided base64 encoded forms of
	/// ciphertext and keybase.  
	/// Requires `base64` feature to be enabled.
	/// # Errors
	/// - [DecodeError](FbError::DecodeError)
	/// - [InvalidParams](FbError::InvalidParams) - Are the parameters in the wrong order?
    #[cfg(feature = "base64")]
	#[cfg_attr(docsrs, doc(cfg(feature = "base64")))]	
	fn from_base64(cipher: &str, keybase: &str) -> Result<Self, FbError>
	where
		Self: Sized;
}

impl<const LIMBS: usize> Encode for FbObj<Uint<LIMBS>>
where
	Uint<LIMBS>: ArrayEncoding,
{
	fn to_bytes(&self) -> (Vec<u8>, Vec<u8>) {
		let c = self.c.read().unwrap()
			.iter()
			.flat_map(|bigint| bigint.to_le_byte_array())
			.collect();
		let r = self.r.iter()
			.flat_map(|bigint| bigint.to_le_byte_array())
			.collect();

		(c, r)
	}

	fn from_bytes(cipher: &[u8], keybase: &[u8]) -> Result<Self, FbError> {
		let to_uint = |chunk| Uint::<LIMBS>::from_le_byte_array(GenericArray::clone_from_slice(chunk));
		let c_vec: Vec<_> = cipher.chunks_exact(Uint::<LIMBS>::BYTES)
			.map(to_uint)
			.collect();
		let r: Vec<_> = keybase.chunks_exact(Uint::<LIMBS>::BYTES)
			.map(to_uint)
			.collect();
		if r.len() > c_vec.len() || r.len() < 2 {
			return Err(FbError::InvalidParams);
		}
		let c = RwLock::new(c_vec);

		Ok(FbObj {c, r})
	}

    #[cfg(feature = "base64")]
	#[cfg_attr(docsrs, doc(cfg(feature = "base64")))]	
	fn to_base64(&self) -> (String, String) {
		let (c, r) = self.to_bytes();

		(BASE64_STANDARD.encode(c), BASE64_STANDARD.encode(r))
	}

    #[cfg(feature = "base64")]
	#[cfg_attr(docsrs, doc(cfg(feature = "base64")))]	
	fn from_base64(cipher: &str, keybase: &str) -> Result<Self, 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)
	}
}