Large Refactor: Implement Rust Traits and Generics
This commit is contained in:
parent
94e89466e6
commit
6286051e12
|
@ -7,6 +7,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
rand = "0.8.5"
|
||||
crypto-bigint = "0.5.5"
|
||||
crypto-bigint = {version = "0.5.5", features = ["generic-array"]}
|
||||
base64 = "0.21.7"
|
||||
bincode = "1.3.3"
|
||||
typenum = "1.17.0"
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
use false_bottom::FBCrypt;
|
||||
use false_bottom::{FB128, FBAlgo};
|
||||
|
||||
fn main() {
|
||||
// Input messages
|
||||
|
@ -8,7 +7,7 @@ fn main() {
|
|||
let real_msg2 = "Please meet me at the Paradise hotel at 5:30 PM";
|
||||
|
||||
// Cipher initialization
|
||||
let mut fb = FBCrypt::init(18, 12).unwrap();
|
||||
let mut fb = FB128::init(18, 12).unwrap();
|
||||
|
||||
// Encryption
|
||||
let real_key1 = fb.add(&real_msg1.as_bytes());
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use false_bottom::{FBCrypt, FBKey};
|
||||
use false_bottom::{FB128, FBKey, FBAlgo, Encode};
|
||||
|
||||
fn main() {
|
||||
// Cipher Initialization
|
||||
let mut fb = FBCrypt::init(18, 9).unwrap();
|
||||
let mut fb = FB128::init(18, 9).unwrap();
|
||||
|
||||
// Encryption
|
||||
let msg1 = "This is a message";
|
||||
|
@ -11,12 +11,13 @@ fn main() {
|
|||
let key2 = fb.add(msg2.as_bytes());
|
||||
|
||||
// Export
|
||||
let (cipher, keybase) = fb.export();
|
||||
let cipher = fb.export_cipher();
|
||||
let keybase = fb.export_keybase();
|
||||
let key1_exp = key1.export();
|
||||
let key2_exp = key2.export();
|
||||
|
||||
// Import
|
||||
let fb_new = FBCrypt::import(&cipher, &keybase).unwrap();
|
||||
let fb_new = FB128::import(&cipher, &keybase).unwrap();
|
||||
let key1_imp = FBKey::import(&key1_exp).unwrap();
|
||||
let key2_imp = FBKey::import(&key2_exp).unwrap();
|
||||
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
use crate::{FBError, FBKey, FBObj, FBObjTrait, FieldOps, Packing};
|
||||
use crypto_bigint::{NonZero, RandomMod};
|
||||
use rand::{Rng, seq::IteratorRandom};
|
||||
|
||||
pub trait FBAlgo<T>
|
||||
where
|
||||
Self: BlockOps<T>,
|
||||
T: FieldOps + Packing + RandomMod,
|
||||
{
|
||||
const MODULUS: NonZero<T>;
|
||||
|
||||
fn init(n: usize, k: usize) -> Result<FBObj<T>, FBError> {
|
||||
if n < k || k < 2 {
|
||||
return Err(FBError::InvalidParams);
|
||||
}
|
||||
let mut rng = rand::thread_rng();
|
||||
let r = (0..k)
|
||||
.map(|_| T::random_mod(&mut rng, &Self::MODULUS))
|
||||
.collect();
|
||||
let c = (0..n)
|
||||
.map(|_| T::random_mod(&mut rng, &Self::MODULUS))
|
||||
.collect();
|
||||
|
||||
Ok(FBObj { c, r })
|
||||
}
|
||||
|
||||
fn add(&mut self, msg: &[u8]) -> FBKey {
|
||||
let indices = T::pack(msg)
|
||||
.into_iter()
|
||||
.map(|msg_uint| self.add_block(&msg_uint))
|
||||
.collect();
|
||||
|
||||
FBKey { indices }
|
||||
}
|
||||
|
||||
fn decrypt(&self, key: &FBKey) -> Result<Vec<u8>, FBError> {
|
||||
let decr = key.indices
|
||||
.iter()
|
||||
.map(|index_row| self.decrypt_block(&index_row))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let mut msg = T::unpack(decr)?;
|
||||
msg.shrink_to_fit();
|
||||
|
||||
Ok(msg)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub trait BlockOps<T>
|
||||
where
|
||||
Self: FBObjTrait<T>,
|
||||
T: FieldOps + RandomMod,
|
||||
{
|
||||
fn add_block(&mut self, msg_uint: &T) -> Vec<(usize, usize)> {
|
||||
let c = self.cipher();
|
||||
let r = self.keybase();
|
||||
let mut rng = rand::thread_rng();
|
||||
let n = rng.gen_range(2..=r.len());
|
||||
let mut c_i = (0..c.len()).choose_multiple(&mut rng, n-1);
|
||||
let r_i = (0..r.len()).choose_multiple(&mut rng, n);
|
||||
let mut sum = T::ZERO;
|
||||
for (&ci, &ri) in c_i.iter().zip( r_i.iter() ) {
|
||||
sum = sum.field_add( &c[ci].field_mul(&r[ri]) );
|
||||
}
|
||||
let ri_last = *r_i.last()
|
||||
.expect("r_i will contain at least 2 elements");
|
||||
let mod_inv = r[ri_last].field_inv();
|
||||
let c_new_el = msg_uint.field_sub(&sum)
|
||||
.field_mul(&mod_inv);
|
||||
let c = self.cipher_mut();
|
||||
c.push(c_new_el);
|
||||
c_i.push(c.len() - 1);
|
||||
let indices = c_i.into_iter()
|
||||
.zip(r_i.into_iter())
|
||||
.collect();
|
||||
|
||||
indices
|
||||
}
|
||||
|
||||
fn decrypt_block(&self, indices: &[(usize, usize)]) -> Result<T, FBError> {
|
||||
let (c, r) = (self.cipher(), self.keybase());
|
||||
if indices.len() > r.len() {
|
||||
return Err(FBError::InvalidKey);
|
||||
}
|
||||
let mut msg = T::ZERO;
|
||||
for &(ci, ri) in indices {
|
||||
let c_el = c.get(ci).ok_or(FBError::InvalidKey)?;
|
||||
let r_el = r.get(ri).ok_or(FBError::InvalidKey)?;
|
||||
msg = msg.field_add( &c_el.field_mul(&r_el) );
|
||||
}
|
||||
|
||||
Ok(msg)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn encrypt_u128() {
|
||||
use crypto_bigint::U128;
|
||||
let msg = U128::from_u32(100);
|
||||
let mut fb = FBObj::<U128>::init(18, 12).unwrap();
|
||||
let key = fb.add_block(&msg);
|
||||
let decrypted = fb.decrypt_block(&key).unwrap();
|
||||
assert_eq!(msg, decrypted);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encrypt_bytes() {
|
||||
use crypto_bigint::U128;
|
||||
let input1 = vec![255_u8; 33];
|
||||
let input2 = vec![0_u8; 102];
|
||||
let mut fb = FBObj::<U128>::init(21, 9).unwrap();
|
||||
let key1 = fb.add(&input1);
|
||||
let key2 = fb.add(&input2);
|
||||
let decr1 = fb.decrypt(&key1).unwrap();
|
||||
let decr2 = fb.decrypt(&key2).unwrap();
|
||||
assert_eq!(input1, decr1);
|
||||
assert_eq!(input2, decr2);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
pub trait FieldOps {
|
||||
fn field_add(&self, rhs: &Self) -> Self;
|
||||
fn field_sub(&self, rhs: &Self) -> Self;
|
||||
fn field_mul(&self, rhs: &Self) -> Self;
|
||||
fn field_inv(&self) -> Self;
|
||||
}
|
||||
|
||||
pub trait WrappingOps {
|
||||
fn wrapping_add(&self, rhs: &Self) -> Self;
|
||||
fn wrapping_sub(&self, rhs: &Self) -> Self;
|
||||
}
|
|
@ -1,60 +1,48 @@
|
|||
use base64::prelude::{BASE64_STANDARD, Engine};
|
||||
use bincode::{Options, DefaultOptions};
|
||||
use crypto_bigint::{U128, Encoding};
|
||||
use crate::{FBCrypt, FBKey, errors::FBError};
|
||||
use crate::{FBError, FBObj, FBObjTrait};
|
||||
use crypto_bigint::{ArrayEncoding, Bounded, generic_array::GenericArray};
|
||||
use base64::{prelude::BASE64_STANDARD, Engine};
|
||||
|
||||
impl FBCrypt {
|
||||
|
||||
pub fn export(&self) -> (String, String) {
|
||||
let c_bytes: Vec<u8> = self.c.iter()
|
||||
.flat_map(|bigint| bigint.to_le_bytes())
|
||||
.collect();
|
||||
let r_bytes: Vec<u8> = self.r.iter()
|
||||
.flat_map(|bigint| bigint.to_le_bytes())
|
||||
pub trait Encode<T>
|
||||
where
|
||||
Self: FBObjTrait<T>,
|
||||
T: ArrayEncoding + Bounded,
|
||||
{
|
||||
fn export_cipher(&self) -> String {
|
||||
let c_bytes: Vec<u8> = self.cipher().iter()
|
||||
.flat_map(|bigint| bigint.to_le_byte_array())
|
||||
.collect();
|
||||
|
||||
(BASE64_STANDARD.encode(c_bytes), BASE64_STANDARD.encode(r_bytes))
|
||||
BASE64_STANDARD.encode(c_bytes)
|
||||
}
|
||||
|
||||
pub fn import(cipher: &str, keybase: &str) -> Result<FBCrypt, FBError> {
|
||||
fn export_keybase(&self) -> String {
|
||||
let r_bytes: Vec<u8> = self.keybase().iter()
|
||||
.flat_map(|bigint| bigint.to_le_byte_array())
|
||||
.collect();
|
||||
|
||||
BASE64_STANDARD.encode(r_bytes)
|
||||
}
|
||||
|
||||
fn import(cipher: &str, keybase: &str) -> Result<FBObj<T>, FBError> {
|
||||
let c_bytes = BASE64_STANDARD.decode(cipher)
|
||||
.map_err(|_| FBError::DecodeError)?;
|
||||
let c: Vec<U128> = c_bytes.chunks_exact(16)
|
||||
.map(|chunk| U128::from_le_bytes(chunk.try_into().unwrap()))
|
||||
.collect();
|
||||
let r_bytes = BASE64_STANDARD.decode(keybase)
|
||||
let r_bytes = BASE64_STANDARD.decode(keybase)
|
||||
.map_err(|_| FBError::DecodeError)?;
|
||||
let r: Vec<U128> = r_bytes.chunks_exact(16)
|
||||
.map(|chunk| U128::from_le_bytes(chunk.try_into().unwrap()))
|
||||
|
||||
let chunk_to_uint = |chunk| {
|
||||
T::from_le_byte_array(
|
||||
GenericArray::clone_from_slice(chunk)
|
||||
)};
|
||||
let c: Vec<T> = c_bytes.chunks_exact(T::BYTES)
|
||||
.map(chunk_to_uint)
|
||||
.collect();
|
||||
if c.len() < r.len() || r.len() < 2 {
|
||||
let r: Vec<T> = r_bytes.chunks_exact(T::BYTES)
|
||||
.map(chunk_to_uint)
|
||||
.collect();
|
||||
if r.len() > c.len() || r.len() < 2 {
|
||||
return Err(FBError::InvalidParams);
|
||||
}
|
||||
|
||||
Ok(FBCrypt {c, r})
|
||||
}
|
||||
}
|
||||
|
||||
impl FBKey {
|
||||
|
||||
pub fn export(&self) -> String {
|
||||
let binc = DefaultOptions::new();
|
||||
let indice_bytes = binc.serialize(&self.indices)
|
||||
.unwrap();
|
||||
|
||||
BASE64_STANDARD.encode(&indice_bytes)
|
||||
}
|
||||
|
||||
pub fn import(key_str: &str) -> Result<FBKey, FBError> {
|
||||
let binc = DefaultOptions::new();
|
||||
let indice_bytes = BASE64_STANDARD.decode(key_str)
|
||||
.map_err(|_| FBError::DecodeError)?;
|
||||
let indices: Vec<_> = binc.deserialize(&indice_bytes)
|
||||
.map_err(|_| FBError::DecodeError)?;
|
||||
if indices.len() < 2 {
|
||||
return Err(FBError::DecodeError);
|
||||
}
|
||||
|
||||
Ok (FBKey {indices})
|
||||
Ok(FBObj {c, r})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,15 +9,15 @@ pub enum FBError {
|
|||
|
||||
impl fmt::Display for FBError {
|
||||
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let message = match self {
|
||||
FBError::DecodeError => "Invalid input",
|
||||
FBError::InvalidKey => "Invalid Key used",
|
||||
FBError::InvalidParams => "Keybase len(k) or Cipher len(n) out of bounds. Valid bounds: (2 <= k <= n)",
|
||||
};
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let message = match self {
|
||||
FBError::DecodeError => "Invalid input",
|
||||
FBError::InvalidKey => "Invalid Key used",
|
||||
FBError::InvalidParams => "Keybase len(k) or Cipher len(n) out of bounds. Valid bounds: (2 <= k <= n)",
|
||||
};
|
||||
|
||||
f.write_fmt(format_args!("{message}"))
|
||||
}
|
||||
f.write_fmt(format_args!("{message}"))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for FBError {}
|
||||
|
|
|
@ -1,115 +0,0 @@
|
|||
use crypto_bigint::{U128, Limb, RandomMod, NonZero};
|
||||
use rand::{seq::IteratorRandom, Rng};
|
||||
use crate::{errors::FBError, packing};
|
||||
|
||||
pub struct FBCrypt {
|
||||
pub(crate) c: Vec<U128>, // Ciphertext
|
||||
pub(crate) r: Vec<U128>, // Keybase
|
||||
}
|
||||
|
||||
pub struct FBKey {
|
||||
// 2D Vec containing (cipher_index, keybase_index) pairs
|
||||
pub(crate) indices: Vec<Vec<(usize, usize)>>,
|
||||
}
|
||||
|
||||
// Value and position of the Prime used (2^128 - 159)
|
||||
const P: U128 = U128::MAX.wrapping_sub(&U128::from_u8(159 - 1));
|
||||
const P_POS: Limb = Limb::from_u8(159);
|
||||
|
||||
impl FBCrypt {
|
||||
pub fn init(n: usize, k: usize) -> Result<FBCrypt, FBError> {
|
||||
if n < k || k < 2 {
|
||||
return Err(FBError::InvalidParams);
|
||||
}
|
||||
const MODULUS: NonZero<U128> = NonZero::<U128>::const_new(P).0;
|
||||
let mut rng = rand::thread_rng();
|
||||
let r = (0..k)
|
||||
.map(|_| U128::random_mod(&mut rng, &MODULUS))
|
||||
.collect();
|
||||
let c = (0..n)
|
||||
.map(|_| U128::random_mod(&mut rng, &MODULUS))
|
||||
.collect();
|
||||
|
||||
Ok(FBCrypt { c, r })
|
||||
}
|
||||
|
||||
pub fn add(&mut self, msg: &[u8]) -> FBKey {
|
||||
let indices = packing::pack(msg).into_iter()
|
||||
.map(|msg_uint| self.add_u128(&msg_uint))
|
||||
.collect();
|
||||
|
||||
FBKey { indices }
|
||||
}
|
||||
|
||||
pub fn decrypt(&self, key: &FBKey) -> Result<Vec<u8>, FBError> {
|
||||
let decr = key.indices.iter()
|
||||
.map(|index_row| self.decrypt_u128(&index_row))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let msg = packing::unpack(&decr)?;
|
||||
|
||||
Ok(msg)
|
||||
}
|
||||
|
||||
fn add_u128(&mut self, msg_uint: &U128) -> Vec<(usize, usize)> {
|
||||
let (r, c) = (&self.r, &mut self.c);
|
||||
let mut rng = rand::thread_rng();
|
||||
let n = rng.gen_range(2..=r.len());
|
||||
let mut c_i = (0..c.len()).choose_multiple(&mut rng, n - 1);
|
||||
let r_i = (0..r.len()).choose_multiple(&mut rng, n);
|
||||
let mut sum = U128::ZERO;
|
||||
for (&ci, &ri) in c_i.iter().zip(r_i.iter()) {
|
||||
sum = sum.add_mod_special(
|
||||
&c[ci].mul_mod_special(&r[ri], P_POS),
|
||||
P_POS);
|
||||
}
|
||||
let ri_last = *r_i.last().expect("r_i will contain at least 2 elements");
|
||||
let mod_inv = r[ri_last].inv_mod(&P).0;
|
||||
let c_new_el = msg_uint.sub_mod_special(&sum, P_POS)
|
||||
.mul_mod_special(&mod_inv, P_POS);
|
||||
c.push(c_new_el);
|
||||
c_i.push(c.len() - 1);
|
||||
let indices = c_i.into_iter()
|
||||
.zip(r_i.into_iter())
|
||||
.collect();
|
||||
|
||||
indices
|
||||
}
|
||||
|
||||
fn decrypt_u128(&self, indices: &[(usize, usize)]) -> Result<U128, FBError> {
|
||||
if indices.len() > self.r.len() {
|
||||
return Err(FBError::InvalidKey);
|
||||
}
|
||||
let mut msg = U128::ZERO;
|
||||
for &(ci, ri) in indices {
|
||||
let c_el = self.c.get(ci).ok_or(FBError::InvalidKey)?;
|
||||
let r_el = self.r.get(ri).ok_or(FBError::InvalidKey)?;
|
||||
msg = msg.add_mod_special(
|
||||
&c_el.mul_mod_special(&r_el, P_POS),
|
||||
P_POS);
|
||||
}
|
||||
|
||||
Ok(msg)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encrypt_u128() {
|
||||
let msg = U128::from_u32(100);
|
||||
let mut fb = FBCrypt::init(20, 12).unwrap();
|
||||
let key = fb.add_u128(&msg);
|
||||
let decrypted = fb.decrypt_u128(&key).unwrap();
|
||||
assert_eq!(msg, decrypted);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encrypt_bytes() {
|
||||
let input1 = vec![255_u8; 150];
|
||||
let input2 = vec![0_u8; 102];
|
||||
let mut fb = FBCrypt::init(21, 12).unwrap();
|
||||
let key1 = fb.add(&input1);
|
||||
let key2 = fb.add(&input2);
|
||||
let decr1 = fb.decrypt(&key1).unwrap();
|
||||
let decr2 = fb.decrypt(&key2).unwrap();
|
||||
assert_eq!(input1, decr1);
|
||||
assert_eq!(input2, decr2);
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
use crate::FBError;
|
||||
use base64::prelude::{BASE64_STANDARD, Engine};
|
||||
use bincode::{Options, DefaultOptions};
|
||||
|
||||
pub struct FBKey {
|
||||
pub(crate) indices: Vec<Vec<(usize, usize)>>,
|
||||
}
|
||||
|
||||
impl FBKey {
|
||||
|
||||
pub fn export(&self) -> String {
|
||||
let binc = DefaultOptions::new();
|
||||
let indice_bytes = binc.serialize(&self.indices)
|
||||
.unwrap();
|
||||
|
||||
BASE64_STANDARD.encode(&indice_bytes)
|
||||
}
|
||||
|
||||
pub fn import(key_str: &str) -> Result<FBKey, FBError> {
|
||||
let binc = DefaultOptions::new();
|
||||
let indice_bytes = BASE64_STANDARD.decode(key_str)
|
||||
.map_err(|_| FBError::DecodeError)?;
|
||||
let indices: Vec<_> = binc.deserialize(&indice_bytes)
|
||||
.map_err(|_| FBError::DecodeError)?;
|
||||
if indices.len() < 2 {
|
||||
return Err(FBError::DecodeError);
|
||||
}
|
||||
|
||||
Ok (FBKey {indices})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
pub mod fb128;
|
||||
|
||||
use crate::{BlockOps, Encode, FieldOps};
|
||||
use crypto_bigint::{ArrayEncoding, Bounded, RandomMod};
|
||||
|
||||
pub struct FBObj<T> {
|
||||
pub(crate) c: Vec<T>,
|
||||
pub(crate) r: Vec<T>,
|
||||
}
|
||||
|
||||
pub trait FBObjTrait<T> {
|
||||
fn cipher(&self) -> &Vec<T>;
|
||||
fn cipher_mut(&mut self) -> &mut Vec<T>;
|
||||
fn keybase(&self) -> &Vec<T>;
|
||||
}
|
||||
|
||||
impl<T> FBObjTrait<T> for FBObj<T> {
|
||||
fn cipher(&self) -> &Vec<T> {
|
||||
&self.c
|
||||
}
|
||||
fn cipher_mut(&mut self) -> &mut Vec<T> {
|
||||
&mut self.c
|
||||
}
|
||||
fn keybase(&self) -> &Vec<T> {
|
||||
&self.r
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> BlockOps<T> for FBObj<T>
|
||||
where
|
||||
T: FieldOps + RandomMod
|
||||
{}
|
||||
|
||||
impl<T> Encode<T> for FBObj<T>
|
||||
where
|
||||
T: ArrayEncoding + Bounded,
|
||||
{}
|
|
@ -0,0 +1,40 @@
|
|||
use crate::{FBAlgo, FBObj, FieldOps, Packing, WrappingOps};
|
||||
use crypto_bigint::{Limb, NonZero, U128};
|
||||
|
||||
pub type FB128 = FBObj<U128>;
|
||||
|
||||
const PRIME_POS_VAL: u16 = 159;
|
||||
const PRIME: U128 = U128::MAX.wrapping_sub(&U128::from_u16(PRIME_POS_VAL-1));
|
||||
const PRIME_POS: Limb = Limb::from_u16(PRIME_POS_VAL);
|
||||
|
||||
impl FBAlgo<U128> for FBObj<U128> {
|
||||
const MODULUS: NonZero<U128> = NonZero::<U128>::const_new(PRIME).0;
|
||||
}
|
||||
|
||||
impl FieldOps for U128 {
|
||||
fn field_add(&self, rhs: &Self) -> Self {
|
||||
self.add_mod_special(rhs, PRIME_POS)
|
||||
}
|
||||
fn field_sub(&self, rhs: &Self) -> Self {
|
||||
self.sub_mod_special(rhs, PRIME_POS)
|
||||
}
|
||||
fn field_mul(&self, rhs: &Self) -> Self {
|
||||
self.mul_mod_special(rhs, PRIME_POS)
|
||||
}
|
||||
fn field_inv(&self) -> Self {
|
||||
self.inv_mod(&PRIME).0
|
||||
}
|
||||
}
|
||||
|
||||
impl Packing for U128 {
|
||||
const R_BOUND: U128 = PRIME.wrapping_sub(&U128::ONE);
|
||||
}
|
||||
|
||||
impl WrappingOps for U128 {
|
||||
fn wrapping_add(&self, rhs: &U128) -> U128 {
|
||||
self.wrapping_add(rhs)
|
||||
}
|
||||
fn wrapping_sub(&self, rhs: &U128) -> U128 {
|
||||
self.wrapping_sub(rhs)
|
||||
}
|
||||
}
|
19
src/lib.rs
19
src/lib.rs
|
@ -1,9 +1,24 @@
|
|||
mod algo;
|
||||
mod arithmetic;
|
||||
mod encoding;
|
||||
mod errors;
|
||||
mod false_bottom;
|
||||
mod fbkey;
|
||||
mod fbobj;
|
||||
mod packing;
|
||||
|
||||
pub use crate::{
|
||||
errors::FBError,
|
||||
false_bottom::{FBCrypt, FBKey},
|
||||
fbobj::{
|
||||
fb128::FB128,
|
||||
},
|
||||
algo::FBAlgo,
|
||||
fbkey::FBKey,
|
||||
encoding::Encode,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
algo::BlockOps,
|
||||
arithmetic::{FieldOps, WrappingOps},
|
||||
fbobj::{FBObj, FBObjTrait},
|
||||
packing::Packing,
|
||||
};
|
||||
|
|
122
src/packing.rs
122
src/packing.rs
|
@ -1,64 +1,76 @@
|
|||
use crypto_bigint::{U128, Encoding};
|
||||
use crate::FBError;
|
||||
use crypto_bigint::{ArrayEncoding, Bounded, generic_array::GenericArray};
|
||||
use std::cmp::PartialOrd;
|
||||
use crate::{FBError, WrappingOps};
|
||||
|
||||
/* PACKING SCHEME
|
||||
* When a number n >= P (out of field) is formed from the byte chunks,
|
||||
* the values P-1 followed by n-3000 are appended to the output vec.
|
||||
* Subtraction is done to bring n within the field (i.e less than P).
|
||||
* This is used to transform message byte chunks into field elements.
|
||||
* Every x byte chunks of a message are combined to form a field element n.
|
||||
* In case a number n >= P (out of field) is formed,
|
||||
* the values P-1 (i.e R_BOUND) followed by n-R_BOUND are appended to the output vec.
|
||||
* While unpacking, P-1 is used as a signaling element to extract n
|
||||
* from the successive element by adding back 3000.
|
||||
* from the successive element after adding back R_BOUND.
|
||||
*/
|
||||
const P_MINUS_ONE: U128 = U128::MAX.wrapping_sub(&U128::from_u8(159));
|
||||
|
||||
pub(crate) fn pack(inp: &[u8]) -> Vec<U128> {
|
||||
let mut out = Vec::with_capacity(inp.len()/16 + 2);
|
||||
inp.chunks(16)
|
||||
.for_each(|inp_chunk| {
|
||||
let mut out_chunk = [0_u8; 16];
|
||||
out_chunk[..inp_chunk.len()].copy_from_slice(inp_chunk);
|
||||
let mut out_uint = U128::from_le_bytes(out_chunk);
|
||||
if out_uint >= P_MINUS_ONE {
|
||||
out.push(P_MINUS_ONE);
|
||||
out_uint = out_uint.wrapping_sub(&U128::from_u16(3000));
|
||||
}
|
||||
out.push(out_uint);
|
||||
});
|
||||
let inp_chunk_last = inp.chunks_exact(16)
|
||||
.remainder();
|
||||
let mut pad_chunk: [u8; 16] = [16; 16];
|
||||
if inp_chunk_last.len() > 0 {
|
||||
pad_chunk[15] += 16 - inp_chunk_last.len() as u8;
|
||||
}
|
||||
out.push(U128::from_le_bytes(pad_chunk));
|
||||
out.shrink_to_fit();
|
||||
pub trait Packing
|
||||
where
|
||||
Self: ArrayEncoding + Bounded + PartialOrd + WrappingOps
|
||||
{
|
||||
const R_BOUND: Self;
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
pub(crate) fn unpack(inp: &[U128]) -> Result<Vec<u8>, FBError> {
|
||||
let pad_len = inp.last()
|
||||
.ok_or(FBError::InvalidKey)?
|
||||
.to_le_bytes()[15] as usize;
|
||||
if pad_len > 31 {
|
||||
return Err(FBError::InvalidKey);
|
||||
}
|
||||
let mut out = Vec::with_capacity(inp.len()*16);
|
||||
let mut add_3k = false;
|
||||
for i in inp {
|
||||
if add_3k {
|
||||
let orig = i.wrapping_add(&U128::from_u16(3000));
|
||||
out.extend(orig.to_le_bytes().into_iter());
|
||||
add_3k = false;
|
||||
} else if *i == P_MINUS_ONE {
|
||||
add_3k = true;
|
||||
} else {
|
||||
out.extend(i.to_le_bytes().into_iter());
|
||||
fn pack(inp: &[u8]) -> Vec<Self> {
|
||||
let mut out: Vec<Self> = inp.chunks(Self::BYTES)
|
||||
.flat_map(|inp_chunk| {
|
||||
let mut out_chunk = GenericArray::<u8, Self::ByteSize>::default();
|
||||
out_chunk[..inp_chunk.len()].copy_from_slice(inp_chunk);
|
||||
let mut out_uint = Self::from_le_byte_array(out_chunk);
|
||||
if out_uint >= Self::R_BOUND {
|
||||
out_uint = out_uint.wrapping_sub(&Self::R_BOUND);
|
||||
vec![Self::R_BOUND, out_uint]
|
||||
} else {
|
||||
vec![out_uint]
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let inp_chunk_last = inp.chunks_exact(Self::BYTES)
|
||||
.remainder();
|
||||
let mut pad_chunk = GenericArray::<u8, Self::ByteSize>::default();
|
||||
pad_chunk[Self::BYTES-1] = Self::BYTES as u8;
|
||||
if inp_chunk_last.len() != 0 {
|
||||
pad_chunk[Self::BYTES - 1] += (Self::BYTES - inp_chunk_last.len()) as u8;
|
||||
}
|
||||
}
|
||||
let trunc_len = out.len().checked_sub(pad_len)
|
||||
.ok_or(FBError::InvalidKey)?;
|
||||
out.truncate(trunc_len);
|
||||
out.shrink_to_fit();
|
||||
out.push(Self::from_le_byte_array(pad_chunk));
|
||||
|
||||
Ok(out)
|
||||
out
|
||||
}
|
||||
|
||||
fn unpack(inp: Vec<Self>) -> Result<Vec<u8>, FBError> {
|
||||
let pad_len: usize = inp.last()
|
||||
.ok_or(FBError::InvalidKey)?
|
||||
.to_le_byte_array()[Self::BYTES-1] as usize;
|
||||
if pad_len > 2 * Self::BYTES - 1 || pad_len < Self::BYTES {
|
||||
return Err(FBError::InvalidKey);
|
||||
}
|
||||
let mut extract = false;
|
||||
let mut out: Vec<u8> = inp.into_iter()
|
||||
.filter_map(|el| {
|
||||
if extract {
|
||||
extract = false;
|
||||
let el = el.wrapping_add(&Self::R_BOUND);
|
||||
Some(el.to_le_byte_array())
|
||||
} else if el == Self::R_BOUND {
|
||||
extract = true;
|
||||
None
|
||||
} else {
|
||||
Some(el.to_le_byte_array())
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
let trunc_len = out.len().checked_sub(pad_len)
|
||||
.ok_or(FBError::InvalidKey)?;
|
||||
out.truncate(trunc_len);
|
||||
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue