Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rand_core::RngCore implementation to chacha20 #63

Merged
merged 1 commit into from
Oct 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions chacha20/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ travis-ci = { repository = "RustCrypto/stream-ciphers" }
byteorder = { version = "1", default-features = false }
stream-cipher = "0.3"
salsa20-core = { version = "0.2", path = "../salsa20-core" }
rand_core = { version = "0.5", optional = true }

[dev-dependencies]
stream-cipher = { version = "0.3", features = ["dev"] }
Expand All @@ -30,6 +31,7 @@ default = ["xchacha20"]
legacy = []
xchacha20 = []
zeroize = ["salsa20-core/zeroize"]
rng = ["rand_core"]

[[bench]]
name = "chacha20"
Expand Down
2 changes: 1 addition & 1 deletion chacha20/src/cipher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use byteorder::{ByteOrder, LE};
use salsa20_core::{SalsaFamilyCipher, IV_WORDS, KEY_WORDS, STATE_WORDS};

/// ChaCha20 core cipher functionality
#[derive(Debug)]
#[derive(Clone, Debug)]
pub(crate) struct Cipher {
/// Secret key
key: [u32; KEY_WORDS],
Expand Down
8 changes: 8 additions & 0 deletions chacha20/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ extern crate salsa20_core;
// TODO: replace with `u32::from_le_bytes`/`to_le_bytes` in libcore (1.32+)
#[cfg(feature = "xchacha20")]
extern crate byteorder;
#[cfg(feature = "rand_core")]
extern crate rand_core;

mod block;
pub(crate) mod cipher;
Expand All @@ -68,6 +70,9 @@ mod legacy;
#[cfg(feature = "xchacha20")]
mod xchacha20;

#[cfg(feature = "rng")]
mod rng;

use self::cipher::Cipher;
use salsa20_core::Ctr;
use stream_cipher::generic_array::{
Expand All @@ -81,6 +86,9 @@ pub use self::legacy::ChaCha20Legacy;
#[cfg(feature = "xchacha20")]
pub use self::xchacha20::XChaCha20;

#[cfg(feature = "rng")]
pub use rng::{ChaCha20Rng, ChaCha20RngCore};

/// Maximum number of blocks that can be encrypted with ChaCha20 before the
/// counter overflows.
pub const MAX_BLOCKS: usize = core::u32::MAX as usize;
Expand Down
71 changes: 71 additions & 0 deletions chacha20/src/rng.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//! Block RNG based on rand_core::BlockRng

use rand_core::{RngCore, SeedableRng, Error};
use rand_core::block::{BlockRng, BlockRngCore};
use salsa20_core::{SalsaFamilyCipher, IV_BYTES, KEY_BYTES, STATE_WORDS};

use crate::cipher::Cipher;

/// Random number generator over the ChaCha20 stream cipher.
#[derive(Clone, Debug)]
pub struct ChaCha20Rng(BlockRng<ChaCha20RngCore>);

impl SeedableRng for ChaCha20Rng {
type Seed = [u8; KEY_BYTES];
#[inline]
fn from_seed(seed: Self::Seed) -> Self {
let core = ChaCha20RngCore::from_seed(seed);
Self(BlockRng::new(core))
}
}

impl RngCore for ChaCha20Rng {
#[inline]
fn next_u32(&mut self) -> u32 {
self.0.next_u32()
}
#[inline]
fn next_u64(&mut self) -> u64 {
self.0.next_u64()
}
#[inline]
fn fill_bytes(&mut self, bytes: &mut [u8]) {
self.0.fill_bytes(bytes)
}
#[inline]
fn try_fill_bytes(&mut self, bytes: &mut [u8]) -> Result<(), Error> {
self.0.try_fill_bytes(bytes)
}
}


/// Core of the [`ChaCha20Rng`] random number generator, for use with
/// [`rand_core::block::BlockRng`].
#[derive(Clone, Debug)]
pub struct ChaCha20RngCore {
cipher: Cipher,
counter: u64,
}

impl SeedableRng for ChaCha20RngCore {
type Seed = [u8; KEY_BYTES];
#[inline]
fn from_seed(seed: Self::Seed) -> Self {
let iv = [0; IV_BYTES];
let cipher = Cipher::new(&seed, &iv, 0);
Self {
cipher,
counter: 0,
}
}
}

impl BlockRngCore for ChaCha20RngCore {
type Item = u32;
type Results = [u32; STATE_WORDS];
fn generate(&mut self, results: &mut Self::Results) {
let out = self.cipher.block(self.counter);
self.counter += 1;
*results = out;
}
}