Skip to content

Commit

Permalink
Tweak SipRng to use 2 rounds, but with 2 extra rounds after hashing
Browse files Browse the repository at this point in the history
  • Loading branch information
dhardy committed Jul 14, 2018
1 parent 050066c commit b71223d
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 27 deletions.
4 changes: 2 additions & 2 deletions rand_sip/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ mod test {
fn make_rng() {
let mut seeder = Seeder::from("test string");
let mut rng = seeder.make_rng::<SipRng>();
assert_eq!(rng.next_u64(), 12663007370304372624);
assert_eq!(rng.next_u64(), 5627962167735916311);
assert_eq!(rng.next_u64(), 7267854722795183454);
assert_eq!(rng.next_u64(), 602994585684902144);
}
}
55 changes: 30 additions & 25 deletions rand_sip/src/sip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ use rand_core::{RngCore, SeedableRng, Error, le, impls};
///
/// This implementation will produce 8-byte (`u64`) output compliant with the
/// reference implementation. Additionally, it can be extended into an RNG able
/// to produce unlimited output (and whose first `u64` matches that of the
/// reference). The RNG itself however is an extension to the original standard.
/// to produce unlimited output, `SipRng`.
///
/// See: <https://131002.net/siphash/>
///
Expand All @@ -43,7 +42,11 @@ pub struct SipHasher {

/// An RNG based around a SipHash core.
///
/// Uses four rounds between output values.
/// This implementation is fixed to use two rounds between output values
/// (similar to how SipHash uses 2 between input values). The construction
/// from a `SipHasher` adds two extra rounds so that there are still four
/// rounds between final input consumption and first output production.
/// The first result is however not equivalent.
#[derive(Debug, Clone)]
pub struct SipRng {
state: State,
Expand Down Expand Up @@ -129,7 +132,7 @@ impl SipRng {
fn from_state(state: State) -> SipRng {
SipRng {
state,
adj: 0xff,
adj: 0x13,
}
}
}
Expand All @@ -141,14 +144,10 @@ impl RngCore for SipRng {
}

fn next_u64(&mut self) -> u64 {
// The initial modification of v2 is consistent with the reference impl
// The ref. modifies v1 for the second output. We only decrement adj.
self.state.v2 ^= self.adj;
self.adj = self.adj.wrapping_sub(0x11);

// The ref. uses d rounds between outputs. This may make the RNG slower
// than necessary, but it's unimportant for short outputs.
Sip24Rounds::d_rounds(&mut self.state);
Sip24Rounds::c_rounds(&mut self.state);

self.state.v0 ^ self.state.v1 ^ self.state.v2 ^ self.state.v3
}
Expand Down Expand Up @@ -250,6 +249,9 @@ impl<S: Sip> Hasher<S> {
S::c_rounds(&mut state);
state.v0 ^= b;

// This is supposed to be d - c rounds (here 4 - 2 = 2)
S::c_rounds(&mut state);

SipRng::from_state(state)
}
}
Expand Down Expand Up @@ -463,14 +465,17 @@ mod test {
let mut seed = [0u8; 32];
let mut rng = SipRng::from_seed(seed);

let vector = [0x3c4ceb5cc070daa0, 0x5bb9e3c18217fae,
0xa69f9b2efe320033, 0x7db235549ebb9bfa,
0x83d8e81476d9026d, 0x26ebdcbe3b39aaaf,
0x6df71f62665e56a3, 0x8476afeb57bd258e,
0x390b28b614d92326, 0x1897e25a6e606898,
0x86d0e787f4385b6d, 0xa7ffd35b9db002a4,
0x17dc3ab652a92f3f, 0x819ec800d5fafc95,
0xce7f906978fa7bb, 0xa1ccc9da17fae68e];
let vector = [0x4c022e4ec04e602a, 0xc2c0399c269058d6,
0xf5c7399cde9c362c, 0x37e5b9491363680a,
0x9582782644903316, 0x2a9d2e160aad88d,
0x983958db9376e6f6, 0xdead8960b8524928,
0xcfa886c6642c1b2f, 0x8f8f91fcf7045f2a,
0x1bbda585fc387fb3, 0x242485d9cc54c688,
0x9be110f767d8cee, 0xd61076dfc3569ab3,
0x8f6092dd2692af57, 0xbdf362ab8e29260b];
// for _ in 0..8 {
// println!("0x{:x}, 0x{:x},", rng.next_u64(), rng.next_u64());
// }
for i in 0..16 {
assert_eq!(rng.next_u64(), vector[i]);
}
Expand All @@ -481,14 +486,14 @@ mod test {
}
let mut rng = SipRng::from_seed(seed);

let vector = [0x439ea507b488f5c9, 0xc416e54e0e63000e,
0xb107c656f764dccc, 0x99e4e68b0fe1454,
0xc94dc7e545004b5b, 0xcdf1211c76138dce,
0xb2c461119268feef, 0x9f2a6c063ff3569,
0x4561da5ccc4336b9, 0x7dba6770f062b7a1,
0x3a6b2de6e869d4d9, 0x250ed5dd48c80e7b,
0x9c1b2cf82f84e849, 0x9b133b17b7bfab1a,
0x744ad3c9c9271bf5, 0x59dc69db54c683d8];
let vector = [0x479bf2823a7a923e, 0xf04e2cbc75d554d,
0xd589aceb3b65f36b, 0x91f8758ab30951a,
0x10d2bebadd90c381, 0xb3a6345b6273b101,
0xd05dbd603684e153, 0xabaaa983f818f5db,
0x2a063ed10d464bf2, 0x1d395c4c511e9073,
0x43011ca87ead4d7c, 0x22acb2bfbca6a069,
0xdd6b8dd2abb4d8f, 0xb3bc3889e7142461,
0x62cbac703609d15, 0x74aec28d9fdd44bf];
for i in 0..16 {
assert_eq!(rng.next_u64(), vector[i]);
}
Expand Down

0 comments on commit b71223d

Please sign in to comment.