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

chacha20: returning rand_core feature #333

Merged
merged 96 commits into from
Apr 29, 2024
Merged
Changes from 1 commit
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
b1fa885
added rand_core feature back
nstilt1 Oct 25, 2023
c5226a9
Delete .vscode directory
nstilt1 Oct 25, 2023
04aabff
fix suggestion for u128 stream_id
nstilt1 Oct 25, 2023
ec262fd
Merge branch 'master' of https://github.com/nstilt1/stream-ciphers-rng
nstilt1 Oct 25, 2023
8a1755f
Update rng.rs
nstilt1 Oct 25, 2023
2117c30
Update rng.rs
nstilt1 Oct 25, 2023
f5b9a4d
remove copied data in generate()
nstilt1 Oct 25, 2023
53a51a7
Merge branch 'master' of https://github.com/nstilt1/stream-ciphers-rng
nstilt1 Oct 25, 2023
425c159
cargo fmt
nstilt1 Oct 25, 2023
a241489
impl ZeroizeOnDrop for BlockRngResults
nstilt1 Oct 25, 2023
6af37f1
removed unnecessary impls and added u128 input for get_stream()
nstilt1 Oct 25, 2023
56462ef
revised set_stream() comment
nstilt1 Oct 25, 2023
c52c607
fix set/get_word_pos() discrepancies
nstilt1 Oct 25, 2023
aac6b9e
add chacha20rng bench code
nstilt1 Oct 26, 2023
0357ad6
aarch64 bench compatibility
Oct 26, 2023
71a1a5b
fix benches for avx2
nstilt1 Oct 26, 2023
9d992e1
adjusted aarch64 bench and added results
Oct 26, 2023
f32ee71
comment for unsafe AsRef/AsMut
nstilt1 Oct 26, 2023
63fcd30
added comment for unsafe AsRef/AsMut
nstilt1 Oct 26, 2023
e765489
fmt :/
nstilt1 Oct 26, 2023
6fb4d82
Delete .vscode directory
nstilt1 Oct 26, 2023
d1907c5
revert an unnecessary change to lib.rs
nstilt1 Oct 26, 2023
694c592
using rand_core v0.7.0 for testing
nstilt1 Oct 27, 2023
a3c3189
replace struct BlockRngResults with union
nstilt1 Oct 27, 2023
bf3f700
passing clone test; still have to update the test vectors
nstilt1 Oct 27, 2023
fd65576
fmt
nstilt1 Oct 27, 2023
4bd6e5a
all tests passing
nstilt1 Oct 27, 2023
2dbb429
safety switch
nstilt1 Oct 27, 2023
b227065
fmt
nstilt1 Oct 27, 2023
5713e7e
remove rand_core-0.7-dependent test; remove unnecessary comments; ren…
nstilt1 Oct 28, 2023
de69a46
replace KeyIvInit and considering references instead of owned inputs ?
nstilt1 Nov 3, 2023
c77dcc2
fix unused mut variable warning when zeroize isn't enabled
nstilt1 Nov 3, 2023
842d0de
if set_word_pos_bytes is desirable, pick your poison between this com…
nstilt1 Nov 3, 2023
21b0862
fix an error with set_word_pos_bytes() and reverted the pick your poi…
nstilt1 Nov 3, 2023
3b6f4cb
added Seed wrapper, moved impl of ChaChaCore to rng.rs, corrected a c…
nstilt1 Nov 3, 2023
af09157
exporting Seed for rand_core
nstilt1 Nov 3, 2023
9d46dd6
Seed's .into() seems to work without exporting it :/
nstilt1 Nov 3, 2023
fb489ef
fix benches; add example for ChaCha20Rng
nstilt1 Nov 3, 2023
03bf69a
using Generic inputs to convert to zeroizable inputs, as well as elim…
nstilt1 Nov 3, 2023
a3a2350
allow for [u8; 12] stream_id, and set_stream() is now slightly optimi…
nstilt1 Nov 4, 2023
5472286
micro-optimized set_word_pos() for [u8; 5]
nstilt1 Nov 5, 2023
72c9e0b
ensure zeroization of a u64 :/
nstilt1 Nov 5, 2023
5997225
fix ZeroizeOnDrop impl
nstilt1 Nov 5, 2023
ef30ccc
added zeroize tests; tests failed :(; tried a non-copyable seed wrapp…
nstilt1 Nov 6, 2023
ea32536
replaced some wrappers with a macro, ensured zeroization of some inpu…
nstilt1 Nov 7, 2023
c10c4b6
end of zeroizing? also adjusted WordPosInput to line up with comment
nstilt1 Nov 7, 2023
26668af
fmt
nstilt1 Nov 7, 2023
ac09d24
no more unused mut input errors
nstilt1 Nov 7, 2023
13aa494
removing AlteredState for now; updated some documentation for clarity
nstilt1 Nov 11, 2023
2d71ada
updated docs for clarity*
nstilt1 Nov 11, 2023
b013266
minor correction: WordPosInput doesn't force the bytes to be in littl…
nstilt1 Nov 11, 2023
7833e11
gitignore .DS_Store and remove impl_zeroize_from
nstilt1 Nov 12, 2023
a687937
Delete .DS_Store
nstilt1 Nov 12, 2023
73088f6
remove some minor zeroizings
nstilt1 Nov 12, 2023
bdb43c0
remove minor zeroizing
nstilt1 Nov 12, 2023
255b481
Merge https://github.com/nstilt1/stream-ciphers-rng into HEAD
nstilt1 Nov 12, 2023
a691b4a
.DS_Store, you hath been banishth
nstilt1 Nov 13, 2023
bf7c307
replace BlockRng and BlockRngCore impl to allow for Results buffer to…
nstilt1 Nov 13, 2023
5f245d5
rename 'rng' member to 'core' to more accurately reflect its purpose
nstilt1 Nov 13, 2023
65e42e8
added benches readme with results
nstilt1 Nov 13, 2023
e8c2df0
removed remnant ZeroizeOnDrop impl that didn't do anything
nstilt1 Nov 13, 2023
ac51b24
edit benches README
nstilt1 Nov 13, 2023
cec3726
ensuring consistency with the cipher block_pos and the rng set/get_wo…
nstilt1 Nov 19, 2023
5603c3c
aligned and tested set_word_pos. removed the index checks in the test…
nstilt1 Nov 19, 2023
11ebab3
removed a check that only worked for the 'default' alignment
nstilt1 Nov 19, 2023
141d54c
baby steps
nstilt1 Nov 25, 2023
d8f9732
lib.rs attempt at fixing generate(); not compiling yet
nstilt1 Nov 25, 2023
7695fb6
update TODO
nstilt1 Nov 25, 2023
0c0e338
rng progress, still working on the ciphers
nstilt1 Nov 26, 2023
14ee01e
working on ChaChaCore::new(); had issues with avx2_cpuid/sse2_cpuid w…
nstilt1 Nov 27, 2023
5e15c4a
rng passes tests; 1.04 cpb for soft; 1.07 cpb for avx2? will try some…
nstilt1 Nov 28, 2023
5d6d0ad
was benching wrong Rng lol... CPB: 0.99 for avx2, 5.16 for soft, 2.89…
nstilt1 Nov 28, 2023
a0c19e8
speedrun of implementing/copy-pasta; neon needs to be checked
nstilt1 Dec 20, 2023
32c7662
fixed neon
nstilt1 Dec 20, 2023
5df80ed
fmt
nstilt1 Dec 20, 2023
e95e3ca
corrected some rustdocs in rng.rs; also trying to pass checks
nstilt1 Dec 20, 2023
8d30f5c
fix checks
nstilt1 Dec 20, 2023
d2d980b
add missing zeroize cfg in rustdocs; still working on Rudra
nstilt1 Dec 22, 2023
8465a4d
generate() is now in rng.rs; added rng feature because rng.rs tests w…
nstilt1 Dec 24, 2023
45a78d3
fixed cargo bench --no-run
nstilt1 Dec 24, 2023
30386f4
fix cargo bench --no-run
nstilt1 Dec 24, 2023
06ff9a8
updated neon and gitignore
nstilt1 Jan 2, 2024
ed4ac1c
update neon and gitignore; not sure why it made me pull
nstilt1 Jan 2, 2024
f501a4f
rebasing #338
nstilt1 Jan 7, 2024
758a0b7
rebasing #339; also added public get/set_block_pos; added From<[u32; …
nstilt1 Jan 17, 2024
9d3d870
Merge branch 'master' into rebase2-electric-boogaloo
nstilt1 Jan 17, 2024
303714a
fmt and fixing loose ends
nstilt1 Jan 17, 2024
0295f7c
cleanup /benches/; also, .cargo/config has stopped working on my end
nstilt1 Jan 17, 2024
a8cd5c3
fixed benches; tried to make set_word_pos more coherent by changing t…
nstilt1 Jan 18, 2024
14e45bc
fmt
nstilt1 Jan 18, 2024
0f494ff
used a wrapper for the so that core methods from cipher are not visi…
nstilt1 Jan 18, 2024
70a9f2d
Merge branch 'master' into rebase2-electric-boogaloo
nstilt1 Mar 13, 2024
86fd8ed
removed getrandom dependency, removed .cargo folders that were for te…
nstilt1 Mar 13, 2024
bee5798
Update .gitignore
nstilt1 Mar 13, 2024
304f2bb
updated rand_core to alpha; impl'd BlockRngCore; moved get/set_word_p…
nstilt1 Apr 6, 2024
1d15d68
impl CryptoBlockRng and ZeroizeOnDrop for Rng and RngCore
nstilt1 Apr 11, 2024
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
Prev Previous commit
Next Next commit
rebasing #339; also added public get/set_block_pos; added From<[u32; …
…3]> for StreamId and From<[u8; 4]> for BlockPos
nstilt1 committed Jan 17, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 758a0b71dcfa0bd0a38dc7a493927432b212b7aa
20 changes: 10 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions chacha20/Cargo.toml
Original file line number Diff line number Diff line change
@@ -20,15 +20,15 @@ categories = ["cryptography", "no-std"]

[dependencies]
cfg-if = "1"
cipher = { version = "=0.5.0-pre.1", optional = true}
cipher = { version = "=0.5.0-pre.2", optional = true}
rand_core = { version = "0.6.4", optional = true, default-features = false, features = ["getrandom"] }
serde = { version = "1.0", features = ["derive"], optional = true }
zeroize = { version = "1.6.0", optional = true }
[target.'cfg(any(target_arch = "x86_64", target_arch = "x86"))'.dependencies]
cpufeatures = "0.2"

[dev-dependencies]
cipher = { version = "=0.5.0-pre.1", features = ["dev"] }
cipher = { version = "=0.5.0-pre.2", features = ["dev"] }
hex-literal = "0.4"
rand_chacha = "0.3.1"
serde_json = "1.0" # Only to test serde1
132 changes: 92 additions & 40 deletions chacha20/src/rng.rs
Original file line number Diff line number Diff line change
@@ -80,9 +80,6 @@ impl Debug for Seed {
/// A wrapper for set_word_pos() input that can be assembled from:
/// * `u64`
/// * `[u8; 5]`
///
/// There would be a minor performance benefit from using a `[u8; 5]`, as it
/// avoids some copies and bit operations.
pub struct WordPosInput([u8; 5]);

impl From<[u8; 5]> for WordPosInput {
@@ -102,16 +99,25 @@ impl From<u64> for WordPosInput {
}
}

/// A wrapper for the `stream_id`. It can be used with a `[u8; 12]` or
/// a `u128`.
///
/// There is a minor performance benefit when using a `[u8; 12]` as the input, as
/// it will avoid a copy.
pub struct StreamId([u8; 12]);
/// A wrapper for the `stream_id`. It can be used with a:
/// * `[u32; 3]`
/// * `[u8; 12]` or
/// * a `u128`
pub struct StreamId([u32; 3]);

impl From<[u32; 3]> for StreamId {
fn from(value: [u32; 3]) -> Self {
Self(value)
}
}

impl From<[u8; 12]> for StreamId {
fn from(value: [u8; 12]) -> Self {
StreamId(value)
let mut result = Self([0u32; 3]);
for (n, chunk) in result.0.iter_mut().zip(value.chunks_exact(4)) {
*n = u32::from_le_bytes(chunk.try_into().unwrap())
}
result
}
}

@@ -120,7 +126,24 @@ impl From<u128> for StreamId {
let mut lower_12_bytes: [u8; 12] = [0u8; 12];
let bytes = value.to_le_bytes();
lower_12_bytes.copy_from_slice(&bytes[0..12]);
Self(lower_12_bytes)
lower_12_bytes.into()
}
}

/// A wrapper for `block_pos`. It can be used with:
/// * u32
/// * [u8; 4]
pub struct BlockPos(u32);

impl From<u32> for BlockPos {
fn from(value: u32) -> Self {
Self(value.to_le())
}
}

impl From<[u8; 4]> for BlockPos {
fn from(value: [u8; 4]) -> Self {
Self(u32::from_le_bytes(value))
}
}

@@ -219,15 +242,15 @@ macro_rules! impl_chacha_rng {
/// let mut rng = ChaCha20Rng::from_seed(seed);
/// rng.set_stream(100);
///
/// // you can also use a [u8; 12] in `.set_stream()`, which has a
/// // *minor* performance benefit over a u128
/// // you can also use a [u8; 12] in `.set_stream()`
/// rng.set_stream([3u8; 12]);
/// // or a [u32; 3]
/// rng.set_stream([4u32; 3]);
///
///
/// rng.set_word_pos(5);
///
/// // you can also use a [u8; 5] in `.set_word_pos()`, which has a
/// // *minor* performance benefit over a u64
/// // you can also use a [u8; 5] in `.set_word_pos()`
/// rng.set_word_pos([2u8; 5]);
///
/// let x = rng.next_u32();
@@ -263,6 +286,23 @@ macro_rules! impl_chacha_rng {
/// The ChaCha core random number generator
pub type $ChaChaXCore = ChaChaCore<$rounds, Ietf>;

impl $ChaChaXCore {
/// Sets the block pos. This does not affect the RNG's index, so if it has
/// already changed, it will not reset it.
///
/// This can be used with either:
/// * u32
/// * [u8; 4]
pub fn set_block_pos<B: Into<BlockPos>>(&mut self, pos: B) {
self.state[12] = pos.into().0
}

/// Gets the block pos.
pub fn get_block_pos(&self) -> u32 {
self.state[12]
}
}

impl SeedableRng for $ChaChaXRng {
type Seed = [u8; 32];

@@ -279,11 +319,11 @@ macro_rules! impl_chacha_rng {
impl RngCore for $ChaChaXRng {
#[inline]
fn next_u32(&mut self) -> u32 {
if self.index >= self.buffer.as_ref().len() {
if self.index >= BUFFER_SIZE {
self.generate_and_set(0);
}

let value = self.buffer.as_ref()[self.index];
let value = self.buffer[self.index];
self.index += 1;
value
}
@@ -295,7 +335,7 @@ macro_rules! impl_chacha_rng {
u64::from(data[1]) << 32 | u64::from(data[0])
};

let len = self.buffer.as_ref().len();
let len = BUFFER_SIZE;

let index = self.index;
if index < len - 1 {
@@ -306,9 +346,9 @@ macro_rules! impl_chacha_rng {
self.generate_and_set(2);
read_u64(self.buffer.as_ref(), 0)
} else {
let x = u64::from(self.buffer.as_ref()[len - 1]);
let x = u64::from(self.buffer[len - 1]);
self.generate_and_set(1);
let y = u64::from(self.buffer.as_ref()[0]);
let y = u64::from(self.buffer[0]);
(y << 32) | x
}
}
@@ -317,11 +357,11 @@ macro_rules! impl_chacha_rng {
fn fill_bytes(&mut self, dest: &mut [u8]) {
let mut read_len = 0;
while read_len < dest.len() {
if self.index >= self.buffer.as_ref().len() {
if self.index >= BUFFER_SIZE {
self.generate_and_set(0);
}
let (consumed_u32, filled_u8) = fill_via_u32_chunks(
&self.buffer.as_ref()[self.index..],
&self.buffer[self.index..],
&mut dest[read_len..],
);

@@ -361,7 +401,7 @@ macro_rules! impl_chacha_rng {
// Copied from rand_core
#[inline]
pub fn generate_and_set(&mut self, index: usize) {
assert!(index < self.buffer.as_ref().len());
assert!(index < BUFFER_SIZE);
self.core.generate(&mut self.buffer);
self.index = index;
}
@@ -376,12 +416,10 @@ macro_rules! impl_chacha_rng {
/// byte-offset.
#[inline]
pub fn get_word_pos(&self) -> u64 {
// block_pos is a multiple of 4, and offset by 4; therefore, it already has the
// last 2 bits set to 0, allowing us to shift it left 4 and add the index
let mut result =
u64::from(self.core.state[12].wrapping_sub(BUF_BLOCKS.into())) << 4;
result += self.index as u64;
// eliminate the 36th bit
// eliminate bits above the 36th bit
result & 0xfffffffff
}

@@ -390,19 +428,13 @@ macro_rules! impl_chacha_rng {
/// * u64
/// * [u8; 5]
///
/// There would be a *minor* performance benefit from using a `[u8; 5]` instead
/// of a `u64`, as it avoids some copies and extra zeroizing.
///
/// As with `get_word_pos`, we use a 36-bit number. Since the generator
/// simply cycles at the end of its period (256 GiB), we ignore the upper 28
/// bits of a `u64`. When given a `[u8; 5]`, we ignore the first 4 bits of the
/// last byte.
#[inline]
pub fn set_word_pos<W: Into<WordPosInput>>(&mut self, word_offset: W) {
let word_offset: WordPosInput = word_offset.into();
// when not using `set_word_pos`, the block_pos is always a multiple of 4.
// This change follows those conventions, as well as maintaining the 6-bit
// index
self.core.state[12] = (u32::from_le_bytes(word_offset.0[0..4].try_into().unwrap()));
// generate will increase block_pos by 4
self.generate_and_set((word_offset.0[4] & 0x0F) as usize);
@@ -413,22 +445,19 @@ macro_rules! impl_chacha_rng {
/// * [u8; 12]
/// * u128
///
/// There is a *minor* performance benefit when using a `[u8; 12]` as the
/// input, although it may be negligible.
///
/// This is initialized to zero; 2<sup>96</sup> unique streams of output
/// are available per seed/key.
#[inline]
pub fn set_stream<S: Into<StreamId>>(&mut self, stream: S) {
let stream: StreamId = stream.into();
for (n, chunk) in self.core.state[Ietf::NONCE_INDEX..BLOCK_WORDS as usize]
for (n, val) in self.core.state[Ietf::NONCE_INDEX..BLOCK_WORDS as usize]
.as_mut()
.iter_mut()
.zip(stream.0.chunks_exact(4))
.zip(stream.0.iter())
{
*n = u32::from_le_bytes(chunk.try_into().unwrap());
*n = *val;
}
if self.index != 64 {
if self.index != BUFFER_SIZE {
self.generate_and_set(self.index);
}
}
@@ -627,6 +656,9 @@ pub(crate) mod tests {
assert_eq!(rng.get_seed(), seed);
assert_eq!(rng.get_stream(), stream);
assert_eq!(rng.get_word_pos(), word_pos);

rng.core.set_block_pos(58392);
assert_eq!(rng.core.get_block_pos(), 58392);
}

#[cfg(feature = "serde1")]
@@ -778,14 +810,34 @@ pub(crate) mod tests {
assert_eq!(rng1.get_word_pos(), expected_end);

// Test block 2 by using `set_word_pos`
let mut rng2 = ChaChaRng::from_seed(seed.into());
let mut rng2 = ChaChaRng::from_seed(seed);
rng2.set_word_pos(2 * 16);
for i in results.iter_mut() {
*i = rng2.next_u32();
}
assert_eq!(results, expected);
assert_eq!(rng2.get_word_pos(), expected_end);

// Test block 2 by using `set_block_pos` and u32
let mut rng3 = ChaChaRng::from_seed(seed);
rng3.core.set_block_pos(2);
results = [0u32; 16];
for i in results.iter_mut() {
*i = rng3.next_u32();
}
assert_eq!(results, expected);
assert_eq!(rng3.get_word_pos(), expected_end);

// Test block 2 by using `set_block_pos` and [u8; 4]
let mut rng4 = ChaChaRng::from_seed(seed);
rng4.core.set_block_pos([2, 0, 0, 0]);
results = [0u32; 16];
for i in results.iter_mut() {
*i = rng4.next_u32();
}
assert_eq!(results, expected);
assert_eq!(rng4.get_word_pos(), expected_end);

// Test skipping behaviour with other types
let mut buf = [0u8; 32];
rng2.fill_bytes(&mut buf[..]);
4 changes: 2 additions & 2 deletions chacha20/src/xchacha.rs
Original file line number Diff line number Diff line change
@@ -197,8 +197,8 @@ mod hchacha20_tests {
);

let actual = hchacha::<R20>(
Array::ref_from_slice(&KEY),
Array::ref_from_slice(&INPUT),
Array::from_slice(&KEY),
Array::from_slice(&INPUT),
);
assert_eq!(actual.as_slice(), &OUTPUT);
}
4 changes: 2 additions & 2 deletions hc-256/Cargo.toml
Original file line number Diff line number Diff line change
@@ -13,10 +13,10 @@ keywords = ["crypto", "stream-cipher", "trait"]
categories = ["cryptography", "no-std"]

[dependencies]
cipher = "=0.5.0-pre.1"
cipher = "=0.5.0-pre.2"

[dev-dependencies]
cipher = { version = "=0.5.0-pre.1", features = ["dev"] }
cipher = { version = "=0.5.0-pre.2", features = ["dev"] }
hex-literal = "0.4"

[features]
4 changes: 2 additions & 2 deletions rabbit/Cargo.toml
Original file line number Diff line number Diff line change
@@ -13,10 +13,10 @@ keywords = ["crypto", "rabbit", "stream-cipher", "trait"]
categories = ["cryptography", "no-std"]

[dependencies]
cipher = "=0.5.0-pre.1"
cipher = "=0.5.0-pre.2"

[dev-dependencies]
cipher = { version = "=0.5.0-pre.1", features = ["dev"] }
cipher = { version = "=0.5.0-pre.2", features = ["dev"] }
hex-literal = "0.4"

[features]
Loading