-
Notifications
You must be signed in to change notification settings - Fork 432
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support CryptoRng
in RngCore
trait objects
#1143
Comments
Thanks for the clear RFC. I agree that the initial proposal makes sense, though it will likely to a while to land (or at least to affect downstream crates like Either way, we should allow some time for comments before making a decision. |
I wonder why we haven't done it initially... I vaguely remember there was kind of a reason for the current design, but I can't remember what was it exactly. If there are no significant obstacles to it, I also would prefer the subtrait approach. |
Would it be possible to cast a |
I don't think that would be possible even with unsafe code. At least not without undefined behavior, since you'd need have a valid There would also not be any guarentee that the original |
I'd expect casts from We never knew if
I suppose one solution would be to deprecate
so folks could insert any warnings the like via say
and if you ask then you get messages like "Non-RandomOracle XorShiftRng contract: Random Oracle". Ideally formal methods and design by contract folks would spend more time developing rust tooling outside rustc itself. |
After sleeping on it I remember there is a reason we can't just implement this: So maybe the |
Ah, yes! It was exactly that. I think that instead of trait CryptoBlockRng: BlockRngCore {}
trait CryptoRng: RngCore {}
impl<T: BlockRngCore> RngCore for BlockRng<T> { .. }
impl<T: CryptoBlockRng> CryptoRng for BlockRng<T> {} |
While I do think that would be a better solution when designing a new API, it likely isn't feasible in this situation, since does have a much bigger impact on downstream users.
Completely changing the meaning of traits (especially "marker" traits like Seeing how |
@aticu I agree that the less breaking change is desirable. The naming of your suggestions in unfortunate though:
|
@dhardy Adding a new trait wouldn't be a breaking change at all. Naming is (as always) tough to get right. Here are some alternative naming ideas, thought I'm not a huge fan of any one of them:
I personally don't really care a lot what the name would be if this were added, but I still think a good name is important, so if you have any better ideas, I'd be open to them. |
We should seriously consider deprecating Aside from the An RFC for permitting |
I should've been more clear: the proposal was for the next breaking release of I think that the // will be removed in rand_core v0.7
trait CryptoRng {}
trait CryptoBlockRngCore: BlockRngCore {}
trait CryptoRngCore: RngCore {}
impl<T: BlockRngCore> RngCore for BlockRng<T> { .. }
impl<T: CryptoBlockRngCore> CryptoRngCore for BlockRng<T> {}
impl<T: CryptoRng + BlockRngCore> CryptoBlockRngCore for T {}
impl<T: CryptoRng + RngCore> CryptoRngCore for T {}
// alternatively we can add impls in different direction:
impl<T: CryptoBlockRngCore> CryptoRng for T {}
impl<T: CryptoRngCore> CryptoRng for T {} It will cause a bit of churn in downstream crates, but I think replacing
As one of the RustCrypto maintainers I am strongly against that. I do not want for our users to accidentally plug clearly insecure RNGs into cryptographic code. Yes, the |
@burdges are you referring to Rust's (current) lack of trait-object upcast (i.e. inability to convert Overall I am in favour of @newpavlov's suggestion ( @aticu is there any urgency to support |
Yes If all you wanted was a
I suggest we do something similarly unorthodox but that captures CSPRG better than |
@burdges You are using strong words against The alternatives you suggested move the problem from compile time to run time. I don't understand why this would be preferable, or more nuanced. |
To be fair to @burdges, adding a method for trait object upcast is not a pure compile time solution either. |
I mentioned one solution that moves the problem to test time, not runtime. It avoids further trait gymnastics inside rand's already complex trait hierarchy. You need Above I also mentioned a solution that becomes compile-time once const generics supports bounds, but currently requires test time test time asserts. I doubt up casting would land before const generics bounds.
I've actually made no concrete proposals however. Instead I've raised four points:
I've actually suggested
I've not yet suggested we add some |
@burdges Thanks for the clarification! |
Here is what I meant by silent breakage: Assume I maintain a library with the following API: fn foo<T: BlockRngCore + CryptoRng>(rng: &mut T); If these changes were made, my code wouldn't break, since I can still use There is no urgency at all.
Unfortunately this method would have to be implemented by each type implementing
This is true, but moving the problem to const generics bounds or any other mechanism changes nothing about that.
That is true, but I don't think that this problem is even solvable in a general way.
Because it is guaranteed to be enforced. |
For many libraries, I imagine it would be preferable to
We can certainly discuss such things, but this is significantly more complex than It's not just provenance (by which I assume you mean the source of the seed), but also side-channel attacks and decisions about which algorithms are sufficiently robust to gain a |
Interesting.. We all agree that
Yes I agree with this more now after some thought.. If someone miss-uses algorithms then they may not even write tests, which sounds archaic but yeah happens. I believe runtime panics in release builds goes too far here, so yeah I spoke up forcefully about this because I've seen idiot proofing via traits go badly repeatedly. I saw I've seen discussion about supporting Are there any indications about const generics bounds being a near future option? If so, then an associated const sounds kinda interesting.
It's not solvable in rust's trait system. It's presumably not even solvable if fancy formal verification languages like F*. I do however think code could assist humans in explaining why what they do is secure, but increasingly I suspect this might prove orthogonal to idiot proofing.. I just dislike it being orthogonal. ;) Alright maybe I derailed things somewhat, but at least a couple different rustc features would address this, if any would land soon enough. |
Personally, I like the alternative solution proposed by @newpavlov in #1143 (comment). It's backwards compatible, and is the only proposed solution that allows us to support upcasting without relying on yet-to-be proposed features. For example (omitting the // Could optionally be removed in rand_core v0.7
trait CryptoRng {}
trait CryptoRngCore: RngCore {
fn upcast(&mut self) -> &mut dyn RngCore;
}
impl<T: CryptoRng + RngCore> CryptoRngCore for T {
fn upcast(&mut self) -> &mut dyn RngCore {
self
}
} Then everything continues working without any of the silent breakage @aticu described. But this feature now allows users to start using Then we could either:
Unfortunately, we can't make this process generic, so having: trait Crypto<Tr>: Tr {
fn upcast(&mut self) -> &mut dyn Tr;
} won't work.
@burdges the associated const (or |
Yes right now, I'd hope they become object safe in two ways eventually, by allowing a |
@josephlr that's the best proposal yet, thanks. Going back to the initial post:
This is also a viable choice IMO, and hopefully eventually Rust will support |
So the way I see it, the Here is my current understanding of the semantics:
I'd argue that these changing semantics aren't necessarily desirable, so I also think the best option would be what @newpavlov and @josephlr proposed: Deprecate |
I'm not sure hacspec is the right vehicle for something like this. Something along the lines of the contract crate is probably more suitable. But I'm not sure this is really solving the issue at hand. |
Summary
Change
CryptoRng
such that it can be used as a random number generator through a trait object, by making it a subtrait ofRngCore
.This would break existing
CryptoRng
implementations, which were previously not implementingRngCore
, but those were likely of limited use.Details
Change the
CryptoRng
trait from thisto this
Motivation
Currently the use of
RngCore
is supported in trait objects, however because of how trait objects are implemented, it is not possible to useCryptoRng
in addition in the trait object, thus making it impossible to actually use aCryptoRng
as a random number generator in trait objects.This change is really small and likely has very little negative impact on users who don't need this change, but it can enable another way to use the API for users who do need it.
Alternatives
Add a
CryptoRngCore
trait to therand_core
crate:This would allow users to use
RngCore + CryptoRng
types through trait objects as well, but at the cost of an additional trait in the (I presume intentionally) smallrand_core
crate.Do nothing and let users implement the
CryptoRngCore
trait above if they need it.This allows them to use
RngCore + CryptoRng
types through trait objects, but since it isn't a unified solution, multiple equivalent traits with the exact same purpose and definition might pop up over time.Optionally this pattern could also be documented in the
CryptoRng
trait.The text was updated successfully, but these errors were encountered: