1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// SPDX-License-Identifier: GPL-3.0-or-later
use crate::{FBError, FBObj, FBObjTrait};
use base64::{prelude::BASE64_STANDARD, Engine};
use crypto_bigint::{generic_array::GenericArray, ArrayEncoding, Bounded};
use std::sync::RwLock;

pub trait Encode<T>
where
	Self: FBObjTrait<T>,
	T: ArrayEncoding + Bounded,
{
	/// Returns the byte representation of the ciphertext and keybase.
	fn as_bytes(&self) -> (Vec<u8>, Vec<u8>) {
		let c = self.cipher().read().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)
	}

	/// Returns the base64 encoded representation of the ciphertext and keybase.
	fn as_base64(&self) -> (String, String) {
		let (c, r) = self.as_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<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 = RwLock::new(c_vec);

		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 from_base64(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)
	}
}