Sign_digest_with_rng() don't work with new ThreadRng - how to fix?

I'm using rsa::signature::RandomizedDigestSigner as well as ecdsa::signature::RandomizedDigestSigner for creating signatures. The function sign_digest_with_rng() takes a &mut impl CryptoRngCore as parameter.

This has been working fine for me with thread_rng() all the time. But, after recently updating some dependencies, I see that thread_rng() has been superseded by rng(). And, that ThreadRng now suddenly implements TryRngCore and TryCryptoRng rather than implementing RngCore and CryptoRng as it used to. This makes sign_digest_with_rng() complain that CryptoRngCore is not implemented when I try to use it with the rng() :worried:

If thought that unwrap_err() is supposed to fix that, by wrapping the TryRngCore as an RngCore again, but it doesn't work! This following code:

sign_digest_with_rng(&sign_key, &mut rng().unwrap_err(), Sha256::new_with_prefix(message))

...won't compile with error:

125 |     EccRandomizedDigestSigner::<Sha256, EccSignature>::sign_digest_with_rng(&sign_key, &mut rng().unwrap_err(), Sha256::new_with_prefix(message))
    |     -----------------------------------------------------------------------            ^^^^^^^^^^^^^^^^^^^^^^^ the trait `rsa::rand_core::RngCore` is not implemented for `UnwrapErr<ThreadRng>`
    |     |
    |     required by a bound introduced by this call

How do I fix this?

(I'm using latest "stable" version of Rust, which is 1.86.0 at this time)

Thanks for any advice!

unwrap_err() looks like the wrong method to call to me. Try calling unwrap() instead.

Edit: where does the rng() function come from? It's not from the rand crate as I initially thought.

I don't think ThreadRng or TryRngCore has an unwrap() function :exclamation_question_mark:

According to the TryRngCore documentation:

An implementation of this trait may be made compatible with code requiring an RngCore through TryRngCore::unwrap_err(). The resulting RNG will panic in case the underlying fallible RNG yields an error.

So, it would seem that TryRngCore::unwrap_err() gives a wrapper that can then be passed to functions that expect a RngCore rather than TryRngCore. Still, somehow it doesn't work with the RandomizedDigestSigner::sign_digest_with_rng() function for me :confused:

It comes from rand:rng, which apparently has replaced the old rand::thread_rng.

Ah, I think you updated your rand version to 0.9, which is incompatible with the current rsa and ecdsa versions. rand 0.9 types implement the rand_core 0.9 traits. But rsa and ecdsa rely on the traits from rand_core 0.6. Try downgrading your rand version to 0.8, which uses rand_core 0.6.

Yeah, problem started when I updated the dependencies. But the ultimate goal is to actually update the dependencies to an up-to-date version. Is there no way to use an up-to-date rand version with rsa and ecdsa signing functions? Or, let me ask: Are there any plans to make the rsa and ecdsa functions compatible with the up-to-date version of rand?

It would seems a bit odd that such fundamental crypto functions don't work with the latest RNG.

Certainly. But updating a core dependency of an ecosystem as vast as rust-crypto takes time I guess. The current rsa 0.10 pre-release already uses rand_core 0.9.

1 Like

Here is a workaround, I have found :relieved_face:

use rand::{rng, RngCore};
use rsa::signature::rand_core::{CryptoRng as LegacyCryptoRng, Error as LegacyRngError, RngCore as LegacyRngCore};

struct LegacyCompatRng;

impl LegacyRngCore for LegacyCompatRng {
    fn next_u32(&mut self) -> u32 {
        rng().next_u32()
    }

    fn next_u64(&mut self) -> u64 {
        rng().next_u64()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        rng().fill_bytes(dest);
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), LegacyRngError> {
        self.fill_bytes(dest);
        Ok(())
    }
}

impl LegacyCryptoRng for LegacyCompatRng {}

Then, the following invocation will now work again:

sign_digest_with_rng(&sign_key, &mut LegacyCryptoRng, Sha256::new_with_prefix(message))

(If there is a more elegant way, please let me know!)