Skip to content

Remove CryptoGenerator and reduce BlockRng to BlockBuffer - #68

Closed
dhardy wants to merge 7 commits into
masterfrom
push-ytsyzvnpyymq
Closed

Remove CryptoGenerator and reduce BlockRng to BlockBuffer#68
dhardy wants to merge 7 commits into
masterfrom
push-ytsyzvnpyymq

Conversation

@dhardy

Copy link
Copy Markdown
Member
  • Added a CHANGELOG.md entry

Motivation

rust-random/rand#1722 makes this useless.

Other

Any suggestions for a new name for trait Generator? As-is it matches its most important generate method, so the name doesn't seem too bad.

@dhardy
dhardy requested a review from newpavlovJanuary 28, 2026 15:56
@newpavlov

newpavlov commented Jan 28, 2026

Copy link
Copy Markdown
Member

Any suggestions for a new name for trait Generator?

BlockRng would be the most consistent name with BlockRng::generate_block (or next_block) method. Instead of the wrapper I would prefer to have a separate BlockBuffer struct.

@dhardy

Copy link
Copy Markdown
MemberAuthor

The names are consistent.

What is the motivation for making BlockBuffer separate? It makes little sense to me (without removing the trait as in the more recent #24 design).

@newpavlov

newpavlov commented Jan 28, 2026

Copy link
Copy Markdown
Member

Separation of concerns. IMO struct Rng { core: RngCore, buffer: BlockBuffer<..> } is more transparent than struct Rng(BlockRng(RngCore));. And zeroization support would look less confusing. It's easy to understand what happens in:

self.core.zeroize();self.buffer = Default::default();
zeroize::optimization_barrier(&self.buffer)

While the wrapper would result in a less straightforward code.

The same applies to serialization as well.

@dhardy

Copy link
Copy Markdown
MemberAuthor

Separation of concerns

If they were truly separate components I'd agree, but the only pub methods not needing both parameters are word_offset and remaining_results.

I see you succeeded in convincing @tarcieri to make optimization_barrier public in RustCrypto/utils#1261, though it's not in a released version yet.

@dhardy

Copy link
Copy Markdown
MemberAuthor

@newpavlov I made significant additions to this PR; please re-review.

@dhardydhardy changed the title Remove CryptoGeneratorRemove CryptoGenerator and reduce BlockRng to BlockBufferJan 28, 2026
Comment threadsrc/block.rs
impl<W: Word + Default, const N: usize, G: Generator<Output = [W; N]>> BlockRng<G> {
/// Create a new `BlockRng` from an existing RNG implementing
/// `Generator`. Results will be generated on first use.
impl<W: Word + Default, const N: usize, G: BlockRng<Output = [W; N]>> Default for BlockBuffer<G> {

@newpavlovnewpavlovJan 28, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Word is already bounded by Default via the Sealed trait.

And I think we can simplify the bound to just G::Output: Default, no? UPD: No, we use Word functionality in the implementation.

Comment threadsrc/block.rs
///
/// Returns `None` if `remaining_results` is too long.
pub fn reconstruct(core: G, remaining_results: &[W]) -> Option<Self> {
pub fn reconstruct(remaining_results: &[W]) -> Option<Self> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this method used in practice? I think we had a discussion about this and came to conclusion that it's better to use serialization/deserialization over [W; N] instead of &[W].

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, it is used: https://github.com/rust-random/rngs/blob/master/rand_isaac/src/isaac.rs#L171

And no, that is the conclusion that you came to. My conclusion was that where fixed-size serialization is preferred it is still possible with this approach (since N is known), while the reverse is not with your approach (and variable length serialization is preferable if the output format happens to be something like JSON).

@newpavlovnewpavlovJan 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sure, whatever...

But at least add methods for fixed-sized (de)serialization. It would mean that your struct has two ways of handling serialization, but so be it.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The existing API is already usable for fixed-size serialization though (with slightly more code elsewhere, but storing the length is not exactly hard).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Are you seriously suggesting that users should manually implement the fixed-size serialization based on the variable sized methods???

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes. And why not? It's possible. It's not that much extra code, and probably won't be used in that many cases anyway. It's not even particularly inefficient, if that even matters for serialisation.

@newpavlovnewpavlovJan 30, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ok... Feel free to do with this module whatever you want. I will not be reviewing/approving PRs which deal with block stuff anymore.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I am confused. But as you wish.

Comment threadsrc/block.rs
Comment threadCHANGELOG.md
- `BlockRng::reset` method ([#44])
- `BlockRng::index` method (replaced with `BlockRng::word_offset`) ([#44])
- `Generator::Item` associated type ([#26])
- `CryptoBlockRng` ([#68])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Update changelog.

Comment threadsrc/block.rs
#[derive(Clone)]
pub struct BlockRng<G: Generator> {
#[allow(missing_debug_implementations)]
pub struct BlockBuffer<G: BlockRng> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Use R instead of G like in all other bounds?

Comment threadsrc/block.rs
@@ -98,32 +89,12 @@ pub trait Generator {
///
/// This must fill `output` with random data.
fn generate(&mut self, output: &mut Self::Output);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe rename the method to next_block for consistency with the Rng methods?

Comment threadsrc/block.rs
Comment threadsrc/block.rs
///
/// This type encompasses a [`Generator`] [`core`](Self::core) and a buffer.
/// This type does not encapuslate a [`BlockRng`], but is designed to be used
/// alongside one.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It would be nice to explicitly document that BlockBuffer::default() initializes all bits of the state to make it friendlier to the optimization_barrier-based zeroization.

@dhardy

Copy link
Copy Markdown
MemberAuthor

Regarding the renaming, the largest problem is actually that we use 'core' to refer to the BlockRng (e.g. in the doc example and as a parameter to methods like next_word). Why 'core'? This is the core (random) generator.

So, BlockRng? The old struct BlockRng referred to a block-based random-number generator. So the name was fine.

BlockBuffer is okay but ultimately a poor name; it buffers results not blocks. ResultsBuffer or just Buffer might work.

The new trait BlockRng is actually a bad name: implementations are (random) (data) block generators, not number generators (no one needs 512-bit numbers).

The old name block::Generator is about as close to "random block generator" as one can get without an unwieldy name I think (unless we want to call it Rbg).


Since the main argument for separation of the core and the buffer seems to be zeroization and alternatives need specific documentation, why don't we just add a method like fn clear?


To avoid complicating history of a single PR too much I will close this one and replace it.

@dhardydhardy closed this Jan 29, 2026
@newpavlov
newpavlov deleted the push-ytsyzvnpyymq branch January 29, 2026 18:17
Sign up for freeto 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

@dhardy@newpavlov
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Remove CryptoGenerator and reduce BlockRng to BlockBuffer by dhardy · Pull Request #68 · rust-random/rand_core · GitHub
Skip to content

Remove CryptoGenerator and reduce BlockRng to BlockBuffer - #68

Closed
dhardy wants to merge 7 commits into
masterfrom
push-ytsyzvnpyymq
Closed

Remove CryptoGenerator and reduce BlockRng to BlockBuffer#68
dhardy wants to merge 7 commits into
masterfrom
push-ytsyzvnpyymq

Conversation

@dhardy

Copy link
Copy Markdown
Member
  • Added a CHANGELOG.md entry

Motivation

rust-random/rand#1722 makes this useless.

Other

Any suggestions for a new name for trait Generator? As-is it matches its most important generate method, so the name doesn't seem too bad.

@dhardy
dhardy requested a review from newpavlovJanuary 28, 2026 15:56
@newpavlov

newpavlov commented Jan 28, 2026

Copy link
Copy Markdown
Member

Any suggestions for a new name for trait Generator?

BlockRng would be the most consistent name with BlockRng::generate_block (or next_block) method. Instead of the wrapper I would prefer to have a separate BlockBuffer struct.

@dhardy

Copy link
Copy Markdown
MemberAuthor

The names are consistent.

What is the motivation for making BlockBuffer separate? It makes little sense to me (without removing the trait as in the more recent #24 design).

@newpavlov

newpavlov commented Jan 28, 2026

Copy link
Copy Markdown
Member

Separation of concerns. IMO struct Rng { core: RngCore, buffer: BlockBuffer<..> } is more transparent than struct Rng(BlockRng(RngCore));. And zeroization support would look less confusing. It's easy to understand what happens in:

self.core.zeroize();self.buffer = Default::default();
zeroize::optimization_barrier(&self.buffer)

While the wrapper would result in a less straightforward code.

The same applies to serialization as well.

@dhardy

Copy link
Copy Markdown
MemberAuthor

Separation of concerns

If they were truly separate components I'd agree, but the only pub methods not needing both parameters are word_offset and remaining_results.

I see you succeeded in convincing @tarcieri to make optimization_barrier public in RustCrypto/utils#1261, though it's not in a released version yet.

@dhardy

Copy link
Copy Markdown
MemberAuthor

@newpavlov I made significant additions to this PR; please re-review.

@dhardydhardy changed the title Remove CryptoGeneratorRemove CryptoGenerator and reduce BlockRng to BlockBufferJan 28, 2026
Comment threadsrc/block.rs
impl<W: Word + Default, const N: usize, G: Generator<Output = [W; N]>> BlockRng<G> {
/// Create a new `BlockRng` from an existing RNG implementing
/// `Generator`. Results will be generated on first use.
impl<W: Word + Default, const N: usize, G: BlockRng<Output = [W; N]>> Default for BlockBuffer<G> {

@newpavlovnewpavlovJan 28, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Word is already bounded by Default via the Sealed trait.

And I think we can simplify the bound to just G::Output: Default, no? UPD: No, we use Word functionality in the implementation.

Comment threadsrc/block.rs
///
/// Returns `None` if `remaining_results` is too long.
pub fn reconstruct(core: G, remaining_results: &[W]) -> Option<Self> {
pub fn reconstruct(remaining_results: &[W]) -> Option<Self> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this method used in practice? I think we had a discussion about this and came to conclusion that it's better to use serialization/deserialization over [W; N] instead of &[W].

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, it is used: https://github.com/rust-random/rngs/blob/master/rand_isaac/src/isaac.rs#L171

And no, that is the conclusion that you came to. My conclusion was that where fixed-size serialization is preferred it is still possible with this approach (since N is known), while the reverse is not with your approach (and variable length serialization is preferable if the output format happens to be something like JSON).

@newpavlovnewpavlovJan 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sure, whatever...

But at least add methods for fixed-sized (de)serialization. It would mean that your struct has two ways of handling serialization, but so be it.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The existing API is already usable for fixed-size serialization though (with slightly more code elsewhere, but storing the length is not exactly hard).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Are you seriously suggesting that users should manually implement the fixed-size serialization based on the variable sized methods???

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes. And why not? It's possible. It's not that much extra code, and probably won't be used in that many cases anyway. It's not even particularly inefficient, if that even matters for serialisation.

@newpavlovnewpavlovJan 30, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ok... Feel free to do with this module whatever you want. I will not be reviewing/approving PRs which deal with block stuff anymore.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I am confused. But as you wish.

Comment threadsrc/block.rs
Comment threadCHANGELOG.md
- `BlockRng::reset` method ([#44])
- `BlockRng::index` method (replaced with `BlockRng::word_offset`) ([#44])
- `Generator::Item` associated type ([#26])
- `CryptoBlockRng` ([#68])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Update changelog.

Comment threadsrc/block.rs
#[derive(Clone)]
pub struct BlockRng<G: Generator> {
#[allow(missing_debug_implementations)]
pub struct BlockBuffer<G: BlockRng> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Use R instead of G like in all other bounds?

Comment threadsrc/block.rs
@@ -98,32 +89,12 @@ pub trait Generator {
///
/// This must fill `output` with random data.
fn generate(&mut self, output: &mut Self::Output);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe rename the method to next_block for consistency with the Rng methods?

Comment threadsrc/block.rs
Comment threadsrc/block.rs
///
/// This type encompasses a [`Generator`] [`core`](Self::core) and a buffer.
/// This type does not encapuslate a [`BlockRng`], but is designed to be used
/// alongside one.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It would be nice to explicitly document that BlockBuffer::default() initializes all bits of the state to make it friendlier to the optimization_barrier-based zeroization.

@dhardy

Copy link
Copy Markdown
MemberAuthor

Regarding the renaming, the largest problem is actually that we use 'core' to refer to the BlockRng (e.g. in the doc example and as a parameter to methods like next_word). Why 'core'? This is the core (random) generator.

So, BlockRng? The old struct BlockRng referred to a block-based random-number generator. So the name was fine.

BlockBuffer is okay but ultimately a poor name; it buffers results not blocks. ResultsBuffer or just Buffer might work.

The new trait BlockRng is actually a bad name: implementations are (random) (data) block generators, not number generators (no one needs 512-bit numbers).

The old name block::Generator is about as close to "random block generator" as one can get without an unwieldy name I think (unless we want to call it Rbg).


Since the main argument for separation of the core and the buffer seems to be zeroization and alternatives need specific documentation, why don't we just add a method like fn clear?


To avoid complicating history of a single PR too much I will close this one and replace it.

@dhardydhardy closed this Jan 29, 2026
@newpavlov
newpavlov deleted the push-ytsyzvnpyymq branch January 29, 2026 18:17
Sign up for freeto 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

@dhardy@newpavlov
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Remove CryptoGenerator and reduce BlockRng to BlockBuffer by dhardy · Pull Request #68 · rust-random/rand_core · GitHub
Skip to content

Remove CryptoGenerator and reduce BlockRng to BlockBuffer - #68

Closed
dhardy wants to merge 7 commits into
masterfrom
push-ytsyzvnpyymq
Closed

Remove CryptoGenerator and reduce BlockRng to BlockBuffer#68
dhardy wants to merge 7 commits into
masterfrom
push-ytsyzvnpyymq

Conversation

@dhardy

Copy link
Copy Markdown
Member
  • Added a CHANGELOG.md entry

Motivation

rust-random/rand#1722 makes this useless.

Other

Any suggestions for a new name for trait Generator? As-is it matches its most important generate method, so the name doesn't seem too bad.

@dhardy
dhardy requested a review from newpavlovJanuary 28, 2026 15:56
@newpavlov

newpavlov commented Jan 28, 2026

Copy link
Copy Markdown
Member

Any suggestions for a new name for trait Generator?

BlockRng would be the most consistent name with BlockRng::generate_block (or next_block) method. Instead of the wrapper I would prefer to have a separate BlockBuffer struct.

@dhardy

Copy link
Copy Markdown
MemberAuthor

The names are consistent.

What is the motivation for making BlockBuffer separate? It makes little sense to me (without removing the trait as in the more recent #24 design).

@newpavlov

newpavlov commented Jan 28, 2026

Copy link
Copy Markdown
Member

Separation of concerns. IMO struct Rng { core: RngCore, buffer: BlockBuffer<..> } is more transparent than struct Rng(BlockRng(RngCore));. And zeroization support would look less confusing. It's easy to understand what happens in:

self.core.zeroize();self.buffer = Default::default();
zeroize::optimization_barrier(&self.buffer)

While the wrapper would result in a less straightforward code.

The same applies to serialization as well.

@dhardy

Copy link
Copy Markdown
MemberAuthor

Separation of concerns

If they were truly separate components I'd agree, but the only pub methods not needing both parameters are word_offset and remaining_results.

I see you succeeded in convincing @tarcieri to make optimization_barrier public in RustCrypto/utils#1261, though it's not in a released version yet.

@dhardy

Copy link
Copy Markdown
MemberAuthor

@newpavlov I made significant additions to this PR; please re-review.

@dhardydhardy changed the title Remove CryptoGeneratorRemove CryptoGenerator and reduce BlockRng to BlockBufferJan 28, 2026
Comment threadsrc/block.rs
impl<W: Word + Default, const N: usize, G: Generator<Output = [W; N]>> BlockRng<G> {
/// Create a new `BlockRng` from an existing RNG implementing
/// `Generator`. Results will be generated on first use.
impl<W: Word + Default, const N: usize, G: BlockRng<Output = [W; N]>> Default for BlockBuffer<G> {

@newpavlovnewpavlovJan 28, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Word is already bounded by Default via the Sealed trait.

And I think we can simplify the bound to just G::Output: Default, no? UPD: No, we use Word functionality in the implementation.

Comment threadsrc/block.rs
///
/// Returns `None` if `remaining_results` is too long.
pub fn reconstruct(core: G, remaining_results: &[W]) -> Option<Self> {
pub fn reconstruct(remaining_results: &[W]) -> Option<Self> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this method used in practice? I think we had a discussion about this and came to conclusion that it's better to use serialization/deserialization over [W; N] instead of &[W].

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, it is used: https://github.com/rust-random/rngs/blob/master/rand_isaac/src/isaac.rs#L171

And no, that is the conclusion that you came to. My conclusion was that where fixed-size serialization is preferred it is still possible with this approach (since N is known), while the reverse is not with your approach (and variable length serialization is preferable if the output format happens to be something like JSON).

@newpavlovnewpavlovJan 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sure, whatever...

But at least add methods for fixed-sized (de)serialization. It would mean that your struct has two ways of handling serialization, but so be it.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The existing API is already usable for fixed-size serialization though (with slightly more code elsewhere, but storing the length is not exactly hard).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Are you seriously suggesting that users should manually implement the fixed-size serialization based on the variable sized methods???

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes. And why not? It's possible. It's not that much extra code, and probably won't be used in that many cases anyway. It's not even particularly inefficient, if that even matters for serialisation.

@newpavlovnewpavlovJan 30, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ok... Feel free to do with this module whatever you want. I will not be reviewing/approving PRs which deal with block stuff anymore.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I am confused. But as you wish.

Comment threadsrc/block.rs
Comment threadCHANGELOG.md
- `BlockRng::reset` method ([#44])
- `BlockRng::index` method (replaced with `BlockRng::word_offset`) ([#44])
- `Generator::Item` associated type ([#26])
- `CryptoBlockRng` ([#68])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Update changelog.

Comment threadsrc/block.rs
#[derive(Clone)]
pub struct BlockRng<G: Generator> {
#[allow(missing_debug_implementations)]
pub struct BlockBuffer<G: BlockRng> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Use R instead of G like in all other bounds?

Comment threadsrc/block.rs
@@ -98,32 +89,12 @@ pub trait Generator {
///
/// This must fill `output` with random data.
fn generate(&mut self, output: &mut Self::Output);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe rename the method to next_block for consistency with the Rng methods?

Comment threadsrc/block.rs
Comment threadsrc/block.rs
///
/// This type encompasses a [`Generator`] [`core`](Self::core) and a buffer.
/// This type does not encapuslate a [`BlockRng`], but is designed to be used
/// alongside one.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It would be nice to explicitly document that BlockBuffer::default() initializes all bits of the state to make it friendlier to the optimization_barrier-based zeroization.

@dhardy

Copy link
Copy Markdown
MemberAuthor

Regarding the renaming, the largest problem is actually that we use 'core' to refer to the BlockRng (e.g. in the doc example and as a parameter to methods like next_word). Why 'core'? This is the core (random) generator.

So, BlockRng? The old struct BlockRng referred to a block-based random-number generator. So the name was fine.

BlockBuffer is okay but ultimately a poor name; it buffers results not blocks. ResultsBuffer or just Buffer might work.

The new trait BlockRng is actually a bad name: implementations are (random) (data) block generators, not number generators (no one needs 512-bit numbers).

The old name block::Generator is about as close to "random block generator" as one can get without an unwieldy name I think (unless we want to call it Rbg).


Since the main argument for separation of the core and the buffer seems to be zeroization and alternatives need specific documentation, why don't we just add a method like fn clear?


To avoid complicating history of a single PR too much I will close this one and replace it.

@dhardydhardy closed this Jan 29, 2026
@newpavlov
newpavlov deleted the push-ytsyzvnpyymq branch January 29, 2026 18:17
Sign up for freeto 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

@dhardy@newpavlov
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Remove CryptoGenerator and reduce BlockRng to BlockBuffer by dhardy · Pull Request #68 · rust-random/rand_core · GitHub
Skip to content

Remove CryptoGenerator and reduce BlockRng to BlockBuffer - #68

Closed
dhardy wants to merge 7 commits into
masterfrom
push-ytsyzvnpyymq
Closed

Remove CryptoGenerator and reduce BlockRng to BlockBuffer#68
dhardy wants to merge 7 commits into
masterfrom
push-ytsyzvnpyymq

Conversation

@dhardy

Copy link
Copy Markdown
Member
  • Added a CHANGELOG.md entry

Motivation

rust-random/rand#1722 makes this useless.

Other

Any suggestions for a new name for trait Generator? As-is it matches its most important generate method, so the name doesn't seem too bad.

@dhardy
dhardy requested a review from newpavlovJanuary 28, 2026 15:56
@newpavlov

newpavlov commented Jan 28, 2026

Copy link
Copy Markdown
Member

Any suggestions for a new name for trait Generator?

BlockRng would be the most consistent name with BlockRng::generate_block (or next_block) method. Instead of the wrapper I would prefer to have a separate BlockBuffer struct.

@dhardy

Copy link
Copy Markdown
MemberAuthor

The names are consistent.

What is the motivation for making BlockBuffer separate? It makes little sense to me (without removing the trait as in the more recent #24 design).

@newpavlov

newpavlov commented Jan 28, 2026

Copy link
Copy Markdown
Member

Separation of concerns. IMO struct Rng { core: RngCore, buffer: BlockBuffer<..> } is more transparent than struct Rng(BlockRng(RngCore));. And zeroization support would look less confusing. It's easy to understand what happens in:

self.core.zeroize();self.buffer = Default::default();
zeroize::optimization_barrier(&self.buffer)

While the wrapper would result in a less straightforward code.

The same applies to serialization as well.

@dhardy

Copy link
Copy Markdown
MemberAuthor

Separation of concerns

If they were truly separate components I'd agree, but the only pub methods not needing both parameters are word_offset and remaining_results.

I see you succeeded in convincing @tarcieri to make optimization_barrier public in RustCrypto/utils#1261, though it's not in a released version yet.

@dhardy

Copy link
Copy Markdown
MemberAuthor

@newpavlov I made significant additions to this PR; please re-review.

@dhardydhardy changed the title Remove CryptoGeneratorRemove CryptoGenerator and reduce BlockRng to BlockBufferJan 28, 2026
Comment threadsrc/block.rs
impl<W: Word + Default, const N: usize, G: Generator<Output = [W; N]>> BlockRng<G> {
/// Create a new `BlockRng` from an existing RNG implementing
/// `Generator`. Results will be generated on first use.
impl<W: Word + Default, const N: usize, G: BlockRng<Output = [W; N]>> Default for BlockBuffer<G> {

@newpavlovnewpavlovJan 28, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Word is already bounded by Default via the Sealed trait.

And I think we can simplify the bound to just G::Output: Default, no? UPD: No, we use Word functionality in the implementation.

Comment threadsrc/block.rs
///
/// Returns `None` if `remaining_results` is too long.
pub fn reconstruct(core: G, remaining_results: &[W]) -> Option<Self> {
pub fn reconstruct(remaining_results: &[W]) -> Option<Self> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this method used in practice? I think we had a discussion about this and came to conclusion that it's better to use serialization/deserialization over [W; N] instead of &[W].

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, it is used: https://github.com/rust-random/rngs/blob/master/rand_isaac/src/isaac.rs#L171

And no, that is the conclusion that you came to. My conclusion was that where fixed-size serialization is preferred it is still possible with this approach (since N is known), while the reverse is not with your approach (and variable length serialization is preferable if the output format happens to be something like JSON).

@newpavlovnewpavlovJan 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sure, whatever...

But at least add methods for fixed-sized (de)serialization. It would mean that your struct has two ways of handling serialization, but so be it.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The existing API is already usable for fixed-size serialization though (with slightly more code elsewhere, but storing the length is not exactly hard).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Are you seriously suggesting that users should manually implement the fixed-size serialization based on the variable sized methods???

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes. And why not? It's possible. It's not that much extra code, and probably won't be used in that many cases anyway. It's not even particularly inefficient, if that even matters for serialisation.

@newpavlovnewpavlovJan 30, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ok... Feel free to do with this module whatever you want. I will not be reviewing/approving PRs which deal with block stuff anymore.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I am confused. But as you wish.

Comment threadsrc/block.rs
Comment threadCHANGELOG.md
- `BlockRng::reset` method ([#44])
- `BlockRng::index` method (replaced with `BlockRng::word_offset`) ([#44])
- `Generator::Item` associated type ([#26])
- `CryptoBlockRng` ([#68])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Update changelog.

Comment threadsrc/block.rs
#[derive(Clone)]
pub struct BlockRng<G: Generator> {
#[allow(missing_debug_implementations)]
pub struct BlockBuffer<G: BlockRng> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Use R instead of G like in all other bounds?

Comment threadsrc/block.rs
@@ -98,32 +89,12 @@ pub trait Generator {
///
/// This must fill `output` with random data.
fn generate(&mut self, output: &mut Self::Output);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe rename the method to next_block for consistency with the Rng methods?

Comment threadsrc/block.rs
Comment threadsrc/block.rs
///
/// This type encompasses a [`Generator`] [`core`](Self::core) and a buffer.
/// This type does not encapuslate a [`BlockRng`], but is designed to be used
/// alongside one.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It would be nice to explicitly document that BlockBuffer::default() initializes all bits of the state to make it friendlier to the optimization_barrier-based zeroization.

@dhardy

Copy link
Copy Markdown
MemberAuthor

Regarding the renaming, the largest problem is actually that we use 'core' to refer to the BlockRng (e.g. in the doc example and as a parameter to methods like next_word). Why 'core'? This is the core (random) generator.

So, BlockRng? The old struct BlockRng referred to a block-based random-number generator. So the name was fine.

BlockBuffer is okay but ultimately a poor name; it buffers results not blocks. ResultsBuffer or just Buffer might work.

The new trait BlockRng is actually a bad name: implementations are (random) (data) block generators, not number generators (no one needs 512-bit numbers).

The old name block::Generator is about as close to "random block generator" as one can get without an unwieldy name I think (unless we want to call it Rbg).


Since the main argument for separation of the core and the buffer seems to be zeroization and alternatives need specific documentation, why don't we just add a method like fn clear?


To avoid complicating history of a single PR too much I will close this one and replace it.

@dhardydhardy closed this Jan 29, 2026
@newpavlov
newpavlov deleted the push-ytsyzvnpyymq branch January 29, 2026 18:17
Sign up for freeto 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

@dhardy@newpavlov
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Remove CryptoGenerator and reduce BlockRng to BlockBuffer by dhardy · Pull Request #68 · rust-random/rand_core · GitHub
Skip to content

Remove CryptoGenerator and reduce BlockRng to BlockBuffer - #68

Closed
dhardy wants to merge 7 commits into
masterfrom
push-ytsyzvnpyymq
Closed

Remove CryptoGenerator and reduce BlockRng to BlockBuffer#68
dhardy wants to merge 7 commits into
masterfrom
push-ytsyzvnpyymq

Conversation

@dhardy

Copy link
Copy Markdown
Member
  • Added a CHANGELOG.md entry

Motivation

rust-random/rand#1722 makes this useless.

Other

Any suggestions for a new name for trait Generator? As-is it matches its most important generate method, so the name doesn't seem too bad.

@dhardy
dhardy requested a review from newpavlovJanuary 28, 2026 15:56
@newpavlov

newpavlov commented Jan 28, 2026

Copy link
Copy Markdown
Member

Any suggestions for a new name for trait Generator?

BlockRng would be the most consistent name with BlockRng::generate_block (or next_block) method. Instead of the wrapper I would prefer to have a separate BlockBuffer struct.

@dhardy

Copy link
Copy Markdown
MemberAuthor

The names are consistent.

What is the motivation for making BlockBuffer separate? It makes little sense to me (without removing the trait as in the more recent #24 design).

@newpavlov

newpavlov commented Jan 28, 2026

Copy link
Copy Markdown
Member

Separation of concerns. IMO struct Rng { core: RngCore, buffer: BlockBuffer<..> } is more transparent than struct Rng(BlockRng(RngCore));. And zeroization support would look less confusing. It's easy to understand what happens in:

self.core.zeroize();self.buffer = Default::default();
zeroize::optimization_barrier(&self.buffer)

While the wrapper would result in a less straightforward code.

The same applies to serialization as well.

@dhardy

Copy link
Copy Markdown
MemberAuthor

Separation of concerns

If they were truly separate components I'd agree, but the only pub methods not needing both parameters are word_offset and remaining_results.

I see you succeeded in convincing @tarcieri to make optimization_barrier public in RustCrypto/utils#1261, though it's not in a released version yet.

@dhardy

Copy link
Copy Markdown
MemberAuthor

@newpavlov I made significant additions to this PR; please re-review.

@dhardydhardy changed the title Remove CryptoGeneratorRemove CryptoGenerator and reduce BlockRng to BlockBufferJan 28, 2026
Comment threadsrc/block.rs
impl<W: Word + Default, const N: usize, G: Generator<Output = [W; N]>> BlockRng<G> {
/// Create a new `BlockRng` from an existing RNG implementing
/// `Generator`. Results will be generated on first use.
impl<W: Word + Default, const N: usize, G: BlockRng<Output = [W; N]>> Default for BlockBuffer<G> {

@newpavlovnewpavlovJan 28, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Word is already bounded by Default via the Sealed trait.

And I think we can simplify the bound to just G::Output: Default, no? UPD: No, we use Word functionality in the implementation.

Comment threadsrc/block.rs
///
/// Returns `None` if `remaining_results` is too long.
pub fn reconstruct(core: G, remaining_results: &[W]) -> Option<Self> {
pub fn reconstruct(remaining_results: &[W]) -> Option<Self> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this method used in practice? I think we had a discussion about this and came to conclusion that it's better to use serialization/deserialization over [W; N] instead of &[W].

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, it is used: https://github.com/rust-random/rngs/blob/master/rand_isaac/src/isaac.rs#L171

And no, that is the conclusion that you came to. My conclusion was that where fixed-size serialization is preferred it is still possible with this approach (since N is known), while the reverse is not with your approach (and variable length serialization is preferable if the output format happens to be something like JSON).

@newpavlovnewpavlovJan 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sure, whatever...

But at least add methods for fixed-sized (de)serialization. It would mean that your struct has two ways of handling serialization, but so be it.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The existing API is already usable for fixed-size serialization though (with slightly more code elsewhere, but storing the length is not exactly hard).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Are you seriously suggesting that users should manually implement the fixed-size serialization based on the variable sized methods???

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes. And why not? It's possible. It's not that much extra code, and probably won't be used in that many cases anyway. It's not even particularly inefficient, if that even matters for serialisation.

@newpavlovnewpavlovJan 30, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ok... Feel free to do with this module whatever you want. I will not be reviewing/approving PRs which deal with block stuff anymore.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I am confused. But as you wish.

Comment threadsrc/block.rs
Comment threadCHANGELOG.md
- `BlockRng::reset` method ([#44])
- `BlockRng::index` method (replaced with `BlockRng::word_offset`) ([#44])
- `Generator::Item` associated type ([#26])
- `CryptoBlockRng` ([#68])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Update changelog.

Comment threadsrc/block.rs
#[derive(Clone)]
pub struct BlockRng<G: Generator> {
#[allow(missing_debug_implementations)]
pub struct BlockBuffer<G: BlockRng> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Use R instead of G like in all other bounds?

Comment threadsrc/block.rs
@@ -98,32 +89,12 @@ pub trait Generator {
///
/// This must fill `output` with random data.
fn generate(&mut self, output: &mut Self::Output);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe rename the method to next_block for consistency with the Rng methods?

Comment threadsrc/block.rs
Comment threadsrc/block.rs
///
/// This type encompasses a [`Generator`] [`core`](Self::core) and a buffer.
/// This type does not encapuslate a [`BlockRng`], but is designed to be used
/// alongside one.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It would be nice to explicitly document that BlockBuffer::default() initializes all bits of the state to make it friendlier to the optimization_barrier-based zeroization.

@dhardy

Copy link
Copy Markdown
MemberAuthor

Regarding the renaming, the largest problem is actually that we use 'core' to refer to the BlockRng (e.g. in the doc example and as a parameter to methods like next_word). Why 'core'? This is the core (random) generator.

So, BlockRng? The old struct BlockRng referred to a block-based random-number generator. So the name was fine.

BlockBuffer is okay but ultimately a poor name; it buffers results not blocks. ResultsBuffer or just Buffer might work.

The new trait BlockRng is actually a bad name: implementations are (random) (data) block generators, not number generators (no one needs 512-bit numbers).

The old name block::Generator is about as close to "random block generator" as one can get without an unwieldy name I think (unless we want to call it Rbg).


Since the main argument for separation of the core and the buffer seems to be zeroization and alternatives need specific documentation, why don't we just add a method like fn clear?


To avoid complicating history of a single PR too much I will close this one and replace it.

@dhardydhardy closed this Jan 29, 2026
@newpavlov
newpavlov deleted the push-ytsyzvnpyymq branch January 29, 2026 18:17
Sign up for freeto 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

@dhardy@newpavlov
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Remove CryptoGenerator and reduce BlockRng to BlockBuffer by dhardy · Pull Request #68 · rust-random/rand_core · GitHub
Skip to content

Remove CryptoGenerator and reduce BlockRng to BlockBuffer - #68

Closed
dhardy wants to merge 7 commits into
masterfrom
push-ytsyzvnpyymq
Closed

Remove CryptoGenerator and reduce BlockRng to BlockBuffer#68
dhardy wants to merge 7 commits into
masterfrom
push-ytsyzvnpyymq

Conversation

@dhardy

Copy link
Copy Markdown
Member
  • Added a CHANGELOG.md entry

Motivation

rust-random/rand#1722 makes this useless.

Other

Any suggestions for a new name for trait Generator? As-is it matches its most important generate method, so the name doesn't seem too bad.

@dhardy
dhardy requested a review from newpavlovJanuary 28, 2026 15:56
@newpavlov

newpavlov commented Jan 28, 2026

Copy link
Copy Markdown
Member

Any suggestions for a new name for trait Generator?

BlockRng would be the most consistent name with BlockRng::generate_block (or next_block) method. Instead of the wrapper I would prefer to have a separate BlockBuffer struct.

@dhardy

Copy link
Copy Markdown
MemberAuthor

The names are consistent.

What is the motivation for making BlockBuffer separate? It makes little sense to me (without removing the trait as in the more recent #24 design).

@newpavlov

newpavlov commented Jan 28, 2026

Copy link
Copy Markdown
Member

Separation of concerns. IMO struct Rng { core: RngCore, buffer: BlockBuffer<..> } is more transparent than struct Rng(BlockRng(RngCore));. And zeroization support would look less confusing. It's easy to understand what happens in:

self.core.zeroize();self.buffer = Default::default();
zeroize::optimization_barrier(&self.buffer)

While the wrapper would result in a less straightforward code.

The same applies to serialization as well.

@dhardy

Copy link
Copy Markdown
MemberAuthor

Separation of concerns

If they were truly separate components I'd agree, but the only pub methods not needing both parameters are word_offset and remaining_results.

I see you succeeded in convincing @tarcieri to make optimization_barrier public in RustCrypto/utils#1261, though it's not in a released version yet.

@dhardy

Copy link
Copy Markdown
MemberAuthor

@newpavlov I made significant additions to this PR; please re-review.

@dhardydhardy changed the title Remove CryptoGeneratorRemove CryptoGenerator and reduce BlockRng to BlockBufferJan 28, 2026
Comment threadsrc/block.rs
impl<W: Word + Default, const N: usize, G: Generator<Output = [W; N]>> BlockRng<G> {
/// Create a new `BlockRng` from an existing RNG implementing
/// `Generator`. Results will be generated on first use.
impl<W: Word + Default, const N: usize, G: BlockRng<Output = [W; N]>> Default for BlockBuffer<G> {

@newpavlovnewpavlovJan 28, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Word is already bounded by Default via the Sealed trait.

And I think we can simplify the bound to just G::Output: Default, no? UPD: No, we use Word functionality in the implementation.

Comment threadsrc/block.rs
///
/// Returns `None` if `remaining_results` is too long.
pub fn reconstruct(core: G, remaining_results: &[W]) -> Option<Self> {
pub fn reconstruct(remaining_results: &[W]) -> Option<Self> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this method used in practice? I think we had a discussion about this and came to conclusion that it's better to use serialization/deserialization over [W; N] instead of &[W].

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, it is used: https://github.com/rust-random/rngs/blob/master/rand_isaac/src/isaac.rs#L171

And no, that is the conclusion that you came to. My conclusion was that where fixed-size serialization is preferred it is still possible with this approach (since N is known), while the reverse is not with your approach (and variable length serialization is preferable if the output format happens to be something like JSON).

@newpavlovnewpavlovJan 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sure, whatever...

But at least add methods for fixed-sized (de)serialization. It would mean that your struct has two ways of handling serialization, but so be it.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The existing API is already usable for fixed-size serialization though (with slightly more code elsewhere, but storing the length is not exactly hard).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Are you seriously suggesting that users should manually implement the fixed-size serialization based on the variable sized methods???

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes. And why not? It's possible. It's not that much extra code, and probably won't be used in that many cases anyway. It's not even particularly inefficient, if that even matters for serialisation.

@newpavlovnewpavlovJan 30, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ok... Feel free to do with this module whatever you want. I will not be reviewing/approving PRs which deal with block stuff anymore.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I am confused. But as you wish.

Comment threadsrc/block.rs
Comment threadCHANGELOG.md
- `BlockRng::reset` method ([#44])
- `BlockRng::index` method (replaced with `BlockRng::word_offset`) ([#44])
- `Generator::Item` associated type ([#26])
- `CryptoBlockRng` ([#68])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Update changelog.

Comment threadsrc/block.rs
#[derive(Clone)]
pub struct BlockRng<G: Generator> {
#[allow(missing_debug_implementations)]
pub struct BlockBuffer<G: BlockRng> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Use R instead of G like in all other bounds?

Comment threadsrc/block.rs
@@ -98,32 +89,12 @@ pub trait Generator {
///
/// This must fill `output` with random data.
fn generate(&mut self, output: &mut Self::Output);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe rename the method to next_block for consistency with the Rng methods?

Comment threadsrc/block.rs
Comment threadsrc/block.rs
///
/// This type encompasses a [`Generator`] [`core`](Self::core) and a buffer.
/// This type does not encapuslate a [`BlockRng`], but is designed to be used
/// alongside one.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It would be nice to explicitly document that BlockBuffer::default() initializes all bits of the state to make it friendlier to the optimization_barrier-based zeroization.

@dhardy

Copy link
Copy Markdown
MemberAuthor

Regarding the renaming, the largest problem is actually that we use 'core' to refer to the BlockRng (e.g. in the doc example and as a parameter to methods like next_word). Why 'core'? This is the core (random) generator.

So, BlockRng? The old struct BlockRng referred to a block-based random-number generator. So the name was fine.

BlockBuffer is okay but ultimately a poor name; it buffers results not blocks. ResultsBuffer or just Buffer might work.

The new trait BlockRng is actually a bad name: implementations are (random) (data) block generators, not number generators (no one needs 512-bit numbers).

The old name block::Generator is about as close to "random block generator" as one can get without an unwieldy name I think (unless we want to call it Rbg).


Since the main argument for separation of the core and the buffer seems to be zeroization and alternatives need specific documentation, why don't we just add a method like fn clear?


To avoid complicating history of a single PR too much I will close this one and replace it.

@dhardydhardy closed this Jan 29, 2026
@newpavlov
newpavlov deleted the push-ytsyzvnpyymq branch January 29, 2026 18:17
Sign up for freeto 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

@dhardy@newpavlov
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); Remove CryptoGenerator and reduce BlockRng to BlockBuffer by dhardy · Pull Request #68 · rust-random/rand_core · GitHub
Skip to content

Remove CryptoGenerator and reduce BlockRng to BlockBuffer - #68

Closed
dhardy wants to merge 7 commits into
masterfrom
push-ytsyzvnpyymq
Closed

Remove CryptoGenerator and reduce BlockRng to BlockBuffer#68
dhardy wants to merge 7 commits into
masterfrom
push-ytsyzvnpyymq

Conversation

@dhardy

Copy link
Copy Markdown
Member
  • Added a CHANGELOG.md entry

Motivation

rust-random/rand#1722 makes this useless.

Other

Any suggestions for a new name for trait Generator? As-is it matches its most important generate method, so the name doesn't seem too bad.

@dhardy
dhardy requested a review from newpavlovJanuary 28, 2026 15:56
@newpavlov

newpavlov commented Jan 28, 2026

Copy link
Copy Markdown
Member

Any suggestions for a new name for trait Generator?

BlockRng would be the most consistent name with BlockRng::generate_block (or next_block) method. Instead of the wrapper I would prefer to have a separate BlockBuffer struct.

@dhardy

Copy link
Copy Markdown
MemberAuthor

The names are consistent.

What is the motivation for making BlockBuffer separate? It makes little sense to me (without removing the trait as in the more recent #24 design).

@newpavlov

newpavlov commented Jan 28, 2026

Copy link
Copy Markdown
Member

Separation of concerns. IMO struct Rng { core: RngCore, buffer: BlockBuffer<..> } is more transparent than struct Rng(BlockRng(RngCore));. And zeroization support would look less confusing. It's easy to understand what happens in:

self.core.zeroize();self.buffer = Default::default();
zeroize::optimization_barrier(&self.buffer)

While the wrapper would result in a less straightforward code.

The same applies to serialization as well.

@dhardy

Copy link
Copy Markdown
MemberAuthor

Separation of concerns

If they were truly separate components I'd agree, but the only pub methods not needing both parameters are word_offset and remaining_results.

I see you succeeded in convincing @tarcieri to make optimization_barrier public in RustCrypto/utils#1261, though it's not in a released version yet.

@dhardy

Copy link
Copy Markdown
MemberAuthor

@newpavlov I made significant additions to this PR; please re-review.

@dhardydhardy changed the title Remove CryptoGeneratorRemove CryptoGenerator and reduce BlockRng to BlockBufferJan 28, 2026
Comment threadsrc/block.rs
impl<W: Word + Default, const N: usize, G: Generator<Output = [W; N]>> BlockRng<G> {
/// Create a new `BlockRng` from an existing RNG implementing
/// `Generator`. Results will be generated on first use.
impl<W: Word + Default, const N: usize, G: BlockRng<Output = [W; N]>> Default for BlockBuffer<G> {

@newpavlovnewpavlovJan 28, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Word is already bounded by Default via the Sealed trait.

And I think we can simplify the bound to just G::Output: Default, no? UPD: No, we use Word functionality in the implementation.

Comment threadsrc/block.rs
///
/// Returns `None` if `remaining_results` is too long.
pub fn reconstruct(core: G, remaining_results: &[W]) -> Option<Self> {
pub fn reconstruct(remaining_results: &[W]) -> Option<Self> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this method used in practice? I think we had a discussion about this and came to conclusion that it's better to use serialization/deserialization over [W; N] instead of &[W].

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, it is used: https://github.com/rust-random/rngs/blob/master/rand_isaac/src/isaac.rs#L171

And no, that is the conclusion that you came to. My conclusion was that where fixed-size serialization is preferred it is still possible with this approach (since N is known), while the reverse is not with your approach (and variable length serialization is preferable if the output format happens to be something like JSON).

@newpavlovnewpavlovJan 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sure, whatever...

But at least add methods for fixed-sized (de)serialization. It would mean that your struct has two ways of handling serialization, but so be it.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The existing API is already usable for fixed-size serialization though (with slightly more code elsewhere, but storing the length is not exactly hard).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Are you seriously suggesting that users should manually implement the fixed-size serialization based on the variable sized methods???

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes. And why not? It's possible. It's not that much extra code, and probably won't be used in that many cases anyway. It's not even particularly inefficient, if that even matters for serialisation.

@newpavlovnewpavlovJan 30, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ok... Feel free to do with this module whatever you want. I will not be reviewing/approving PRs which deal with block stuff anymore.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I am confused. But as you wish.

Comment threadsrc/block.rs
Comment threadCHANGELOG.md
- `BlockRng::reset` method ([#44])
- `BlockRng::index` method (replaced with `BlockRng::word_offset`) ([#44])
- `Generator::Item` associated type ([#26])
- `CryptoBlockRng` ([#68])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Update changelog.

Comment threadsrc/block.rs
#[derive(Clone)]
pub struct BlockRng<G: Generator> {
#[allow(missing_debug_implementations)]
pub struct BlockBuffer<G: BlockRng> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Use R instead of G like in all other bounds?

Comment threadsrc/block.rs
@@ -98,32 +89,12 @@ pub trait Generator {
///
/// This must fill `output` with random data.
fn generate(&mut self, output: &mut Self::Output);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe rename the method to next_block for consistency with the Rng methods?

Comment threadsrc/block.rs
Comment threadsrc/block.rs
///
/// This type encompasses a [`Generator`] [`core`](Self::core) and a buffer.
/// This type does not encapuslate a [`BlockRng`], but is designed to be used
/// alongside one.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It would be nice to explicitly document that BlockBuffer::default() initializes all bits of the state to make it friendlier to the optimization_barrier-based zeroization.

@dhardy

Copy link
Copy Markdown
MemberAuthor

Regarding the renaming, the largest problem is actually that we use 'core' to refer to the BlockRng (e.g. in the doc example and as a parameter to methods like next_word). Why 'core'? This is the core (random) generator.

So, BlockRng? The old struct BlockRng referred to a block-based random-number generator. So the name was fine.

BlockBuffer is okay but ultimately a poor name; it buffers results not blocks. ResultsBuffer or just Buffer might work.

The new trait BlockRng is actually a bad name: implementations are (random) (data) block generators, not number generators (no one needs 512-bit numbers).

The old name block::Generator is about as close to "random block generator" as one can get without an unwieldy name I think (unless we want to call it Rbg).


Since the main argument for separation of the core and the buffer seems to be zeroization and alternatives need specific documentation, why don't we just add a method like fn clear?


To avoid complicating history of a single PR too much I will close this one and replace it.

@dhardydhardy closed this Jan 29, 2026
@newpavlov
newpavlov deleted the push-ytsyzvnpyymq branch January 29, 2026 18:17
Sign up for freeto 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

@dhardy@newpavlov