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

ChaCha: fix behavior on block count wrap #980

Merged
merged 1 commit into from
May 22, 2020

Conversation

kazcw
Copy link
Contributor

@kazcw kazcw commented May 21, 2020

Documented behavior is to allow the counter to wrap around, but
implementation was panicking on that event in debug-mode builds.

Also fix get_word_pos handling of counter-wrapping, add some tests,
and make math easier to read.

Documented behavior is to allow the counter to wrap around, but
implementation was panicking on that event in debug-mode builds.

Also fix `get_word_pos` handling of counter-wrapping, add some tests,
and make math easier to read.
Comment on lines -190 to +207
let mut block = u128::from(self.rng.core.state.get_stream_param(STREAM_PARAM_BLOCK));
// counter is incremented *after* filling buffer
block -= 4;
(block << 4) + self.rng.index() as u128
let buf_start_block = {
let buf_end_block = self.rng.core.state.get_stream_param(STREAM_PARAM_BLOCK);
u64::wrapping_sub(buf_end_block, BUF_BLOCKS.into())
};
let (buf_offset_blocks, block_offset_words) = {
let buf_offset_words = self.rng.index() as u64;
let blocks_part = buf_offset_words / u64::from(BLOCK_WORDS);
let words_part = buf_offset_words % u64::from(BLOCK_WORDS);
(blocks_part, words_part)
};
let pos_block = u64::wrapping_add(buf_start_block, buf_offset_blocks);
let pos_block_words = u128::from(pos_block) * u128::from(BLOCK_WORDS);
pos_block_words + u128::from(block_offset_words)
Copy link
Member

Choose a reason for hiding this comment

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

Yes, so I missed that the block size is still 16 words when we're dealing with four blocks at once. But you call this easier to read? I see no advantage in splitting the buffer offset into block and word parts, or using inner code blocks here.

In general easy to comprehend implies both sufficient detail and concise.

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 see no advantage in splitting the buffer offset into block and word parts,

There are two ways to fix this function's behavior in the counter-wrapping case: use wrapping 64-bit arithmetic for the high bits, or masked 128-bit arithmetic. I could change it to the other way if you prefer.

Copy link
Member

Choose a reason for hiding this comment

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

If I understand correctly, buf_start_block + buf_offset_blocks cannot wrap since the former should be a multiple of 4 and the latter less than 4.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The buffer is a 4-block window. It is always at a block-aligned position in the stream but if the stream has been seeked it may not be self-aligned. The new tests fail without changing this.

Comment on lines +22 to +25
// NB. this must remain consistent with some currently hard-coded numbers in this module
const BUF_BLOCKS: u8 = 4;
// number of 32-bit words per ChaCha block (fixed by algorithm definition)
const BLOCK_WORDS: u8 = 16;
Copy link
Member

Choose a reason for hiding this comment

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

These are used as u64 / u128 and should be inlined anyway, so use of u8 here just adds noise.

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 was thinking this module might be further improved in the future to use values based on the named constants rather than hard-coded numbers for its usize values. u8 is the only type that can be converted to both u64 and usize with the total functions.

Copy link
Member

@dhardy dhardy left a comment

Choose a reason for hiding this comment

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

Fair enough. Okay then, thanks for this!

@dhardy dhardy merged commit 22cc8fe into rust-random:master May 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants