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

Replace convert_slice_{32,64} with read_u{32,64}_into #77

Merged
merged 2 commits into from
Dec 27, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
80 changes: 31 additions & 49 deletions rand_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,69 +396,51 @@ impl stdError for Error {
/// Little-Endian order has been chosen for internal usage; this makes some
/// useful functions available.
pub mod le {
use core::slice;
use core::ptr;

/// Helper function to turn a slice into an array reference

/// Read a `u32` from a byte sequence, in litte-endian order
///
/// Consider usage with the `arrayref` crate.
pub fn read_u32(bytes: &[u8; 4]) -> u32 {
unsafe{ *(bytes as *const [u8; 4] as *const u32) }.to_le()
}

/// Read a `u64` from a byte sequence, in litte-endian order
///
/// Consider usage with the `arrayref` crate.
pub fn read_u64(bytes: &[u8; 8]) -> u64 {
unsafe{ *(bytes as *const [u8; 8] as *const u64) }.to_le()
}

/// Convert a byte slice to a `u32` slice and mutate endianness in-place
pub fn convert_slice_32(bytes: &mut [u8]) -> &mut [u32] {
assert_eq!(bytes.len() % 4, 0);
let l = bytes.len() / 4;
let p = bytes.as_ptr() as *mut u8 as *mut u32;
let s = unsafe{ slice::from_raw_parts_mut(p, l) };
for i in s.iter_mut() {
*i = (*i).to_le();
}
s
}

/// Convert a byte slice to a `u64` slice and mutate endianness in-place
pub fn convert_slice_64(bytes: &mut [u8]) -> &mut [u64] {
assert_eq!(bytes.len() % 8, 0);
let l = bytes.len() / 8;
let p = bytes.as_ptr() as *mut u8 as *mut u64;
let s = unsafe{ slice::from_raw_parts_mut(p, l) };
for i in s.iter_mut() {
*i = (*i).to_le();
}
s
}

#[cfg(test)]
mod tests {
use super::*;
#[test]

fn test_read() {
assert_eq!(read_u32(&[1, 2, 3, 4]), 0x04030201);
assert_eq!(read_u64(&[1, 2, 3, 4, 5, 6, 7, 8]), 0x0807060504030201);

{
let mut bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
let slice = convert_slice_32(&mut bytes[..]);
assert_eq!(slice[0], 0x04030201);
assert_eq!(slice[3], 0x100F0E0D);

macro_rules! read_slice {
($src:expr, $dst:expr, $size:expr, $which:ident) => {{
assert_eq!($src.len(), $size * $dst.len());

unsafe {
ptr::copy_nonoverlapping(
$src.as_ptr(),
$dst.as_mut_ptr() as *mut u8,
$src.len());
}
{
let mut bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
let slice = convert_slice_64(&mut bytes[..]);
assert_eq!(slice[0], 0x0807060504030201);
assert_eq!(slice[1], 0x100F0E0D0C0B0A09);
for v in $dst.iter_mut() {
*v = v.$which();
}
}
}};
}

/// Reads unsigned 32 bit integers from `src` into `dst`.
/// Borrowed from the `byteorder` crate.
#[inline]
pub fn read_u32_into(src: &[u8], dst: &mut [u32]) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks fine. Oh, you copied the name from byteorder? I guess it'll do.

read_slice!(src, dst, 4, to_le);
}

/// Reads unsigned 64 bit integers from `src` into `dst`.
/// Borrowed from the `byteorder` crate.
#[inline]
pub fn read_u64_into(src: &[u8], dst: &mut [u64]) {
read_slice!(src, dst, 8, to_le);
}
}
73 changes: 27 additions & 46 deletions src/prng/chacha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,14 @@

//! The ChaCha random number generator.

use core::fmt;
use rand_core::impls;
use core::{fmt, slice};
use rand_core::{impls, le};
use {Rng, CryptoRng, SeedFromRng, SeedableRng, Error};

const KEY_WORDS : usize = 8; // 8 words for the 256-bit key
const STATE_WORDS : usize = 16;
const CHACHA_ROUNDS: u32 = 20; // Cryptographically secure from 8 upwards as of this writing

const CHACHA_EMPTY: ChaChaRng = ChaChaRng {
buffer: [0; STATE_WORDS],
state: [0; STATE_WORDS],
index: STATE_WORDS
};
const SEED_WORDS: usize = 8; // 8 words for the 256-bit key
const STATE_WORDS: usize = 16;
const CHACHA_ROUNDS: u32 = 20; // Cryptographically secure from 8 upwards as of
// this writing

/// A random number generator that uses the ChaCha20 algorithm [1].
///
Expand Down Expand Up @@ -106,9 +101,7 @@ impl ChaChaRng {
/// - 2917185654
/// - 2419978656
pub fn new_unseeded() -> ChaChaRng {
let mut rng = CHACHA_EMPTY;
rng.init(&[0; KEY_WORDS]);
rng
ChaChaRng::init([0; SEED_WORDS])
}

/// Sets the internal 128-bit ChaCha counter to
Expand Down Expand Up @@ -157,22 +150,15 @@ impl ChaChaRng {
/// ```
/// [1]: Daniel J. Bernstein. [*Extending the Salsa20
/// nonce.*](http://cr.yp.to/papers.html#xsalsa)
fn init(&mut self, key: &[u32; KEY_WORDS]) {
self.state[0] = 0x61707865;
self.state[1] = 0x3320646E;
self.state[2] = 0x79622D32;
self.state[3] = 0x6B206574;

for i in 0..KEY_WORDS {
self.state[4+i] = key[i];
}

self.state[12] = 0;
self.state[13] = 0;
self.state[14] = 0;
self.state[15] = 0;

self.index = STATE_WORDS;
fn init(seed: [u32; SEED_WORDS]) -> Self {
ChaChaRng {
buffer: [0; STATE_WORDS],
state: [0x61707865, 0x3320646E, 0x79622D32, 0x6B206574, // constants
seed[0], seed[1], seed[2], seed[3], // seed
seed[4], seed[5], seed[6], seed[7], // seed
0, 0, 0, 0], // counter
index: STATE_WORDS, // generate on first use
}
}

/// Refill the internal output buffer (`self.buffer`)
Expand Down Expand Up @@ -240,27 +226,22 @@ impl CryptoRng for ChaChaRng {}

impl SeedFromRng for ChaChaRng {
fn from_rng<R: Rng>(mut other: R) -> Result<Self, Error> {
let mut key = [0; KEY_WORDS];
for word in key.iter_mut() {
*word = other.next_u32();
let mut seed = [0u32; SEED_WORDS];
unsafe {
let ptr = seed.as_mut_ptr() as *mut u8;
let slice = slice::from_raw_parts_mut(ptr, SEED_WORDS * 4);
other.try_fill(slice)?;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're converting from bytes to u32 here. I think this will produce different results on BE CPUs? We went to all that trouble to make sure fill_bytes is portable, so I think this should be too. Maybe the best option is to use from_seed here :/

}
let mut rng = CHACHA_EMPTY;
rng.init(&key);
Ok(rng)
Ok(ChaChaRng::init(seed))
}
}

impl SeedableRng for ChaChaRng {
type Seed = [u8; 32];
fn from_seed(mut seed: Self::Seed) -> Self {
let mut rng = CHACHA_EMPTY;
let p = &mut seed as *mut [u8; 32] as *mut [u32; 8];
let key = unsafe{ &mut *p };
for k in key.iter_mut() {
*k = k.to_le();
}
rng.init(key);
rng
type Seed = [u8; SEED_WORDS*4];
fn from_seed(seed: Self::Seed) -> Self {
let mut seed_u32 = [0u32; SEED_WORDS];
le::read_u32_into(&seed, &mut seed_u32);
ChaChaRng::init(seed_u32)
}
}

Expand Down
28 changes: 13 additions & 15 deletions src/prng/hc128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@

//! The HC-128 random number generator.

use core::fmt;
use core::slice;

use core::{fmt, slice};
use rand_core::{impls, le};

use {Rng, CryptoRng, SeedFromRng, SeedableRng, Error};

const SEED_WORDS: usize = 8; // 128 bit key followed by 128 bit iv

/// A cryptographically secure random number generator that uses the HC-128
/// algorithm.
///
Expand Down Expand Up @@ -84,7 +83,7 @@ impl fmt::Debug for Hc128Rng {
}

impl Hc128Rng {
pub fn init(seed: &[u32]) -> Hc128Rng {
fn init(seed: [u32; SEED_WORDS]) -> Self {
#[inline]
fn f1(x: u32) -> u32 {
x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3)
Expand Down Expand Up @@ -124,15 +123,12 @@ impl Hc128Rng {
let mut state = Hc128Rng {
state: Hc128 { t: t, counter1024: 0 },
results: [0; 16],
index: 0,
index: 16, // generate on first use
};

// run the cipher 1024 steps
for _ in 0..64 { state.state.sixteen_steps() };
state.state.counter1024 = 0;

// Prepare the first set of results
state.state.update(&mut state.results);
state
}
}
Expand Down Expand Up @@ -398,20 +394,22 @@ impl Rng for Hc128Rng {

impl SeedFromRng for Hc128Rng {
fn from_rng<R: Rng>(mut other: R) -> Result<Self, Error> {
let mut seed = [0u32; 8];
let mut seed = [0u32; SEED_WORDS];
unsafe {
let ptr = seed.as_mut_ptr() as *mut u8;
let slice = slice::from_raw_parts_mut(ptr, 8 * 4);
let slice = slice::from_raw_parts_mut(ptr, SEED_WORDS * 4);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as ChaCha: watch Endianness

other.try_fill(slice)?;
}
Ok(Hc128Rng::init(&seed))
Ok(Hc128Rng::init(seed))
}
}

impl SeedableRng for Hc128Rng {
type Seed = [u8; 32]; /* 128 bit key followed by 128 bit iv */
fn from_seed(mut seed: Self::Seed) -> Self {
Hc128Rng::init(&le::convert_slice_32(&mut seed))
type Seed = [u8; SEED_WORDS*4];
fn from_seed(seed: Self::Seed) -> Self {
let mut seed_u32 = [0u32; SEED_WORDS];
le::read_u32_into(&seed, &mut seed_u32);
Hc128Rng::init(seed_u32)
}
}

Expand Down
31 changes: 13 additions & 18 deletions src/prng/isaac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,9 @@

//! The ISAAC random number generator.

use core::slice;
use core::{fmt, slice};
use core::num::Wrapping as w;
use core::fmt;

use rand_core::{impls, le};

use {Rng, SeedFromRng, SeedableRng, Error};

#[allow(non_camel_case_types)]
Expand Down Expand Up @@ -309,18 +306,14 @@ fn init(mut mem: [w32; RAND_SIZE], rounds: u32) -> IsaacRng {
}
}

let mut rng = IsaacRng {
IsaacRng {
rsl: [0; RAND_SIZE],
mem: mem,
a: w(0),
b: w(0),
c: w(0),
index: 0,
};

// Prepare the first set of results
rng.isaac();
rng
index: RAND_SIZE as u32, // generate on first use
}
}

fn mix(a: &mut w32, b: &mut w32, c: &mut w32, d: &mut w32,
Expand All @@ -337,26 +330,28 @@ fn mix(a: &mut w32, b: &mut w32, c: &mut w32, d: &mut w32,

impl SeedFromRng for IsaacRng {
fn from_rng<R: Rng>(mut other: R) -> Result<Self, Error> {
let mut key = [w(0); RAND_SIZE];
let mut seed = [w(0); RAND_SIZE];
unsafe {
let ptr = key.as_mut_ptr() as *mut u8;
let ptr = seed.as_mut_ptr() as *mut u8;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess here too


let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE * 4);
other.try_fill(slice)?;
}

Ok(init(key, 2))
Ok(init(seed, 2))
}
}

impl SeedableRng for IsaacRng {
type Seed = [u8; 32];
fn from_seed(mut seed: Self::Seed) -> Self {
let mut key = [w(0); RAND_SIZE];
for (x, y) in key.iter_mut().zip(le::convert_slice_32(&mut seed[..]).iter()) {
fn from_seed(seed: Self::Seed) -> Self {
let mut seed_u32 = [0u32; 8];
le::read_u32_into(&seed, &mut seed_u32);
let mut seed_extended = [w(0); RAND_SIZE];
for (x, y) in seed_extended.iter_mut().zip(seed_u32.iter()) {
*x = w(*y);
}
init(key, 2)
init(seed_extended, 2)
}
}

Expand Down
Loading