# The compiler suggests replacing crypto:rand\_uniform with rand:uniform. Bad idea?

**URL:** <https://erlangforums.com/t/the-compiler-suggests-replacing-crypto-rand-uniform-with-rand-uniform-bad-idea/4375>\
**Category:** Questions / Help\
**Tags:** erlang\
**Created:** [January 10, 2025, 3:42pm UTC](https://erlangforums.com/t/the-compiler-suggests-replacing-crypto-rand-uniform-with-rand-uniform-bad-idea/4375 "2025-01-10T15:42:12Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![matthiasl](https://erlangforums.com/user_avatar/erlangforums.com/matthiasl/32/1652_2.png) [@matthiasl](https://erlangforums.com/u/matthiasl)\
**Post date:** [January 10, 2025, 3:42pm UTC](https://erlangforums.com/t/the-compiler-suggests-replacing-crypto-rand-uniform-with-rand-uniform-bad-idea/4375/1 "2025-01-10T15:42:12Z")

</div>

Hi,

Using 27.1.2, the compiler tells me:

```erlang
fwknop.erl:78:25: Warning: crypto:rand_uniform/2 is deprecated; use rand:uniform/1 instead

```

As far as I can tell, rand\_uniform is not cryptographically secure, whereas crypto:rand\_uniform was intended to be, and probably (?) was, at least from about OTP 20 onwards.

Is the compiler’s advice as bad as it seems?

Matthias

---

<div class="post-metadata">

**Author:** ![garazdawi](https://erlangforums.com/user_avatar/erlangforums.com/garazdawi/32/175_2.png) [@garazdawi](https://erlangforums.com/u/garazdawi)\
**Post date:** [January 10, 2025, 4:04pm UTC](https://erlangforums.com/t/the-compiler-suggests-replacing-crypto-rand-uniform-with-rand-uniform-bad-idea/4375/2 "2025-01-10T16:04:04Z")

</div>

Before crypto 3.0 the API used is **BN\_pseudo\_rand\_range** which is documented as:

> pseudo-random numbers generated by this function are not necessarily unpredictabl

Reference: [BN\_rand\_range(3)](https://sortix.org/man/man3/BN_rand_range.3.html)

When running crypto 3.0 it uses **BN\_rand\_range** which is cryptographigally secure. So it depends on which version of libcrypto you are using. The deprecation of crypto:rand\_uniform was done long before crypto 3.0 was created.

So using rand instead is a good option. If you want something that is cryptographically secure no matter which version of crypto you have, you should use strong rand bytes.

This should probably be made clear in the crypto docs. A PR would be most welcome.

---

<div class="post-metadata">

**Author:** ![matthiasl](https://erlangforums.com/user_avatar/erlangforums.com/matthiasl/32/1652_2.png) [@matthiasl](https://erlangforums.com/u/matthiasl)\
**Post date:** [April 7, 2025, 9:12pm UTC](https://erlangforums.com/t/the-compiler-suggests-replacing-crypto-rand-uniform-with-rand-uniform-bad-idea/4375/3 "2025-04-07T21:12:19Z")

</div>

Replying to my own post, and Lukas’ reply.

I decided to abandon the security code I was trying to update. It’s from a project that’s looking semi-abandoned and I decided leaving it semi-broken was better than risking introducing security problems because I’m not confident I know everything about the code.

The project is ‘fwknop’. It’s a good little tool (it protects SSH servers from being scanned from all over the internet), but its popularity has waned, in part because ‘wireguard’ has overlapping properties and is more popular. The github repo doesn’t have many recent commits, the mailing list has no posts for several years and the code has rotted in several ways.

---

<div class="post-metadata">

**Author:** ![adamu](https://erlangforums.com/user_avatar/erlangforums.com/adamu/32/2097_2.png) [@adamu](https://erlangforums.com/u/adamu)\
**Post date:** [October 7, 2025, 12:24pm UTC](https://erlangforums.com/t/the-compiler-suggests-replacing-crypto-rand-uniform-with-rand-uniform-bad-idea/4375/4 "2025-10-07T12:24:13Z")

</div>

I am also looking at this.

The [:rand docs](https://www.erlang.org/docs/28/apps/stdlib/rand.html#module-plug-in-framework) state:

> The builtin random number generator algorithms are not cryptographically strong. If a cryptographically strong random number generator is needed, use something like [`crypto:rand_seed/0`](https://www.erlang.org/docs/28/apps/crypto/crypto#rand_seed/0).

So it would seem that the following is safe:

```erlang
crypto:rand_seed().
rand:uniform(10).

```

However, it seems that the only way to be sure that `rand` is using the secure seed provided by crypto is to wrap every call to `rand` with a check that `rand:export_seed/0` returns `{crypto, _}`:

```erlang
1> rand:uniform(10) % insecure!
   .
9
2> {crypto, _} = rand:export_seed(), rand:uniform(10).
** exception error: no match of right hand side value {exsss,[...]}
3> crypto:rand_seed().
{#{type => crypto, ...}, no_seed}
4> {crypto, _} = rand:export_seed(), rand:uniform(10).
3

```

This is not ideal, as it could be possible to forget to call `rand:export_seed`, or accidentally remove it, ending up with insufficient randomness. It would be nice if `rand` had a mode that allowed us to be sure we are getting cryptographically secure randomness. With `crypto:rand_uniform`, this is unambiguous.

---

<div class="post-metadata">

**Author:** ![raimo](https://erlangforums.com/user_avatar/erlangforums.com/raimo/32/867_2.png) [@raimo](https://erlangforums.com/u/raimo)\
**Post date:** [October 7, 2025, 4:59pm UTC](https://erlangforums.com/t/the-compiler-suggests-replacing-crypto-rand-uniform-with-rand-uniform-bad-idea/4375/5 "2025-10-07T16:59:50Z")

</div>

I don’t know why you would _need_ to wrap all calls to`rand`…

`rand` _has_ a mode that guarantees cryptographically secure random numbers, and that mode is invoked by calling `crypto:rand_seed/0` or friends. After that all calls to e.g `rand:uniform/1`, _in the same process_ returns strong random numbers from `crypto`.

Or you can keep the return value from `crypto:rand_seed/0` and use that explicit state with the `rand:*_s/*` functions, from any process.

The `rand` module has a framework for creating numbers of any range, and floats. Having a new set of API functions for every new algorithm is not feasible. Doubling all API functions just for the sake of cryptographically strong numbers would be awkward, so they live within the same API as all other pseudo random number algorithms, but with initialization from `crypto`…

---

<div class="post-metadata">

**Author:** ![adamu](https://erlangforums.com/user_avatar/erlangforums.com/adamu/32/2097_2.png) [@adamu](https://erlangforums.com/u/adamu)\
**Post date:** [October 8, 2025, 5:32am UTC](https://erlangforums.com/t/the-compiler-suggests-replacing-crypto-rand-uniform-with-rand-uniform-bad-idea/4375/6 "2025-10-08T05:32:28Z")

</div>

I think there are two issues for people who want secure randomness:

1. The default is not secure
2. The usage does not guarantee that the result is secure

Unless the call to `rand` comes immediately after either the `crypto:rand_seed` call or an assertion that it’s set, it’s possible that the randomness does not come from `crypto`. Another example in addition to the ones I mentioned in the post above is if, for example, `rand`’s algoritm gets changed somehow by other code before code that expects secure randomness is called.

```erlang
crypto:rand_seed()
more_code() % this changes rand's seed
rand:uniform() % not cryptographically secure

```

Compared to:

```erlang
crypto:rand_seed()
more_code() % this changes rand's seed
crypto:rand_uniform() % still secure

```

What I’m getting at is that the intention of the programmer who wrote `crypto:rand_uniform()` is quite clear, but with `rand:uniform()` it is necessary to check the surrounding context - which may not be clear, or may be incorrect due to coding errors/bugs. That is an area of potential defects that could be avoided with an explicit option.

---

<div class="post-metadata">

**Author:** ![adamu](https://erlangforums.com/user_avatar/erlangforums.com/adamu/32/2097_2.png) [@adamu](https://erlangforums.com/u/adamu)\
**Post date:** [October 8, 2025, 5:57am UTC](https://erlangforums.com/t/the-compiler-suggests-replacing-crypto-rand-uniform-with-rand-uniform-bad-idea/4375/7 "2025-10-08T05:57:47Z")

</div>

> [@raimo](#):
>
> Or you can keep the return value from `crypto:rand_seed/0` and use that explicit state with the `rand:*_s/*` functions, from any process.

Sorry I missed this comment when writing the reply. This is also a good option, thanks!

---

<div class="post-metadata">

**Author:** ![phild](https://erlangforums.com/user_avatar/erlangforums.com/phild/32/742_2.png) [@phild](https://erlangforums.com/u/phild)\
**Post date:** [October 8, 2025, 8:00am UTC](https://erlangforums.com/t/the-compiler-suggests-replacing-crypto-rand-uniform-with-rand-uniform-bad-idea/4375/8 "2025-10-08T08:00:35Z")

</div>

> [@raimo](#):
>
> Or you can keep the return value from `crypto:rand_seed/0` and use that explicit state with the `rand:*_s/*` functions, from any process.

This seems like it should be the recommended approach for most use cases?

---

<div class="post-metadata">

**Author:** ![raimo](https://erlangforums.com/user_avatar/erlangforums.com/raimo/32/867_2.png) [@raimo](https://erlangforums.com/u/raimo)\
**Post date:** [October 8, 2025, 8:55am UTC](https://erlangforums.com/t/the-compiler-suggests-replacing-crypto-rand-uniform-with-rand-uniform-bad-idea/4375/9 "2025-10-08T08:55:04Z")

</div>

Correct code requires discipline.

To store state in the process dictionary is sometimes convenient, but frowned upon because it deviates from functional programming, and requires the discipline to ensure that the state in the process dictionary is not accidentally altered.

The explicit state functions in `rand` offers a functional interface which some would say must be the only right way, while others would prefer the convenience of not having to store the state.

The API has both alternatives.

The `rand` module is written for Pseudo Random Number Generation, and cryptographically strong generators is a special case in that algorithm class. That is stated in the section “Quality of the Generated Numberts”. The default is chosen for speed and distribution, for example simulations, not for cryptography.

---

<div class="post-metadata">

**Author:** ![adamu](https://erlangforums.com/user_avatar/erlangforums.com/adamu/32/2097_2.png) [@adamu](https://erlangforums.com/u/adamu)\
**Post date:** [October 8, 2025, 3:57pm UTC](https://erlangforums.com/t/the-compiler-suggests-replacing-crypto-rand-uniform-with-rand-uniform-bad-idea/4375/10 "2025-10-08T15:57:51Z")

</div>

> [@raimo](#):
>
> Correct code requires discipline.

I’m sure Matthias is very disciplined, yet the change has prompted him to start this thread, and me to follow up!

---

<div class="post-metadata">

**Author:** ![eproxus](https://erlangforums.com/user_avatar/erlangforums.com/eproxus/32/452_2.png) [@eproxus](https://erlangforums.com/u/eproxus)\
**Post date:** [October 8, 2025, 5:41pm UTC](https://erlangforums.com/t/the-compiler-suggests-replacing-crypto-rand-uniform-with-rand-uniform-bad-idea/4375/11 "2025-10-08T17:41:39Z")

</div>

> [@raimo](#):
>
> Correct code requires discipline.

Such a good quote! 🤩

---

<div class="post-metadata">

**Author:** ![raimo](https://erlangforums.com/user_avatar/erlangforums.com/raimo/32/867_2.png) [@raimo](https://erlangforums.com/u/raimo)\
**Post date:** [October 9, 2025, 11:15am UTC](https://erlangforums.com/t/the-compiler-suggests-replacing-crypto-rand-uniform-with-rand-uniform-bad-idea/4375/12 "2025-10-09T11:15:11Z")

</div>

> [@adamu](#):
>
> I’m sure Matthias is very disciplined, yet the change has prompted him to start this thread, and me to follow up!

Misunderstand me correctely ;-), I am sure you are.

But sometimes the code that is called between PRNG init and use is limited and all under your control, so you can trust your own discipline. And sometimes the code called is managed by a number of other teams in other parts of a big organization and then you don’t want to trust the collective to be disciplined enough.

So when security is at stake I agree that using the functional API with explicit state in general is the better choice since you can then verify a limited amount of code and prove (at least to yourself) that it is correct.

---

<div class="post-metadata">

**Author:** ![adamu](https://erlangforums.com/user_avatar/erlangforums.com/adamu/32/2097_2.png) [@adamu](https://erlangforums.com/u/adamu)\
**Post date:** [October 11, 2025, 12:00pm UTC](https://erlangforums.com/t/the-compiler-suggests-replacing-crypto-rand-uniform-with-rand-uniform-bad-idea/4375/13 "2025-10-11T12:00:03Z")

</div>

> [@raimo](#):
>
> Having a new set of API functions for every new algorithm is not feasible. Doubling all API functions just for the sake of cryptographically strong numbers would be awkward

I notice a few things after thinking about this more:

1. `crypto` has provided `strong_rand_bytes/1` since 2011, which is redundant due to `rand:bytes/1` if I’ve understood correctly.

2. The `crypto` module also includes [undocumented functions](https://github.com/erlang/otp/blob/fea600b12f3da2bf72c839d81f5044a8e0423d85/lib/crypto/src/crypto.erl#L164-L169) (`rand_plugin_uniform/1` etc.) to support `rand`’s plugin API so has basically implemented this logic even if not indented to be called directly.

3. The `jump` part of `rand`’s plugin API does not apply to cryptographically secure random number generation, because the numbers are never predictable.

It feels to me that it might be cleaner for `rand` to state that it should not be used for cryptographic operations at all. Then `crypto` would not need to implement the Plugin API. It already has functions for bytes and integers. So would need maybe 1 or 2 more (`normal` and `uniform_real`)? This is also seems to be the intention in the [commit that deprecated `crypto:rand_uniform`](https://github.com/erlang/otp/commit/4e44a1414bcdae81305f98d7789fdad00a0bc94d):

> rand module should be used if not cryptographically strong is required.  
> If cryptographically strong is required, new cryptographically strong  
> functions should be added to crypto.

---

<div class="post-metadata">

**Author:** ![raimo](https://erlangforums.com/user_avatar/erlangforums.com/raimo/32/867_2.png) [@raimo](https://erlangforums.com/u/raimo)\
**Post date:** [October 13, 2025, 9:46am UTC](https://erlangforums.com/t/the-compiler-suggests-replacing-crypto-rand-uniform-with-rand-uniform-bad-idea/4375/14 "2025-10-13T09:46:29Z")

</div>

Regarding:

1. `crypto:strong_rand_bytes/1` and `rand:bytes/1` overlap but have different use cases. If it is cryptographically strong bytes that is needed, use `crypto`. `rand` also supports generating bytes, from any of the PRNG backends. So if you need to be able to switch backend, use `rand`, or if you need more lightweight not cryptographically strong bytes, and/or don’t want to waste entropy. To use `rand` solely for strong random bytes is, as we say in Sweden, to go over the river to fetch water. It only adds overhead since the plugin framework forces `crypto`’s bytes into 56 bit integers and converts them into bytes. Much ado about nothing…
2. The plugin functions are for the `rand` module and not very useful without it.
3. Correct. Jumping contradicts non-predictability so it doesn’t apply

In `rand` we have `uniform` for any integer range and for float, `uniform_real` for another variant of float, and `normal` for normal distribution float. For any random (pun intended) new features like `shuffle` that we add, we would get further into API multiplication since we have an API for these features in `rand`. Doubling them all into `crypto` would be awkward. For example the implementation of uniform range, normal distribution, shuffle, is tricky to get right, so one would want just one implementation, and some plug-in structure…

The commit commenter that deprecated `crypto:rand_uniform` was probably not aware of the plug-in work in `rand` for uniform integers.

---

<div class="post-metadata">

**Author:** ![adamu](https://erlangforums.com/user_avatar/erlangforums.com/adamu/32/2097_2.png) [@adamu](https://erlangforums.com/u/adamu)\
**Post date:** [October 16, 2025, 4:19am UTC](https://erlangforums.com/t/the-compiler-suggests-replacing-crypto-rand-uniform-with-rand-uniform-bad-idea/4375/15 "2025-10-16T04:19:39Z")

</div>

> [@raimo](#):
>
> To use `rand` solely for strong random bytes is, as we say in Sweden, to go over the river to fetch water. It only adds overhead since the plugin framework forces `crypto`’s bytes into 56 bit integers and converts them into bytes. Much ado about nothing…

Yes, this is the argument I am making too, except for _all_ cryptographically strong operations. I think that the risks associated with having to go via `rand`, when you only want cryptographically strong operations are higher than the benefits achieved by being able to use `rand`’s API. I’m suggesting that a restricted subset in `crypto` - just like `crypto:strong_rand_bytes/1 ` - only for cryptographic operations would be more desirable for the times when cryptographically strong guarantees are desired.

---

<div class="post-metadata">

**Author:** ![raimo](https://erlangforums.com/user_avatar/erlangforums.com/raimo/32/867_2.png) [@raimo](https://erlangforums.com/u/raimo)\
**Post date:** [November 3, 2025, 4:25pm UTC](https://erlangforums.com/t/the-compiler-suggests-replacing-crypto-rand-uniform-with-rand-uniform-bad-idea/4375/16 "2025-11-03T16:25:09Z")

</div>

For what it’s worth; I am rewriting the documentation to clarify this situation and to recommend the explicit state `rand` functions for cryptographic applications.

> <https://github.com/erlang/otp/pull/10344>
>
> This PR improves the documentation to clarify how to use the \`crypto\` plug-in ge…nerator(s) in \`rand\` in a safe manner.
> 
> While at it I also (hopefully) improved the overview section in the \`rand\` documentation a bit.

---

<div class="post-metadata">

**Author:** ![raimo](https://erlangforums.com/user_avatar/erlangforums.com/raimo/32/867_2.png) [@raimo](https://erlangforums.com/u/raimo)\
**Post date:** [November 6, 2025, 5:20pm UTC](https://erlangforums.com/t/the-compiler-suggests-replacing-crypto-rand-uniform-with-rand-uniform-bad-idea/4375/17 "2025-11-06T17:20:58Z")

</div>

> [@adamu](#):
>
> It feels to me that it might be cleaner for `rand` to state that it should not be used for cryptographic operations at all. Then `crypto` would not need to implement the Plugin API. It already has functions for bytes and integers. So would need maybe 1 or 2 more (`normal` and `uniform_real`)?

The latest suggestion, in the PR I linked to above, is to export `crypto:strong_rand_range/1`, and point the deprecated function to that. But I don’t think any more of `rand`’s functionality belongs in `crypto`. The functions that OpenSSL’s libcrypto implements do, since they are building blocks for `rand`, but not all of the code in e.g `rand:normal/*` or the new `rand:shuffle/1` etc.
