dhardy / rand

http://doc.rust-lang.org/rand
Other
2 stars 2 forks source link

Wrapper Rngs to support IETF RFCs, alternative implementations, etc. #87

Closed burdges closed 6 years ago

burdges commented 6 years ago

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 Rngs into Rngs that behave more like byte streams. These include specifying (a) endianness and (b) exactly when bytes output bytes get dropped by next_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.

dhardy commented 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?

burdges commented 6 years ago

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 Rngs 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.

dhardy commented 6 years ago

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.

burdges commented 6 years ago

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.

dhardy commented 6 years ago

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?

burdges commented 6 years ago

I'll ping @str4d for this too.

dhardy commented 6 years ago

I think this is solved now.