Docs: Add documentation comments
This commit is contained in:
parent
c08ad88303
commit
392d0ca315
10
Cargo.toml
10
Cargo.toml
|
@ -1,13 +1,19 @@
|
||||||
[package]
|
[package]
|
||||||
name = "false-bottom"
|
name = "false-bottom"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
description = "A deniable encryption scheme"
|
||||||
|
repository = "https://codeberg.org/skran/false-bottom"
|
||||||
|
author = ["K Shiva Kiran <shiva_kr@riseup.net>"]
|
||||||
|
license = "GPL-3.0-or-later"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
crypto-bigint = {version = "0.5.5", features = ["generic-array"]}
|
crypto-bigint = {version = "0.5.5", features = ["generic-array"]}
|
||||||
base64 = "0.21.7"
|
base64 = "0.21.7"
|
||||||
bincode = "1.3.3"
|
bincode = "1.3.3"
|
||||||
typenum = "1.17.0"
|
typenum = "1.17.0"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
doctest = false
|
17
src/algo.rs
17
src/algo.rs
|
@ -9,21 +9,27 @@ where
|
||||||
{
|
{
|
||||||
const MODULUS: NonZero<T>;
|
const MODULUS: NonZero<T>;
|
||||||
|
|
||||||
fn init(n: usize, k: usize) -> Result<FBObj<T>, FBError> {
|
/// Creates a new [`FBObj`].
|
||||||
if n < k || k < 2 {
|
/// The keybase and ciphertext are initialized from random values.
|
||||||
|
/// Bounds: `2 <= keybase_len <= cipher_len`
|
||||||
|
/// # Errors
|
||||||
|
/// [InvalidParams](FBError::InvalidParams)
|
||||||
|
fn init(cipher_len: usize, keybase_len: usize) -> Result<FBObj<T>, FBError> {
|
||||||
|
if cipher_len < keybase_len || keybase_len < 2 {
|
||||||
return Err(FBError::InvalidParams);
|
return Err(FBError::InvalidParams);
|
||||||
}
|
}
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let r = (0..k)
|
let r = (0..keybase_len)
|
||||||
.map(|_| T::random_mod(&mut rng, &Self::MODULUS))
|
.map(|_| T::random_mod(&mut rng, &Self::MODULUS))
|
||||||
.collect();
|
.collect();
|
||||||
let c = (0..n)
|
let c = (0..cipher_len)
|
||||||
.map(|_| T::random_mod(&mut rng, &Self::MODULUS))
|
.map(|_| T::random_mod(&mut rng, &Self::MODULUS))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(FBObj { c, r })
|
Ok(FBObj { c, r })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds the provided message to the ciphertext.
|
||||||
fn add(&mut self, msg: &[u8]) -> FBKey {
|
fn add(&mut self, msg: &[u8]) -> FBKey {
|
||||||
let indices = T::pack(msg)
|
let indices = T::pack(msg)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -33,6 +39,9 @@ where
|
||||||
FBKey { indices }
|
FBKey { indices }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Decrypts the message that corresponds to the provided key.
|
||||||
|
/// # Errors
|
||||||
|
/// [InvalidKey](FBError::InvalidKey)
|
||||||
fn decrypt(&self, key: &FBKey) -> Result<Vec<u8>, FBError> {
|
fn decrypt(&self, key: &FBKey) -> Result<Vec<u8>, FBError> {
|
||||||
let decr = key.indices
|
let decr = key.indices
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -7,6 +7,7 @@ where
|
||||||
Self: FBObjTrait<T>,
|
Self: FBObjTrait<T>,
|
||||||
T: ArrayEncoding + Bounded,
|
T: ArrayEncoding + Bounded,
|
||||||
{
|
{
|
||||||
|
/// Returns the byte representation of the ciphertext and keybase.
|
||||||
fn to_bytes(&self) -> (Vec<u8>, Vec<u8>) {
|
fn to_bytes(&self) -> (Vec<u8>, Vec<u8>) {
|
||||||
let c = self.cipher().iter()
|
let c = self.cipher().iter()
|
||||||
.flat_map(|bigint| bigint.to_le_byte_array())
|
.flat_map(|bigint| bigint.to_le_byte_array())
|
||||||
|
@ -18,12 +19,17 @@ where
|
||||||
(c, r)
|
(c, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the base64 encoded representation of the ciphertext and keybase.
|
||||||
fn export(&self) -> (String, String) {
|
fn export(&self) -> (String, String) {
|
||||||
let (c, r) = self.to_bytes();
|
let (c, r) = self.to_bytes();
|
||||||
|
|
||||||
(BASE64_STANDARD.encode(c), BASE64_STANDARD.encode(r))
|
(BASE64_STANDARD.encode(c), BASE64_STANDARD.encode(r))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs the [`FBObj`] from the provided byte representations of
|
||||||
|
/// ciphertext and keybase.
|
||||||
|
/// # Errors
|
||||||
|
/// - [InvalidParams](FBError::InvalidParams) - Are the parameters in the wrong order?
|
||||||
fn from_bytes(cipher: &[u8], keybase: &[u8]) -> Result<FBObj<T>, FBError> {
|
fn from_bytes(cipher: &[u8], keybase: &[u8]) -> Result<FBObj<T>, FBError> {
|
||||||
let chunk_to_uint = |chunk| {
|
let chunk_to_uint = |chunk| {
|
||||||
T::from_le_byte_array(
|
T::from_le_byte_array(
|
||||||
|
@ -42,6 +48,11 @@ where
|
||||||
Ok(FBObj {c, r})
|
Ok(FBObj {c, r})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs the [`FBObj`] from the provided base64 encoded forms of
|
||||||
|
/// ciphertext and keybase.
|
||||||
|
/// # Errors
|
||||||
|
/// - [DecodeError](FBError::DecodeError)
|
||||||
|
/// - [InvalidParams](FBError::InvalidParams) - Are the parameters in the wrong order?
|
||||||
fn import(cipher: &str, keybase: &str) -> Result<FBObj<T>, FBError> {
|
fn import(cipher: &str, keybase: &str) -> Result<FBObj<T>, FBError> {
|
||||||
let c_bytes = BASE64_STANDARD.decode(cipher)
|
let c_bytes = BASE64_STANDARD.decode(cipher)
|
||||||
.map_err(|_| FBError::DecodeError)?;
|
.map_err(|_| FBError::DecodeError)?;
|
||||||
|
|
|
@ -2,8 +2,12 @@ use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FBError {
|
pub enum FBError {
|
||||||
|
/// Unable to decode the given data.
|
||||||
DecodeError,
|
DecodeError,
|
||||||
|
/// The provided key is invalid w.r.t this False Bottom Object.
|
||||||
InvalidKey,
|
InvalidKey,
|
||||||
|
/// Keybase length (k) or Cipher length (n) out of bounds.
|
||||||
|
/// Valid bounds: (2 <= k <= n).
|
||||||
InvalidParams,
|
InvalidParams,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,22 +2,28 @@ use crate::FBError;
|
||||||
use base64::prelude::{BASE64_STANDARD, Engine};
|
use base64::prelude::{BASE64_STANDARD, Engine};
|
||||||
use bincode::{Options, DefaultOptions};
|
use bincode::{Options, DefaultOptions};
|
||||||
|
|
||||||
|
/// A key object that is specific to a message.
|
||||||
pub struct FBKey {
|
pub struct FBKey {
|
||||||
pub(crate) indices: Vec<Vec<(usize, usize)>>,
|
pub(crate) indices: Vec<Vec<(usize, usize)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FBKey {
|
impl FBKey {
|
||||||
|
|
||||||
|
/// Returns the byte representation of the key.
|
||||||
pub fn to_bytes(&self) -> Vec<u8> {
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
let binc = DefaultOptions::new();
|
let binc = DefaultOptions::new();
|
||||||
binc.serialize(&self.indices)
|
binc.serialize(&self.indices)
|
||||||
.expect("Should be fine")
|
.expect("Should be fine")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the base64 encoded representation of the key.
|
||||||
pub fn export(&self) -> String {
|
pub fn export(&self) -> String {
|
||||||
BASE64_STANDARD.encode(&self.to_bytes())
|
BASE64_STANDARD.encode(&self.to_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs the key from the provided bytes.
|
||||||
|
/// # Errors
|
||||||
|
/// [DecodeError](FBError::DecodeError)
|
||||||
pub fn from_bytes(fbkey: &[u8]) -> Result<FBKey, FBError> {
|
pub fn from_bytes(fbkey: &[u8]) -> Result<FBKey, FBError> {
|
||||||
let binc = DefaultOptions::new();
|
let binc = DefaultOptions::new();
|
||||||
let indices: Vec<_> = binc.deserialize(&fbkey)
|
let indices: Vec<_> = binc.deserialize(&fbkey)
|
||||||
|
@ -29,6 +35,9 @@ impl FBKey {
|
||||||
Ok (FBKey {indices})
|
Ok (FBKey {indices})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs the key from the provided base64 encoded form.
|
||||||
|
/// # Errors
|
||||||
|
/// [DecodeError](FBError::DecodeError)
|
||||||
pub fn import(key_str: &str) -> Result<FBKey, FBError> {
|
pub fn import(key_str: &str) -> Result<FBKey, FBError> {
|
||||||
let indice_bytes = BASE64_STANDARD.decode(key_str)
|
let indice_bytes = BASE64_STANDARD.decode(key_str)
|
||||||
.map_err(|_| FBError::DecodeError)?;
|
.map_err(|_| FBError::DecodeError)?;
|
||||||
|
|
|
@ -3,6 +3,7 @@ pub mod fb128;
|
||||||
use crate::{BlockOps, Encode, FieldOps};
|
use crate::{BlockOps, Encode, FieldOps};
|
||||||
use crypto_bigint::{ArrayEncoding, Bounded, RandomMod};
|
use crypto_bigint::{ArrayEncoding, Bounded, RandomMod};
|
||||||
|
|
||||||
|
/// 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 struct FBObj<T> {
|
||||||
pub(crate) c: Vec<T>,
|
pub(crate) c: Vec<T>,
|
||||||
pub(crate) r: Vec<T>,
|
pub(crate) r: Vec<T>,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::{FBAlgo, FBObj, FieldOps, Packing, WrappingOps};
|
use crate::{FBAlgo, FBObj, FieldOps, Packing, WrappingOps};
|
||||||
use crypto_bigint::{Limb, NonZero, U128};
|
use crypto_bigint::{Limb, NonZero, U128};
|
||||||
|
|
||||||
|
/// [`FBObj`] with a block size of 128 bits.
|
||||||
pub type FB128 = FBObj<U128>;
|
pub type FB128 = FBObj<U128>;
|
||||||
|
|
||||||
const PRIME_POS_VAL: u16 = 159;
|
const PRIME_POS_VAL: u16 = 159;
|
||||||
|
|
42
src/lib.rs
42
src/lib.rs
|
@ -1,3 +1,42 @@
|
||||||
|
//! ## Usage
|
||||||
|
//! Unlike traditional encryption algorithms that output ciphertext to a given plaintext,
|
||||||
|
//! False Bottom works by "adding" messages to an existing ciphertext.
|
||||||
|
//! As such, the initial ciphertext and the keybase are generated from random data.
|
||||||
|
//! The ciphertext then grows as messages are added whereas the keybase is fixed
|
||||||
|
//! after initialization and is used to generate the keys for the ciphertext.
|
||||||
|
//! The parameters for the [`init()`](FBObj::init()) function determine the size
|
||||||
|
//! (in number of blocks) of the initial ciphertext and keybase respectively.
|
||||||
|
//! Type aliases over [`FBObj`] are provided to pick a block size.
|
||||||
|
//! Ex: [`FB128`] corresponds to a block size of 128 bits.
|
||||||
|
//!
|
||||||
|
//! ### Cipher Initialization:
|
||||||
|
//! ```rust
|
||||||
|
//! use false_bottom::{FB128, FBAlgo};
|
||||||
|
//! // 15 blocks of ciphertext and 12 blocks of keybase with a block size of 128 bits.
|
||||||
|
//! let fb = FB128::init(15, 12);
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ### Adding Messages:
|
||||||
|
//! Messages can be added using the [`add()`](FBObj::add()) method.
|
||||||
|
//! This method returns an object [`FBKey`] that represents the corresponding key for this message.
|
||||||
|
//! This key can only be used to decrypt this message.
|
||||||
|
//! ```rust
|
||||||
|
//! let msg = b"Hello World!";
|
||||||
|
//! let key = fb.add(&msg);
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ### Decryption:
|
||||||
|
//! The [`decrypt()`](FBObj::decrypt()) method returns the message that corresponds
|
||||||
|
//! to the provided [`FBKey`].
|
||||||
|
//! ```rust
|
||||||
|
//! let decrypted = fb.decrypt(&key);
|
||||||
|
//! ```
|
||||||
|
//! There is also an example [here](examples/encryption.rs).
|
||||||
|
//!
|
||||||
|
//! ### Import and Export
|
||||||
|
//! Available formats: Raw bytes and Base64 encoded.
|
||||||
|
//! Refer to the [example](examples/export.rs).
|
||||||
|
|
||||||
mod algo;
|
mod algo;
|
||||||
mod arithmetic;
|
mod arithmetic;
|
||||||
mod encoding;
|
mod encoding;
|
||||||
|
@ -9,6 +48,7 @@ mod packing;
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
errors::FBError,
|
errors::FBError,
|
||||||
fbobj::{
|
fbobj::{
|
||||||
|
FBObj,
|
||||||
fb128::FB128,
|
fb128::FB128,
|
||||||
},
|
},
|
||||||
algo::FBAlgo,
|
algo::FBAlgo,
|
||||||
|
@ -19,6 +59,6 @@ pub use crate::{
|
||||||
use crate::{
|
use crate::{
|
||||||
algo::BlockOps,
|
algo::BlockOps,
|
||||||
arithmetic::{FieldOps, WrappingOps},
|
arithmetic::{FieldOps, WrappingOps},
|
||||||
fbobj::{FBObj, FBObjTrait},
|
fbobj::FBObjTrait,
|
||||||
packing::Packing,
|
packing::Packing,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue