Skip to content

Add rand_core::InfallibleRng marker trait - #1412

Closed
newpavlov wants to merge 1 commit into
masterfrom
infallible_rng
Closed

Add rand_core::InfallibleRng marker trait#1412
newpavlov wants to merge 1 commit into
masterfrom
infallible_rng

Conversation

@newpavlov

@newpavlovnewpavlov commented Mar 18, 2024

Copy link
Copy Markdown
Member

Implementers of the rand_core::InfallibleRng trait indicate that they will never return errors from the RngCore::try_fill_bytes method and will never panic on unwrapping rand_core::Error while calling other methods.

@ctz
Does it address your concerns mentioned in this comment? If you have other concerns/suggestion, feel free to list them here or in a separate issue.

@newpavlov
newpavlov requested a review from dhardyMarch 18, 2024 16:54
@newpavlov

Copy link
Copy Markdown
MemberAuthor

This PR got a bunch of unrelated formatting changes in the edited files, which were introduced automatically by my editor. Later we probably need to fix formatting for the whole project and add rustfmt check to CI.

@dhardy

Copy link
Copy Markdown
Member

Later we probably need to fix formatting for the whole project and add rustfmt check to CI.

Yes; I was thinking try to resolve most PRs first. But we could also just go ahead...

Comment threadrand_chacha/src/chacha.rs Outdated
Comment threadrand_core/src/lib.rs
Comment on lines +215 to +221
/// A marker trait used to indicate that an [`RngCore`] implementation is
/// supposed to never return errors from the [`RngCore::try_fill_bytes`] method
/// and never panic on unwrapping [`Error`] while calling other methods.
///
/// This trait is usually implemented by PRNGs, as opposed to OS, hardware,
/// and periodically-reseeded RNGs, which may fail with IO errors.
pub trait InfallibleRng: RngCore {}

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.

Commenting just for visibility of the significant addition.

It falls into the same trap as std::iter::TrustedLen in that it promises something about another trait.

I think I'm okay with this, but worth thinking about / getting more input on.

@newpavlovnewpavlovMar 22, 2024

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 thought about different alternatives and it looks like it's the simplest option. Plus, we already have the CryptoRng trait.

One potential option is to make error an associated type (and CryptoRng may become associated bool constant). This way we could use Infallible by default. But without trait aliases it would be significantly less ergonomic to work with. Here is a draft of how it could look in future: playground.

@dhardydhardyMar 22, 2024

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.

Adding associated types + consts to RngCore changes the meaning on every existing usage as a generic bound.

For "crypto grade", I prefer the trait-inheritance model. After all, every CryptoRng is also a valid RNG. Also, can't have CRYPTO_STRONG default to true on all impls.

For infallibility, we'd at least need a bound on that error type: Error: std::error::Error or Error: Into<Something> where Something is a summarized RNG error (NotInitialized, EndOfSequence, IOError, MissingHardwareDevice, ???).

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.

every CryptoRng is also a valid RNG.

Yes, and? I don't see why the associated constant would be at odds with it. "Cryptographically strong" is a binary property of RNG, which can be modeled perfectly by an associated bool constant.

Also, can't have CRYPTO_STRONG default to true on all impls.

Yes, it should've been false in my example.

For infallibility, we'd at least need a bound on that error type

Sure. But I think it's an unimportant detail. Without stabilization of at least trait aliases, this approach is, arguably, not practical anyway.

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.

Yes, and?

Only that this case does work well with the trait inheritance model; not every boolean property does.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

I've cleaned up the formatting changes.

@dhardy

dhardy commented Mar 22, 2024

Copy link
Copy Markdown
Member

Also, if @ctz doesn't appreciate the design of RngCore, he's not the only one. It's a compromise that I don't think anyone likes. There's a tracker of some suggestions here: #1261.

This PR adds something, yes, but is a more fundamental revision a better option?

@dhardy

dhardy commented Mar 22, 2024

Copy link
Copy Markdown
Member

There is a much simpler alternative to this PR: require that all RngCore impls are infallible (or at least document possible panics).

Implication: we should drop OsRng. Since we no longer use this for seeding, I am not aware of any good reason to keep this. (We already removed ReadRng.)

We can also drop try_fill_bytes and all the stuff about converting between fallible and infallible cases.

Am I missing anything important?

@newpavlov

newpavlov commented Mar 22, 2024

Copy link
Copy Markdown
MemberAuthor

I am open to a more global rework (e.g. it may be worth to remove BlockRng stuff and replace it with helper macros/functions). But I think it's better to do in a separate PR after merging this one, since it's not given that we will be able to finalize it for v0.9 release cycle.

There is a much simpler alternative to this PR: require that all RngCore impls are infallible (or at least document possible panics).

In my opinion, it's tantamount to sweeping the problem under the rug.

IO-based RNGs such as OsRng or hardware-based RNGs (not an unusual thing with cryptographic applications) can fail as any other IO. It's a simple truth of life. Imagine someone has misconfigured, or forgot to plug-in a HW RNG. It's better for a cryptographic application/library to return a sensible error, instead of unconditionally panicking outright. Even PRNGs may fail in some cases, e.g. ChaCha-based RNGs may return error on detected looping, which may happen in practice in the presence of seeking.

As for OsRng, it can be a preferred way of generating sensitive information such as cryptographic keys, especially considering that ThreadRng does not implement any protection against exposed state. You may say "then use getrandom directly", but it would be less flexible, e.g. we would not be able to use PRNGs for reproducible testing of such methods.

@dhardy

Copy link
Copy Markdown
Member

You are right that such questions are beyond the scope of this PR, however we should at least determine whether we actually want trait InfallibleRng before merging this. Right, new issue then.

@dhardydhardy mentioned this pull request Mar 23, 2024
@newpavlov

Copy link
Copy Markdown
MemberAuthor

Closing in favor of #1424.

@newpavlov
newpavlov deleted the infallible_rng branch April 1, 2024 16:40
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

@newpavlov@dhardy
, '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" + '
Add `rand_core::InfallibleRng` marker trait by newpavlov · Pull Request #1412 · rust-random/rand · GitHub
Skip to content

