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