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 HC-128 #210

Merged
merged 4 commits into from
Jan 10, 2018
Merged
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
42 changes: 21 additions & 21 deletions src/prng/hc128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@

//! The HC-128 random number generator.

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

use core::{fmt, slice};
use {Rng, SeedableRng, Rand};
use impls;

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 All @@ -39,6 +39,11 @@ use impls;
/// brute-force search of 2<sup>128</sup>. A very comprehensive analysis of the
/// current state of known attacks / weaknesses of HC-128 is given in [4].
///
/// The average cycle length is expected to be
/// 2<sup>1024*32-1</sup> = 2<sup>32767</sup>.
/// We support seeding with a 256-bit array, which matches the 128-bit key
/// concatenated with a 128-bit IV from the stream cipher.
///
/// ## References
/// [1]: Hongjun Wu (2008). ["The Stream Cipher HC-128"]
/// (http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf).
Expand All @@ -55,8 +60,7 @@ use impls;
/// (http://library.isical.ac.in:8080/jspui/bitstream/123456789/6636/1/TH431.pdf).
///
/// [5]: Internet Engineering Task Force (Februari 2015),
/// ["Prohibiting RC4 Cipher Suites"]
/// (https://tools.ietf.org/html/rfc7465).
/// ["Prohibiting RC4 Cipher Suites"](https://tools.ietf.org/html/rfc7465).
#[derive(Clone)]
pub struct Hc128Rng {
Copy link
Member

Choose a reason for hiding this comment

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

I guess this is the wrong time to bring it up, but we should think about the naming scheme. I know Rust will complain, but HC128 might be preferable (ugh, camel case applied to acronyms — if HC is even an acronym)! Okay, ignore this for now but lets open an issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't really mind. ISAAC is already IsaacRng. In the standard library ARC is Arc, RC is Rc etc.

state: Hc128,
Expand Down Expand Up @@ -89,7 +93,7 @@ impl Hc128Rng {
// Initialize an HC-128 random number generator. The seed has to be
// 256 bits in length (`[u32; 8]`), matching the 128 bit `key` followed by
// 128 bit `iv` when HC-128 where to be used as a stream cipher.
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 @@ -129,15 +133,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);
Copy link
Member

Choose a reason for hiding this comment

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

Why did this code get dropped?

I also noticed a similar difference with ISAAC when merging upstream into my branch; not sure why it was there.

Isn't it better to do as much as possible during init?

Copy link
Contributor Author

@pitdicker pitdicker Jan 8, 2018

Choose a reason for hiding this comment

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

To be honest, I don't completely remember. I had reasons for it when working on the BlockRngCore stuff, this change to the seeding was part of the 'functional' changes.

ChaCha generated the set of results on first use, while ISAAC and HC-128 did on initialization. So it seemed a good idea to pick one default.

Generating results on first use made the seeding function for slightly simpler, it is just initializing a struct:

impl<R> SeedableRng for BlockRng<R>
where R: BlockRngCore + SeedableRng,
{
    type Seed = R::Seed;

    fn from_seed(seed: Self::Seed) -> Self {
        let results_empty = R::Results::default();
        Self {
            core: R::from_seed(seed),
            index: results_empty.as_ref().len(), // generate on first use
            results: results_empty,
        }
    }

    fn from_rng<Rseed: Rng>(rng: Rseed) -> Result<Self, Error> {
        let results_empty = R::Results::default();
        Ok(Self {
            core: R::from_rng(rng)?,
            index: results_empty.as_ref().len(), // generate on first use
            results: results_empty,
        })
    }
}

I feel like I had a better reason, but can't remember it.

state
}
}
Expand Down Expand Up @@ -400,19 +401,18 @@ impl Rand for Hc128Rng {
let slice = slice::from_raw_parts_mut(ptr, 8 * 4);
other.fill_bytes(slice);
}
Hc128Rng::init(&seed)
Hc128Rng::init(seed)
}
}

impl<'a> SeedableRng<&'a [u32]> for Hc128Rng {
fn reseed(&mut self, seed: &'a [u32]) {
impl SeedableRng<[u32; SEED_WORDS]> for Hc128Rng {
fn reseed(&mut self, seed: [u32; SEED_WORDS]) {
*self = Self::from_seed(seed);
}
/// Create an HC-128 random number generator with a seed. The seed has to be
/// 256 bits in length, matching the 128 bit `key` followed by 128 bit `iv`
/// when HC-128 where to be used as a stream cipher.
fn from_seed(seed: &'a [u32]) -> Hc128Rng {
assert!(seed.len() == 8);
fn from_seed(seed: [u32; SEED_WORDS]) -> Hc128Rng {
Hc128Rng::init(seed)
}
}
Expand All @@ -427,7 +427,7 @@ mod test {
fn test_hc128_true_values_a() {
let seed = [0u32, 0, 0, 0, // key
0, 0, 0, 0]; // iv
let mut rng = Hc128Rng::from_seed(&seed);
let mut rng = Hc128Rng::from_seed(seed);

let v = (0..16).map(|_| rng.next_u32()).collect::<Vec<_>>();
assert_eq!(v,
Expand All @@ -442,7 +442,7 @@ mod test {
fn test_hc128_true_values_b() {
let seed = [0u32, 0, 0, 0, // key
1, 0, 0, 0]; // iv
let mut rng = Hc128Rng::from_seed(&seed);
let mut rng = Hc128Rng::from_seed(seed);

let v = (0..16).map(|_| rng.next_u32()).collect::<Vec<_>>();
assert_eq!(v,
Expand All @@ -457,7 +457,7 @@ mod test {
fn test_hc128_true_values_c() {
let seed = [0x55u32, 0, 0, 0, // key
0, 0, 0, 0]; // iv
let mut rng = Hc128Rng::from_seed(&seed);
let mut rng = Hc128Rng::from_seed(seed);

let v = (0..16).map(|_| rng.next_u32()).collect::<Vec<_>>();
assert_eq!(v,
Expand All @@ -471,7 +471,7 @@ mod test {
fn test_hc128_true_values_u64() {
let seed = [0u32, 0, 0, 0, // key
0, 0, 0, 0]; // iv
let mut rng = Hc128Rng::from_seed(&seed);
let mut rng = Hc128Rng::from_seed(seed);

let v = (0..8).map(|_| rng.next_u64()).collect::<Vec<_>>();
assert_eq!(v,
Expand All @@ -497,7 +497,7 @@ mod test {
fn test_hc128_true_values_bytes() {
let seed = [0x55u32, 0, 0, 0, // key
0, 0, 0, 0]; // iv
let mut rng = Hc128Rng::from_seed(&seed);
let mut rng = Hc128Rng::from_seed(seed);
let expected =
vec!(0x31, 0xf9, 0x2a, 0xb0, 0x32, 0xf0, 0x39, 0x06,
0x7a, 0xa4, 0xb4, 0xbc, 0x0b, 0x48, 0x22, 0x57,
Expand Down Expand Up @@ -534,7 +534,7 @@ mod test {
fn test_hc128_clone() {
let seed = [0x55, 0, 0, 0, // key
0, 0, 0, 0]; // iv
let mut rng1 = Hc128Rng::from_seed(&seed);
let mut rng1 = Hc128Rng::from_seed(seed);
let mut rng2 = rng1.clone();
for _ in 0..16 {
assert_eq!(rng1.next_u32(), rng2.next_u32());
Expand Down