Add rand_core::InfallibleRng marker trait - #1412

Closed
newpavlov wants to merge 1 commit into
masterfrom
infallible_rng
Closed

Add rand_core::InfallibleRng marker trait#1412
newpavlov wants to merge 1 commit into
masterfrom
infallible_rng

Conversation

@newpavlov

@newpavlovnewpavlov commented Mar 18, 2024

Copy link
Copy Markdown
Member

Implementers of the rand_core::InfallibleRng trait indicate that they will never return errors from the RngCore::try_fill_bytes method and will never panic on unwrapping rand_core::Error while calling other methods.

@ctz
Does it address your concerns mentioned in this comment? If you have other concerns/suggestion, feel free to list them here or in a separate issue.

@newpavlov
newpavlov requested a review from dhardyMarch 18, 2024 16:54
@newpavlov

Copy link
Copy Markdown
MemberAuthor

This PR got a bunch of unrelated formatting changes in the edited files, which were introduced automatically by my editor. Later we probably need to fix formatting for the whole project and add rustfmt check to CI.

@dhardy

Copy link
Copy Markdown
Member

Later we probably need to fix formatting for the whole project and add rustfmt check to CI.

Yes; I was thinking try to resolve most PRs first. But we could also just go ahead...

Comment threadrand_chacha/src/chacha.rs Outdated
Comment threadrand_core/src/lib.rs
Comment on lines +215 to +221
/// A marker trait used to indicate that an [`RngCore`] implementation is
/// supposed to never return errors from the [`RngCore::try_fill_bytes`] method
/// and never panic on unwrapping [`Error`] while calling other methods.
///
/// This trait is usually implemented by PRNGs, as opposed to OS, hardware,
/// and periodically-reseeded RNGs, which may fail with IO errors.
pub trait InfallibleRng: RngCore {}

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.

Commenting just for visibility of the significant addition.

It falls into the same trap as std::iter::TrustedLen in that it promises something about another trait.

I think I'm okay with this, but worth thinking about / getting more input on.

@newpavlovnewpavlovMar 22, 2024

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 thought about different alternatives and it looks like it's the simplest option. Plus, we already have the CryptoRng trait.

One potential option is to make error an associated type (and CryptoRng may become associated bool constant). This way we could use Infallible by default. But without trait aliases it would be significantly less ergonomic to work with. Here is a draft of how it could look in future: playground.

@dhardydhardyMar 22, 2024

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.

Adding associated types + consts to RngCore changes the meaning on every existing usage as a generic bound.

For "crypto grade", I prefer the trait-inheritance model. After all, every CryptoRng is also a valid RNG. Also, can't have CRYPTO_STRONG default to true on all impls.

For infallibility, we'd at least need a bound on that error type: Error: std::error::Error or Error: Into<Something> where Something is a summarized RNG error (NotInitialized, EndOfSequence, IOError, MissingHardwareDevice, ???).

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.

every CryptoRng is also a valid RNG.

Yes, and? I don't see why the associated constant would be at odds with it. "Cryptographically strong" is a binary property of RNG, which can be modeled perfectly by an associated bool constant.

Also, can't have CRYPTO_STRONG default to true on all impls.

Yes, it should've been false in my example.

For infallibility, we'd at least need a bound on that error type

Sure. But I think it's an unimportant detail. Without stabilization of at least trait aliases, this approach is, arguably, not practical anyway.

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.

Yes, and?

Only that this case does work well with the trait inheritance model; not every boolean property does.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

I've cleaned up the formatting changes.

@dhardy

dhardy commented Mar 22, 2024

Copy link
Copy Markdown
Member

Also, if @ctz doesn't appreciate the design of RngCore, he's not the only one. It's a compromise that I don't think anyone likes. There's a tracker of some suggestions here: #1261.

This PR adds something, yes, but is a more fundamental revision a better option?

@dhardy

dhardy commented Mar 22, 2024

Copy link
Copy Markdown
Member

There is a much simpler alternative to this PR: require that all RngCore impls are infallible (or at least document possible panics).

Implication: we should drop OsRng. Since we no longer use this for seeding, I am not aware of any good reason to keep this. (We already removed ReadRng.)

We can also drop try_fill_bytes and all the stuff about converting between fallible and infallible cases.

Am I missing anything important?

@newpavlov

newpavlov commented Mar 22, 2024

Copy link
Copy Markdown
MemberAuthor

I am open to a more global rework (e.g. it may be worth to remove BlockRng stuff and replace it with helper macros/functions). But I think it's better to do in a separate PR after merging this one, since it's not given that we will be able to finalize it for v0.9 release cycle.

There is a much simpler alternative to this PR: require that all RngCore impls are infallible (or at least document possible panics).

In my opinion, it's tantamount to sweeping the problem under the rug.

IO-based RNGs such as OsRng or hardware-based RNGs (not an unusual thing with cryptographic applications) can fail as any other IO. It's a simple truth of life. Imagine someone has misconfigured, or forgot to plug-in a HW RNG. It's better for a cryptographic application/library to return a sensible error, instead of unconditionally panicking outright. Even PRNGs may fail in some cases, e.g. ChaCha-based RNGs may return error on detected looping, which may happen in practice in the presence of seeking.

As for OsRng, it can be a preferred way of generating sensitive information such as cryptographic keys, especially considering that ThreadRng does not implement any protection against exposed state. You may say "then use getrandom directly", but it would be less flexible, e.g. we would not be able to use PRNGs for reproducible testing of such methods.

@dhardy

Copy link
Copy Markdown
Member

You are right that such questions are beyond the scope of this PR, however we should at least determine whether we actually want trait InfallibleRng before merging this. Right, new issue then.

@dhardydhardy mentioned this pull request Mar 23, 2024
@newpavlov

Copy link
Copy Markdown
MemberAuthor

Closing in favor of #1424.

@newpavlov
newpavlov deleted the infallible_rng branch April 1, 2024 16:40
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

@newpavlov@dhardy
, '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('^' + ".*" + ' Add `rand_core::InfallibleRng` marker trait by newpavlov · Pull Request #1412 · rust-random/rand · GitHub
Skip to content

