Clarify the cryptographic properties of SystemRandomNumberGenerator

I recently proposed a patch to change the documentation of SystemRandomNumberGenerator to affirmatively state that it is cryptographically secure on all platforms, and that it will crash on any platform where it cannot provide that guarantee.

@nnnnnnnn has correctly pointed out on that issue that the original proposal for SystemRandomNumberGenerator calls out that on some platforms it may not meet the requirements for being a CSPRNG:

The aspiration is that this RNG should be cryptographically secure, provide reasonable performance, and should be thread safe. If a vendor is unable to provide these goals, they should document it clearly.

This is a pretty unfortunate clause, so I'd like to get feedback on whether the community (and in particular the core team) are interested in a pitch to supplement SE-0202 that improves matters.

My primary issue with this language is that it explicitly allows for SystemRandomNumberGenerator to be backed by a non-CSPRNG implementation. This has the implicit effect of meaning that SystemRandomNumberGenerator's suitability for cryptographic use applies on a per-platform basis. As a result, any library wanting to use a CSPRNG is forced to make a choice between three options:

  1. Guard the use of SystemRandomNumberGenerator with #if(os), #if(swift), and if @available guards to attempt to restrict its use to platforms and Swift versions where the standard library guarantees that SystemRandomNumberGenerator is a CSPRNG.
  2. Copy the code of SystemRandomNumberGenerator and reinvent it in their library, ensuring that it will be a CSPRNG whenever their library is built.
  3. Use SystemRandomNumberGenerator and hope that no platform is ever written that doesn't make SystemRandomNumberGenerator a CSPRNG, or their library will silently fail to meet its security requirements.

So I'd like to clarify: is it really the intent that SystemRandomNumberGenreator is not supposed to guarantee cryptographic security? If that is, is there interest in an alternative version in the standard library that does provide that guarantee?

5 Likes

To my recollection, yes, it really is the intent that it's best-effort, not a guarantee. The type is called SystemRandomNumberGenerator because it does what it reasonably can with what the system provides.

Ok, thanks. Can you think of any reason the standard library shouldn't also provide a CSPRNG?

Alternatively, could we not add a second, guaranteed-secure PRNG, which elevates that "aspiration" of SRNG to a bonafide feature?

So when porting the standard library to a platform without an available CSPRNG, you couldn't implement this and it would result in a compile-time error.

2 Likes

In my opinion, there's definitely room for more generators, both cryptographically secure and not. The proposal stopped short of adding those, but the groundwork is all there. Seedable generators are another important use case that a filling out could include.

1 Like

I remember seedable generators being mentioned in the original thread discussions as future functionality but there is no mention of them (or any future directions for that matter) in the proposal text.

I'm sure there are many things that could be added to the Random API to make it more full-featured. Things like sendable generators, custom counts of random bytes, CSPRNGs, etc would probably all need to be individual proposals wouldn't they?

1 Like

Agree, this is my top request for the random APIs. Most of the things I do with randomness would benefit from seeding. We should have a high quality seedable implementation in the standard library.

2 Likes

Perhaps a small “Random” library/core-library could be created with specific algorithms and specialised generators such as you’re describing. The standard library should just offer basic randomness IMO, for simple things like shuffling an array.

A CSPRNG library would basically never change: there is only one correct implementation for any platform, and once it’s there you have it. So I’d be inclined, if we were doing this outside the stdlib, to have these be separate from the seeded RNGs.

It is a bit of a shame to do the CSPRNG work outside the stdlib though: the stdlib already has the code we need in it!

(I think) there’s definitely room for a seedable RNG in the stdlib, but it should be developed in a package first. One thing to keep in mind is that any seedable RNG should be able generate identical results across stdlib versions in order to be really useful, so we want to get its behavior completely locked down before adding it; we wouldn’t be able to fix bugs or make other changes that would otherwise be possible behind the API surface.

(We could also provide an explicitly versioned API for people who need stable behavior, which works around this to some extent, but you’re stuck supporting the old versions forever no matter what.)

1 Like

In a package or in the package?

1 Like

I imagine it would just be a typealias behind a platform check, if you did this, so there’d be no duplicate work.

1 Like

Probably a package, initially, since the bar for entry to “the package” requires resolving these API design issues first =)