From 1726d456473f82845a631aaaf330cbcc3b9183f2 Mon Sep 17 00:00:00 2001 From: K Shiva Kiran Date: Thu, 18 Apr 2024 19:21:23 +0530 Subject: [PATCH] Added Threading --- src/algo.rs | 76 +++++++++++++++++++++++++--------------------- src/encoding.rs | 18 +++++------ src/fbobj.rs | 16 +++++----- src/fbobj/fb128.rs | 2 +- 4 files changed, 59 insertions(+), 53 deletions(-) diff --git a/src/algo.rs b/src/algo.rs index 98c337b..5554c62 100644 --- a/src/algo.rs +++ b/src/algo.rs @@ -1,16 +1,19 @@ // SPDX-License-Identifier: GPL-3.0-or-later use crate::{FBError, FBKey, FBObj, FBObjTrait, FieldOps, Packing}; use crypto_bigint::{NonZero, RandomMod}; -use rand::{Rng, seq::IteratorRandom}; +use rand::{rngs::ThreadRng, seq::index, Rng}; +use rayon::iter::*; +use std::marker::Send; +use std::sync::RwLock; pub trait FBAlgo where - Self: BlockOps, - T: FieldOps + Packing + RandomMod, + Self: BlockOps + Sync + Send, + T: FieldOps + Packing + RandomMod + Send + Sync, { const MODULUS: NonZero; - /// Creates a new [`FBObj`]. + /// Creates a new [`FBObj`]. /// The keybase and ciphertext are initialized from random values. /// Bounds: `2 <= keybase_len <= cipher_len` /// # Errors @@ -23,9 +26,10 @@ where let r = (0..keybase_len) .map(|_| T::random_mod(&mut rng, &Self::MODULUS)) .collect(); - let c = (0..cipher_len) + let c_vec = (0..cipher_len) .map(|_| T::random_mod(&mut rng, &Self::MODULUS)) .collect(); + let c = RwLock::new(c_vec); Ok(FBObj { c, r }) } @@ -33,8 +37,11 @@ where /// Adds the provided message to the ciphertext. fn add(&mut self, msg: &[u8]) -> FBKey { let indices = T::pack(msg) - .into_iter() - .map(|msg_uint| self.add_block(&msg_uint)) + .into_par_iter() + .map_init( + || rand::thread_rng(), + |rng, index_row| self.add_block(rng, &index_row), + ) .collect(); FBKey { indices } @@ -44,8 +51,7 @@ where /// # Errors /// [InvalidKey](FBError::InvalidKey) fn decrypt(&self, key: &FBKey) -> Result, FBError> { - let decr = key.indices - .iter() + let decr = key.indices.iter() .map(|index_row| self.decrypt_block(&index_row)) .collect::, _>>()?; let mut msg = T::unpack(decr)?; @@ -55,40 +61,42 @@ where } } - pub trait BlockOps where Self: FBObjTrait, - T: FieldOps + RandomMod, + T: FieldOps + RandomMod + Send + Sync, { - fn add_block(&mut self, msg_uint: &T) -> Vec<(usize, usize)> { - let c = self.cipher(); + fn add_block(&self, rng: &mut ThreadRng, msg_uint: &T) -> Vec<(usize, usize)> { 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() + let r_i = index::sample(rng, r.len(), n); + let ri_last = r_i.iter().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()) + let ri_last_inv = r[ri_last].field_inv(); + let c_i; + let c_len; + { + let mut c = self.cipher().write().unwrap(); + c_i = index::sample(rng, c.len(), n - 1); + let sum = c_i.iter() + .zip(r_i.iter()) + .map(|(ci, ri)| c[ci].field_mul(&r[ri])) + .reduce(|acc, i| acc.field_add(&i)) + .unwrap(); + let c_new_el = msg_uint.field_sub(&sum).field_mul(&ri_last_inv); + c.push(c_new_el); + c_len = c.len(); + } + let indices = c_i.iter() + .chain([c_len - 1].into_iter()) + .zip(r_i.iter()) .collect(); indices } fn decrypt_block(&self, indices: &[(usize, usize)]) -> Result { - let (c, r) = (self.cipher(), self.keybase()); + let (c, r) = (self.cipher().read().unwrap(), self.keybase()); if indices.len() > r.len() { return Err(FBError::InvalidKey); } @@ -96,20 +104,20 @@ where 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) ); + 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::::init(18, 12).unwrap(); - let key = fb.add_block(&msg); + let fb = FBObj::::init(18, 12).unwrap(); + let rng = &mut rand::thread_rng(); + let key = fb.add_block(rng, &msg); let decrypted = fb.decrypt_block(&key).unwrap(); assert_eq!(msg, decrypted); } diff --git a/src/encoding.rs b/src/encoding.rs index 1dfef77..1b557a4 100644 --- a/src/encoding.rs +++ b/src/encoding.rs @@ -1,7 +1,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later use crate::{FBError, FBObj, FBObjTrait}; -use crypto_bigint::{ArrayEncoding, Bounded, generic_array::GenericArray}; use base64::{prelude::BASE64_STANDARD, Engine}; +use crypto_bigint::{generic_array::GenericArray, ArrayEncoding, Bounded}; +use std::sync::RwLock; pub trait Encode where @@ -10,7 +11,8 @@ where { /// Returns the byte representation of the ciphertext and keybase. fn to_bytes(&self) -> (Vec, Vec) { - let c = self.cipher().iter() + let c = self.cipher().read().unwrap() + .iter() .flat_map(|bigint| bigint.to_le_byte_array()) .collect(); let r = self.keybase().iter() @@ -32,19 +34,17 @@ where /// # Errors /// - [InvalidParams](FBError::InvalidParams) - Are the parameters in the wrong order? fn from_bytes(cipher: &[u8], keybase: &[u8]) -> Result, FBError> { - let chunk_to_uint = |chunk| { - T::from_le_byte_array( - GenericArray::clone_from_slice(chunk) - )}; - let c: Vec = cipher.chunks_exact(T::BYTES) + let chunk_to_uint = |chunk| T::from_le_byte_array(GenericArray::clone_from_slice(chunk)); + let c_vec: Vec = cipher.chunks_exact(T::BYTES) .map(chunk_to_uint) .collect(); let r: Vec = keybase.chunks_exact(T::BYTES) .map(chunk_to_uint) .collect(); - if r.len() > c.len() || r.len() < 2 { + if r.len() > c_vec.len() || r.len() < 2 { return Err(FBError::InvalidParams); } + let c = RwLock::new(c_vec); Ok(FBObj {c, r}) } @@ -54,7 +54,7 @@ where /// # Errors /// - [DecodeError](FBError::DecodeError) /// - [InvalidParams](FBError::InvalidParams) - Are the parameters in the wrong order? - fn import(cipher: &str, keybase: &str) -> Result, FBError> { + fn import(cipher: &str, keybase: &str) -> Result, FBError> { let c_bytes = BASE64_STANDARD.decode(cipher) .map_err(|_| FBError::DecodeError)?; let r_bytes = BASE64_STANDARD.decode(keybase) diff --git a/src/fbobj.rs b/src/fbobj.rs index 4d929d5..f27a0ba 100644 --- a/src/fbobj.rs +++ b/src/fbobj.rs @@ -3,26 +3,24 @@ pub mod fb128; use crate::{BlockOps, Encode, FieldOps}; use crypto_bigint::{ArrayEncoding, Bounded, RandomMod}; +use std::sync::RwLock; +use std::marker::Sync; /// The False Bottom Object holds the ciphertext and the keybase. The provided type aliases can be used to pick a block size. pub struct FBObj { - pub(crate) c: Vec, + pub(crate) c: RwLock>, pub(crate) r: Vec, } pub trait FBObjTrait { - fn cipher(&self) -> &Vec; - fn cipher_mut(&mut self) -> &mut Vec; + fn cipher(&self) -> &RwLock>; fn keybase(&self) -> &Vec; } impl FBObjTrait for FBObj { - fn cipher(&self) -> &Vec { + fn cipher(&self) -> &RwLock> { &self.c } - fn cipher_mut(&mut self) -> &mut Vec { - &mut self.c - } fn keybase(&self) -> &Vec { &self.r } @@ -30,10 +28,10 @@ impl FBObjTrait for FBObj { impl BlockOps for FBObj where - T: FieldOps + RandomMod + T: FieldOps + RandomMod + Send + Sync {} impl Encode for FBObj where - T: ArrayEncoding + Bounded, + T: ArrayEncoding + Bounded {} diff --git a/src/fbobj/fb128.rs b/src/fbobj/fb128.rs index 15e23e1..d39b724 100644 --- a/src/fbobj/fb128.rs +++ b/src/fbobj/fb128.rs @@ -24,7 +24,7 @@ impl FieldOps for U128 { self.mul_mod_special(rhs, PRIME_POS) } fn field_inv(&self) -> Self { - self.inv_mod(&PRIME).0 + self.inv_odd_mod(&PRIME).0 } }