Add rand_core::InfallibleRng marker trait - #1412

Closed
newpavlov wants to merge 1 commit into
masterfrom
infallible_rng
Closed

Add rand_core::InfallibleRng marker trait#1412
newpavlov wants to merge 1 commit into
masterfrom
infallible_rng

Conversation

@newpavlov

@newpavlovnewpavlov commented Mar 18, 2024

Copy link
Copy Markdown
Member

Implementers of the rand_core::InfallibleRng trait indicate that they will never return errors from the RngCore::try_fill_bytes method and will never panic on unwrapping rand_core::Error while calling other methods.

@ctz
Does it address your concerns mentioned in this comment? If you have other concerns/suggestion, feel free to list them here or in a separate issue.

@newpavlov
newpavlov requested a review from dhardyMarch 18, 2024 16:54
@newpavlov

Copy link
Copy Markdown
MemberAuthor

This PR got a bunch of unrelated formatting changes in the edited files, which were introduced automatically by my editor. Later we probably need to fix formatting for the whole project and add rustfmt check to CI.

@dhardy

Copy link
Copy Markdown
Member

Later we probably need to fix formatting for the whole project and add rustfmt check to CI.

Yes; I was thinking try to resolve most PRs first. But we could also just go ahead...

Comment threadrand_chacha/src/chacha.rs Outdated
Comment threadrand_core/src/lib.rs
Comment on lines +215 to +221
/// A marker trait used to indicate that an [`RngCore`] implementation is
/// supposed to never return errors from the [`RngCore::try_fill_bytes`] method
/// and never panic on unwrapping [`Error`] while calling other methods.
///
/// This trait is usually implemented by PRNGs, as opposed to OS, hardware,
/// and periodically-reseeded RNGs, which may fail with IO errors.
pub trait InfallibleRng: RngCore {}

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.

Commenting just for visibility of the significant addition.

It falls into the same trap as std::iter::TrustedLen in that it promises something about another trait.

I think I'm okay with this, but worth thinking about / getting more input on.

@newpavlovnewpavlovMar 22, 2024

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 thought about different alternatives and it looks like it's the simplest option. Plus, we already have the CryptoRng trait.

One potential option is to make error an associated type (and CryptoRng may become associated bool constant). This way we could use Infallible by default. But without trait aliases it would be significantly less ergonomic to work with. Here is a draft of how it could look in future: playground.

@dhardydhardyMar 22, 2024

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.

Adding associated types + consts to RngCore changes the meaning on every existing usage as a generic bound.

For "crypto grade", I prefer the trait-inheritance model. After all, every CryptoRng is also a valid RNG. Also, can't have CRYPTO_STRONG default to true on all impls.

For infallibility, we'd at least need a bound on that error type: Error: std::error::Error or Error: Into<Something> where Something is a summarized RNG error (NotInitialized, EndOfSequence, IOError, MissingHardwareDevice, ???).

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.

every CryptoRng is also a valid RNG.

Yes, and? I don't see why the associated constant would be at odds with it. "Cryptographically strong" is a binary property of RNG, which can be modeled perfectly by an associated bool constant.

Also, can't have CRYPTO_STRONG default to true on all impls.

Yes, it should've been false in my example.

For infallibility, we'd at least need a bound on that error type

Sure. But I think it's an unimportant detail. Without stabilization of at least trait aliases, this approach is, arguably, not practical anyway.

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.

Yes, and?

Only that this case does work well with the trait inheritance model; not every boolean property does.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

I've cleaned up the formatting changes.

@dhardy

dhardy commented Mar 22, 2024

Copy link
Copy Markdown
Member

Also, if @ctz doesn't appreciate the design of RngCore, he's not the only one. It's a compromise that I don't think anyone likes. There's a tracker of some suggestions here: #1261.

This PR adds something, yes, but is a more fundamental revision a better option?

@dhardy

dhardy commented Mar 22, 2024

Copy link
Copy Markdown
Member

There is a much simpler alternative to this PR: require that all RngCore impls are infallible (or at least document possible panics).

Implication: we should drop OsRng. Since we no longer use this for seeding, I am not aware of any good reason to keep this. (We already removed ReadRng.)

We can also drop try_fill_bytes and all the stuff about converting between fallible and infallible cases.

Am I missing anything important?

@newpavlov

newpavlov commented Mar 22, 2024

Copy link
Copy Markdown
MemberAuthor

I am open to a more global rework (e.g. it may be worth to remove BlockRng stuff and replace it with helper macros/functions). But I think it's better to do in a separate PR after merging this one, since it's not given that we will be able to finalize it for v0.9 release cycle.

There is a much simpler alternative to this PR: require that all RngCore impls are infallible (or at least document possible panics).

In my opinion, it's tantamount to sweeping the problem under the rug.

IO-based RNGs such as OsRng or hardware-based RNGs (not an unusual thing with cryptographic applications) can fail as any other IO. It's a simple truth of life. Imagine someone has misconfigured, or forgot to plug-in a HW RNG. It's better for a cryptographic application/library to return a sensible error, instead of unconditionally panicking outright. Even PRNGs may fail in some cases, e.g. ChaCha-based RNGs may return error on detected looping, which may happen in practice in the presence of seeking.

As for OsRng, it can be a preferred way of generating sensitive information such as cryptographic keys, especially considering that ThreadRng does not implement any protection against exposed state. You may say "then use getrandom directly", but it would be less flexible, e.g. we would not be able to use PRNGs for reproducible testing of such methods.

@dhardy

Copy link
Copy Markdown
Member

You are right that such questions are beyond the scope of this PR, however we should at least determine whether we actually want trait InfallibleRng before merging this. Right, new issue then.

@dhardydhardy mentioned this pull request Mar 23, 2024
@newpavlov

Copy link
Copy Markdown
MemberAuthor

Closing in favor of #1424.

@newpavlov
newpavlov deleted the infallible_rng branch April 1, 2024 16:40
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

@newpavlov@dhardy
, '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('^' + ".*" + ' Add `rand_core::InfallibleRng` marker trait by newpavlov · Pull Request #1412 · rust-random/rand · GitHub
Skip to content

