diff --git a/Cargo.toml b/Cargo.toml
index 9d0c0fc..981b941 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,6 +14,7 @@ crypto-bigint = {version = "0.5.5", features = ["generic-array"]}
 base64 = "0.21.7"
 bincode = "1.3.3"
 typenum = "1.17.0"
+rayon = "1.10.0"
 
 [lib]
 doctest = false
\ No newline at end of file
diff --git a/examples/export.rs b/examples/export.rs
index 6bb3d46..4c0df7f 100644
--- a/examples/export.rs
+++ b/examples/export.rs
@@ -2,13 +2,13 @@ use false_bottom::{FB128, FBKey, FBAlgo, Encode};
 
 fn main() {
 	// Cipher Initialization
-	let mut fb = FB128::init(18, 9).unwrap();
+	let mut fb = FB128::init(2, 2).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());
+	let msg1 = "This is a message".as_bytes();
+	let key1 = fb.add(msg1);
+	let msg2 = "This is another message".as_bytes();
+	let key2 = fb.add(msg2);
 
 	// Export as base64
 	let (cipher, keybase) = fb.export(); // Careful with the order
@@ -16,6 +16,14 @@ fn main() {
 	// Or as raw bytes
 	let key2_exp = key2.to_bytes();
 
+	let inp_len = msg1.len() + msg2.len();
+	let out_len = fb.to_bytes().0.len();
+	let extra = out_len - inp_len;
+	let percent = extra as f32/out_len as f32 * 100_f32;
+
+	println!("Input: {inp_len}B \nOutput: {out_len}B");
+	println!("Extra: {extra}B ({percent}%)");
+	
 	// Import from base64
 	let fb_new = FB128::import(&cipher, &keybase).unwrap();
 	let key1_imp = FBKey::import(&key1_exp).unwrap();
@@ -34,6 +42,6 @@ Key 1: {key1_exp}
 Key 2: {key2_exp:?}
 ");
 
-	assert_eq!(msg1.as_bytes(), decr1);
-	assert_eq!(msg2.as_bytes(), decr2);
+	assert_eq!(msg1, decr1);
+	assert_eq!(msg2, decr2);
 }
diff --git a/examples/file.rs b/examples/file.rs
new file mode 100644
index 0000000..22ede5f
--- /dev/null
+++ b/examples/file.rs
@@ -0,0 +1,23 @@
+use false_bottom::{FB128, FBAlgo, Encode};
+use std::fs;
+use std::time::Instant;
+
+fn main() {
+	//let inp = fs::read("input1").unwrap();
+	let inp = vec![0_u8; 204800];
+	println!("Input size: {} Bytes", inp.len());
+	let mut fb = FB128::init(2, 2).unwrap();
+	println!("Encrypting...");
+	let now = Instant::now();
+	let _key = fb.add(&inp);
+	let elapsed = now.elapsed().as_secs_f32();
+	println!("Took {} secs", elapsed);
+
+	println!("Exporting...");
+	let encr = fb.to_bytes().0;
+	let rate = encr.len() as f32 / elapsed;
+	println!("Rate: {rate:.1} B/sec");
+	let extra = encr.len() - inp.len();
+	let percent = extra as f32/encr.len() as f32 * 100_f32;
+	println!("Extra Bytes: {extra} Bytes ({percent}%)");
+}
diff --git a/input b/input
new file mode 100644
index 0000000..da1dfb9
Binary files /dev/null and b/input differ
diff --git a/input1 b/input1
new file mode 100644
index 0000000..52972ec
Binary files /dev/null and b/input1 differ
diff --git a/src/algo.rs b/src/algo.rs
index 98c337b..9f59fb5 100644
--- a/src/algo.rs
+++ b/src/algo.rs
@@ -2,11 +2,14 @@
 use crate::{FBError, FBKey, FBObj, FBObjTrait, FieldOps, Packing};
 use crypto_bigint::{NonZero, RandomMod};
 use rand::{Rng, seq::IteratorRandom};
+use rayon::iter::*;
+use std::marker::Send;
+use std::sync::RwLock;
 
 pub trait FBAlgo<T>
 where
-	Self: BlockOps<T>,
-	T: FieldOps + Packing + RandomMod,
+	Self: BlockOps<T> + Sync + Send,
+	T: FieldOps + Packing + RandomMod + Send,
 {
 	const MODULUS: NonZero<T>;
 
@@ -23,19 +26,20 @@ 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 })
 	}
 
 	/// 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))
-			.collect();
+			.into_par_iter()
+			.map(|msg_uint|	self.add_block(&msg_uint))
+			.collect(); 
 
 		FBKey { indices }
 	}
