From 7ad2ba8de818567b287badc2f055136ecdf6b2ca Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Wed, 20 Mar 2024 11:38:54 -0700 Subject: [PATCH] Add some more docs to chacha --- src/chacha.rs | 75 +++++++++++++++++++++++++++++++++++-------------- src/poly1305.rs | 2 +- 2 files changed, 55 insertions(+), 22 deletions(-) diff --git a/src/chacha.rs b/src/chacha.rs index 6bb4d61..334e614 100644 --- a/src/chacha.rs +++ b/src/chacha.rs @@ -1,38 +1,56 @@ +//! The ChaCha20 stream cipher based on RFC7539. + +/// The first four words (32 bits) of the ChaCha stream cipher state are constants. const WORD_1: u32 = 0x61707865; const WORD_2: u32 = 0x3320646e; const WORD_3: u32 = 0x79622d32; const WORD_4: u32 = 0x6b206574; + +/// Each quarter round of ChaCha scrambles 4 words (32-bit) of the state +/// using some Addition (mod 2^32), Rotation, and XOR (ARX). 8 quarter +/// rounds make up a round. A block is broken up into 16 32-bit words +/// and each quarter round takes 4 words as input. const CHACHA_ROUND_INDICIES: [(usize, usize, usize, usize); 8] = [ + // The first 4 rounds are rows of a 4x4 matrix + // of the block broken up into 32-bit words. (0, 4, 8, 12), (1, 5, 9, 13), (2, 6, 10, 14), (3, 7, 11, 15), + // The first 4 rounds are diagonals of a 4x4 matrix + // of the block broken up into 32-bit words. (0, 5, 10, 15), (1, 6, 11, 12), (2, 7, 8, 13), (3, 4, 9, 14), ]; + +/// The cipher's block size is 64 bytes. const CHACHA_BLOCKSIZE: usize = 64; /// The ChaCha20 stream cipher. #[derive(Debug)] pub(crate) struct ChaCha20 { + /// A 256 bit secret session key shared by the parties communitcating. key: [u8; 32], + /// A 96 bit initialization vector (IV), or nonce. A key/nonce pair should only be used once. nonce: [u8; 12], - inner: u32, - seek: usize, + /// Internal block index of keystream. + block_count: u32, + /// Interal byte offset index of the block_count. + seek_offset_bytes: usize, } impl ChaCha20 { /// Make a new instance of ChaCha20 from an index in the keystream. pub fn new(key: [u8; 32], nonce: [u8; 12], seek: u32) -> Self { - let inner = seek / 64; - let seek = (seek % 64) as usize; + let block_count = seek / 64; + let seek_offset_bytes = (seek % 64) as usize; ChaCha20 { key, nonce, - inner, - seek, + block_count, + seek_offset_bytes, } } @@ -43,8 +61,8 @@ impl ChaCha20 { ChaCha20 { key, nonce, - inner, - seek, + block_count: inner, + seek_offset_bytes: seek, } } @@ -53,7 +71,12 @@ impl ChaCha20 { let num_full_blocks = to.len() / CHACHA_BLOCKSIZE; let mut j = 0; while j < num_full_blocks { - let kstream = keystream_at_slice(self.key, self.nonce, self.inner, self.seek); + let kstream = keystream_at_slice( + self.key, + self.nonce, + self.block_count, + self.seek_offset_bytes, + ); for (c, k) in to[j * CHACHA_BLOCKSIZE..(j + 1) * CHACHA_BLOCKSIZE] .iter_mut() .zip(kstream.iter()) @@ -61,14 +84,19 @@ impl ChaCha20 { *c ^= *k } j += 1; - self.inner += 1; + self.block_count += 1; } if to.len() % 64 > 0 { - let kstream = keystream_at_slice(self.key, self.nonce, self.inner, self.seek); + let kstream = keystream_at_slice( + self.key, + self.nonce, + self.block_count, + self.seek_offset_bytes, + ); for (c, k) in to[j * CHACHA_BLOCKSIZE..].iter_mut().zip(kstream.iter()) { *c ^= *k } - self.inner += 1; + self.block_count += 1; } to } @@ -76,19 +104,24 @@ impl ChaCha20 { /// Get the keystream block at a specified block. pub(crate) fn get_keystream(&mut self, block: u32) -> [u8; 64] { self.block(block); - keystream_at_slice(self.key, self.nonce, self.inner, self.seek) + keystream_at_slice( + self.key, + self.nonce, + self.block_count, + self.seek_offset_bytes, + ) } - /// Update the index of the keystream to an index in the keystream. + /// Update the index of the keystream to the given byte. pub(crate) fn seek(&mut self, seek: u32) { - self.inner = seek / 64; - self.seek = (seek % 64) as usize; + self.block_count = seek / 64; + self.seek_offset_bytes = (seek % 64) as usize; } /// Update the index of the keystream to a block. pub(crate) fn block(&mut self, block: u32) { - self.inner = block; - self.seek = 0; + self.block_count = block; + self.seek_offset_bytes = 0; } } @@ -187,12 +220,12 @@ fn keystream_from_state(state: &mut [u32; 16]) -> [u8; 64] { keystream } -fn keystream_at_slice(key: [u8; 32], nonce: [u8; 12], inner: u32, seek: usize) -> [u8; 64] { +fn keystream_at_slice(key: [u8; 32], nonce: [u8; 12], count: u32, seek: usize) -> [u8; 64] { let mut keystream: [u8; 128] = [0; 128]; - let mut state = prepare_state(key, nonce, inner); + let mut state = prepare_state(key, nonce, count); chacha_block(&mut state); let first_half = keystream_from_state(&mut state); - let mut state = prepare_state(key, nonce, inner + 1); + let mut state = prepare_state(key, nonce, count + 1); chacha_block(&mut state); let second_half = keystream_from_state(&mut state); keystream[..64].copy_from_slice(&first_half); diff --git a/src/poly1305.rs b/src/poly1305.rs index 3e6ac79..9fbc98f 100644 --- a/src/poly1305.rs +++ b/src/poly1305.rs @@ -1,4 +1,4 @@ -/// Implementation of Poly1305 function heavily inspired by the following [this implementation in C](https://github.com/floodyberry/poly1305-donna/blob/master/poly1305-donna-32.h) +/// Implementation of Poly1305 function heavily inspired by [this implementation in C](https://github.com/floodyberry/poly1305-donna/blob/master/poly1305-donna-32.h) /// referred to as "Donna". Further reference to [this](https://loup-vaillant.fr/tutorials/poly1305-design) article was used to formulate the multiplication loop. const BITMASK: u32 = 0x03ffffff;