Add rand_core::InfallibleRng marker trait - #1412

Closed
newpavlov wants to merge 1 commit into
masterfrom
infallible_rng
Closed

Add rand_core::InfallibleRng marker trait#1412
newpavlov wants to merge 1 commit into
masterfrom
infallible_rng

Conversation

@newpavlov

@newpavlovnewpavlov commented Mar 18, 2024

Copy link
Copy Markdown
Member

Implementers of the rand_core::InfallibleRng trait indicate that they will never return errors from the RngCore::try_fill_bytes method and will never panic on unwrapping rand_core::Error while calling other methods.

@ctz
Does it address your concerns mentioned in this comment? If you have other concerns/suggestion, feel free to list them here or in a separate issue.

@newpavlov
newpavlov requested a review from dhardyMarch 18, 2024 16:54
@newpavlov

Copy link
Copy Markdown
MemberAuthor

This PR got a bunch of unrelated formatting changes in the edited files, which were introduced automatically by my editor. Later we probably need to fix formatting for the whole project and add rustfmt check to CI.

@dhardy

Copy link
Copy Markdown
Member

Later we probably need to fix formatting for the whole project and add rustfmt check to CI.

Yes; I was thinking try to resolve most PRs first. But we could also just go ahead...

Comment threadrand_chacha/src/chacha.rs Outdated
Comment threadrand_core/src/lib.rs
Comment on lines +215 to +221
/// A marker trait used to indicate that an [`RngCore`] implementation is
/// supposed to never return errors from the [`RngCore::try_fill_bytes`] method
/// and never panic on unwrapping [`Error`] while calling other methods.
///
/// This trait is usually implemented by PRNGs, as opposed to OS, hardware,
/// and periodically-reseeded RNGs, which may fail with IO errors.
pub trait InfallibleRng: RngCore {}

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.

Commenting just for visibility of the significant addition.

It falls into the same trap as std::iter::TrustedLen in that it promises something about another trait.

I think I'm okay with this, but worth thinking about / getting more input on.

@newpavlovnewpavlovMar 22, 2024

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 thought about different alternatives and it looks like it's the simplest option. Plus, we already have the CryptoRng trait.

One potential option is to make error an associated type (and CryptoRng may become associated bool constant). This way we could use Infallible by default. But without trait aliases it would be significantly less ergonomic to work with. Here is a draft of how it could look in future: playground.

@dhardydhardyMar 22, 2024

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.

Adding associated types + consts to RngCore changes the meaning on every existing usage as a generic bound.

For "crypto grade", I prefer the trait-inheritance model. After all, every CryptoRng is also a valid RNG. Also, can't have CRYPTO_STRONG default to true on all impls.

For infallibility, we'd at least need a bound on that error type: Error: std::error::Error or Error: Into<Something> where Something is a summarized RNG error (NotInitialized, EndOfSequence, IOError, MissingHardwareDevice, ???).

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.

every CryptoRng is also a valid RNG.

Yes, and? I don't see why the associated constant would be at odds with it. "Cryptographically strong" is a binary property of RNG, which can be modeled perfectly by an associated bool constant.

Also, can't have CRYPTO_STRONG default to true on all impls.

Yes, it should've been false in my example.

For infallibility, we'd at least need a bound on that error type

Sure. But I think it's an unimportant detail. Without stabilization of at least trait aliases, this approach is, arguably, not practical anyway.

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.

Yes, and?

Only that this case does work well with the trait inheritance model; not every boolean property does.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

I've cleaned up the formatting changes.

@dhardy

dhardy commented Mar 22, 2024

Copy link
Copy Markdown
Member

Also, if @ctz doesn't appreciate the design of RngCore, he's not the only one. It's a compromise that I don't think anyone likes. There's a tracker of some suggestions here: #1261.

This PR adds something, yes, but is a more fundamental revision a better option?

@dhardy

dhardy commented Mar 22, 2024

Copy link
Copy Markdown
Member

There is a much simpler alternative to this PR: require that all RngCore impls are infallible (or at least document possible panics).

Implication: we should drop OsRng. Since we no longer use this for seeding, I am not aware of any good reason to keep this. (We already removed ReadRng.)

We can also drop try_fill_bytes and all the stuff about converting between fallible and infallible cases.

Am I missing anything important?

@newpavlov

newpavlov commented Mar 22, 2024

Copy link
Copy Markdown
MemberAuthor

I am open to a more global rework (e.g. it may be worth to remove BlockRng stuff and replace it with helper macros/functions). But I think it's better to do in a separate PR after merging this one, since it's not given that we will be able to finalize it for v0.9 release cycle.

There is a much simpler alternative to this PR: require that all RngCore impls are infallible (or at least document possible panics).

In my opinion, it's tantamount to sweeping the problem under the rug.

IO-based RNGs such as OsRng or hardware-based RNGs (not an unusual thing with cryptographic applications) can fail as any other IO. It's a simple truth of life. Imagine someone has misconfigured, or forgot to plug-in a HW RNG. It's better for a cryptographic application/library to return a sensible error, instead of unconditionally panicking outright. Even PRNGs may fail in some cases, e.g. ChaCha-based RNGs may return error on detected looping, which may happen in practice in the presence of seeking.

As for OsRng, it can be a preferred way of generating sensitive information such as cryptographic keys, especially considering that ThreadRng does not implement any protection against exposed state. You may say "then use getrandom directly", but it would be less flexible, e.g. we would not be able to use PRNGs for reproducible testing of such methods.

@dhardy

Copy link
Copy Markdown
Member

You are right that such questions are beyond the scope of this PR, however we should at least determine whether we actually want trait InfallibleRng before merging this. Right, new issue then.

@dhardydhardy mentioned this pull request Mar 23, 2024
@newpavlov

Copy link
Copy Markdown
MemberAuthor

Closing in favor of #1424.

@newpavlov
newpavlov deleted the infallible_rng branch April 1, 2024 16:40
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

