People: Josh Triplett, Diggory, TC, Amanieu
JoshT: My expectation: the trait should exist in core. The concept of generating random numbers doesn't require OS. But the (default) random source could be in std and getrandom could be in std.
Diggory: This might require initialisation.
Josh:
trait RandomSource
- in core, infalliblestruct DefaultRandomSource
- in stdfn getrandom(...) -> io::Result<...>
- in std, fallible
impl Read for DefaultRandomSource
TC: need for a non-blocking API. Alternative:
fn is_getrandom_ready()
: yes, not yet, other errorAmanieu:
fn secure_random_source() -> Result<DefaultRandomSource, Error>;
Josh:
struct DefaultRandomSource;
// May fail:
impl Read for DefaultRandomSource { .. }
// Can't fail (would panic instead)
impl RandomSource for DefaultRandomSource { .. }
Diggory: in Rand we have two traits – one with error handling TryRngCore
and one withoutRngCore
. And we have a wrapper for converting one from the other.
Amanieu: Do people use TryRngCore
?
Amanieu: Feel strongly that the trait in core should be without error handling.
Josh: We can add the "try" version later in the future. If you want something that has the possibility of failing, you can call getrandom
yourself.
TC: We were talking about the random source implementing Read
. And Read is fallible.
Amanieu: That was an alternative proposal instead of the getrandom
function.
Josh: Could we use Read
as the implementation of the random source. It's fallible and couldn't possible be put in core (and not clear path forward). We can't put io::Error
into core. We might be able to put io::Error
into alloc
but core should be able to have the random trait.
TC: Why wouldn't we implement Read
for DefaultRandomSource
? That seems extremely useful.
Josh: That is potentially a workable idea. Can we just provide impl Read
for DefaultRandomSource
– could you then call call read/read_buf and have that be your source?
Diggory: Yes.
Josh: TC, would that (impl Read for default random source?
)?
TC: Have we solved reading into uninitialized buffers?
Josh: Read
supports that but we need to stabilize it.
(Someone): See also:
https://blog.sunfishcode.online/writingintouninitializedbuffersinrust/
TC: I think user should use that most of the time. I still like the idea to stabilize the unsafe primitive as well – we'll need to implement that anyway.
Diggory: would the DefaultRandomSource
implement both Read
and the RandomSource
trait?
Josh: Yes, you would get "fill a buffer" from read and the higher-level functionality like get i32
.
Josh: Why does rng::Source implement so many different ways (next_u32, next_u64, fill_bytes) of getting individual values?
Diggory: Some rngs are faster doing that.
Josh: Is there a reason why all these are required and some of them can't be implemented (by default) in terms of the other ones?
Diggory: We provide implementations people can call, but different RNGs want to provide a different interface; block-based generators would provide fill_buf
, word-based interfaces would provide next_u64
.
Josh: We're working on something in the language that would help here: say that these things all have default implementations that depend on each other but you'd need to implement at least one.
TC: Usecase for why non-blocking is important: you're writing an SSH implementation in rust. You want to write this using async rust (you have executors and all that). You need to generate server-side keys. That's a difficult problem – SSH is one of the first things the OS starts. OS might start you early before it's ready to generate randomness. So you want to wait until the OS is ready. But you're also running an async executor. You can't call "getrandom blocking" because that can block you. That's a correctness problem. I'd prefer to call a non-blocking mode so it returns an error and then could signal to the OS that I'm not ready to start up yet. And try again later. If I can't do that I'm not sure how to write the server correctly.
Josh: Sounds like you're ready to rely on OS's "once it's ready, it'll never be not ready".
TC: For the time being yes.
Josh: If we're going to provide a "is_random_ready" function, would that work?
TC: Yes.
TC: Writing an SSH server is something that's not obscure – something we really should support. So we really need to nail this solution.
Josh: No objection to having an is_random_ready
function. An OS that doesn't have it always fails. An OS that has it ready always can return true
. Just necessarily ready to stabilize this at the same time.
Diggory: Sounds like that could go against "not easy to misuse"?
Josh: You can just not call it, and still use the
TC+Josh: Need to document that (a) once it returns success, DefaultRandomSource won't block, and (b) that if a source is ready it won't stop being ready.
Josh: getrandom
would only block when the OS's randomness is not ready yet.
Amanieu: for something like Tokio you need to wake up once something is ready. Typically you'd open /dev/random and wait for it to be ready.
Josh: Is is_random_ready
something that could go to the std. But something that asynchronously watches the OS randomness to be ready is not something we're not ready add yet (because we don't have any executor etc. to add it).
Josh: If we had this set of interfaces (possibly is_random_ready
), DefaultRandomSource
that implements Read and Rand. What should the RandomSource
have?
Diggory: Depends on applications. Is this to be used as a replacement for Rand
?
Josh: What is the performance delta of using a word-based generation to do fill_buf
compared to having it implement multiple functions instead of one.
Diggore: Maybe like 20% loss or something? Depends on your application.
Josh: Definitely non-trivial.
Amanieuu: Are you converting a single word into multiple bytes?
Diggory: Yes, you're using the same input.
Amanieu: That should still optimize away.
Diggory: If you know the length & alignment. If you don't, maybe not.
Josh: What we want teh properties of the interface be? DefaultRandomSource: OS-based and secure. We haven't talked about any sources for insecure randomness.
Diggory: The hashmap initialisation uses the insecure implementation already.
Josh: You're talking about calling getrandom
without the grnd flag? Effectively using random
rather than urandom
?
Josh: in the spirit of hard to misuse – we should give you secure random. And maybe require you to call into another library for insecure random number.
Diggory: Should RandomSource
have the implication be that it should provide secure random bytes?
Amanieu: No.
Diggory: Should we have a marker trait that declares this to be secure?
Josh: There's different meanings of "secure" here.
Amanieu: I'd expect anyone who needs secure random data to just use the DefaultRandomSource
directly.
Josh: There is an argument for why someone building a cryptographic library to use a non-default source: testing and fuzzing – e.g. getting a seedable source (to verify you get the same key out).
Amanieu: In that case you wouldn't require an secure trait bound, just any random trait bound. Either you allow a different source for testing. Or you allow for
Josh: Seedable doesn't imply insecure.
Amanieu: Don't see much use for the marker trait. We should ship without it.
Josh: We should ship without it first. We need to see what people expect. Not clear whether we want to provide a generic argument for seeding. There are usecases for having a marker saying this is definitely CSRNG.
Josh: We may want to consider having a crypto random source. But we don't want to provide a way for someone to fake out a crypto random source for testing. Would be nice to dodge those questions.
Amanieu: Can be added later if needed.
Amanieu: Good to have 2 sources: (1) default random source: give me the best random source you can provide (always succeeds). (2) Secure rando source: the platform will fail on a platform that doesn't have a secure random source.
Josh: Concern about the naming ("default" implying possibly an insecure source)
Amaniou: There's a random source that always succeeds and one that always fails.
Josh: Why wouldn't we provide best effort at all? Is there anything other than wasm that we don't want people to copy?
Josh: Are you saying that the "insecure" source is PRNG?
Amanieu: There's a value in having a "thread RNG" and secure RNG.
Diggory: Thread RNG in rand is secure. Don't see necessarily a lot of value.
Josh: The concept of an insecure source makes sense for a different reason: the insecure one doesn't have to have its algorithm changed in the future. So it can always to stay the same and then have it be the source for fuzzing, games etc.
Josh:
The goal of the original library ACP was to get
dhardy:
rand::rng
replacement. Probably wants a trait like rand::RngCore
.TC:
For getrandom
, agree we'll want error handling, and we'll also want to talk about how to support use cases that need its blocking behavior and those that need its nonblocking one (i.e. GRND_NONBLOCK
).
Personally, I'd also like to see us eventually stabilize something that works without std
(maybe, e.g., in core::arch
, in the spirit of breakpoint
) that uses the features of the target CPU (maybe it'd only be available on such targets). These instructions are now widespread. I'd see this function as being low level and e.g. only returning a single word.
Random source requirements:
no_std
compatibility, but may not be useful.getrandom
is partly about using Miri's initialization proof for randomization.u32
/ u64
?#[global_allocator]
or using RFC 3632? But libraries in the dep tree should not be able to replace the source for security reasons. See this comment and the next…Default random source requirements (trait based):
rand::rng
does because it cannot guarantee the perf. of the system RNG.Alternative RNGs:
core
?newpavlov suggests (at least) three sources in std
: SecureRandomSource
, InsecureRandomSource
, ThreadRng
"Easy to use" vs "hard to misuse" in API design, and tradeoffs like interfaces with error handling vs interfaces that are harder to misuse.
Trait design and error reporting.
Entropy source (e.g. getrandom
) vs default random source.
dhardy: "PRNGs like PCG or Xoshiro are much smaller and somewhat faster than CSPRNGs like ChaCha, so there's incentive for both to exist."
Lower-priority topics: