From 70abb4303a12a9d24a9ce6df8e6504ab3ecf4760 Mon Sep 17 00:00:00 2001 From: Avril Date: Sat, 20 Mar 2021 02:59:10 +0000 Subject: [PATCH] better docs --- Cargo.toml | 4 +-- src/c.rs | 4 +-- src/ctx.rs | 24 ++++++++++++++--- src/error.rs | 2 +- src/lib.rs | 71 ++++++++++++++++++++++++++++++++++++++++++++++++--- src/salt.rs | 41 ++++++++++++++++++++++++++--- src/stream.rs | 14 +++++++--- 7 files changed, 141 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 451c6e6..dd3517b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "khash" description = "Kana hashes" -version = "2.0.3" +version = "2.0.4" authors = ["Avril "] edition = "2018" license = "GPL-3.0-or-later" @@ -26,7 +26,7 @@ sha2 = "0.9" malloc-array = {version = "1.4", optional=true} libc = {version = "0.2", optional=true} crc = {version = "1.8", optional=true} -hex-literal = "0.2" +hex-literal = "0.3" getrandom = "0.1" [build-dependencies] diff --git a/src/c.rs b/src/c.rs index 2b9df6f..453a69c 100644 --- a/src/c.rs +++ b/src/c.rs @@ -155,8 +155,8 @@ pub unsafe extern "C" fn khash_max_length(algo: u8, _input_sz: libc::size_t, max { no_unwind!{ let hash_sz = match ctx::Algorithm::from(algo) { - ctx::Algorithm::Crc32 => std::mem::size_of::(), - ctx::Algorithm::Crc64 => std::mem::size_of::(), + #[cfg(feature="crc")] ctx::Algorithm::Crc32 => std::mem::size_of::(), + #[cfg(feature="crc")] ctx::Algorithm::Crc64 => std::mem::size_of::(), ctx::Algorithm::Sha256 => std::mem::size_of::(), ctx::Algorithm::Sha256Truncated => std::mem::size_of::(), }; diff --git a/src/ctx.rs b/src/ctx.rs index 55a4c8f..9e0682d 100644 --- a/src/ctx.rs +++ b/src/ctx.rs @@ -1,4 +1,11 @@ -//! Contains contexts used for algorithms +//! Contains contexts used for the digest algorithms. +//! +//! These contexts contain the digest name and the salt to be used with the digest. +//! +//! # Defaults +//! Both the digest name (`Algorithm`) and the `Context` itself implement `Default`. +//! The default algorithm is `SHA256Truncated`, and the default `Context` uses this algorithm along with the default salt (which is the library's hard-coded static salt.) + use crate::*; use std::{ io::{ @@ -7,14 +14,22 @@ use std::{ }; /// An algorithm to use for the context. +/// +/// # CRC +/// `CRC32` and `CRC64` are only available if compiled with the default "crc" feature enabled. +/// If the library is compiled without this feature, but with the "ffi" feature (i.e. generates native libraries), then FFI requests for the CRC family of digests will instead use the default (`Sha256Truncated`). #[derive(Clone,Debug,PartialEq,Eq,Hash)] pub enum Algorithm { - #[cfg(feature="crc")] + #[cfg(feature="crc")] + /// The 32 bit CRC checksum (requires default feature `crc`) Crc32, - #[cfg(feature="crc")] + #[cfg(feature="crc")] + /// The 64 bit CRC checksum (requires default feature `crc`) Crc64, + /// The SHA256 hash Sha256, + /// The SHA256 hash truncated to the first 64 bits Sha256Truncated, } @@ -27,6 +42,9 @@ impl Default for Algorithm } /// A kana-hash context containing it's salt and algorithm. +/// +/// # Default +/// The default context contains the `SHA256Truncated` digest algorithm and the library's hard-coded static salt. #[derive(Clone,Debug,PartialEq,Eq,Hash)] pub struct Context { diff --git a/src/error.rs b/src/error.rs index 966861e..0a515b1 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,4 @@ -//! Error for kana-hash functions +//! Error for kana-hash operation use std::{ fmt, io, diff --git a/src/lib.rs b/src/lib.rs index 8830b08..071b4cf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,36 @@ +//! # khash - Kana mnemonic hashes +//! +//! This library pretty prints salted hashes of a veriaty of digests in kana. +//! Mnemonics can be generated from slices or from streams. +//! +//! It has a Rust API documented here, as well as C FFI bindings and a C header (see `include/`.) +//! +//! ## Digest +//! The digests available are: +//! * SHA256 truncated to the first 64 bits (8 bytes) (default digest) +//! * SHA256 full +//! * CRC64 (requires "crc" default feature enabled) +//! * CRC32 (requires "crc" default feature enabled) +//! +//! ### Salting +//! The salting options for the digests are: +//! * Hard-coded embedded 32 byte salt (default) +//! * Fixed compile time 32 byte salt +//! * Fixed runtime 32 byte salt +//! * Dynamically sized runtime salt +//! * No salt +//! The salt (if any) is fed into the digest directly after all the data. +//! (See `ctx` and `salt` modules). +//! +//! ## Generating kana mnemonics from arbitrary data +//! To use the mnemonic generation algorithm on any binary data instead of just hash outputs, the `Digest` iterator type is provided. +//! The `Digest` iterator can be created from any type implementing `std::io::Read` and produces a kana mnemonic reading from the stream until its end. +//! ``` +//! # use khash::Digest; +//! let input = "Hello world!"; +//! let mnemonic: String = Digest::new(&mut input.as_bytes()).collect(); // Read the bytes from the `input` string and collect the kana mnemonic into a `String` +//! ``` + #![cfg_attr(nightly, feature(test))] #![allow(dead_code)] #![allow(unused_imports)] @@ -162,7 +195,10 @@ mod tests { let input = "owowowoakpwodkapowkdapowkdpaokwpdoakwd"; - let algos = [ctx::Algorithm::Crc32, ctx::Algorithm::Crc64, ctx::Algorithm::Sha256, ctx::Algorithm::Sha256Truncated]; + let algos = [#[cfg(feature="crc")] ctx::Algorithm::Crc32, + #[cfg(feature="crc")] ctx::Algorithm::Crc64, + ctx::Algorithm::Sha256, + ctx::Algorithm::Sha256Truncated]; for i in 0..1000 { let max_len = max_length(algos[i%algos.len()].clone(), 0); @@ -177,7 +213,8 @@ mod tests { } } -pub const BUFFER_SIZE: usize = 4096; +/// The size used for internal buffers +const BUFFER_SIZE: usize = 4096; mod array; mod reinterpret; @@ -217,7 +254,14 @@ fn compute(context: &ctx::Context, mut from: T) -> Result<(usize, Strin Ok((read,output)) } -/// Generate kana hash from a slice. +/// Generate kana hash from a slice of bytes with this digest. +/// +/// # Example +/// To generate a hash with the default digest from a string +/// ``` +/// # use khash::generate; +/// generate(&Default::default(), "Hello world!").expect("Failed to generate hash string"); +/// ``` pub fn generate>(context: &ctx::Context, bytes: T) -> Result { let bytes = bytes.as_ref(); @@ -230,7 +274,26 @@ pub fn generate>(context: &ctx::Context, bytes: T) -> Result) -> String +/// { +/// let mut file = OpenOptions::new() +/// .read(true) +/// .open(file_name).expect("Failed to open file"); +/// +/// let file_size = file.metadata().expect("Failed to stat file").len(); +/// +/// let (bytes_read, hash) = generate_stream(&Default::default(), &mut file).expect("Failed to generate hash from file"); +/// assert_eq!(bytes_read as u64, file_size, "Failed to read whole file"); +/// +/// hash +/// } +/// ``` #[inline] pub fn generate_stream(context: &ctx::Context, from: &mut T) -> Result<(usize, String), error::Error> { compute(context, from) diff --git a/src/salt.rs b/src/salt.rs index 3bbbba4..7f38fee 100644 --- a/src/salt.rs +++ b/src/salt.rs @@ -1,3 +1,20 @@ +//! Salt for the digest `Context` (see module `ctx`) +//! +//! # Salt kinds +//! * Hard-coded embedded 32 byte salt (default) +//! * Fixed compile time or global static 32 byte salt +//! * Fixed runtime 32 byte salt +//! * Dynamically sized runtime salt +//! * No salt +//! +//! You can also generate a random salt at runtime with `Salt::random()` which uses `getrandom`'s RNG to create a fixed 32 bytes salt. +//! +//! # Method of salting +//! The salt is fed into the hashing function directly after the data. +//! +//! # FFI note +//! When generating a dynamic salt from an FFI context, there is a hard limit of 1024 bytes for safety reasons. This is more than enough data for a salt. + #[cfg(feature="ffi")] use malloc_array::*; use getrandom::{ @@ -14,19 +31,35 @@ use std::{ convert::{TryInto,TryFrom}, }; -/// The static salt size +/// The static salt size. (32 bytes.) +/// +/// When providing a compile-time or otherwise global salt, it must be of this size. pub const SIZE: usize = 32; -/// The default static salt +/// The default embedded static salt. +/// +/// It is recommended to use your own salt instead of this one, but this is used as the default if a salt option is not provided. +/// +/// # Guarantee +/// This salt is guaranteed stay the same throughout all versions and iterations of this library. +/// It was randomly generated as the 32 bytes hex literal `hex!("6787f049791466d5a31a3aa6f7138d8fbb907fd1785758298b5c97b0f3fb31ff")`. +pub static EMBEDDED_SALT: &'static [u8; SIZE] = STATIC_SALT; + const STATIC_SALT: &[u8; SIZE] = &hex!("6787f049791466d5a31a3aa6f7138d8fbb907fd1785758298b5c97b0f3fb31ff"); -/// A salt to use for the kana-hash algorithm +/// A salt to use for the kana-hash algorithm, or lack thereof. +/// +/// It is recommended to provide your own salt, but the default `EMBEDDED_SALT` can be used instead. #[derive(Clone,PartialEq,Eq,Hash,Debug)] pub enum Salt { + /// Do not salt the hash at all None, + /// Salt with a compile-time, global, or leaked 32 byte array Static(&'static [u8; SIZE]), + /// Salt with a runtime 32 byte array Fixed([u8; SIZE]), + /// Salt with a runtime dynamic boxed byte slice of any size (must be at least 1) Dynamic(Box<[u8]>), } @@ -65,7 +98,7 @@ impl Salt getrandom(&mut buffer[..])?; Ok(Self::Fixed(buffer)) } - /// The default internal salt + /// The default embedded salt pub const fn internal() -> Self { Self::Static(STATIC_SALT) diff --git a/src/stream.rs b/src/stream.rs index 5b2d2d0..9429aac 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -1,6 +1,14 @@ use crate::*; -/// A streaming kana hash digest +/// A streaming kana hash digest. +/// +/// This type can be used to generate kana mnemonics from any data. +/// It wraps a type implementing `std::io::Read` and produces a kana mnemonic reading from the stream until its end. +/// ``` +/// # use khash::Digest; +/// let input = "Hello world!"; +/// let mnemonic: String = Digest::new(&mut input.as_bytes()).collect(); // Read the bytes from the `input` string and collect the kana mnemonic into a `String` +/// ``` pub struct Digest<'a, T> where T: Read { @@ -9,7 +17,7 @@ where T: Read impl<'a, T: Read> Digest<'a, T> { - /// Create a new stream digest from the input + /// Create a new stream digest iterator from the input stream. pub fn new(input: &'a mut T) -> Self { Self{input} @@ -18,7 +26,7 @@ impl<'a, T: Read> Digest<'a, T> impl<'a, T: Read> Iterator for Digest<'a, T> { - type Item = String; + type Item = String; //TODO: Change this to `char` and keep an internal buffer that we `fmt::write!` the mnemonic digest to instead of `format!`ing it. fn next(&mut self) -> Option { let mut buffer = [0u8; 2];