@newpavlov@dhardy
, '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" + ' Add `rand_core::InfallibleRng` marker trait by newpavlov · Pull Request #1412 · rust-random/rand · GitHub
Skip to content

Add rand_core::InfallibleRng marker trait - #1412

Closed
newpavlov wants to merge 1 commit into
masterfrom
infallible_rng
Closed

Add rand_core::InfallibleRng marker trait#1412
newpavlov wants to merge 1 commit into
masterfrom
infallible_rng

Conversation

@newpavlov

@newpavlovnewpavlov commented Mar 18, 2024

Copy link
Copy Markdown
Member

Implementers of the rand_core::InfallibleRng trait indicate that they will never return errors from the RngCore::try_fill_bytes method and will never panic on unwrapping rand_core::Error while calling other methods.

@ctz
Does it address your concerns mentioned in this comment? If you have other concerns/suggestion, feel free to list them here or in a separate issue.

@newpavlov
newpavlov requested a review from dhardyMarch 18, 2024 16:54
@newpavlov

Copy link
Copy Markdown
MemberAuthor

This PR got a bunch of unrelated formatting changes in the edited files, which were introduced automatically by my editor. Later we probably need to fix formatting for the whole project and add rustfmt check to CI.

@dhardy

Copy link
Copy Markdown
Member

Later we probably need to fix formatting for the whole project and add rustfmt check to CI.

Yes; I was thinking try to resolve most PRs first. But we could also just go ahead...

Comment threadrand_chacha/src/chacha.rs Outdated
Comment threadrand_core/src/lib.rs
Comment on lines +215 to +221
/// A marker trait used to indicate that an [`RngCore`] implementation is
/// supposed to never return errors from the [`RngCore::try_fill_bytes`] method
/// and never panic on unwrapping [`Error`] while calling other methods.
///
/// This trait is usually implemented by PRNGs, as opposed to OS, hardware,
/// and periodically-reseeded RNGs, which may fail with IO errors.
pub trait InfallibleRng: RngCore {}

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.

Commenting just for visibility of the significant addition.

It falls into the same trap as std::iter::TrustedLen in that it promises something about another trait.

I think I'm okay with this, but worth thinking about / getting more input on.

@newpavlovnewpavlovMar 22, 2024

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 thought about different alternatives and it looks like it's the simplest option. Plus, we already have the CryptoRng trait.

One potential option is to make error an associated type (and CryptoRng may become associated bool constant). This way we could use Infallible by default. But without trait aliases it would be significantly less ergonomic to work with. Here is a draft of how it could look in future: playground.

@dhardydhardyMar 22, 2024

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.

Adding associated types + consts to RngCore changes the meaning on every existing usage as a generic bound.

For "crypto grade", I prefer the trait-inheritance model. After all, every CryptoRng is also a valid RNG. Also, can't have CRYPTO_STRONG default to true on all impls.

For infallibility, we'd at least need a bound on that error type: Error: std::error::Error or Error: Into<Something> where Something is a summarized RNG error (NotInitialized, EndOfSequence, IOError, MissingHardwareDevice, ???).

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.

every CryptoRng is also a valid RNG.

Yes, and? I don't see why the associated constant would be at odds with it. "Cryptographically strong" is a binary property of RNG, which can be modeled perfectly by an associated bool constant.

Also, can't have CRYPTO_STRONG default to true on all impls.

Yes, it should've been false in my example.

For infallibility, we'd at least need a bound on that error type

Sure. But I think it's an unimportant detail. Without stabilization of at least trait aliases, this approach is, arguably, not practical anyway.

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.

Yes, and?

Only that this case does work well with the trait inheritance model; not every boolean property does.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

I've cleaned up the formatting changes.

@dhardy

dhardy commented Mar 22, 2024

Copy link
Copy Markdown
Member

Also, if @ctz doesn't appreciate the design of RngCore, he's not the only one. It's a compromise that I don't think anyone likes. There's a tracker of some suggestions here: #1261.

This PR adds something, yes, but is a more fundamental revision a better option?

@dhardy

dhardy commented Mar 22, 2024

Copy link
Copy Markdown
Member

There is a much simpler alternative to this PR: require that all RngCore impls are infallible (or at least document possible panics).

Implication: we should drop OsRng. Since we no longer use this for seeding, I am not aware of any good reason to keep this. (We already removed ReadRng.)

We can also drop try_fill_bytes and all the stuff about converting between fallible and infallible cases.

Am I missing anything important?

@newpavlov

newpavlov commented Mar 22, 2024

Copy link
Copy Markdown
MemberAuthor

I am open to a more global rework (e.g. it may be worth to remove BlockRng stuff and replace it with helper macros/functions). But I think it's better to do in a separate PR after merging this one, since it's not given that we will be able to finalize it for v0.9 release cycle.

There is a much simpler alternative to this PR: require that all RngCore impls are infallible (or at least document possible panics).

In my opinion, it's tantamount to sweeping the problem under the rug.

IO-based RNGs such as OsRng or hardware-based RNGs (not an unusual thing with cryptographic applications) can fail as any other IO. It's a simple truth of life. Imagine someone has misconfigured, or forgot to plug-in a HW RNG. It's better for a cryptographic application/library to return a sensible error, instead of unconditionally panicking outright. Even PRNGs may fail in some cases, e.g. ChaCha-based RNGs may return error on detected looping, which may happen in practice in the presence of seeking.

As for OsRng, it can be a preferred way of generating sensitive information such as cryptographic keys, especially considering that ThreadRng does not implement any protection against exposed state. You may say "then use getrandom directly", but it would be less flexible, e.g. we would not be able to use PRNGs for reproducible testing of such methods.

@dhardy

Copy link
Copy Markdown
Member

You are right that such questions are beyond the scope of this PR, however we should at least determine whether we actually want trait InfallibleRng before merging this. Right, new issue then.

@dhardydhardy mentioned this pull request Mar 23, 2024
@newpavlov

Copy link
Copy Markdown
MemberAuthor

Closing in favor of #1424.

@newpavlov
newpavlov deleted the infallible_rng branch April 1, 2024 16:40
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

