Improved encoding, packing and added more examples
Improved serialization for key exports with variable integer encoding. Space efficient custom byte packing scheme for input [u8] slice. Added example to demo import/exports. Removed unnecessary error enums. Lots of refactoring.
This commit is contained in:
parent
1ff02271ad
commit
60b9d875f1
|
@ -1,26 +1,34 @@
|
||||||
|
|
||||||
use false_bottom::FBCrypt;
|
use false_bottom::FBCrypt;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let real_msg = "The troops are headed due north";
|
// Input messages
|
||||||
let fake_msg = "The troops are headed due south";
|
let fake_msg = "Weather department warns of heavy rains within the upcoming two days";
|
||||||
|
let real_msg1 = "I have obtained intel regarding the government's illegal spying";
|
||||||
|
let real_msg2 = "Please meet me at the Paradise hotel at 5:30 PM";
|
||||||
|
|
||||||
let mut fb = FBCrypt::init(18, 12).unwrap();
|
// Cipher initialization
|
||||||
|
let mut fb = FBCrypt::init(18, 12).unwrap();
|
||||||
|
|
||||||
let real_key = fb.add(&real_msg.as_bytes()).unwrap();
|
// Encryption
|
||||||
let fake_key = fb.add(&fake_msg.as_bytes()).unwrap();
|
let real_key1 = fb.add(&real_msg1.as_bytes());
|
||||||
|
let real_key2 = fb.add(&real_msg2.as_bytes());
|
||||||
|
let fake_key = fb.add(&fake_msg.as_bytes());
|
||||||
|
|
||||||
let cipher = fb.export().unwrap();
|
// Decryption
|
||||||
let mut fb_new = FBCrypt::import(&cipher).unwrap();
|
let fake_decr = fb.decrypt(&fake_key).unwrap();
|
||||||
|
let real1_decr = fb.decrypt(&real_key1).unwrap();
|
||||||
|
let real2_decr = fb.decrypt(&real_key2).unwrap();
|
||||||
|
|
||||||
let real_decr = fb_new.decrypt(&real_key).unwrap();
|
let fake_str = String::from_utf8(fake_decr).unwrap();
|
||||||
let fake_decr = fb_new.decrypt(&fake_key).unwrap();
|
let real_str1 = String::from_utf8(real1_decr).unwrap();
|
||||||
|
let real_str2 = String::from_utf8(real2_decr).unwrap();
|
||||||
let real_str = String::from_utf8(real_decr).unwrap();
|
|
||||||
let fake_str = String::from_utf8(fake_decr).unwrap();
|
|
||||||
|
|
||||||
println!("Cipher: {cipher}");
|
|
||||||
println!("Decrypted Contents:");
|
|
||||||
println!("Real: {real_str}\nFake: {fake_str}");
|
|
||||||
assert_eq!(real_msg, real_str);
|
|
||||||
|
|
||||||
|
println!("Decrypted Contents:");
|
||||||
|
println!("Fake Message: {fake_str}");
|
||||||
|
println!("Real Message 1: {real_str1}");
|
||||||
|
println!("Real Message 2: {real_str2}");
|
||||||
|
assert_eq!(fake_msg, fake_str);
|
||||||
|
assert_eq!(real_msg1, real_str1);
|
||||||
|
assert_eq!(real_msg2, real_str2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
use false_bottom::{FBCrypt, FBKey};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Cipher Initialization
|
||||||
|
let mut fb = FBCrypt::init(18, 9).unwrap();
|
||||||
|
|
||||||
|
// Encryption
|
||||||
|
let msg1 = "This is a message";
|
||||||
|
let key1 = fb.add(msg1.as_bytes());
|
||||||
|
let msg2 = "This is another message";
|
||||||
|
let key2 = fb.add(msg2.as_bytes());
|
||||||
|
|
||||||
|
// Export
|
||||||
|
let (cipher, keybase) = fb.export();
|
||||||
|
let key1_exp = key1.export();
|
||||||
|
let key2_exp = key2.export();
|
||||||
|
|
||||||
|
// Import
|
||||||
|
let fb_new = FBCrypt::import(&cipher, &keybase).unwrap();
|
||||||
|
let key1_imp = FBKey::import(&key1_exp).unwrap();
|
||||||
|
let key2_imp = FBKey::import(&key2_exp).unwrap();
|
||||||
|
|
||||||
|
// Decryption
|
||||||
|
let decr1 = fb_new.decrypt(&key1_imp).unwrap();
|
||||||
|
let decr2 = fb_new.decrypt(&key2_imp).unwrap();
|
||||||
|
|
||||||
|
// Display
|
||||||
|
println!("
|
||||||
|
CipherText: \n{cipher}\n
|
||||||
|
KeyBase: \n{keybase}\n
|
||||||
|
Key 1: {key1_exp}
|
||||||
|
Key 2: {key2_exp}
|
||||||
|
");
|
||||||
|
|
||||||
|
assert_eq!(msg1.as_bytes(), decr1);
|
||||||
|
assert_eq!(msg2.as_bytes(), decr2);
|
||||||
|
}
|
|
@ -1,40 +0,0 @@
|
||||||
use crate::{errors::FBError, FBCrypt};
|
|
||||||
use crypto_bigint::{U128, Encoding};
|
|
||||||
|
|
||||||
// This uses a custom conversion scheme to ensure that
|
|
||||||
// all 128 bit integers are within the prime field (i.e < 2^128 - 159)
|
|
||||||
// As of now, this is achieved by utilizing only 120 bits out of 128 bits
|
|
||||||
|
|
||||||
pub(crate) fn msg_to_u128_blocks(inp: &[u8]) -> Result<Vec<U128>, FBError> {
|
|
||||||
if inp.len() == 0 {
|
|
||||||
return Err(FBError::EmptyInput);
|
|
||||||
}
|
|
||||||
let mut out: Vec<U128> = inp.chunks_exact(15)
|
|
||||||
.map(|chunk| {
|
|
||||||
let mut padded_chunk = [0_u8; 16];
|
|
||||||
padded_chunk[..15].copy_from_slice(chunk);
|
|
||||||
U128::from_le_bytes(padded_chunk)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let rem = inp.chunks_exact(15)
|
|
||||||
.remainder();
|
|
||||||
if rem.len() > 0 {
|
|
||||||
let mut rem_chunk: [u8; 16] = [0; 16];
|
|
||||||
rem_chunk[..rem.len()].copy_from_slice(rem);
|
|
||||||
rem_chunk[15] = 16 - rem.len() as u8;
|
|
||||||
out.push(U128::from_le_bytes(rem_chunk));
|
|
||||||
}
|
|
||||||
Ok(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn to_msg_bytes(inp: &[U128]) -> Result<Vec<u8>, FBError> {
|
|
||||||
if inp.len() == 0 {
|
|
||||||
return Err(FBError::EmptyInput)
|
|
||||||
}
|
|
||||||
let mut out: Vec<u8> = inp.iter()
|
|
||||||
.flat_map(|big_num| big_num.to_le_bytes()[..15].to_vec())
|
|
||||||
.collect();
|
|
||||||
let pad = inp.last().unwrap().to_le_bytes()[15];
|
|
||||||
out.truncate(out.len()+1-pad as usize);
|
|
||||||
Ok(out)
|
|
||||||
}
|
|
|
@ -1,41 +1,60 @@
|
||||||
use base64::prelude::*;
|
use base64::prelude::{BASE64_STANDARD, Engine};
|
||||||
|
use bincode::{Options, DefaultOptions};
|
||||||
use crypto_bigint::{U128, Encoding};
|
use crypto_bigint::{U128, Encoding};
|
||||||
use crate::{
|
use crate::{FBCrypt, FBKey, errors::FBError};
|
||||||
FBCrypt,
|
|
||||||
errors::FBError,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl FBCrypt {
|
impl FBCrypt {
|
||||||
pub fn export(&self) -> Result<String, FBError> {
|
|
||||||
let c_bytes: Vec<u8> = self.c.iter()
|
|
||||||
.flat_map(|bigint| bigint.to_le_bytes().to_vec())
|
|
||||||
.collect();
|
|
||||||
let r_bytes: Vec<u8> = self.r.iter()
|
|
||||||
.flat_map(|bigint| bigint.to_le_bytes().to_vec())
|
|
||||||
.collect();
|
|
||||||
Ok(
|
|
||||||
BASE64_STANDARD.encode(c_bytes) + ":"
|
|
||||||
+ &BASE64_STANDARD.encode(r_bytes)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn import(string: &str) -> Result<FBCrypt, FBError> {
|
pub fn export(&self) -> (String, String) {
|
||||||
let (c_str, r_str) = string.split_once(':')
|
let c_bytes: Vec<u8> = self.c.iter()
|
||||||
.ok_or_else(|| FBError::DecodeError)?;
|
.flat_map(|bigint| bigint.to_le_bytes())
|
||||||
let c_bytes = BASE64_STANDARD.decode(c_str)
|
.collect();
|
||||||
.map_err(|_| FBError::DecodeError)?;
|
let r_bytes: Vec<u8> = self.r.iter()
|
||||||
let c: Vec<U128> = c_bytes.chunks_exact(16)
|
.flat_map(|bigint| bigint.to_le_bytes())
|
||||||
.map(|chunk| U128::from_le_bytes(chunk.try_into().unwrap()))
|
.collect();
|
||||||
.collect();
|
|
||||||
let r_bytes = BASE64_STANDARD.decode(r_str)
|
(BASE64_STANDARD.encode(c_bytes), BASE64_STANDARD.encode(r_bytes))
|
||||||
.map_err(|_| FBError::DecodeError)?;
|
}
|
||||||
let r: Vec<U128> = r_bytes.chunks_exact(16)
|
|
||||||
.map(|chunk| U128::from_le_bytes(chunk.try_into().unwrap()))
|
pub fn import(cipher: &str, keybase: &str) -> Result<FBCrypt, FBError> {
|
||||||
.collect();
|
let c_bytes = BASE64_STANDARD.decode(cipher)
|
||||||
Ok(FBCrypt {c, r})
|
.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)
|
||||||
|
.map_err(|_| FBError::DecodeError)?;
|
||||||
|
let r: Vec<U128> = r_bytes.chunks_exact(16)
|
||||||
|
.map(|chunk| U128::from_le_bytes(chunk.try_into().unwrap()))
|
||||||
|
.collect();
|
||||||
|
if c.len() < r.len() || r.len() < 2 {
|
||||||
|
return Err(FBError::InvalidParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(FBCrypt {c, r})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FBKey {
|
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})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FBError {
|
pub enum FBError {
|
||||||
DecodeError,
|
DecodeError,
|
||||||
EmptyInput,
|
InvalidKey,
|
||||||
IntegerTooLarge,
|
InvalidParams,
|
||||||
InvalidKey,
|
|
||||||
InvalidParams,
|
|
||||||
NoModInverse,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,122 +1,115 @@
|
||||||
use rand::{Rng, seq::IteratorRandom};
|
use crypto_bigint::{U128, Limb, RandomMod, NonZero};
|
||||||
use crate::{errors::FBError, convert::*};
|
use rand::{seq::IteratorRandom, Rng};
|
||||||
use crypto_bigint::{U128, RandomMod, NonZero, rand_core::OsRng, Limb};
|
use crate::{errors::FBError, packing};
|
||||||
|
|
||||||
pub struct FBCrypt {
|
pub struct FBCrypt {
|
||||||
pub(crate) c: Vec<U128>,
|
pub(crate) c: Vec<U128>, // Ciphertext
|
||||||
pub(crate) r: Vec<U128>,
|
pub(crate) r: Vec<U128>, // Keybase
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FBKey {
|
pub struct FBKey {
|
||||||
pub(crate) r: Vec<U128>,
|
// 2D Vec containing (cipher_index, keybase_index) pairs
|
||||||
pub(crate) indices: Vec<Vec<(usize, usize)>>,
|
pub(crate) indices: Vec<Vec<(usize, usize)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prime number value
|
// Value and position of the Prime used (2^128 - 159)
|
||||||
const P: U128 = U128::MAX.wrapping_sub(&U128::from_u32(159 - 1));
|
const P: U128 = U128::MAX.wrapping_sub(&U128::from_u8(159 - 1));
|
||||||
// Our prime is at 159th position to the left of 2^128
|
const P_POS: Limb = Limb::from_u8(159);
|
||||||
const P_POS: Limb = Limb::from_u32(159);
|
|
||||||
|
|
||||||
impl FBCrypt {
|
impl FBCrypt {
|
||||||
pub fn init(n: usize, k: usize) -> Result<FBCrypt, FBError> {
|
pub fn init(n: usize, k: usize) -> Result<FBCrypt, FBError> {
|
||||||
if n < k || k < 2 {
|
if n < k || k < 2 {
|
||||||
return Err(FBError::InvalidParams)
|
return Err(FBError::InvalidParams);
|
||||||
}
|
}
|
||||||
const MODULUS: NonZero<U128> = NonZero::<U128>::const_new(P).0;
|
const MODULUS: NonZero<U128> = NonZero::<U128>::const_new(P).0;
|
||||||
let r: Vec<U128> = (0..k)
|
let mut rng = rand::thread_rng();
|
||||||
.map(|_| U128::random_mod(&mut OsRng, &MODULUS))
|
let r = (0..k)
|
||||||
.collect();
|
.map(|_| U128::random_mod(&mut rng, &MODULUS))
|
||||||
let c: Vec<U128> = (0..n)
|
.collect();
|
||||||
.map(|_| U128::random_mod(&mut OsRng, &MODULUS))
|
let c = (0..n)
|
||||||
.collect();
|
.map(|_| U128::random_mod(&mut rng, &MODULUS))
|
||||||
Ok(FBCrypt {c, r})
|
.collect();
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add(&mut self, m: &[u8]) -> Result<FBKey, FBError> {
|
Ok(FBCrypt { c, r })
|
||||||
let msg: Vec<U128> = msg_to_u128_blocks(m)?;
|
}
|
||||||
let mut key = FBKey {
|
|
||||||
r: self.r.clone(),
|
|
||||||
indices: Vec::new()
|
|
||||||
};
|
|
||||||
for m in msg {
|
|
||||||
key.indices.push(self.add_u128(&m)?)
|
|
||||||
}
|
|
||||||
Ok(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decrypt(&mut self, key: &FBKey) -> Result<Vec<u8>, FBError> {
|
pub fn add(&mut self, msg: &[u8]) -> FBKey {
|
||||||
let mut decrypted: Vec<U128> = Vec::new();
|
let indices = packing::pack(msg).into_iter()
|
||||||
for indices in &key.indices {
|
.map(|msg_uint| self.add_u128(&msg_uint))
|
||||||
decrypted.push(self.decrypt_u128(&indices)?)
|
.collect();
|
||||||
}
|
|
||||||
let msg = to_msg_bytes(&decrypted)?;
|
|
||||||
Ok(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_u128(&mut self, m: &U128) -> Result<Vec<(usize, usize)>, FBError> {
|
FBKey { indices }
|
||||||
if m.ge(&P) {
|
}
|
||||||
return Err(FBError::IntegerTooLarge);
|
|
||||||
}
|
|
||||||
let (r, c) = (&mut self.r, &mut self.c);
|
|
||||||
let n = OsRng.gen_range(2..=r.len());
|
|
||||||
let mut c_i: Vec<usize> = (0..c.len())
|
|
||||||
.choose_multiple(&mut OsRng, n-1);
|
|
||||||
let r_i: Vec<usize> = (0..r.len())
|
|
||||||
.choose_multiple(&mut OsRng, n);
|
|
||||||
|
|
||||||
let mut sum: U128 = U128::ZERO;
|
pub fn decrypt(&self, key: &FBKey) -> Result<Vec<u8>, FBError> {
|
||||||
for (&ci, &ri) in c_i.iter()
|
let decr = key.indices.iter()
|
||||||
.zip(r_i.iter())
|
.map(|index_row| self.decrypt_u128(&index_row))
|
||||||
{
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
sum = sum.add_mod(
|
let msg = packing::unpack(&decr)?;
|
||||||
&c[ci].mul_mod_special(&r[ri], P_POS),
|
|
||||||
&P);
|
|
||||||
}
|
|
||||||
let r_last = *r_i.last().unwrap();
|
|
||||||
let (mod_inv, inv_exists) = r[r_last].inv_mod(&P);
|
|
||||||
let inv_exists: bool = inv_exists.into();
|
|
||||||
if !inv_exists {
|
|
||||||
return Err(FBError::NoModInverse);
|
|
||||||
}
|
|
||||||
let c_new = m.sub_mod(&sum, &P)
|
|
||||||
.mul_mod_special(&mod_inv, P_POS);
|
|
||||||
c.push(c_new);
|
|
||||||
c_i.push(c.len()-1);
|
|
||||||
|
|
||||||
let indices: Vec<(usize, usize)> = c_i.into_iter()
|
Ok(msg)
|
||||||
.zip(r_i.into_iter())
|
}
|
||||||
.collect();
|
|
||||||
Ok(indices)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn decrypt_u128(&self, indices: &[(usize, usize)]) -> Result<U128, FBError> {
|
fn add_u128(&mut self, msg_uint: &U128) -> Vec<(usize, usize)> {
|
||||||
if indices.len() > self.c.len() {
|
let (r, c) = (&self.r, &mut self.c);
|
||||||
return Err(FBError::InvalidKey)
|
let mut rng = rand::thread_rng();
|
||||||
}
|
let n = rng.gen_range(2..=r.len());
|
||||||
let mut m: U128 = U128::ZERO;
|
let mut c_i = (0..c.len()).choose_multiple(&mut rng, n - 1);
|
||||||
for &(ci, ri) in indices {
|
let r_i = (0..r.len()).choose_multiple(&mut rng, n);
|
||||||
m = m.add_mod(
|
let mut sum = U128::ZERO;
|
||||||
&self.c[ci].mul_mod_special(&self.r[ri], P_POS),
|
for (&ci, &ri) in c_i.iter().zip(r_i.iter()) {
|
||||||
&P);
|
sum = sum.add_mod_special(
|
||||||
}
|
&c[ci].mul_mod_special(&r[ri], P_POS),
|
||||||
Ok(m)
|
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]
|
#[test]
|
||||||
fn encrypt_u128() {
|
fn encrypt_u128() {
|
||||||
let msg: U128 = U128::from_u32(100);
|
let msg = U128::from_u32(100);
|
||||||
let mut fb = FBCrypt::init(20, 12).unwrap();
|
let mut fb = FBCrypt::init(20, 12).unwrap();
|
||||||
let key = fb.add_u128(&msg).unwrap();
|
let key = fb.add_u128(&msg);
|
||||||
let decrypted = fb.decrypt_u128(&key).unwrap();
|
let decrypted = fb.decrypt_u128(&key).unwrap();
|
||||||
assert_eq!(msg, decrypted);
|
assert_eq!(msg, decrypted);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn encrypt_bytes() {
|
fn encrypt_bytes() {
|
||||||
let input = vec![0xff; 150];
|
let input1 = vec![255_u8; 150];
|
||||||
let mut fb = FBCrypt::init(21, 12).unwrap();
|
let input2 = vec![0_u8; 102];
|
||||||
let key = fb.add(&input).unwrap();
|
let mut fb = FBCrypt::init(21, 12).unwrap();
|
||||||
let decrypted = fb.decrypt(&key).unwrap();
|
let key1 = fb.add(&input1);
|
||||||
assert_eq!(input, decrypted);
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
mod errors;
|
|
||||||
mod convert;
|
|
||||||
mod encoding;
|
mod encoding;
|
||||||
|
mod errors;
|
||||||
mod false_bottom;
|
mod false_bottom;
|
||||||
|
mod packing;
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
errors::FBError,
|
errors::FBError,
|
||||||
false_bottom::{FBCrypt, FBKey},
|
false_bottom::{FBCrypt, FBKey},
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
use crypto_bigint::{U128, Encoding};
|
||||||
|
use crate::FBError;
|
||||||
|
|
||||||
|
/* 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).
|
||||||
|
* While unpacking, P-1 is used as a signaling element to extract n
|
||||||
|
* from the successive element by adding back 3000.
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let trunc_len = out.len().checked_sub(pad_len)
|
||||||
|
.ok_or(FBError::InvalidKey)?;
|
||||||
|
out.truncate(trunc_len);
|
||||||
|
out.shrink_to_fit();
|
||||||
|
|
||||||
|
Ok(out)
|
||||||
|
}
|
Loading…
Reference in New Issue