Skip to content

Rework CryptoRng - #1273

Merged
dhardy merged 1 commit into
masterfrom
crypto_rework
Feb 20, 2023
Merged

Rework CryptoRng#1273
dhardy merged 1 commit into
masterfrom
crypto_rework

Conversation

@newpavlov

@newpavlovnewpavlov commented Dec 6, 2022

Copy link
Copy Markdown
Member

This PR introduces the CryptoBlockRng marker trait. It's used instead of CryptoRng on block RNGs, which allows us to mark CryptoRng as a subtrait of RngCore and makes the CryptoRngCore trait redundant.

Additionally, try_fill_bytes is moved to CryptoRng and renamed to crypto_fill_bytes. The rationale here is that error checks for potential RNG failures are practically exclusive to cryptographic code.

Unfortunately, this PR also contains a bunch of formatting changes introduced by cargo fmt. I think it could be worth to include formatting check into our CI to prevent such changes in future.

cc @tarcieri

@newpavlov
newpavlov requested a review from dhardyDecember 6, 2022 08:08
@newpavlovnewpavlov added the B-API Breakage: API label Dec 6, 2022
@dhardy

Copy link
Copy Markdown
Member

Unfortunately, this PR also contains a bunch of formatting changes introduced by cargo fmt. I think it could be worth to include formatting check into our CI to prevent such changes in future.

Er, yes. Please either remove formatting changes to old code or run rustfmtfirst, commit, and rebase on top of that. I.e. isolate your changes from formatting.

We should use rustfmt everywhere, but we don't. Last time I looked at this, it was rejected on grounds of too much poor formatting, and that in theory rustfmt 2.0 was coming at some point. I haven't followed everything, but I don't think 2.0 is happening any time soon, meanwhile almost every major Rust project now uses it so we should too. The main issue is that we have a lot of open PRs which would conflict.

Is it a major pain to remove formatting-only changes from this PR in the mean-time? (I usually use git checkout -p --.)


As for the actual purpose of this PR — these issues would appear related. Didn't we already discuss this?

@newpavlov

Copy link
Copy Markdown
MemberAuthor

Please either remove formatting changes to old code or run rustfmt first, commit, and rebase on top of that. I.e. isolate your changes from formatting.

Yeah, I will do it somewhat later. I executed cargo fmt automatically and only during commit creation found the size of formatting changes. :( Before that, I hope to get initial reaction regarding the drafted approach, whether its worthwhile or not.

As for the actual purpose of this PR — these issues would appear related. Didn't we already discuss this?

I think I floated the drafted idea somewhere in issues. CryptoRngCore was designed with backward compatibility in mind, while changes in this PR are breaking ones.

@dhardy

Copy link
Copy Markdown
Member

Summary of this PR:

pubtraitRngCore{// keeps methods next_u32, next_u64, fill_bytes// loses try_fill_bytes}// New bound on RngCore:pubtraitCryptoRng:RngCore{fncrypto_fill_bytes(&mutself,dest:&mut[u8]) -> Result<(),Error>{/* default impl */}}// New:pubtraitCryptoBlockRng:BlockRngCore{}// Removed:// pub trait CryptoRngCore: CryptoRng + RngCore { .. }

My thoughts, somewhat detached from the above...

In the long term, do we even keep BlockRng? Given the suggestions in #1261, especially yours regarding generic_const_exprs. Well, probably yes to provide a "next int please" API over a block generator.

Given that, maybe we should make larger changes:

// A revised BlockRngCore (maybe renamed or maybe not):pubtraitByteRng{constLEN:usize;fngenerate(&mutself) -> Result<[u8;Self::LEN]>;}// A cut-down RngCore (maybe we should keep the old name):pubtraitNumRng{fnnext_u32(&mutself) -> u32;fnnext_u64(&mutself) -> u64;}pubstructBlockRng<R:ByteRng>(..);impl<R: ..>NumRngforByteRng<R>{}

Except, it would be nice to know at compile time the generation size of NumRng, hence we could add const NATIVE_BITS: u32 or even use a type parameter NumRng<N>. Except this doesn't work for users needing an object-safe trait which means we would need a separate object-safe trait and blanket impls. Which (surprise!) means we need Rust's number one missing feature, Specialization (or maybe negative trait bounds).

Maybe we should hold off on such a re-design until rand_core 2.0 considering neither required feature is likely to make it into Rust in the near future? Or we could use a cut-down version of the above (without LEN) now, perhaps.

Either way, this would mean:

  • a ByteRng does not implement NumRng / Rng directly; so type StdRng = BlockRng<ChaCha12>;
  • NumRng does not provide for byte-filling; users must use Rng::fill
  • ... except that would be very inefficient for block-RNGs without using Specialization to impl Rng::fill, so maybe we need to keep RngCore::fill_bytes as is
  • ChaChaXRng (the RngCore implementor, not the core) has a few methods directly implemented on it so maybe we shouldn't only export the BlockRngCore implementor from the crate

But this is mostly orthogonal to your changes. So:

  • I like pub trait CryptoRng: RngCore
  • I don't really like the name crypto_fill_bytes, and do we even need it — can those who want it directly use the BlockRngCore? Maybe that doesn't work.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

See #1261 (comment) for reply to the middle part of the previous comment.

I don't really like the name crypto_fill_bytes, and do we even need it — can those who want it directly use the BlockRngCore?

I don't think the name is good either, so I am open to changing it. BlockRngCore is irrelevant here, the method is about making error handling possible for OsRng and hardware RNGs, which are usually used in cryptographic code.

But I am not sure whether it's a good idea to move try_fill_bytes to CryptoRng. While it simplifies some things, it introduces issues around error handling, e.g. in the io::Read compatibility layer. IIUC try_fill_bytes should be accessible for &mut dyn CryptoRng. So I probably will revert this change.

@dhardy

Copy link
Copy Markdown
Member

which are usually used in cryptographic code

Do these uses even want a RngCore or just a byte-generator? Of course it is useful having the buffering logic that BlockRng provides, but possibly a simpler version would suffice without the next_u* methods.

whether it's a good idea to move try_fill_bytes ... e.g. in the io::Read compatibility.

The ReadRng adapter is deprecated, so I see no worry there. However I don't see any reason for this change either.

I don't think the name is good either

Nor is the original, but it seems we don't have a good reason to change it.

If we want to simplify, we could probably remove RngCore::fill_bytes... at risk of doing more permutation than simplification (i.e. probably a needless breaking change).

@newpavlov

newpavlov commented Jan 6, 2023

Copy link
Copy Markdown
MemberAuthor

@dhardy
Can you remind me why rand_chacha and ReseedingRng use newtype wrappers instead of type aliases? Is it only because rustdoc does not show trait impls for type aliases?

If such type aliases is the "recommended way" of doing things, then removal of the BlockRngCore trait could be warranted despite some amount of buffering boilerplate in implementation crates. But, personally, I would prefer if we simply used type aliases.

@dhardy

Copy link
Copy Markdown
Member

I think the new-type wrappers are used (a) to hide the inner type (thus not an API breaking change to replace it) and (b) to allow custom methods on that type. Without re-examining I don't know how important these are (probably only (b) is applicable to ChaCha).

I don't follow why this justifies removing BlockRngCore; that's an impl target used by BlockRng.

Thanks for cleaning up the PR.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

I don't follow why this justifies removing BlockRngCore; that's an impl target used by BlockRng.

It does not look like we have users of BlockRngCore outside of implementation crates. Since they introduce their own opaque newtypes, we can replace BlockRngCore and the wrapper types with a bunch of helper functions. I think it will result in a bit simpler rand_core and implementation crates.

@dhardydhardy left a comment

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.

I wish we'd named RngCore as Rng instead, and what is now Rng as RngExt. Is it worth renaming now? It would make the names noted below more consistent, while also being better for common usage (where people use bounds like R: RngCore).

Besides this is the idea that maybe we should move one or some RngCore methods to a different trait. Most users don't need try_fill_bytesandnext_u32. You mentioned moving try_fill_bytes to CryptoRng and we seem to have rejected that idea. If we wanted a separate ByteRng for try_fill_bytes, we'd then need pub trait CryptoByteRng: ByteRng {} too.

Anyway, I'll provisionally approve this PR. If I don't, it might just get stuck.

/// supposed to be cryptographically secure.
///
/// See [`CryptoRng`][crate::CryptoRng] docs for more information.
pub trait CryptoBlockRng: BlockRngCore { }

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.

The naming seems off: CryptoRng: RngCore, CryptoBlockRng: BlockRngCore.

@tarcieri

Copy link
Copy Markdown
Contributor

I wish we'd named RngCore as Rng instead, and what is now Rng as RngExt. Is it worth renaming now?

Sounds great to me!

@dhardy

Copy link
Copy Markdown
Member

@newpavlov this is still marked as a draft, but I think it's ready to be merged? I already approved.

I'm also happy to rename RngCoreRng, RngRngExt. But that should be a new PR.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-APIBreakage: API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@newpavlov@dhardy@tarcieri
, '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" + '
Rework CryptoRng by newpavlov · Pull Request #1273 · rust-random/rand · GitHub
Skip to content

Rework CryptoRng - #1273

Merged
dhardy merged 1 commit into
masterfrom
crypto_rework
Feb 20, 2023
Merged

Rework CryptoRng#1273
dhardy merged 1 commit into
masterfrom
crypto_rework

Conversation

@newpavlov

@newpavlovnewpavlov commented Dec 6, 2022

Copy link
Copy Markdown
Member

This PR introduces the CryptoBlockRng marker trait. It's used instead of CryptoRng on block RNGs, which allows us to mark CryptoRng as a subtrait of RngCore and makes the CryptoRngCore trait redundant.

Additionally, try_fill_bytes is moved to CryptoRng and renamed to crypto_fill_bytes. The rationale here is that error checks for potential RNG failures are practically exclusive to cryptographic code.

Unfortunately, this PR also contains a bunch of formatting changes introduced by cargo fmt. I think it could be worth to include formatting check into our CI to prevent such changes in future.

cc @tarcieri

@newpavlov
newpavlov requested a review from dhardyDecember 6, 2022 08:08
@newpavlovnewpavlov added the B-API Breakage: API label Dec 6, 2022
@dhardy

Copy link
Copy Markdown
Member

Unfortunately, this PR also contains a bunch of formatting changes introduced by cargo fmt. I think it could be worth to include formatting check into our CI to prevent such changes in future.

Er, yes. Please either remove formatting changes to old code or run rustfmtfirst, commit, and rebase on top of that. I.e. isolate your changes from formatting.

We should use rustfmt everywhere, but we don't. Last time I looked at this, it was rejected on grounds of too much poor formatting, and that in theory rustfmt 2.0 was coming at some point. I haven't followed everything, but I don't think 2.0 is happening any time soon, meanwhile almost every major Rust project now uses it so we should too. The main issue is that we have a lot of open PRs which would conflict.

Is it a major pain to remove formatting-only changes from this PR in the mean-time? (I usually use git checkout -p --.)


As for the actual purpose of this PR — these issues would appear related. Didn't we already discuss this?

@newpavlov

Copy link
Copy Markdown
MemberAuthor

Please either remove formatting changes to old code or run rustfmt first, commit, and rebase on top of that. I.e. isolate your changes from formatting.

Yeah, I will do it somewhat later. I executed cargo fmt automatically and only during commit creation found the size of formatting changes. :( Before that, I hope to get initial reaction regarding the drafted approach, whether its worthwhile or not.

As for the actual purpose of this PR — these issues would appear related. Didn't we already discuss this?

I think I floated the drafted idea somewhere in issues. CryptoRngCore was designed with backward compatibility in mind, while changes in this PR are breaking ones.

@dhardy

Copy link
Copy Markdown
Member

Summary of this PR:

pubtraitRngCore{// keeps methods next_u32, next_u64, fill_bytes// loses try_fill_bytes}// New bound on RngCore:pubtraitCryptoRng:RngCore{fncrypto_fill_bytes(&mutself,dest:&mut[u8]) -> Result<(),Error>{/* default impl */}}// New:pubtraitCryptoBlockRng:BlockRngCore{}// Removed:// pub trait CryptoRngCore: CryptoRng + RngCore { .. }

My thoughts, somewhat detached from the above...

In the long term, do we even keep BlockRng? Given the suggestions in #1261, especially yours regarding generic_const_exprs. Well, probably yes to provide a "next int please" API over a block generator.

Given that, maybe we should make larger changes:

// A revised BlockRngCore (maybe renamed or maybe not):pubtraitByteRng{constLEN:usize;fngenerate(&mutself) -> Result<[u8;Self::LEN]>;}// A cut-down RngCore (maybe we should keep the old name):pubtraitNumRng{fnnext_u32(&mutself) -> u32;fnnext_u64(&mutself) -> u64;}pubstructBlockRng<R:ByteRng>(..);impl<R: ..>NumRngforByteRng<R>{}

Except, it would be nice to know at compile time the generation size of NumRng, hence we could add const NATIVE_BITS: u32 or even use a type parameter NumRng<N>. Except this doesn't work for users needing an object-safe trait which means we would need a separate object-safe trait and blanket impls. Which (surprise!) means we need Rust's number one missing feature, Specialization (or maybe negative trait bounds).

Maybe we should hold off on such a re-design until rand_core 2.0 considering neither required feature is likely to make it into Rust in the near future? Or we could use a cut-down version of the above (without LEN) now, perhaps.

Either way, this would mean:

  • a ByteRng does not implement NumRng / Rng directly; so type StdRng = BlockRng<ChaCha12>;
  • NumRng does not provide for byte-filling; users must use Rng::fill
  • ... except that would be very inefficient for block-RNGs without using Specialization to impl Rng::fill, so maybe we need to keep RngCore::fill_bytes as is
  • ChaChaXRng (the RngCore implementor, not the core) has a few methods directly implemented on it so maybe we shouldn't only export the BlockRngCore implementor from the crate

But this is mostly orthogonal to your changes. So:

  • I like pub trait CryptoRng: RngCore
  • I don't really like the name crypto_fill_bytes, and do we even need it — can those who want it directly use the BlockRngCore? Maybe that doesn't work.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

See #1261 (comment) for reply to the middle part of the previous comment.

I don't really like the name crypto_fill_bytes, and do we even need it — can those who want it directly use the BlockRngCore?

I don't think the name is good either, so I am open to changing it. BlockRngCore is irrelevant here, the method is about making error handling possible for OsRng and hardware RNGs, which are usually used in cryptographic code.

But I am not sure whether it's a good idea to move try_fill_bytes to CryptoRng. While it simplifies some things, it introduces issues around error handling, e.g. in the io::Read compatibility layer. IIUC try_fill_bytes should be accessible for &mut dyn CryptoRng. So I probably will revert this change.

@dhardy

Copy link
Copy Markdown
Member

which are usually used in cryptographic code

Do these uses even want a RngCore or just a byte-generator? Of course it is useful having the buffering logic that BlockRng provides, but possibly a simpler version would suffice without the next_u* methods.

whether it's a good idea to move try_fill_bytes ... e.g. in the io::Read compatibility.

The ReadRng adapter is deprecated, so I see no worry there. However I don't see any reason for this change either.

I don't think the name is good either

Nor is the original, but it seems we don't have a good reason to change it.

If we want to simplify, we could probably remove RngCore::fill_bytes... at risk of doing more permutation than simplification (i.e. probably a needless breaking change).

@newpavlov

newpavlov commented Jan 6, 2023

Copy link
Copy Markdown
MemberAuthor

@dhardy
Can you remind me why rand_chacha and ReseedingRng use newtype wrappers instead of type aliases? Is it only because rustdoc does not show trait impls for type aliases?

If such type aliases is the "recommended way" of doing things, then removal of the BlockRngCore trait could be warranted despite some amount of buffering boilerplate in implementation crates. But, personally, I would prefer if we simply used type aliases.

@dhardy

Copy link
Copy Markdown
Member

I think the new-type wrappers are used (a) to hide the inner type (thus not an API breaking change to replace it) and (b) to allow custom methods on that type. Without re-examining I don't know how important these are (probably only (b) is applicable to ChaCha).

I don't follow why this justifies removing BlockRngCore; that's an impl target used by BlockRng.

Thanks for cleaning up the PR.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

I don't follow why this justifies removing BlockRngCore; that's an impl target used by BlockRng.

It does not look like we have users of BlockRngCore outside of implementation crates. Since they introduce their own opaque newtypes, we can replace BlockRngCore and the wrapper types with a bunch of helper functions. I think it will result in a bit simpler rand_core and implementation crates.

@dhardydhardy left a comment

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.

I wish we'd named RngCore as Rng instead, and what is now Rng as RngExt. Is it worth renaming now? It would make the names noted below more consistent, while also being better for common usage (where people use bounds like R: RngCore).

Besides this is the idea that maybe we should move one or some RngCore methods to a different trait. Most users don't need try_fill_bytesandnext_u32. You mentioned moving try_fill_bytes to CryptoRng and we seem to have rejected that idea. If we wanted a separate ByteRng for try_fill_bytes, we'd then need pub trait CryptoByteRng: ByteRng {} too.

Anyway, I'll provisionally approve this PR. If I don't, it might just get stuck.

/// supposed to be cryptographically secure.
///
/// See [`CryptoRng`][crate::CryptoRng] docs for more information.
pub trait CryptoBlockRng: BlockRngCore { }

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.

The naming seems off: CryptoRng: RngCore, CryptoBlockRng: BlockRngCore.

@tarcieri

Copy link
Copy Markdown
Contributor

I wish we'd named RngCore as Rng instead, and what is now Rng as RngExt. Is it worth renaming now?

Sounds great to me!

@dhardy

Copy link
Copy Markdown
Member

@newpavlov this is still marked as a draft, but I think it's ready to be merged? I already approved.

I'm also happy to rename RngCoreRng, RngRngExt. But that should be a new PR.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-APIBreakage: API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@newpavlov@dhardy@tarcieri
, '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('^' + ".*" + ' Rework CryptoRng by newpavlov · Pull Request #1273 · rust-random/rand · GitHub
Skip to content

Rework CryptoRng - #1273

Merged
dhardy merged 1 commit into
masterfrom
crypto_rework
Feb 20, 2023
Merged

Rework CryptoRng#1273
dhardy merged 1 commit into
masterfrom
crypto_rework

Conversation

@newpavlov

@newpavlovnewpavlov commented Dec 6, 2022

Copy link
Copy Markdown
Member

This PR introduces the CryptoBlockRng marker trait. It's used instead of CryptoRng on block RNGs, which allows us to mark CryptoRng as a subtrait of RngCore and makes the CryptoRngCore trait redundant.

Additionally, try_fill_bytes is moved to CryptoRng and renamed to crypto_fill_bytes. The rationale here is that error checks for potential RNG failures are practically exclusive to cryptographic code.

Unfortunately, this PR also contains a bunch of formatting changes introduced by cargo fmt. I think it could be worth to include formatting check into our CI to prevent such changes in future.

cc @tarcieri

@newpavlov
newpavlov requested a review from dhardyDecember 6, 2022 08:08
@newpavlovnewpavlov added the B-API Breakage: API label Dec 6, 2022
@dhardy

Copy link
Copy Markdown
Member

Unfortunately, this PR also contains a bunch of formatting changes introduced by cargo fmt. I think it could be worth to include formatting check into our CI to prevent such changes in future.

Er, yes. Please either remove formatting changes to old code or run rustfmtfirst, commit, and rebase on top of that. I.e. isolate your changes from formatting.

We should use rustfmt everywhere, but we don't. Last time I looked at this, it was rejected on grounds of too much poor formatting, and that in theory rustfmt 2.0 was coming at some point. I haven't followed everything, but I don't think 2.0 is happening any time soon, meanwhile almost every major Rust project now uses it so we should too. The main issue is that we have a lot of open PRs which would conflict.

Is it a major pain to remove formatting-only changes from this PR in the mean-time? (I usually use git checkout -p --.)


As for the actual purpose of this PR — these issues would appear related. Didn't we already discuss this?

@newpavlov

Copy link
Copy Markdown
MemberAuthor

Please either remove formatting changes to old code or run rustfmt first, commit, and rebase on top of that. I.e. isolate your changes from formatting.

Yeah, I will do it somewhat later. I executed cargo fmt automatically and only during commit creation found the size of formatting changes. :( Before that, I hope to get initial reaction regarding the drafted approach, whether its worthwhile or not.

As for the actual purpose of this PR — these issues would appear related. Didn't we already discuss this?

I think I floated the drafted idea somewhere in issues. CryptoRngCore was designed with backward compatibility in mind, while changes in this PR are breaking ones.

@dhardy

Copy link
Copy Markdown
Member

Summary of this PR:

pubtraitRngCore{// keeps methods next_u32, next_u64, fill_bytes// loses try_fill_bytes}// New bound on RngCore:pubtraitCryptoRng:RngCore{fncrypto_fill_bytes(&mutself,dest:&mut[u8]) -> Result<(),Error>{/* default impl */}}// New:pubtraitCryptoBlockRng:BlockRngCore{}// Removed:// pub trait CryptoRngCore: CryptoRng + RngCore { .. }

My thoughts, somewhat detached from the above...

In the long term, do we even keep BlockRng? Given the suggestions in #1261, especially yours regarding generic_const_exprs. Well, probably yes to provide a "next int please" API over a block generator.

Given that, maybe we should make larger changes:

// A revised BlockRngCore (maybe renamed or maybe not):pubtraitByteRng{constLEN:usize;fngenerate(&mutself) -> Result<[u8;Self::LEN]>;}// A cut-down RngCore (maybe we should keep the old name):pubtraitNumRng{fnnext_u32(&mutself) -> u32;fnnext_u64(&mutself) -> u64;}pubstructBlockRng<R:ByteRng>(..);impl<R: ..>NumRngforByteRng<R>{}

Except, it would be nice to know at compile time the generation size of NumRng, hence we could add const NATIVE_BITS: u32 or even use a type parameter NumRng<N>. Except this doesn't work for users needing an object-safe trait which means we would need a separate object-safe trait and blanket impls. Which (surprise!) means we need Rust's number one missing feature, Specialization (or maybe negative trait bounds).

Maybe we should hold off on such a re-design until rand_core 2.0 considering neither required feature is likely to make it into Rust in the near future? Or we could use a cut-down version of the above (without LEN) now, perhaps.

Either way, this would mean:

  • a ByteRng does not implement NumRng / Rng directly; so type StdRng = BlockRng<ChaCha12>;
  • NumRng does not provide for byte-filling; users must use Rng::fill
  • ... except that would be very inefficient for block-RNGs without using Specialization to impl Rng::fill, so maybe we need to keep RngCore::fill_bytes as is
  • ChaChaXRng (the RngCore implementor, not the core) has a few methods directly implemented on it so maybe we shouldn't only export the BlockRngCore implementor from the crate

But this is mostly orthogonal to your changes. So:

  • I like pub trait CryptoRng: RngCore
  • I don't really like the name crypto_fill_bytes, and do we even need it — can those who want it directly use the BlockRngCore? Maybe that doesn't work.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

See #1261 (comment) for reply to the middle part of the previous comment.

I don't really like the name crypto_fill_bytes, and do we even need it — can those who want it directly use the BlockRngCore?

I don't think the name is good either, so I am open to changing it. BlockRngCore is irrelevant here, the method is about making error handling possible for OsRng and hardware RNGs, which are usually used in cryptographic code.

But I am not sure whether it's a good idea to move try_fill_bytes to CryptoRng. While it simplifies some things, it introduces issues around error handling, e.g. in the io::Read compatibility layer. IIUC try_fill_bytes should be accessible for &mut dyn CryptoRng. So I probably will revert this change.

@dhardy

Copy link
Copy Markdown
Member

which are usually used in cryptographic code

Do these uses even want a RngCore or just a byte-generator? Of course it is useful having the buffering logic that BlockRng provides, but possibly a simpler version would suffice without the next_u* methods.

whether it's a good idea to move try_fill_bytes ... e.g. in the io::Read compatibility.

The ReadRng adapter is deprecated, so I see no worry there. However I don't see any reason for this change either.

I don't think the name is good either

Nor is the original, but it seems we don't have a good reason to change it.

If we want to simplify, we could probably remove RngCore::fill_bytes... at risk of doing more permutation than simplification (i.e. probably a needless breaking change).

@newpavlov

newpavlov commented Jan 6, 2023

Copy link
Copy Markdown
MemberAuthor

@dhardy
Can you remind me why rand_chacha and ReseedingRng use newtype wrappers instead of type aliases? Is it only because rustdoc does not show trait impls for type aliases?

If such type aliases is the "recommended way" of doing things, then removal of the BlockRngCore trait could be warranted despite some amount of buffering boilerplate in implementation crates. But, personally, I would prefer if we simply used type aliases.

@dhardy

Copy link
Copy Markdown
Member

I think the new-type wrappers are used (a) to hide the inner type (thus not an API breaking change to replace it) and (b) to allow custom methods on that type. Without re-examining I don't know how important these are (probably only (b) is applicable to ChaCha).

I don't follow why this justifies removing BlockRngCore; that's an impl target used by BlockRng.

Thanks for cleaning up the PR.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

I don't follow why this justifies removing BlockRngCore; that's an impl target used by BlockRng.

It does not look like we have users of BlockRngCore outside of implementation crates. Since they introduce their own opaque newtypes, we can replace BlockRngCore and the wrapper types with a bunch of helper functions. I think it will result in a bit simpler rand_core and implementation crates.

@dhardydhardy left a comment

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.

I wish we'd named RngCore as Rng instead, and what is now Rng as RngExt. Is it worth renaming now? It would make the names noted below more consistent, while also being better for common usage (where people use bounds like R: RngCore).

Besides this is the idea that maybe we should move one or some RngCore methods to a different trait. Most users don't need try_fill_bytesandnext_u32. You mentioned moving try_fill_bytes to CryptoRng and we seem to have rejected that idea. If we wanted a separate ByteRng for try_fill_bytes, we'd then need pub trait CryptoByteRng: ByteRng {} too.

Anyway, I'll provisionally approve this PR. If I don't, it might just get stuck.

/// supposed to be cryptographically secure.
///
/// See [`CryptoRng`][crate::CryptoRng] docs for more information.
pub trait CryptoBlockRng: BlockRngCore { }

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.

The naming seems off: CryptoRng: RngCore, CryptoBlockRng: BlockRngCore.

@tarcieri

Copy link
Copy Markdown
Contributor

I wish we'd named RngCore as Rng instead, and what is now Rng as RngExt. Is it worth renaming now?

Sounds great to me!

@dhardy

Copy link
Copy Markdown
Member

@newpavlov this is still marked as a draft, but I think it's ready to be merged? I already approved.

I'm also happy to rename RngCoreRng, RngRngExt. But that should be a new PR.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-APIBreakage: API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@newpavlov@dhardy@tarcieri
, '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('^' + ".*" + ' Rework CryptoRng by newpavlov · Pull Request #1273 · rust-random/rand · GitHub
Skip to content

Rework CryptoRng - #1273

Merged
dhardy merged 1 commit into
masterfrom
crypto_rework
Feb 20, 2023
Merged

Rework CryptoRng#1273
dhardy merged 1 commit into
masterfrom
crypto_rework

Conversation

@newpavlov

@newpavlovnewpavlov commented Dec 6, 2022

Copy link
Copy Markdown
Member

This PR introduces the CryptoBlockRng marker trait. It's used instead of CryptoRng on block RNGs, which allows us to mark CryptoRng as a subtrait of RngCore and makes the CryptoRngCore trait redundant.

Additionally, try_fill_bytes is moved to CryptoRng and renamed to crypto_fill_bytes. The rationale here is that error checks for potential RNG failures are practically exclusive to cryptographic code.

Unfortunately, this PR also contains a bunch of formatting changes introduced by cargo fmt. I think it could be worth to include formatting check into our CI to prevent such changes in future.

cc @tarcieri

@newpavlov
newpavlov requested a review from dhardyDecember 6, 2022 08:08
@newpavlovnewpavlov added the B-API Breakage: API label Dec 6, 2022
@dhardy

Copy link
Copy Markdown
Member

Unfortunately, this PR also contains a bunch of formatting changes introduced by cargo fmt. I think it could be worth to include formatting check into our CI to prevent such changes in future.

Er, yes. Please either remove formatting changes to old code or run rustfmtfirst, commit, and rebase on top of that. I.e. isolate your changes from formatting.

We should use rustfmt everywhere, but we don't. Last time I looked at this, it was rejected on grounds of too much poor formatting, and that in theory rustfmt 2.0 was coming at some point. I haven't followed everything, but I don't think 2.0 is happening any time soon, meanwhile almost every major Rust project now uses it so we should too. The main issue is that we have a lot of open PRs which would conflict.

Is it a major pain to remove formatting-only changes from this PR in the mean-time? (I usually use git checkout -p --.)


As for the actual purpose of this PR — these issues would appear related. Didn't we already discuss this?

@newpavlov

Copy link
Copy Markdown
MemberAuthor

Please either remove formatting changes to old code or run rustfmt first, commit, and rebase on top of that. I.e. isolate your changes from formatting.

Yeah, I will do it somewhat later. I executed cargo fmt automatically and only during commit creation found the size of formatting changes. :( Before that, I hope to get initial reaction regarding the drafted approach, whether its worthwhile or not.

As for the actual purpose of this PR — these issues would appear related. Didn't we already discuss this?

I think I floated the drafted idea somewhere in issues. CryptoRngCore was designed with backward compatibility in mind, while changes in this PR are breaking ones.

@dhardy

Copy link
Copy Markdown
Member

Summary of this PR:

pubtraitRngCore{// keeps methods next_u32, next_u64, fill_bytes// loses try_fill_bytes}// New bound on RngCore:pubtraitCryptoRng:RngCore{fncrypto_fill_bytes(&mutself,dest:&mut[u8]) -> Result<(),Error>{/* default impl */}}// New:pubtraitCryptoBlockRng:BlockRngCore{}// Removed:// pub trait CryptoRngCore: CryptoRng + RngCore { .. }

My thoughts, somewhat detached from the above...

In the long term, do we even keep BlockRng? Given the suggestions in #1261, especially yours regarding generic_const_exprs. Well, probably yes to provide a "next int please" API over a block generator.

Given that, maybe we should make larger changes:

// A revised BlockRngCore (maybe renamed or maybe not):pubtraitByteRng{constLEN:usize;fngenerate(&mutself) -> Result<[u8;Self::LEN]>;}// A cut-down RngCore (maybe we should keep the old name):pubtraitNumRng{fnnext_u32(&mutself) -> u32;fnnext_u64(&mutself) -> u64;}pubstructBlockRng<R:ByteRng>(..);impl<R: ..>NumRngforByteRng<R>{}

Except, it would be nice to know at compile time the generation size of NumRng, hence we could add const NATIVE_BITS: u32 or even use a type parameter NumRng<N>. Except this doesn't work for users needing an object-safe trait which means we would need a separate object-safe trait and blanket impls. Which (surprise!) means we need Rust's number one missing feature, Specialization (or maybe negative trait bounds).

Maybe we should hold off on such a re-design until rand_core 2.0 considering neither required feature is likely to make it into Rust in the near future? Or we could use a cut-down version of the above (without LEN) now, perhaps.

Either way, this would mean:

  • a ByteRng does not implement NumRng / Rng directly; so type StdRng = BlockRng<ChaCha12>;
  • NumRng does not provide for byte-filling; users must use Rng::fill
  • ... except that would be very inefficient for block-RNGs without using Specialization to impl Rng::fill, so maybe we need to keep RngCore::fill_bytes as is
  • ChaChaXRng (the RngCore implementor, not the core) has a few methods directly implemented on it so maybe we shouldn't only export the BlockRngCore implementor from the crate

But this is mostly orthogonal to your changes. So:

  • I like pub trait CryptoRng: RngCore
  • I don't really like the name crypto_fill_bytes, and do we even need it — can those who want it directly use the BlockRngCore? Maybe that doesn't work.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

See #1261 (comment) for reply to the middle part of the previous comment.

I don't really like the name crypto_fill_bytes, and do we even need it — can those who want it directly use the BlockRngCore?

I don't think the name is good either, so I am open to changing it. BlockRngCore is irrelevant here, the method is about making error handling possible for OsRng and hardware RNGs, which are usually used in cryptographic code.

But I am not sure whether it's a good idea to move try_fill_bytes to CryptoRng. While it simplifies some things, it introduces issues around error handling, e.g. in the io::Read compatibility layer. IIUC try_fill_bytes should be accessible for &mut dyn CryptoRng. So I probably will revert this change.

@dhardy

Copy link
Copy Markdown
Member

which are usually used in cryptographic code

Do these uses even want a RngCore or just a byte-generator? Of course it is useful having the buffering logic that BlockRng provides, but possibly a simpler version would suffice without the next_u* methods.

whether it's a good idea to move try_fill_bytes ... e.g. in the io::Read compatibility.

The ReadRng adapter is deprecated, so I see no worry there. However I don't see any reason for this change either.

I don't think the name is good either

Nor is the original, but it seems we don't have a good reason to change it.

If we want to simplify, we could probably remove RngCore::fill_bytes... at risk of doing more permutation than simplification (i.e. probably a needless breaking change).

@newpavlov

newpavlov commented Jan 6, 2023

Copy link
Copy Markdown
MemberAuthor

@dhardy
Can you remind me why rand_chacha and ReseedingRng use newtype wrappers instead of type aliases? Is it only because rustdoc does not show trait impls for type aliases?

If such type aliases is the "recommended way" of doing things, then removal of the BlockRngCore trait could be warranted despite some amount of buffering boilerplate in implementation crates. But, personally, I would prefer if we simply used type aliases.

@dhardy

Copy link
Copy Markdown
Member

I think the new-type wrappers are used (a) to hide the inner type (thus not an API breaking change to replace it) and (b) to allow custom methods on that type. Without re-examining I don't know how important these are (probably only (b) is applicable to ChaCha).

I don't follow why this justifies removing BlockRngCore; that's an impl target used by BlockRng.

Thanks for cleaning up the PR.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

I don't follow why this justifies removing BlockRngCore; that's an impl target used by BlockRng.

It does not look like we have users of BlockRngCore outside of implementation crates. Since they introduce their own opaque newtypes, we can replace BlockRngCore and the wrapper types with a bunch of helper functions. I think it will result in a bit simpler rand_core and implementation crates.

@dhardydhardy left a comment

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.

I wish we'd named RngCore as Rng instead, and what is now Rng as RngExt. Is it worth renaming now? It would make the names noted below more consistent, while also being better for common usage (where people use bounds like R: RngCore).

Besides this is the idea that maybe we should move one or some RngCore methods to a different trait. Most users don't need try_fill_bytesandnext_u32. You mentioned moving try_fill_bytes to CryptoRng and we seem to have rejected that idea. If we wanted a separate ByteRng for try_fill_bytes, we'd then need pub trait CryptoByteRng: ByteRng {} too.

Anyway, I'll provisionally approve this PR. If I don't, it might just get stuck.

/// supposed to be cryptographically secure.
///
/// See [`CryptoRng`][crate::CryptoRng] docs for more information.
pub trait CryptoBlockRng: BlockRngCore { }

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.

The naming seems off: CryptoRng: RngCore, CryptoBlockRng: BlockRngCore.

@tarcieri

Copy link
Copy Markdown
Contributor

I wish we'd named RngCore as Rng instead, and what is now Rng as RngExt. Is it worth renaming now?

Sounds great to me!

@dhardy

Copy link
Copy Markdown
Member

@newpavlov this is still marked as a draft, but I think it's ready to be merged? I already approved.

I'm also happy to rename RngCoreRng, RngRngExt. But that should be a new PR.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-APIBreakage: API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@newpavlov@dhardy@tarcieri
, '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" + ' Rework CryptoRng by newpavlov · Pull Request #1273 · rust-random/rand · GitHub
Skip to content

Rework CryptoRng - #1273

Merged
dhardy merged 1 commit into
masterfrom
crypto_rework
Feb 20, 2023
Merged

Rework CryptoRng#1273
dhardy merged 1 commit into
masterfrom
crypto_rework

Conversation

@newpavlov

@newpavlovnewpavlov commented Dec 6, 2022

Copy link
Copy Markdown
Member

This PR introduces the CryptoBlockRng marker trait. It's used instead of CryptoRng on block RNGs, which allows us to mark CryptoRng as a subtrait of RngCore and makes the CryptoRngCore trait redundant.

Additionally, try_fill_bytes is moved to CryptoRng and renamed to crypto_fill_bytes. The rationale here is that error checks for potential RNG failures are practically exclusive to cryptographic code.

Unfortunately, this PR also contains a bunch of formatting changes introduced by cargo fmt. I think it could be worth to include formatting check into our CI to prevent such changes in future.

cc @tarcieri

@newpavlov
newpavlov requested a review from dhardyDecember 6, 2022 08:08
@newpavlovnewpavlov added the B-API Breakage: API label Dec 6, 2022
@dhardy

Copy link
Copy Markdown
Member

Unfortunately, this PR also contains a bunch of formatting changes introduced by cargo fmt. I think it could be worth to include formatting check into our CI to prevent such changes in future.

Er, yes. Please either remove formatting changes to old code or run rustfmtfirst, commit, and rebase on top of that. I.e. isolate your changes from formatting.

We should use rustfmt everywhere, but we don't. Last time I looked at this, it was rejected on grounds of too much poor formatting, and that in theory rustfmt 2.0 was coming at some point. I haven't followed everything, but I don't think 2.0 is happening any time soon, meanwhile almost every major Rust project now uses it so we should too. The main issue is that we have a lot of open PRs which would conflict.

Is it a major pain to remove formatting-only changes from this PR in the mean-time? (I usually use git checkout -p --.)


As for the actual purpose of this PR — these issues would appear related. Didn't we already discuss this?

@newpavlov

Copy link
Copy Markdown
MemberAuthor

Please either remove formatting changes to old code or run rustfmt first, commit, and rebase on top of that. I.e. isolate your changes from formatting.

Yeah, I will do it somewhat later. I executed cargo fmt automatically and only during commit creation found the size of formatting changes. :( Before that, I hope to get initial reaction regarding the drafted approach, whether its worthwhile or not.

As for the actual purpose of this PR — these issues would appear related. Didn't we already discuss this?

I think I floated the drafted idea somewhere in issues. CryptoRngCore was designed with backward compatibility in mind, while changes in this PR are breaking ones.

@dhardy

Copy link
Copy Markdown
Member

Summary of this PR:

pubtraitRngCore{// keeps methods next_u32, next_u64, fill_bytes// loses try_fill_bytes}// New bound on RngCore:pubtraitCryptoRng:RngCore{fncrypto_fill_bytes(&mutself,dest:&mut[u8]) -> Result<(),Error>{/* default impl */}}// New:pubtraitCryptoBlockRng:BlockRngCore{}// Removed:// pub trait CryptoRngCore: CryptoRng + RngCore { .. }

My thoughts, somewhat detached from the above...

In the long term, do we even keep BlockRng? Given the suggestions in #1261, especially yours regarding generic_const_exprs. Well, probably yes to provide a "next int please" API over a block generator.

Given that, maybe we should make larger changes:

// A revised BlockRngCore (maybe renamed or maybe not):pubtraitByteRng{constLEN:usize;fngenerate(&mutself) -> Result<[u8;Self::LEN]>;}// A cut-down RngCore (maybe we should keep the old name):pubtraitNumRng{fnnext_u32(&mutself) -> u32;fnnext_u64(&mutself) -> u64;}pubstructBlockRng<R:ByteRng>(..);impl<R: ..>NumRngforByteRng<R>{}

Except, it would be nice to know at compile time the generation size of NumRng, hence we could add const NATIVE_BITS: u32 or even use a type parameter NumRng<N>. Except this doesn't work for users needing an object-safe trait which means we would need a separate object-safe trait and blanket impls. Which (surprise!) means we need Rust's number one missing feature, Specialization (or maybe negative trait bounds).

Maybe we should hold off on such a re-design until rand_core 2.0 considering neither required feature is likely to make it into Rust in the near future? Or we could use a cut-down version of the above (without LEN) now, perhaps.

Either way, this would mean:

  • a ByteRng does not implement NumRng / Rng directly; so type StdRng = BlockRng<ChaCha12>;
  • NumRng does not provide for byte-filling; users must use Rng::fill
  • ... except that would be very inefficient for block-RNGs without using Specialization to impl Rng::fill, so maybe we need to keep RngCore::fill_bytes as is
  • ChaChaXRng (the RngCore implementor, not the core) has a few methods directly implemented on it so maybe we shouldn't only export the BlockRngCore implementor from the crate

But this is mostly orthogonal to your changes. So:

  • I like pub trait CryptoRng: RngCore
  • I don't really like the name crypto_fill_bytes, and do we even need it — can those who want it directly use the BlockRngCore? Maybe that doesn't work.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

See #1261 (comment) for reply to the middle part of the previous comment.

I don't really like the name crypto_fill_bytes, and do we even need it — can those who want it directly use the BlockRngCore?

I don't think the name is good either, so I am open to changing it. BlockRngCore is irrelevant here, the method is about making error handling possible for OsRng and hardware RNGs, which are usually used in cryptographic code.

But I am not sure whether it's a good idea to move try_fill_bytes to CryptoRng. While it simplifies some things, it introduces issues around error handling, e.g. in the io::Read compatibility layer. IIUC try_fill_bytes should be accessible for &mut dyn CryptoRng. So I probably will revert this change.

@dhardy

Copy link
Copy Markdown
Member

which are usually used in cryptographic code

Do these uses even want a RngCore or just a byte-generator? Of course it is useful having the buffering logic that BlockRng provides, but possibly a simpler version would suffice without the next_u* methods.

whether it's a good idea to move try_fill_bytes ... e.g. in the io::Read compatibility.

The ReadRng adapter is deprecated, so I see no worry there. However I don't see any reason for this change either.

I don't think the name is good either

Nor is the original, but it seems we don't have a good reason to change it.

If we want to simplify, we could probably remove RngCore::fill_bytes... at risk of doing more permutation than simplification (i.e. probably a needless breaking change).

@newpavlov

newpavlov commented Jan 6, 2023

Copy link
Copy Markdown
MemberAuthor

@dhardy
Can you remind me why rand_chacha and ReseedingRng use newtype wrappers instead of type aliases? Is it only because rustdoc does not show trait impls for type aliases?

If such type aliases is the "recommended way" of doing things, then removal of the BlockRngCore trait could be warranted despite some amount of buffering boilerplate in implementation crates. But, personally, I would prefer if we simply used type aliases.

@dhardy

Copy link
Copy Markdown
Member

I think the new-type wrappers are used (a) to hide the inner type (thus not an API breaking change to replace it) and (b) to allow custom methods on that type. Without re-examining I don't know how important these are (probably only (b) is applicable to ChaCha).

I don't follow why this justifies removing BlockRngCore; that's an impl target used by BlockRng.

Thanks for cleaning up the PR.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

I don't follow why this justifies removing BlockRngCore; that's an impl target used by BlockRng.

It does not look like we have users of BlockRngCore outside of implementation crates. Since they introduce their own opaque newtypes, we can replace BlockRngCore and the wrapper types with a bunch of helper functions. I think it will result in a bit simpler rand_core and implementation crates.

@dhardydhardy left a comment

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.

I wish we'd named RngCore as Rng instead, and what is now Rng as RngExt. Is it worth renaming now? It would make the names noted below more consistent, while also being better for common usage (where people use bounds like R: RngCore).

Besides this is the idea that maybe we should move one or some RngCore methods to a different trait. Most users don't need try_fill_bytesandnext_u32. You mentioned moving try_fill_bytes to CryptoRng and we seem to have rejected that idea. If we wanted a separate ByteRng for try_fill_bytes, we'd then need pub trait CryptoByteRng: ByteRng {} too.

Anyway, I'll provisionally approve this PR. If I don't, it might just get stuck.

/// supposed to be cryptographically secure.
///
/// See [`CryptoRng`][crate::CryptoRng] docs for more information.
pub trait CryptoBlockRng: BlockRngCore { }

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.

The naming seems off: CryptoRng: RngCore, CryptoBlockRng: BlockRngCore.

@tarcieri

Copy link
Copy Markdown
Contributor

I wish we'd named RngCore as Rng instead, and what is now Rng as RngExt. Is it worth renaming now?

Sounds great to me!

@dhardy

Copy link
Copy Markdown
Member

@newpavlov this is still marked as a draft, but I think it's ready to be merged? I already approved.

I'm also happy to rename RngCoreRng, RngRngExt. But that should be a new PR.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-APIBreakage: API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@newpavlov@dhardy@tarcieri
, '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('^' + ".*" + ' Rework CryptoRng by newpavlov · Pull Request #1273 · rust-random/rand · GitHub
Skip to content

Rework CryptoRng - #1273

Merged
dhardy merged 1 commit into
masterfrom
crypto_rework
Feb 20, 2023
Merged

Rework CryptoRng#1273
dhardy merged 1 commit into
masterfrom
crypto_rework

Conversation

@newpavlov

@newpavlovnewpavlov commented Dec 6, 2022

Copy link
Copy Markdown
Member

This PR introduces the CryptoBlockRng marker trait. It's used instead of CryptoRng on block RNGs, which allows us to mark CryptoRng as a subtrait of RngCore and makes the CryptoRngCore trait redundant.

Additionally, try_fill_bytes is moved to CryptoRng and renamed to crypto_fill_bytes. The rationale here is that error checks for potential RNG failures are practically exclusive to cryptographic code.

Unfortunately, this PR also contains a bunch of formatting changes introduced by cargo fmt. I think it could be worth to include formatting check into our CI to prevent such changes in future.

cc @tarcieri

@newpavlov
newpavlov requested a review from dhardyDecember 6, 2022 08:08
@newpavlovnewpavlov added the B-API Breakage: API label Dec 6, 2022
@dhardy

Copy link
Copy Markdown
Member

Unfortunately, this PR also contains a bunch of formatting changes introduced by cargo fmt. I think it could be worth to include formatting check into our CI to prevent such changes in future.

Er, yes. Please either remove formatting changes to old code or run rustfmtfirst, commit, and rebase on top of that. I.e. isolate your changes from formatting.

We should use rustfmt everywhere, but we don't. Last time I looked at this, it was rejected on grounds of too much poor formatting, and that in theory rustfmt 2.0 was coming at some point. I haven't followed everything, but I don't think 2.0 is happening any time soon, meanwhile almost every major Rust project now uses it so we should too. The main issue is that we have a lot of open PRs which would conflict.

Is it a major pain to remove formatting-only changes from this PR in the mean-time? (I usually use git checkout -p --.)


As for the actual purpose of this PR — these issues would appear related. Didn't we already discuss this?

@newpavlov

Copy link
Copy Markdown
MemberAuthor

Please either remove formatting changes to old code or run rustfmt first, commit, and rebase on top of that. I.e. isolate your changes from formatting.

Yeah, I will do it somewhat later. I executed cargo fmt automatically and only during commit creation found the size of formatting changes. :( Before that, I hope to get initial reaction regarding the drafted approach, whether its worthwhile or not.

As for the actual purpose of this PR — these issues would appear related. Didn't we already discuss this?

I think I floated the drafted idea somewhere in issues. CryptoRngCore was designed with backward compatibility in mind, while changes in this PR are breaking ones.

@dhardy

Copy link
Copy Markdown
Member

Summary of this PR:

pubtraitRngCore{// keeps methods next_u32, next_u64, fill_bytes// loses try_fill_bytes}// New bound on RngCore:pubtraitCryptoRng:RngCore{fncrypto_fill_bytes(&mutself,dest:&mut[u8]) -> Result<(),Error>{/* default impl */}}// New:pubtraitCryptoBlockRng:BlockRngCore{}// Removed:// pub trait CryptoRngCore: CryptoRng + RngCore { .. }

My thoughts, somewhat detached from the above...

In the long term, do we even keep BlockRng? Given the suggestions in #1261, especially yours regarding generic_const_exprs. Well, probably yes to provide a "next int please" API over a block generator.

Given that, maybe we should make larger changes:

// A revised BlockRngCore (maybe renamed or maybe not):pubtraitByteRng{constLEN:usize;fngenerate(&mutself) -> Result<[u8;Self::LEN]>;}// A cut-down RngCore (maybe we should keep the old name):pubtraitNumRng{fnnext_u32(&mutself) -> u32;fnnext_u64(&mutself) -> u64;}pubstructBlockRng<R:ByteRng>(..);impl<R: ..>NumRngforByteRng<R>{}

Except, it would be nice to know at compile time the generation size of NumRng, hence we could add const NATIVE_BITS: u32 or even use a type parameter NumRng<N>. Except this doesn't work for users needing an object-safe trait which means we would need a separate object-safe trait and blanket impls. Which (surprise!) means we need Rust's number one missing feature, Specialization (or maybe negative trait bounds).

Maybe we should hold off on such a re-design until rand_core 2.0 considering neither required feature is likely to make it into Rust in the near future? Or we could use a cut-down version of the above (without LEN) now, perhaps.

Either way, this would mean:

  • a ByteRng does not implement NumRng / Rng directly; so type StdRng = BlockRng<ChaCha12>;
  • NumRng does not provide for byte-filling; users must use Rng::fill
  • ... except that would be very inefficient for block-RNGs without using Specialization to impl Rng::fill, so maybe we need to keep RngCore::fill_bytes as is
  • ChaChaXRng (the RngCore implementor, not the core) has a few methods directly implemented on it so maybe we shouldn't only export the BlockRngCore implementor from the crate

But this is mostly orthogonal to your changes. So:

  • I like pub trait CryptoRng: RngCore
  • I don't really like the name crypto_fill_bytes, and do we even need it — can those who want it directly use the BlockRngCore? Maybe that doesn't work.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

See #1261 (comment) for reply to the middle part of the previous comment.

I don't really like the name crypto_fill_bytes, and do we even need it — can those who want it directly use the BlockRngCore?

I don't think the name is good either, so I am open to changing it. BlockRngCore is irrelevant here, the method is about making error handling possible for OsRng and hardware RNGs, which are usually used in cryptographic code.

But I am not sure whether it's a good idea to move try_fill_bytes to CryptoRng. While it simplifies some things, it introduces issues around error handling, e.g. in the io::Read compatibility layer. IIUC try_fill_bytes should be accessible for &mut dyn CryptoRng. So I probably will revert this change.

@dhardy

Copy link
Copy Markdown
Member

which are usually used in cryptographic code

Do these uses even want a RngCore or just a byte-generator? Of course it is useful having the buffering logic that BlockRng provides, but possibly a simpler version would suffice without the next_u* methods.

whether it's a good idea to move try_fill_bytes ... e.g. in the io::Read compatibility.

The ReadRng adapter is deprecated, so I see no worry there. However I don't see any reason for this change either.

I don't think the name is good either

Nor is the original, but it seems we don't have a good reason to change it.

If we want to simplify, we could probably remove RngCore::fill_bytes... at risk of doing more permutation than simplification (i.e. probably a needless breaking change).

@newpavlov

newpavlov commented Jan 6, 2023

Copy link
Copy Markdown
MemberAuthor

@dhardy
Can you remind me why rand_chacha and ReseedingRng use newtype wrappers instead of type aliases? Is it only because rustdoc does not show trait impls for type aliases?

If such type aliases is the "recommended way" of doing things, then removal of the BlockRngCore trait could be warranted despite some amount of buffering boilerplate in implementation crates. But, personally, I would prefer if we simply used type aliases.

@dhardy

Copy link
Copy Markdown
Member

I think the new-type wrappers are used (a) to hide the inner type (thus not an API breaking change to replace it) and (b) to allow custom methods on that type. Without re-examining I don't know how important these are (probably only (b) is applicable to ChaCha).

I don't follow why this justifies removing BlockRngCore; that's an impl target used by BlockRng.

Thanks for cleaning up the PR.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

I don't follow why this justifies removing BlockRngCore; that's an impl target used by BlockRng.

It does not look like we have users of BlockRngCore outside of implementation crates. Since they introduce their own opaque newtypes, we can replace BlockRngCore and the wrapper types with a bunch of helper functions. I think it will result in a bit simpler rand_core and implementation crates.

@dhardydhardy left a comment

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.

I wish we'd named RngCore as Rng instead, and what is now Rng as RngExt. Is it worth renaming now? It would make the names noted below more consistent, while also being better for common usage (where people use bounds like R: RngCore).

Besides this is the idea that maybe we should move one or some RngCore methods to a different trait. Most users don't need try_fill_bytesandnext_u32. You mentioned moving try_fill_bytes to CryptoRng and we seem to have rejected that idea. If we wanted a separate ByteRng for try_fill_bytes, we'd then need pub trait CryptoByteRng: ByteRng {} too.

Anyway, I'll provisionally approve this PR. If I don't, it might just get stuck.

/// supposed to be cryptographically secure.
///
/// See [`CryptoRng`][crate::CryptoRng] docs for more information.
pub trait CryptoBlockRng: BlockRngCore { }

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.

The naming seems off: CryptoRng: RngCore, CryptoBlockRng: BlockRngCore.

@tarcieri

Copy link
Copy Markdown
Contributor

I wish we'd named RngCore as Rng instead, and what is now Rng as RngExt. Is it worth renaming now?

Sounds great to me!

@dhardy

Copy link
Copy Markdown
Member

@newpavlov this is still marked as a draft, but I think it's ready to be merged? I already approved.

I'm also happy to rename RngCoreRng, RngRngExt. But that should be a new PR.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-APIBreakage: API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@newpavlov@dhardy@tarcieri
, '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('^' + ".*" + ' Rework CryptoRng by newpavlov · Pull Request #1273 · rust-random/rand · GitHub
Skip to content

Rework CryptoRng - #1273

Merged
dhardy merged 1 commit into
masterfrom
crypto_rework
Feb 20, 2023
Merged

Rework CryptoRng#1273
dhardy merged 1 commit into
masterfrom
crypto_rework

Conversation

@newpavlov

@newpavlovnewpavlov commented Dec 6, 2022

Copy link
Copy Markdown
Member

This PR introduces the CryptoBlockRng marker trait. It's used instead of CryptoRng on block RNGs, which allows us to mark CryptoRng as a subtrait of RngCore and makes the CryptoRngCore trait redundant.

Additionally, try_fill_bytes is moved to CryptoRng and renamed to crypto_fill_bytes. The rationale here is that error checks for potential RNG failures are practically exclusive to cryptographic code.

Unfortunately, this PR also contains a bunch of formatting changes introduced by cargo fmt. I think it could be worth to include formatting check into our CI to prevent such changes in future.

cc @tarcieri

@newpavlov
newpavlov requested a review from dhardyDecember 6, 2022 08:08
@newpavlovnewpavlov added the B-API Breakage: API label Dec 6, 2022
@dhardy

Copy link
Copy Markdown
Member

Unfortunately, this PR also contains a bunch of formatting changes introduced by cargo fmt. I think it could be worth to include formatting check into our CI to prevent such changes in future.

Er, yes. Please either remove formatting changes to old code or run rustfmtfirst, commit, and rebase on top of that. I.e. isolate your changes from formatting.

We should use rustfmt everywhere, but we don't. Last time I looked at this, it was rejected on grounds of too much poor formatting, and that in theory rustfmt 2.0 was coming at some point. I haven't followed everything, but I don't think 2.0 is happening any time soon, meanwhile almost every major Rust project now uses it so we should too. The main issue is that we have a lot of open PRs which would conflict.

Is it a major pain to remove formatting-only changes from this PR in the mean-time? (I usually use git checkout -p --.)


As for the actual purpose of this PR — these issues would appear related. Didn't we already discuss this?

@newpavlov

Copy link
Copy Markdown
MemberAuthor

Please either remove formatting changes to old code or run rustfmt first, commit, and rebase on top of that. I.e. isolate your changes from formatting.

Yeah, I will do it somewhat later. I executed cargo fmt automatically and only during commit creation found the size of formatting changes. :( Before that, I hope to get initial reaction regarding the drafted approach, whether its worthwhile or not.

As for the actual purpose of this PR — these issues would appear related. Didn't we already discuss this?

I think I floated the drafted idea somewhere in issues. CryptoRngCore was designed with backward compatibility in mind, while changes in this PR are breaking ones.

@dhardy

Copy link
Copy Markdown
Member

Summary of this PR:

pubtraitRngCore{// keeps methods next_u32, next_u64, fill_bytes// loses try_fill_bytes}// New bound on RngCore:pubtraitCryptoRng:RngCore{fncrypto_fill_bytes(&mutself,dest:&mut[u8]) -> Result<(),Error>{/* default impl */}}// New:pubtraitCryptoBlockRng:BlockRngCore{}// Removed:// pub trait CryptoRngCore: CryptoRng + RngCore { .. }

My thoughts, somewhat detached from the above...

In the long term, do we even keep BlockRng? Given the suggestions in #1261, especially yours regarding generic_const_exprs. Well, probably yes to provide a "next int please" API over a block generator.

Given that, maybe we should make larger changes:

// A revised BlockRngCore (maybe renamed or maybe not):pubtraitByteRng{constLEN:usize;fngenerate(&mutself) -> Result<[u8;Self::LEN]>;}// A cut-down RngCore (maybe we should keep the old name):pubtraitNumRng{fnnext_u32(&mutself) -> u32;fnnext_u64(&mutself) -> u64;}pubstructBlockRng<R:ByteRng>(..);impl<R: ..>NumRngforByteRng<R>{}

Except, it would be nice to know at compile time the generation size of NumRng, hence we could add const NATIVE_BITS: u32 or even use a type parameter NumRng<N>. Except this doesn't work for users needing an object-safe trait which means we would need a separate object-safe trait and blanket impls. Which (surprise!) means we need Rust's number one missing feature, Specialization (or maybe negative trait bounds).

Maybe we should hold off on such a re-design until rand_core 2.0 considering neither required feature is likely to make it into Rust in the near future? Or we could use a cut-down version of the above (without LEN) now, perhaps.

Either way, this would mean:

  • a ByteRng does not implement NumRng / Rng directly; so type StdRng = BlockRng<ChaCha12>;
  • NumRng does not provide for byte-filling; users must use Rng::fill
  • ... except that would be very inefficient for block-RNGs without using Specialization to impl Rng::fill, so maybe we need to keep RngCore::fill_bytes as is
  • ChaChaXRng (the RngCore implementor, not the core) has a few methods directly implemented on it so maybe we shouldn't only export the BlockRngCore implementor from the crate

But this is mostly orthogonal to your changes. So:

  • I like pub trait CryptoRng: RngCore
  • I don't really like the name crypto_fill_bytes, and do we even need it — can those who want it directly use the BlockRngCore? Maybe that doesn't work.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

See #1261 (comment) for reply to the middle part of the previous comment.

I don't really like the name crypto_fill_bytes, and do we even need it — can those who want it directly use the BlockRngCore?

I don't think the name is good either, so I am open to changing it. BlockRngCore is irrelevant here, the method is about making error handling possible for OsRng and hardware RNGs, which are usually used in cryptographic code.

But I am not sure whether it's a good idea to move try_fill_bytes to CryptoRng. While it simplifies some things, it introduces issues around error handling, e.g. in the io::Read compatibility layer. IIUC try_fill_bytes should be accessible for &mut dyn CryptoRng. So I probably will revert this change.

@dhardy

Copy link
Copy Markdown
Member

which are usually used in cryptographic code

Do these uses even want a RngCore or just a byte-generator? Of course it is useful having the buffering logic that BlockRng provides, but possibly a simpler version would suffice without the next_u* methods.

whether it's a good idea to move try_fill_bytes ... e.g. in the io::Read compatibility.

The ReadRng adapter is deprecated, so I see no worry there. However I don't see any reason for this change either.

I don't think the name is good either

Nor is the original, but it seems we don't have a good reason to change it.

If we want to simplify, we could probably remove RngCore::fill_bytes... at risk of doing more permutation than simplification (i.e. probably a needless breaking change).

@newpavlov

newpavlov commented Jan 6, 2023

Copy link
Copy Markdown
MemberAuthor

@dhardy
Can you remind me why rand_chacha and ReseedingRng use newtype wrappers instead of type aliases? Is it only because rustdoc does not show trait impls for type aliases?

If such type aliases is the "recommended way" of doing things, then removal of the BlockRngCore trait could be warranted despite some amount of buffering boilerplate in implementation crates. But, personally, I would prefer if we simply used type aliases.

@dhardy

Copy link
Copy Markdown
Member

I think the new-type wrappers are used (a) to hide the inner type (thus not an API breaking change to replace it) and (b) to allow custom methods on that type. Without re-examining I don't know how important these are (probably only (b) is applicable to ChaCha).

I don't follow why this justifies removing BlockRngCore; that's an impl target used by BlockRng.

Thanks for cleaning up the PR.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

I don't follow why this justifies removing BlockRngCore; that's an impl target used by BlockRng.

It does not look like we have users of BlockRngCore outside of implementation crates. Since they introduce their own opaque newtypes, we can replace BlockRngCore and the wrapper types with a bunch of helper functions. I think it will result in a bit simpler rand_core and implementation crates.

@dhardydhardy left a comment

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.

I wish we'd named RngCore as Rng instead, and what is now Rng as RngExt. Is it worth renaming now? It would make the names noted below more consistent, while also being better for common usage (where people use bounds like R: RngCore).

Besides this is the idea that maybe we should move one or some RngCore methods to a different trait. Most users don't need try_fill_bytesandnext_u32. You mentioned moving try_fill_bytes to CryptoRng and we seem to have rejected that idea. If we wanted a separate ByteRng for try_fill_bytes, we'd then need pub trait CryptoByteRng: ByteRng {} too.

Anyway, I'll provisionally approve this PR. If I don't, it might just get stuck.

/// supposed to be cryptographically secure.
///
/// See [`CryptoRng`][crate::CryptoRng] docs for more information.
pub trait CryptoBlockRng: BlockRngCore { }

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.

The naming seems off: CryptoRng: RngCore, CryptoBlockRng: BlockRngCore.

@tarcieri

Copy link
Copy Markdown
Contributor

I wish we'd named RngCore as Rng instead, and what is now Rng as RngExt. Is it worth renaming now?

Sounds great to me!

@dhardy

Copy link
Copy Markdown
Member

@newpavlov this is still marked as a draft, but I think it's ready to be merged? I already approved.

I'm also happy to rename RngCoreRng, RngRngExt. But that should be a new PR.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-APIBreakage: API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@newpavlov@dhardy@tarcieri
, '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); } })(); })(); Rework CryptoRng by newpavlov · Pull Request #1273 · rust-random/rand · GitHub
Skip to content

Rework CryptoRng - #1273

Merged
dhardy merged 1 commit into
masterfrom
crypto_rework
Feb 20, 2023
Merged

Rework CryptoRng#1273
dhardy merged 1 commit into
masterfrom
crypto_rework

Conversation

@newpavlov

@newpavlovnewpavlov commented Dec 6, 2022

Copy link
Copy Markdown
Member

This PR introduces the CryptoBlockRng marker trait. It's used instead of CryptoRng on block RNGs, which allows us to mark CryptoRng as a subtrait of RngCore and makes the CryptoRngCore trait redundant.

Additionally, try_fill_bytes is moved to CryptoRng and renamed to crypto_fill_bytes. The rationale here is that error checks for potential RNG failures are practically exclusive to cryptographic code.

Unfortunately, this PR also contains a bunch of formatting changes introduced by cargo fmt. I think it could be worth to include formatting check into our CI to prevent such changes in future.

cc @tarcieri

@newpavlov
newpavlov requested a review from dhardyDecember 6, 2022 08:08
@newpavlovnewpavlov added the B-API Breakage: API label Dec 6, 2022
@dhardy

Copy link
Copy Markdown
Member

Unfortunately, this PR also contains a bunch of formatting changes introduced by cargo fmt. I think it could be worth to include formatting check into our CI to prevent such changes in future.

Er, yes. Please either remove formatting changes to old code or run rustfmtfirst, commit, and rebase on top of that. I.e. isolate your changes from formatting.

We should use rustfmt everywhere, but we don't. Last time I looked at this, it was rejected on grounds of too much poor formatting, and that in theory rustfmt 2.0 was coming at some point. I haven't followed everything, but I don't think 2.0 is happening any time soon, meanwhile almost every major Rust project now uses it so we should too. The main issue is that we have a lot of open PRs which would conflict.

Is it a major pain to remove formatting-only changes from this PR in the mean-time? (I usually use git checkout -p --.)


As for the actual purpose of this PR — these issues would appear related. Didn't we already discuss this?

@newpavlov

Copy link
Copy Markdown
MemberAuthor

Please either remove formatting changes to old code or run rustfmt first, commit, and rebase on top of that. I.e. isolate your changes from formatting.

Yeah, I will do it somewhat later. I executed cargo fmt automatically and only during commit creation found the size of formatting changes. :( Before that, I hope to get initial reaction regarding the drafted approach, whether its worthwhile or not.

As for the actual purpose of this PR — these issues would appear related. Didn't we already discuss this?

I think I floated the drafted idea somewhere in issues. CryptoRngCore was designed with backward compatibility in mind, while changes in this PR are breaking ones.

@dhardy

Copy link
Copy Markdown
Member

Summary of this PR:

pubtraitRngCore{// keeps methods next_u32, next_u64, fill_bytes// loses try_fill_bytes}// New bound on RngCore:pubtraitCryptoRng:RngCore{fncrypto_fill_bytes(&mutself,dest:&mut[u8]) -> Result<(),Error>{/* default impl */}}// New:pubtraitCryptoBlockRng:BlockRngCore{}// Removed:// pub trait CryptoRngCore: CryptoRng + RngCore { .. }

My thoughts, somewhat detached from the above...

In the long term, do we even keep BlockRng? Given the suggestions in #1261, especially yours regarding generic_const_exprs. Well, probably yes to provide a "next int please" API over a block generator.

Given that, maybe we should make larger changes:

// A revised BlockRngCore (maybe renamed or maybe not):pubtraitByteRng{constLEN:usize;fngenerate(&mutself) -> Result<[u8;Self::LEN]>;}// A cut-down RngCore (maybe we should keep the old name):pubtraitNumRng{fnnext_u32(&mutself) -> u32;fnnext_u64(&mutself) -> u64;}pubstructBlockRng<R:ByteRng>(..);impl<R: ..>NumRngforByteRng<R>{}

Except, it would be nice to know at compile time the generation size of NumRng, hence we could add const NATIVE_BITS: u32 or even use a type parameter NumRng<N>. Except this doesn't work for users needing an object-safe trait which means we would need a separate object-safe trait and blanket impls. Which (surprise!) means we need Rust's number one missing feature, Specialization (or maybe negative trait bounds).

Maybe we should hold off on such a re-design until rand_core 2.0 considering neither required feature is likely to make it into Rust in the near future? Or we could use a cut-down version of the above (without LEN) now, perhaps.

Either way, this would mean:

  • a ByteRng does not implement NumRng / Rng directly; so type StdRng = BlockRng<ChaCha12>;
  • NumRng does not provide for byte-filling; users must use Rng::fill
  • ... except that would be very inefficient for block-RNGs without using Specialization to impl Rng::fill, so maybe we need to keep RngCore::fill_bytes as is
  • ChaChaXRng (the RngCore implementor, not the core) has a few methods directly implemented on it so maybe we shouldn't only export the BlockRngCore implementor from the crate

But this is mostly orthogonal to your changes. So:

  • I like pub trait CryptoRng: RngCore
  • I don't really like the name crypto_fill_bytes, and do we even need it — can those who want it directly use the BlockRngCore? Maybe that doesn't work.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

See #1261 (comment) for reply to the middle part of the previous comment.

I don't really like the name crypto_fill_bytes, and do we even need it — can those who want it directly use the BlockRngCore?

I don't think the name is good either, so I am open to changing it. BlockRngCore is irrelevant here, the method is about making error handling possible for OsRng and hardware RNGs, which are usually used in cryptographic code.

But I am not sure whether it's a good idea to move try_fill_bytes to CryptoRng. While it simplifies some things, it introduces issues around error handling, e.g. in the io::Read compatibility layer. IIUC try_fill_bytes should be accessible for &mut dyn CryptoRng. So I probably will revert this change.

@dhardy

Copy link
Copy Markdown
Member

which are usually used in cryptographic code

Do these uses even want a RngCore or just a byte-generator? Of course it is useful having the buffering logic that BlockRng provides, but possibly a simpler version would suffice without the next_u* methods.

whether it's a good idea to move try_fill_bytes ... e.g. in the io::Read compatibility.

The ReadRng adapter is deprecated, so I see no worry there. However I don't see any reason for this change either.

I don't think the name is good either

Nor is the original, but it seems we don't have a good reason to change it.

If we want to simplify, we could probably remove RngCore::fill_bytes... at risk of doing more permutation than simplification (i.e. probably a needless breaking change).

@newpavlov

newpavlov commented Jan 6, 2023

Copy link
Copy Markdown
MemberAuthor

@dhardy
Can you remind me why rand_chacha and ReseedingRng use newtype wrappers instead of type aliases? Is it only because rustdoc does not show trait impls for type aliases?

If such type aliases is the "recommended way" of doing things, then removal of the BlockRngCore trait could be warranted despite some amount of buffering boilerplate in implementation crates. But, personally, I would prefer if we simply used type aliases.

@dhardy

Copy link
Copy Markdown
Member

I think the new-type wrappers are used (a) to hide the inner type (thus not an API breaking change to replace it) and (b) to allow custom methods on that type. Without re-examining I don't know how important these are (probably only (b) is applicable to ChaCha).

I don't follow why this justifies removing BlockRngCore; that's an impl target used by BlockRng.

Thanks for cleaning up the PR.

@newpavlov

Copy link
Copy Markdown
MemberAuthor

I don't follow why this justifies removing BlockRngCore; that's an impl target used by BlockRng.

It does not look like we have users of BlockRngCore outside of implementation crates. Since they introduce their own opaque newtypes, we can replace BlockRngCore and the wrapper types with a bunch of helper functions. I think it will result in a bit simpler rand_core and implementation crates.

@dhardydhardy left a comment

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.

I wish we'd named RngCore as Rng instead, and what is now Rng as RngExt. Is it worth renaming now? It would make the names noted below more consistent, while also being better for common usage (where people use bounds like R: RngCore).

Besides this is the idea that maybe we should move one or some RngCore methods to a different trait. Most users don't need try_fill_bytesandnext_u32. You mentioned moving try_fill_bytes to CryptoRng and we seem to have rejected that idea. If we wanted a separate ByteRng for try_fill_bytes, we'd then need pub trait CryptoByteRng: ByteRng {} too.

Anyway, I'll provisionally approve this PR. If I don't, it might just get stuck.

/// supposed to be cryptographically secure.
///
/// See [`CryptoRng`][crate::CryptoRng] docs for more information.
pub trait CryptoBlockRng: BlockRngCore { }

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.

The naming seems off: CryptoRng: RngCore, CryptoBlockRng: BlockRngCore.

@tarcieri

Copy link
Copy Markdown
Contributor

I wish we'd named RngCore as Rng instead, and what is now Rng as RngExt. Is it worth renaming now?

Sounds great to me!

@dhardy

Copy link
Copy Markdown
Member

@newpavlov this is still marked as a draft, but I think it's ready to be merged? I already approved.

I'm also happy to rename RngCoreRng, RngRngExt. But that should be a new PR.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-APIBreakage: API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@newpavlov@dhardy@tarcieri