@newpavlov@dhardy
, '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('^' + ".*" + ' Add `rand_core::InfallibleRng` marker trait by newpavlov · Pull Request #1412 · rust-random/rand · GitHub
Skip to content

Add rand_core::InfallibleRng marker trait - #1412

Closed
newpavlov wants to merge 1 commit into
masterfrom
infallible_rng
Closed

Add rand_core::InfallibleRng marker trait#1412
newpavlov wants to merge 1 commit into
masterfrom
infallible_rng

Conversation

@newpavlov

@newpavlovnewpavlov commented Mar 18, 2024

Copy link
Copy Markdown
Member

Implementers of the rand_core::InfallibleRng trait indicate that they will never return errors from the RngCore::try_fill_bytes method and will never panic on unwrapping rand_core::Error while calling other methods.

@ctz
Does it address your concerns mentioned in this comment? If you have other concerns/suggestion, feel free to list them here or in a separate issue.

@newpavlov
newpavlov requested a review from dhardyMarch 18, 2024 16:54
@newpavlov

Copy link
Copy Markdown
MemberAuthor

This PR got a bunch of unrelated formatting changes in the edited files, which were introduced automatically by my editor. Later we probably need to fix formatting for the whole project and add rustfmt check to CI.

@dhardy

Copy link
Copy Markdown
Member

Later we probably need to fix formatting for the whole project and add rustfmt check to CI.

Yes; I was thinking try to resolve most PRs first. But we could also just go ahead...

Comment threadrand_chacha/src/chacha.rs Outdated
Comment threadrand_core/src/lib.rs
Comment on lines +215 to +221
/// A marker trait used to indicate that an [`RngCore`] implementation is
/// supposed to never return errors from the [`RngCore::try_fill_bytes`] method
/// and never panic on unwrapping [`Error`] while calling other methods.
///
/// This trait is usually implemented by PRNGs, as opposed to OS, hardware,
/// and periodically-reseeded RNGs, which may fail with IO errors.
pub trait InfallibleRng: RngCore {}

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.

Commenting just for visibility of the significant addition.

It falls into the same trap as std::iter::TrustedLen in that it promises something about another trait.

I think I'm okay with this, but worth thinking about / getting more input on.

@newpavlovnewpavlovMar 22, 2024

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 thought about different alternatives and it looks like it's the simplest option. Plus, we already have the CryptoRng trait.

One potential option is to make error an associated type (and CryptoRng may become associated bool constant). This way we could use Infallible by default. But without trait aliases it would be significantly less ergonomic to work with. Here is a draft of how it could look in future: playground.

@dhardydhardyMar 22, 2024

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.

Adding associated types + consts to RngCore changes the meaning on every existing usage as a generic bound.

For "crypto grade", I prefer the trait-inheritance model. After all, every CryptoRng is also a valid RNG. Also, can't have CRYPTO_STRONG default to true on all impls.

For infallibility, we'd at least need a bound on that error type: Error: std::error::Error or Error: Into<Something> where Something is a summarized RNG error (NotInitialized, EndOfSequence, IOError, MissingHardwareDevice, ???).

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.

every CryptoRng is also a valid RNG.

Yes, and? I don't see why the associated constant would be at odds with it. "Cryptographically strong" is a binary property of RNG, which can be modeled perfectly by an associated bool constant.

Also, can't have CRYPTO_STRONG default to true on all impls.

Yes, it should've been false in my example.

For infallibility, we'd at least need a bound on that error type

Sure. But I think it's an unimportant detail. Without stabilization of at least trait aliases, this approach is, arguably, not practical anyway.

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.

Yes, and?

Only that this case does work well with the trait inheritance model; not every boolean property does.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

I've cleaned up the formatting changes.

@dhardy

dhardy commented Mar 22, 2024

Copy link
Copy Markdown
Member

Also, if @ctz doesn't appreciate the design of RngCore, he's not the only one. It's a compromise that I don't think anyone likes. There's a tracker of some suggestions here: #1261.

This PR adds something, yes, but is a more fundamental revision a better option?

@dhardy

dhardy commented Mar 22, 2024

Copy link
Copy Markdown
Member

There is a much simpler alternative to this PR: require that all RngCore impls are infallible (or at least document possible panics).

Implication: we should drop OsRng. Since we no longer use this for seeding, I am not aware of any good reason to keep this. (We already removed ReadRng.)

We can also drop try_fill_bytes and all the stuff about converting between fallible and infallible cases.

Am I missing anything important?

@newpavlov

newpavlov commented Mar 22, 2024

Copy link
Copy Markdown
MemberAuthor

I am open to a more global rework (e.g. it may be worth to remove BlockRng stuff and replace it with helper macros/functions). But I think it's better to do in a separate PR after merging this one, since it's not given that we will be able to finalize it for v0.9 release cycle.

There is a much simpler alternative to this PR: require that all RngCore impls are infallible (or at least document possible panics).

In my opinion, it's tantamount to sweeping the problem under the rug.

IO-based RNGs such as OsRng or hardware-based RNGs (not an unusual thing with cryptographic applications) can fail as any other IO. It's a simple truth of life. Imagine someone has misconfigured, or forgot to plug-in a HW RNG. It's better for a cryptographic application/library to return a sensible error, instead of unconditionally panicking outright. Even PRNGs may fail in some cases, e.g. ChaCha-based RNGs may return error on detected looping, which may happen in practice in the presence of seeking.

As for OsRng, it can be a preferred way of generating sensitive information such as cryptographic keys, especially considering that ThreadRng does not implement any protection against exposed state. You may say "then use getrandom directly", but it would be less flexible, e.g. we would not be able to use PRNGs for reproducible testing of such methods.

@dhardy

Copy link
Copy Markdown
Member

You are right that such questions are beyond the scope of this PR, however we should at least determine whether we actually want trait InfallibleRng before merging this. Right, new issue then.

@dhardydhardy mentioned this pull request Mar 23, 2024
@newpavlov

Copy link
Copy Markdown
MemberAuthor

Closing in favor of #1424.

@newpavlov
newpavlov deleted the infallible_rng branch April 1, 2024 16:40
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

