diff --git a/examples/encryption.rs b/examples/encryption.rs
index dff3672..0306050 100644
--- a/examples/encryption.rs
+++ b/examples/encryption.rs
@@ -1,5 +1,4 @@
-
-use false_bottom::FBCrypt;
+use false_bottom::{FB128, FalseBottom};
 
 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());
diff --git a/examples/export.rs b/examples/export.rs
index 497b14c..b0863b5 100644
--- a/examples/export.rs
+++ b/examples/export.rs
@@ -1,8 +1,8 @@
-use false_bottom::{FBCrypt, FBKey};
+use false_bottom::{FBObj, FBKey};
 
 fn main() {
 	// Cipher Initialization
-	let mut fb = FBCrypt::init(18, 9).unwrap();
+	let mut fb = FBObj::init(18, 9).unwrap();
 
 	// Encryption
 	let msg1 = "This is a message";
@@ -16,7 +16,7 @@ fn main() {
 	let key2_exp = key2.export();
 
 	// Import
-	let fb_new = FBCrypt::import(&cipher, &keybase).unwrap();
+	let fb_new = FBObj::import(&cipher, &keybase).unwrap();
 	let key1_imp = FBKey::import(&key1_exp).unwrap();
 	let key2_imp = FBKey::import(&key2_exp).unwrap();
 
diff --git a/src/crypt.rs b/src/crypt.rs
deleted file mode 100644
index adc360e..0000000
--- a/src/crypt.rs
+++ /dev/null
@@ -1,130 +0,0 @@
-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>,
-}
diff --git a/src/crypt/fb128.rs b/src/crypt/fb128.rs
deleted file mode 100644
index fcdb45f..0000000
--- a/src/crypt/fb128.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-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);
-}
diff --git a/src/encoding.rs b/src/encoding.rs
index 2bdddef..6796b36 100644
--- a/src/encoding.rs
+++ b/src/encoding.rs
@@ -1,60 +1,14 @@
-use base64::prelude::{BASE64_STANDARD, Engine};
-use bincode::{Options, DefaultOptions};
-use crypto_bigint::{U128, Encoding};
-use crate::{FBCrypt, FBKey, errors::FBError};
+use crypto_bigint::Encoding;
+use crate::FBError;
 
-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())
-			.collect();
-
-		(BASE64_STANDARD.encode(c_bytes), BASE64_STANDARD.encode(r_bytes))
-	}
-
-	pub fn import(cipher: &str, keybase: &str) -> Result<FBCrypt, 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)
-			.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 {
-
-	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})
-	}
+pub trait Encode<T>
+where
+	T: Encoding
+{
+	const BYTES: usize;
+	
+	fn export(&self) -> (String, String);
+	fn import(cipher: &str, keybase: &str) -> Result<Self, FBError>
+	where
+		Self: Sized;
 }
diff --git a/src/false_bottom.rs b/src/false_bottom.rs
index d808812..f2a03ef 100644
--- a/src/false_bottom.rs
+++ b/src/false_bottom.rs
@@ -1,71 +1,96 @@
-use crypto_bigint::{U128, Limb, RandomMod, NonZero};
-use rand::{seq::IteratorRandom, Rng};
-use crate::{errors::FBError, packing};
+pub mod fb128;
 
-pub struct FBCrypt {
-	pub(crate) c: Vec<U128>, // Ciphertext
-	pub(crate) r: Vec<U128>, // Keybase
+use crypto_bigint::{Limb, RandomMod, NonZero, Encoding};
+use base64::prelude::{BASE64_STANDARD, Engine};
+use crate::{FBError, Packing, FBKey, Encode};
+use rand::{Rng, prelude::IteratorRandom};
+use std::cmp::PartialOrd;
+
+pub struct FBObj<T> {
+    pub(crate) c: Vec<T>,
+    pub(crate) r: Vec<T>,
 }
 
-pub struct FBKey {
-	// 2D Vec containing (cipher_index, keybase_index) pairs
-	pub(crate) indices: Vec<Vec<(usize, usize)>>,
-}
+pub trait FalseBottom<T>: FBBlockOperations<T>
+where
+    T: RandomMod + ModPrime<T> + Encoding + PartialOrd + Packing<T>
+{
+    const MODULUS: NonZero<T>;
 
-// 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> {
+    fn init(n: usize, k: usize) -> Result<FBObj<T>, FBError>
+    where
+        T: RandomMod
+    {
 		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))
+			.map(|_| T::random_mod(&mut rng, &Self::MODULUS))
 			.collect();
 		let c = (0..n)
-			.map(|_| U128::random_mod(&mut rng, &MODULUS))
+			.map(|_| T::random_mod(&mut rng, &Self::MODULUS))
 			.collect();
 
-		Ok(FBCrypt { c, r })
+		Ok(FBObj { c, r })
 	}
-
-	pub fn add(&mut self, msg: &[u8]) -> FBKey {
-		let indices = packing::pack(msg).into_iter()
+    
+    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 }
 	}
 
-	pub fn decrypt(&self, key: &FBKey) -> Result<Vec<u8>, FBError> {
+	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)?;
+		let msg = T::unpack(&decr)?;
 
 		Ok(msg)
 	}
+}
 
-	fn add_u128(&mut self, msg_uint: &U128) -> Vec<(usize, usize)> {
-		let (r, c) = (&self.r, &mut self.c);
+pub trait ModPrime<T> {
+    const PRIME_POS: Limb;
+    const PRIME: T;
+    fn mul_mod_prime(&self, rhs: &Self) -> Self;
+    fn add_mod_prime(&self, rhs: &Self) -> Self;
+    fn sub_mod_prime(&self, rhs: &Self) -> Self;
+    fn inv_mod_prime(&self) -> Self;
+}
+
+
+pub trait FBBlockOperations<T>
+where
+    T: RandomMod + ModPrime<T>
+{
+    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 = 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 mut sum = T::ZERO;
+		for (&ci, &ri) in c_i.iter().zip( r_i.iter() ) {
+			sum = sum.add_mod_prime( &c[ci].mul_mod_prime(&r[ri]) );
 		}
-		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);
+		let ri_last = *r_i.last()
+			.expect("r_i will contain at least 2 elements");
+		let mod_inv = r[ri_last].inv_mod_prime();
+		let c_new_el = msg_uint.sub_mod_prime(&sum)
+			.mul_mod_prime(&mod_inv);
+        let c = self.cipher_mut();
 		c.push(c_new_el);
 		c_i.push(c.len() - 1);
 		let indices = c_i.into_iter()
@@ -75,41 +100,59 @@ impl FBCrypt {
 		indices
 	}
 
-	fn decrypt_u128(&self, indices: &[(usize, usize)]) -> Result<U128, FBError> {
-		if indices.len() > self.r.len() {
+	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 = U128::ZERO;
+		let mut msg = T::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);
+			let c_el = c.get(ci).ok_or(FBError::InvalidKey)?;
+			let r_el = r.get(ri).ok_or(FBError::InvalidKey)?;
+			msg = msg.add_mod_prime(&c_el.mul_mod_prime(&r_el));
 		}
 
 		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);
-}
+impl<T> Encode<T> for FBObj<T>
+where
+	T: Encoding + crypto_bigint::Bounded,
+<T as Encoding>::Repr: Iterator + for <'a> From<&'a [u8]>,
+Vec<u8>: FromIterator<<<T as Encoding>::Repr as Iterator>::Item>
+{
+	const BYTES: usize = T::BYTES;
 
-#[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);
+	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())
+			.collect();
+
+		(BASE64_STANDARD.encode(c_bytes), BASE64_STANDARD.encode(r_bytes))
+	}
+
+	fn import(cipher: &str, keybase: &str) -> Result<Self, FBError>
+	where
+		Self: Sized
+	{
+		let c_bytes = BASE64_STANDARD.decode(cipher)
+			.map_err(|_| FBError::DecodeError)?;
+		let c: Vec<T> = c_bytes.chunks_exact(Self::BYTES)
+			.map(|chunk| T::from_le_bytes(chunk.try_into().unwrap()))
+			.collect();
+		let r_bytes = BASE64_STANDARD.decode(keybase)
+			.map_err(|_| FBError::DecodeError)?;
+		let r: Vec<T> = r_bytes.chunks_exact(Self::BYTES)
+			.map(|chunk| T::from_le_bytes(chunk.try_into().unwrap()))
+			.collect();
+		if c.len() < r.len() || r.len() < 2 {
+			return Err(FBError::InvalidParams);
+		}
+
+		Ok(Self {c, r})
+	}
 }
diff --git a/src/false_bottom/fb128.rs b/src/false_bottom/fb128.rs
new file mode 100644
index 0000000..8721ea7
--- /dev/null
+++ b/src/false_bottom/fb128.rs
@@ -0,0 +1,126 @@
+use crypto_bigint::{U128, Limb, NonZero, Encoding};
+use crate::{
+    false_bottom::{FalseBottom, ModPrime, FBBlockOperations, FBObj},
+    pack::Packing, FBError,
+};
+
+pub type FB128 = FBObj<U128>;
+
+impl FalseBottom<U128> for FBObj<U128> {
+    const MODULUS: NonZero<U128> = NonZero::<U128>::const_new(Self::P).0;
+}
+
+impl FBBlockOperations<U128> for FBObj<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 ModPrime<U128> for U128 {
+    const PRIME_POS: Limb = Limb::from_u32(159);
+    const PRIME: U128 = U128::MAX.wrapping_sub(&U128::from_u8(159 - 1));
+    
+    fn mul_mod_prime(&self, rhs: &Self) -> Self {
+		self.mul_mod_special(rhs, Self::PRIME_POS)
+    }
+    fn add_mod_prime(&self, rhs: &Self) -> Self {
+		self.add_mod_special(rhs, Self::PRIME_POS)
+    }
+    fn sub_mod_prime(&self, rhs: &Self) -> Self {
+		self.sub_mod_special(rhs, Self::PRIME_POS)
+    }
+    fn inv_mod_prime(&self) -> Self {
+        self.inv_mod(&Self::PRIME).0
+    }
+}
+
+impl Packing<U128> for U128 {
+    const P_MINUS_ONE: U128 = U128::MAX.wrapping_sub(&U128::from_u8(159));
+
+    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 >= Self::P_MINUS_ONE {
+					out.push(Self::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
+    }
+
+    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 == 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)
+    }
+
+}
+
+#[test]
+fn encrypt_u128() {
+    let msg = U128::from_u32(100);
+    let mut fb = FBObj::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 = FBObj::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);
+}
diff --git a/src/key.rs b/src/key.rs
new file mode 100644
index 0000000..cd5caaf
--- /dev/null
+++ b/src/key.rs
@@ -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})
+	}
+}
diff --git a/src/lib.rs b/src/lib.rs
index 1148ad9..00e4259 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,11 +1,15 @@
 mod encoding;
 mod errors;
 mod false_bottom;
+mod key;
 mod packing;
 mod pack;
-mod crypt;
 
 pub use crate::{
 	errors::FBError,
-	false_bottom::{FBCrypt, FBKey},
+	false_bottom::fb128::FB128,
+	key::FBKey,
+	encoding::Encode,
 };
+
+pub(crate) use crate::pack::Packing;
diff --git a/src/pack.rs b/src/pack.rs
index 7575f98..5120592 100644
--- a/src/pack.rs
+++ b/src/pack.rs
@@ -1,4 +1,5 @@
 use crypto_bigint::{Encoding};
+use std::cmp::PartialOrd;
 use crate::FBError;
 
 /* PACKING SCHEME
@@ -11,61 +12,10 @@ use crate::FBError;
 
 pub(crate) trait Packing<T>
 where
-    T: Encoding + std::cmp::PartialOrd
+    T: Encoding + 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)
-    }    
+    fn pack(inp: &[u8]) -> Vec<T>;
+    fn unpack(inp: &[T]) -> Result<Vec<u8>, FBError>;
 }