Docs: Add documentation comments

This commit is contained in:
K Shiva Kiran 2024-04-09 22:18:33 +05:30
parent c08ad88303
commit 392d0ca315
8 changed files with 88 additions and 7 deletions

View File

@ -1,9 +1,12 @@
[package]
name = "false-bottom"
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"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rand = "0.8.5"
@ -11,3 +14,6 @@ crypto-bigint = {version = "0.5.5", features = ["generic-array"]}
base64 = "0.21.7"
bincode = "1.3.3"
typenum = "1.17.0"
[lib]
doctest = false

View File

@ -9,21 +9,27 @@ where
{
const MODULUS: NonZero<T>;
fn init(n: usize, k: usize) -> Result<FBObj<T>, FBError> {
if n < k || k < 2 {
/// Creates a new [`FBObj`].
/// 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);
}
let mut rng = rand::thread_rng();
let r = (0..k)
let r = (0..keybase_len)
.map(|_| T::random_mod(&mut rng, &Self::MODULUS))
.collect();
let c = (0..n)
let c = (0..cipher_len)
.map(|_| T::random_mod(&mut rng, &Self::MODULUS))
.collect();
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()
@ -33,6 +39,9 @@ where
FBKey { indices }
}
/// Decrypts the message that corresponds to the provided key.
/// # Errors
/// [InvalidKey](FBError::InvalidKey)
fn decrypt(&self, key: &FBKey) -> Result<Vec<u8>, FBError> {
let decr = key.indices
.iter()

View File

@ -7,6 +7,7 @@ where
Self: FBObjTrait<T>,
T: ArrayEncoding + Bounded,
{
/// Returns the byte representation of the ciphertext and keybase.
fn to_bytes(&self) -> (Vec<u8>, Vec<u8>) {
let c = self.cipher().iter()
.flat_map(|bigint| bigint.to_le_byte_array())
@ -18,12 +19,17 @@ where
(c, r)
}
/// Returns the base64 encoded representation of the ciphertext and keybase.
fn export(&self) -> (String, String) {
let (c, r) = self.to_bytes();
(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> {
let chunk_to_uint = |chunk| {
T::from_le_byte_array(
@ -42,6 +48,11 @@ where
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> {
let c_bytes = BASE64_STANDARD.decode(cipher)
.map_err(|_| FBError::DecodeError)?;

View File

@ -2,8 +2,12 @@ use std::fmt;
#[derive(Debug)]
pub enum FBError {
/// Unable to decode the given data.
DecodeError,
/// The provided key is invalid w.r.t this False Bottom Object.
InvalidKey,
/// Keybase length (k) or Cipher length (n) out of bounds.
/// Valid bounds: (2 <= k <= n).
InvalidParams,
}

View File

@ -2,22 +2,28 @@ use crate::FBError;
use base64::prelude::{BASE64_STANDARD, Engine};
use bincode::{Options, DefaultOptions};
/// A key object that is specific to a message.
pub struct FBKey {
pub(crate) indices: Vec<Vec<(usize, usize)>>,
}
impl FBKey {
/// Returns the byte representation of the key.
pub fn to_bytes(&self) -> Vec<u8> {
let binc = DefaultOptions::new();
binc.serialize(&self.indices)
.expect("Should be fine")
}
/// Returns the base64 encoded representation of the key.
pub fn export(&self) -> String {
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> {
let binc = DefaultOptions::new();
let indices: Vec<_> = binc.deserialize(&fbkey)
@ -29,6 +35,9 @@ impl FBKey {
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> {
let indice_bytes = BASE64_STANDARD.decode(key_str)
.map_err(|_| FBError::DecodeError)?;

View File

@ -3,6 +3,7 @@ pub mod fb128;
use crate::{BlockOps, Encode, FieldOps};
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(crate) c: Vec<T>,
pub(crate) r: Vec<T>,

View File

@ -1,6 +1,7 @@
use crate::{FBAlgo, FBObj, FieldOps, Packing, WrappingOps};
use crypto_bigint::{Limb, NonZero, U128};
/// [`FBObj`] with a block size of 128 bits.
pub type FB128 = FBObj<U128>;
const PRIME_POS_VAL: u16 = 159;

View File

@ -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 arithmetic;
mod encoding;
@ -9,6 +48,7 @@ mod packing;
pub use crate::{
errors::FBError,
fbobj::{
FBObj,
fb128::FB128,
},
algo::FBAlgo,
@ -19,6 +59,6 @@ pub use crate::{
use crate::{
algo::BlockOps,
arithmetic::{FieldOps, WrappingOps},
fbobj::{FBObj, FBObjTrait},
fbobj::FBObjTrait,
packing::Packing,
};