@newpavlov@dhardy
, '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); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add `rand_core::InfallibleRng` marker trait by newpavlov · Pull Request #1412 · rust-random/rand · GitHub
Skip to content

Add rand_core::InfallibleRng marker trait - #1412

Closed
newpavlov wants to merge 1 commit into
masterfrom
infallible_rng
Closed

Add rand_core::InfallibleRng marker trait#1412
newpavlov wants to merge 1 commit into
masterfrom
infallible_rng

Conversation

@newpavlov

@newpavlovnewpavlov commented Mar 18, 2024

Copy link
Copy Markdown
Member

Implementers of the rand_core::InfallibleRng trait indicate that they will never return errors from the RngCore::try_fill_bytes method and will never panic on unwrapping rand_core::Error while calling other methods.

@ctz
Does it address your concerns mentioned in this comment? If you have other concerns/suggestion, feel free to list them here or in a separate issue.

@newpavlov
newpavlov requested a review from dhardyMarch 18, 2024 16:54
@newpavlov

Copy link
Copy Markdown
MemberAuthor

This PR got a bunch of unrelated formatting changes in the edited files, which were introduced automatically by my editor. Later we probably need to fix formatting for the whole project and add rustfmt check to CI.

@dhardy

Copy link
Copy Markdown
Member

Later we probably need to fix formatting for the whole project and add rustfmt check to CI.

Yes; I was thinking try to resolve most PRs first. But we could also just go ahead...

Comment threadrand_chacha/src/chacha.rs Outdated
Comment threadrand_core/src/lib.rs
Comment on lines +215 to +221
/// A marker trait used to indicate that an [`RngCore`] implementation is
/// supposed to never return errors from the [`RngCore::try_fill_bytes`] method
/// and never panic on unwrapping [`Error`] while calling other methods.
///
/// This trait is usually implemented by PRNGs, as opposed to OS, hardware,
/// and periodically-reseeded RNGs, which may fail with IO errors.
pub trait InfallibleRng: RngCore {}

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.

Commenting just for visibility of the significant addition.

It falls into the same trap as std::iter::TrustedLen in that it promises something about another trait.

I think I'm okay with this, but worth thinking about / getting more input on.

@newpavlovnewpavlovMar 22, 2024

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 thought about different alternatives and it looks like it's the simplest option. Plus, we already have the CryptoRng trait.

One potential option is to make error an associated type (and CryptoRng may become associated bool constant). This way we could use Infallible by default. But without trait aliases it would be significantly less ergonomic to work with. Here is a draft of how it could look in future: playground.

@dhardydhardyMar 22, 2024

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.

Adding associated types + consts to RngCore changes the meaning on every existing usage as a generic bound.

For "crypto grade", I prefer the trait-inheritance model. After all, every CryptoRng is also a valid RNG. Also, can't have CRYPTO_STRONG default to true on all impls.

For infallibility, we'd at least need a bound on that error type: Error: std::error::Error or Error: Into<Something> where Something is a summarized RNG error (NotInitialized, EndOfSequence, IOError, MissingHardwareDevice, ???).

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.

every CryptoRng is also a valid RNG.

Yes, and? I don't see why the associated constant would be at odds with it. "Cryptographically strong" is a binary property of RNG, which can be modeled perfectly by an associated bool constant.

Also, can't have CRYPTO_STRONG default to true on all impls.

Yes, it should've been false in my example.

For infallibility, we'd at least need a bound on that error type

Sure. But I think it's an unimportant detail. Without stabilization of at least trait aliases, this approach is, arguably, not practical anyway.

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.

Yes, and?

Only that this case does work well with the trait inheritance model; not every boolean property does.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

I've cleaned up the formatting changes.

@dhardy

dhardy commented Mar 22, 2024

Copy link
Copy Markdown
Member

Also, if @ctz doesn't appreciate the design of RngCore, he's not the only one. It's a compromise that I don't think anyone likes. There's a tracker of some suggestions here: #1261.

This PR adds something, yes, but is a more fundamental revision a better option?

@dhardy

dhardy commented Mar 22, 2024

Copy link
Copy Markdown
Member

There is a much simpler alternative to this PR: require that all RngCore impls are infallible (or at least document possible panics).

Implication: we should drop OsRng. Since we no longer use this for seeding, I am not aware of any good reason to keep this. (We already removed ReadRng.)

We can also drop try_fill_bytes and all the stuff about converting between fallible and infallible cases.

Am I missing anything important?

@newpavlov

newpavlov commented Mar 22, 2024

Copy link
Copy Markdown
MemberAuthor

I am open to a more global rework (e.g. it may be worth to remove BlockRng stuff and replace it with helper macros/functions). But I think it's better to do in a separate PR after merging this one, since it's not given that we will be able to finalize it for v0.9 release cycle.

There is a much simpler alternative to this PR: require that all RngCore impls are infallible (or at least document possible panics).

In my opinion, it's tantamount to sweeping the problem under the rug.

IO-based RNGs such as OsRng or hardware-based RNGs (not an unusual thing with cryptographic applications) can fail as any other IO. It's a simple truth of life. Imagine someone has misconfigured, or forgot to plug-in a HW RNG. It's better for a cryptographic application/library to return a sensible error, instead of unconditionally panicking outright. Even PRNGs may fail in some cases, e.g. ChaCha-based RNGs may return error on detected looping, which may happen in practice in the presence of seeking.

As for OsRng, it can be a preferred way of generating sensitive information such as cryptographic keys, especially considering that ThreadRng does not implement any protection against exposed state. You may say "then use getrandom directly", but it would be less flexible, e.g. we would not be able to use PRNGs for reproducible testing of such methods.

@dhardy

Copy link
Copy Markdown
Member

You are right that such questions are beyond the scope of this PR, however we should at least determine whether we actually want trait InfallibleRng before merging this. Right, new issue then.

@dhardydhardy mentioned this pull request Mar 23, 2024
@newpavlov

Copy link
Copy Markdown
MemberAuthor

Closing in favor of #1424.

@newpavlov
newpavlov deleted the infallible_rng branch April 1, 2024 16:40
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

@newpavlov@dhardy
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Add `rand_core::InfallibleRng` marker trait by newpavlov · Pull Request #1412 · rust-random/rand · GitHub
Skip to content

Add rand_core::InfallibleRng marker trait - #1412

Closed
newpavlov wants to merge 1 commit into
masterfrom
infallible_rng
Closed

Add rand_core::InfallibleRng marker trait#1412
newpavlov wants to merge 1 commit into
masterfrom
infallible_rng

Conversation

@newpavlov

@newpavlovnewpavlov commented Mar 18, 2024

Copy link
Copy Markdown
Member

Implementers of the rand_core::InfallibleRng trait indicate that they will never return errors from the RngCore::try_fill_bytes method and will never panic on unwrapping rand_core::Error while calling other methods.

@ctz
Does it address your concerns mentioned in this comment? If you have other concerns/suggestion, feel free to list them here or in a separate issue.

@newpavlov
newpavlov requested a review from dhardyMarch 18, 2024 16:54
@newpavlov

Copy link
Copy Markdown
MemberAuthor

This PR got a bunch of unrelated formatting changes in the edited files, which were introduced automatically by my editor. Later we probably need to fix formatting for the whole project and add rustfmt check to CI.

@dhardy

Copy link
Copy Markdown
Member

Later we probably need to fix formatting for the whole project and add rustfmt check to CI.

Yes; I was thinking try to resolve most PRs first. But we could also just go ahead...

Comment threadrand_chacha/src/chacha.rs Outdated
Comment threadrand_core/src/lib.rs
Comment on lines +215 to +221
/// A marker trait used to indicate that an [`RngCore`] implementation is
/// supposed to never return errors from the [`RngCore::try_fill_bytes`] method
/// and never panic on unwrapping [`Error`] while calling other methods.
///
/// This trait is usually implemented by PRNGs, as opposed to OS, hardware,
/// and periodically-reseeded RNGs, which may fail with IO errors.
pub trait InfallibleRng: RngCore {}

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.

Commenting just for visibility of the significant addition.

It falls into the same trap as std::iter::TrustedLen in that it promises something about another trait.

I think I'm okay with this, but worth thinking about / getting more input on.

@newpavlovnewpavlovMar 22, 2024

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 thought about different alternatives and it looks like it's the simplest option. Plus, we already have the CryptoRng trait.

One potential option is to make error an associated type (and CryptoRng may become associated bool constant). This way we could use Infallible by default. But without trait aliases it would be significantly less ergonomic to work with. Here is a draft of how it could look in future: playground.

@dhardydhardyMar 22, 2024

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.

Adding associated types + consts to RngCore changes the meaning on every existing usage as a generic bound.

For "crypto grade", I prefer the trait-inheritance model. After all, every CryptoRng is also a valid RNG. Also, can't have CRYPTO_STRONG default to true on all impls.

For infallibility, we'd at least need a bound on that error type: Error: std::error::Error or Error: Into<Something> where Something is a summarized RNG error (NotInitialized, EndOfSequence, IOError, MissingHardwareDevice, ???).

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.

every CryptoRng is also a valid RNG.

Yes, and? I don't see why the associated constant would be at odds with it. "Cryptographically strong" is a binary property of RNG, which can be modeled perfectly by an associated bool constant.

Also, can't have CRYPTO_STRONG default to true on all impls.

Yes, it should've been false in my example.

For infallibility, we'd at least need a bound on that error type

Sure. But I think it's an unimportant detail. Without stabilization of at least trait aliases, this approach is, arguably, not practical anyway.

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.

Yes, and?

Only that this case does work well with the trait inheritance model; not every boolean property does.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

I've cleaned up the formatting changes.

@dhardy

dhardy commented Mar 22, 2024

Copy link
Copy Markdown
Member

Also, if @ctz doesn't appreciate the design of RngCore, he's not the only one. It's a compromise that I don't think anyone likes. There's a tracker of some suggestions here: #1261.

This PR adds something, yes, but is a more fundamental revision a better option?

@dhardy

dhardy commented Mar 22, 2024

Copy link
Copy Markdown
Member

There is a much simpler alternative to this PR: require that all RngCore impls are infallible (or at least document possible panics).

Implication: we should drop OsRng. Since we no longer use this for seeding, I am not aware of any good reason to keep this. (We already removed ReadRng.)

We can also drop try_fill_bytes and all the stuff about converting between fallible and infallible cases.

Am I missing anything important?

@newpavlov

newpavlov commented Mar 22, 2024

Copy link
Copy Markdown
MemberAuthor

I am open to a more global rework (e.g. it may be worth to remove BlockRng stuff and replace it with helper macros/functions). But I think it's better to do in a separate PR after merging this one, since it's not given that we will be able to finalize it for v0.9 release cycle.

There is a much simpler alternative to this PR: require that all RngCore impls are infallible (or at least document possible panics).

In my opinion, it's tantamount to sweeping the problem under the rug.

IO-based RNGs such as OsRng or hardware-based RNGs (not an unusual thing with cryptographic applications) can fail as any other IO. It's a simple truth of life. Imagine someone has misconfigured, or forgot to plug-in a HW RNG. It's better for a cryptographic application/library to return a sensible error, instead of unconditionally panicking outright. Even PRNGs may fail in some cases, e.g. ChaCha-based RNGs may return error on detected looping, which may happen in practice in the presence of seeking.

As for OsRng, it can be a preferred way of generating sensitive information such as cryptographic keys, especially considering that ThreadRng does not implement any protection against exposed state. You may say "then use getrandom directly", but it would be less flexible, e.g. we would not be able to use PRNGs for reproducible testing of such methods.

@dhardy

Copy link
Copy Markdown
Member

You are right that such questions are beyond the scope of this PR, however we should at least determine whether we actually want trait InfallibleRng before merging this. Right, new issue then.

@dhardydhardy mentioned this pull request Mar 23, 2024
@newpavlov

Copy link
Copy Markdown
MemberAuthor

Closing in favor of #1424.

@newpavlov
newpavlov deleted the infallible_rng branch April 1, 2024 16:40
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

@newpavlov@dhardy