Closed burdges closed 6 years ago
Are you talking about compatibility with stream cipher specifications? Because in this case I would assume any usage of next_u32
or next_u64
would be outside of the specification.
Do you have a specific goal in mind — e.g. do you mean the ability to write some kind of crypto library in another language and get compatible results? I guess so — are there other APIs/libraries you think we should aim for output compatibility with?
It's a stream cipher under the hood probably, but it might still need next_u32
. If you require that RFC complaint code ban next_u32
, then you essentially ban rand from RFC complaint code, which makes rand much less useful.
The goal is that a program written quickly in idiomatic Rust can easily be understood in a context where the rand crate does not exist, i.e. an RFC or another language. It's kinda okay if this requires changing the Rng
s used, like by putting wrappers on them, because if the option is made obvious then people will use it early. It's bad if such an easy option does not exist because once the code exists in the wild you cannot necessarily change the Rng
. This happened with ZCash's powers of tau ceremony recently.
As I said, I think ChaChaRng
should make next_u32
and next_u64
into little endian byte reads because the extra chacha rounds will be slower than some extra copying.
It should be okay then to state that next_u32
skips bytes to align to the next 4-byte boundary.
But you might be right; @pitdicker did some similar tests recently (I think next_u64
for 32-bit HC-128) and determined it wasn't worth re-aligning, IIRC.
It's endianness though too, not just alignment.
I agree alignment is not complex, well actually the realigning code is arguable simpler in Rust, but it's unlikely to be simpler when describing it from a "stream cipher" abstraction in say English for an RFC or Go, Javascript, etc. It boils down to a byte stream being the common currency everywhere.
There are plenty more complexities here like distributions, etc., but if we can reduce the initial burden then it'll make people's lives easier.
To be clear, I don't know that we need wrapper types per se, maybe we just need to advise cryptographic stream ciphers, XOFs, etc. to do this.
Technical specifications are not always complete (especially with things like programming languages), so a reference implementation and test data is often used. For this reason I'm less worried.
Regarding Endianness, we already recommend that implementations use LE, though we can't force it (it's up to the RNG implementation). So I think this is just documentation?
I'll ping @str4d for this too.
I think this is solved now.
Right now, if you write Rust code using rand then reimplementing your code in another language or writing an IETF RFC becomes hard.
We should've wrapper types that make
Rng
s intoRng
s that behave more like byte streams. These include specifying (a) endianness and (b) exactly when bytes output bytes get dropped bynext_u32
, etc. or avoid omitting bytes all together.We might alternatively demand such properties from
CryptoRng
or whatever, as slower cryptotaphic PRNGs should avoid dropped bytes anyway.