I think that we have moved a bit from the original intent of this question, but at the same time your comment is very interesting.
I think that the ring crate specifically uses many rust type safety features of rust to gain cryptography safety. For example, ephemeral keys can never be cloned, and any algorithm that uses them takes ownership over them.
You could claim that this shouldn't be done, because ephemeral keys can actually be cloned if we wanted them to be cloned (They are just an array of bytes), but ring won't let you do that. You can also claim that the algorithm using the ephemeral keys should take the ephemeral key by reference, because it doesn't need to take ownership over the memory. But it does take ownership, to make sure nobody else is using it again: This is what making it an ephemeral key.
So here, taking ownership and not allowing to clone are not features designed for memory safety in the old school senes in Rust. Instead, those two together provide some kind of cryptographic safety for the user.
unsafe for the random trait: The ring crate does not allow external users to implement SecureRandom, because that might be unsafe. This is why I think adding unsafe for the
TestRandom trait is an interesting idea. Whenever the user implements
TestRandom for some structure, exactly what you said happens: The programmer takes over some responsibility from the compiler.
If the user never uses unsafe in this case, he can only use the random generator provided by ring. However, by using
unsafe and implementing
TestRandom it allows the user to take responsibility over the contract made with the compiler.
Stated otherwise: ring tries to promise me that if I use only safe code, I am not likely to make cryptographic mistakes. However, if I choose to implement
TestRandom myself (thus having to use unsafe), it means that I take responsibility over implementing a secure random myself, and if I mess it up my cryptography will be unsafe.
To summarize, my claim is that maybe
unsafe can have a meaning larger than memory UB.
Thanks for sending this example!
I think it is another possible solution, but I prefer not to write my code this way. It feels like it is too easy for me to make a mistake, and the compiler will not be able to protect me here.