Adding Trait generics
This commit is contained in:
parent
60b9d875f1
commit
182832bc6e
|
@ -0,0 +1,130 @@
|
|||
use crypto_bigint::{U128, Limb, RandomMod, NonZero, Encoding};
|
||||
use crate::{FBError, FBKey, pack::Packing};
|
||||
use rand::{Rng, prelude::IteratorRandom};
|
||||
mod fb128;
|
||||
|
||||
pub trait FB<T>: FBBlock<T>
|
||||
where
|
||||
T: RandomMod + SpecialMod + InvMod + Encoding + std::cmp::PartialOrd + Packing<T>
|
||||
{
|
||||
const MODULUS: NonZero<T>;
|
||||
|
||||
fn init(n: usize, k: usize) -> Result<FBStruct<T>, FBError>
|
||||
where
|
||||
T: RandomMod
|
||||
{
|
||||
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(FBStruct { c, r })
|
||||
}
|
||||
|
||||
fn add(&mut self, msg: &[u8]) -> FBKey {
|
||||
let indices = T::pack(msg).into_iter()
|
||||
.map(|msg_uint| self.add_u128(&msg_uint))
|
||||
.collect();
|
||||
|
||||
FBKey { indices }
|
||||
}
|
||||
|
||||
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 = T::unpack(&decr)?;
|
||||
|
||||
Ok(msg)
|
||||
}
|
||||
}
|
||||
|
||||
trait SpecialMod {
|
||||
fn mul_mod_special(&self, rhs: &Self, c: Limb) -> Self;
|
||||
fn add_mod_special(&self, rhs: &Self, c: Limb) -> Self;
|
||||
fn sub_mod_special(&self, rhs: &Self, c: Limb) -> Self;
|
||||
}
|
||||
|
||||
use crypto_bigint::CtChoice;
|
||||
trait InvMod {
|
||||
fn inv_mod(&self, modulus: &Self) -> (Self, CtChoice)
|
||||
where Self: Sized;
|
||||
}
|
||||
|
||||
impl SpecialMod for U128 {
|
||||
fn mul_mod_special(&self, rhs: &Self, c: Limb) -> Self {self.mul_mod_special(rhs, c)}
|
||||
fn add_mod_special(&self, rhs: &Self, c: Limb) -> Self {self.add_mod_special(rhs, c)}
|
||||
fn sub_mod_special(&self, rhs: &Self, c: Limb) -> Self {self.sub_mod_special(rhs, c)}
|
||||
}
|
||||
|
||||
impl InvMod for U128 {
|
||||
fn inv_mod(&self, modulus: &Self) -> (Self, CtChoice) {
|
||||
self.inv_mod(modulus)
|
||||
}
|
||||
}
|
||||
|
||||
trait FBBlock<T>
|
||||
where
|
||||
T: RandomMod + SpecialMod + InvMod
|
||||
{
|
||||
const P: T;
|
||||
const P_POS: Limb;
|
||||
|
||||
fn cipher(&self) -> &Vec<T>;
|
||||
fn cipher_mut(&mut self) -> &mut Vec<T>;
|
||||
fn keybase(&self) -> &Vec<T>;
|
||||
|
||||
fn add_u128(&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.add_mod_special(
|
||||
&c[ci].mul_mod_special(&r[ri], Self::P_POS),
|
||||
Self::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(&Self::P).0;
|
||||
let c_new_el = msg_uint.sub_mod_special(&sum, Self::P_POS)
|
||||
.mul_mod_special(&mod_inv, Self::P_POS);
|
||||
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_u128(&self, indices: &[(usize, usize)]) -> Result<T, FBError> {
|
||||
let (r, c) = (self.keybase(), self.cipher());
|
||||
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.add_mod_special(
|
||||
&c_el.mul_mod_special(&r_el, Self::P_POS),
|
||||
Self::P_POS);
|
||||
}
|
||||
|
||||
Ok(msg)
|
||||
}
|
||||
}
|
||||
pub struct FBStruct<T> {
|
||||
pub(crate) c: Vec<T>,
|
||||
pub(crate) r: Vec<T>,
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
use crypto_bigint::{U128, Limb, NonZero};
|
||||
use crate::{
|
||||
crypt::{FB, FBStruct, FBBlock},
|
||||
pack::Packing,
|
||||
};
|
||||
|
||||
impl FB<U128> for FBStruct<U128> {
|
||||
const MODULUS: NonZero<U128> = NonZero::<U128>::const_new(Self::P).0;
|
||||
}
|
||||
|
||||
impl FBBlock<U128> for FBStruct<U128> {
|
||||
const P: U128 = U128::MAX.wrapping_sub(&U128::from_u8(159 - 1));
|
||||
const P_POS: Limb = Limb::from_u8(159);
|
||||
|
||||
fn cipher(&self) -> &Vec<U128> {
|
||||
&self.c
|
||||
}
|
||||
|
||||
fn cipher_mut(&mut self) -> &mut Vec<U128> {
|
||||
&mut self.c
|
||||
}
|
||||
|
||||
fn keybase(&self) -> &Vec<U128> {
|
||||
&self.r
|
||||
}
|
||||
}
|
||||
|
||||
impl Packing<U128> for U128 {
|
||||
const P_MINUS_ONE: U128 = U128::MAX.wrapping_sub(&U128::from_u8(159));
|
||||
const BYTES: usize = 16;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encrypt_u128() {
|
||||
let msg = U128::from_u32(100);
|
||||
let mut fb = FBStruct::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 = FBStruct::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);
|
||||
}
|
|
@ -2,6 +2,8 @@ mod encoding;
|
|||
mod errors;
|
||||
mod false_bottom;
|
||||
mod packing;
|
||||
mod pack;
|
||||
mod crypt;
|
||||
|
||||
pub use crate::{
|
||||
errors::FBError,
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
use crypto_bigint::{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.
|
||||
*/
|
||||
|
||||
pub(crate) trait Packing<T>
|
||||
where
|
||||
T: Encoding + std::cmp::PartialOrd
|
||||
{
|
||||
const P_MINUS_ONE: T;
|
||||
const BYTES: usize;
|
||||
|
||||
fn pack(inp: &[u8]) -> Vec<T> {
|
||||
let mut out = Vec::with_capacity(inp.len()/Self::BYTES + 2);
|
||||
inp.chunks(Self::BYTES)
|
||||
.for_each(|inp_chunk| {
|
||||
let mut out_chunk = [0_u8; Self::BYTES];
|
||||
out_chunk[..inp_chunk.len()].copy_from_slice(inp_chunk);
|
||||
let mut out_uint = T::from_le_bytes(out_chunk);
|
||||
if out_uint >= Self::P_MINUS_ONE {
|
||||
out.push(Self::P_MINUS_ONE);
|
||||
out_uint = out_uint.wrapping_sub(&T::from_u16(3000));
|
||||
}
|
||||
out.push(out_uint);
|
||||
});
|
||||
let inp_chunk_last = inp.chunks_exact(Self::BYTES)
|
||||
.remainder();
|
||||
let mut pad_chunk = [Self::BYTES as u8; Self::BYTES];
|
||||
if inp_chunk_last.len() > 0 {
|
||||
pad_chunk[Self::BYTES as u8 - 1] += Self::BYTES as u8 - inp_chunk_last.len() as u8;
|
||||
}
|
||||
out.push(T::from_le_bytes(pad_chunk));
|
||||
out.shrink_to_fit();
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
fn unpack(inp: &[T]) -> 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(&T::from_u16(3000));
|
||||
out.extend(orig.to_le_bytes().into_iter());
|
||||
add_3k = false;
|
||||
} else if *i == Self::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