@@ -45,7 +49,7 @@ where
 	/// [InvalidKey](FBError::InvalidKey)
 	fn decrypt(&self, key: &FBKey) -> Result<Vec<u8>, FBError> {
 		let decr = key.indices
-			.iter()
+			.par_iter()
 			.map(|index_row| self.decrypt_block(&index_row))
 			.collect::<Result<Vec<_>, _>>()?;
 		let mut msg = T::unpack(decr)?;
@@ -61,25 +65,32 @@ where
 	Self: FBObjTrait<T>,
 	T: FieldOps + RandomMod,
 {
-	fn add_block(&mut self, msg_uint: &T) -> Vec<(usize, usize)> {
-		let c = self.cipher();
+	fn add_block(&self, msg_uint: &T) -> Vec<(usize, usize)> {
+		let mut c_len = self.cipher().read().unwrap().len();
 		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 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 ri_last_inv = r[ri_last].field_inv();
+		let mut sum = T::ZERO;
+		{
+			let c = self.cipher().read().unwrap();
+			for (&ci, &ri) in c_i.iter().zip( r_i.iter() ) {
+				sum = sum.field_add( &c[ci].field_mul(&r[ri]) );
+			}
+		}
+
 		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);
+			.field_mul(&ri_last_inv);
+		{
+			let mut c = self.cipher().write().unwrap();
+			c.push(c_new_el);
+			c_len = c.len();
+		}
+		c_i.push(c_len - 1);
 		let indices = c_i.into_iter()
 			.zip(r_i.into_iter())
 			.collect();
@@ -88,7 +99,7 @@ where
 	}
 
 	fn decrypt_block(&self, indices: &[(usize, usize)]) -> Result<T, FBError> {
-		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);
 		}
@@ -109,7 +120,8 @@ 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 lock = RwLock::new(&mut fb);
+	let key = FBObj::<U128>::add_block(&lock, &msg);
 	let decrypted = fb.decrypt_block(&key).unwrap();
 	assert_eq!(msg, decrypted);
 }
diff --git a/src/encoding.rs b/src/encoding.rs
index 1dfef77..b034353 100644
--- a/src/encoding.rs
+++ b/src/encoding.rs
@@ -2,6 +2,7 @@
 use crate::{FBError, FBObj, FBObjTrait};
 use crypto_bigint::{ArrayEncoding, Bounded, generic_array::GenericArray};
 use base64::{prelude::BASE64_STANDARD, Engine};
+use std::sync::RwLock;
 
 pub trait Encode<T>
 where
@@ -10,7 +11,8 @@ where
 {
 	/// Returns the byte representation of the ciphertext and keybase.
 	fn to_bytes(&self) -> (Vec<u8>, Vec<u8>) {
-		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()
@@ -36,15 +38,16 @@ where
 			T::from_le_byte_array(
 				GenericArray::clone_from_slice(chunk)
 			)};
-		let c: Vec<T> = cipher.chunks_exact(T::BYTES)
+		let c_vec: Vec<T> = cipher.chunks_exact(T::BYTES)
 			.map(chunk_to_uint)
 			.collect();
 		let r: Vec<T> = 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})
 	}
diff --git a/src/fbobj.rs b/src/fbobj.rs
index 4d929d5..0436afc 100644
--- a/src/fbobj.rs
+++ b/src/fbobj.rs
@@ -3,26 +3,23 @@ pub mod fb128;
 
 use crate::{BlockOps, Encode, FieldOps};
 use crypto_bigint::{ArrayEncoding, Bounded, RandomMod};
+use std::sync::RwLock;
 
 /// 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<T> {
-	pub(crate) c: Vec<T>,
+	pub(crate) c: RwLock<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 cipher(&self) -> &RwLock<Vec<T>>;
 	fn keybase(&self) -> &Vec<T>;
 }
 
 impl<T> FBObjTrait<T> for FBObj<T> {
-	fn cipher(&self) -> &Vec<T> {
+	fn cipher(&self) -> &RwLock<Vec<T>> {
 		&self.c
 	}
-	fn cipher_mut(&mut self) -> &mut Vec<T> {
-		&mut self.c
-	}
 	fn keybase(&self) -> &Vec<T> {
 		&self.r
 	}
diff --git a/src/packing.rs b/src/packing.rs
index acb06a5..d706018 100644
--- a/src/packing.rs
+++ b/src/packing.rs
@@ -19,12 +19,14 @@ where
 	const R_BOUND: Self;
 
 	fn pack(inp: &[u8]) -> Vec<Self> {
+		let mut cnt = 0;
 		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 {
+					cnt += 1;
 					out_uint = out_uint.wrapping_sub(&Self::R_BOUND);
 					vec![Self::R_BOUND, out_uint]
 				} else {
@@ -40,6 +42,8 @@ where
 			pad_chunk[Self::BYTES - 1] += (Self::BYTES - inp_chunk_last.len()) as u8;
 		}
 		out.push(Self::from_le_byte_array(pad_chunk));
+		eprintln!("Packing: Out of field: {cnt}");
+
 
 		out
 	}