-1

Python has a very convenient way to get cryptographically secure random hexadecimal; secrets.token_hex(n)

So by running secrets.token_hex(8) you get 16 hexadecimal, secrets.token_hex(12) gives 24 hexadecimal and so on. There is basically no upper lever. The number in the parentheses is in bytes.

My question, as recently started to learn Rust, is if there is a similar smart way to get a very high randomized hexadecimal output?

In Python:

import secrets


for x in range(1):
    xxx = secrets.token_hex(8)
   
  • There is an [entry](https://rust-lang-nursery.github.io/rust-cookbook/algorithms/randomness.html) in the Rust cookbook about how to generate random stuff. – jthulhu Mar 20 '23 at 08:13
  • Offtop, but please have mercy and don't call variable `hex` (it's a function...) and use f-string for formatting / format if it's older python. – Gameplay Mar 20 '23 at 08:19
  • @Gameplay, well had this small python program for a long time. Its so small and works as intended even though not good locking. – Slow but learning Mar 20 '23 at 08:23
  • @jthulhu, can't say that I find that part of the cookbook useful. Not if want to get 64 or 128 hexadecimal. Pythons secrets.token_hex(n) is rather clever. Wish Rust would have a similar thing. Maybe it does, but I haven't seen yet – Slow but learning Mar 20 '23 at 08:27
  • @Slowbutlearning you could always use the [create a random password from a set of user-defined characters](https://rust-lang-nursery.github.io/rust-cookbook/algorithms/randomness.html#create-random-passwords-from-a-set-of-user-defined-characters) recipe with the set being hexadecimal characters. Just provide the size in nibbles instead of bytes (so double it). And there's nothing especially clever about `token_hex`. Convenient yes, but it's completely straightforward and exactly what you'd expect it to be: generate the requested number of random bytes, then hex-encode that. – Masklinn Mar 20 '23 at 08:31
  • @Masklinn, why I mean its clever is because its simplicity. The solution you proved below works. Its just Pythons solution is "clever"! – Slow but learning Mar 20 '23 at 09:16

2 Answers2

2

token_hex is literally nothing more than the hex-encoding of token_bytes, which is why you specify a number of bytes:

def token_hex(nbytes=None):
    return binascii.hexlify(token_bytes(nbytes)).decode('ascii')

Thus while rust has nothing which does that out of the box (to say nothing of builtin) the solution is simple: generate random bytes, then hex-encode them.

Funnily enough the hex-encoding is the more annoying of the two (on the playground anyway) because &[u8] doesn't implement LowerHex but the playground has neither hex nor rustc_serialize (which I believe are the two most popular crates for hex encoding, if you don't want to hand-roll it).

Anyway,

use rand::RngCore;
use rustc_serialize::hex::ToHex;

fn main() {
    // compile-time length, use `vec![0;len]` for runtime
    let mut bytes = [0; 16];
    rand::thread_rng().fill_bytes(&mut bytes);
    // demo-ing both crates, either works
    println!("{}", hex::encode(&bytes));
    println!("{}", bytes.to_hex());
}

For a single-expression version you could use Rng::gen but I don't think it works for runtime sizes, and I don't think it looks great either:

use rand::Rng;

fn main() {
    println!("{}", hex::encode(&rand::thread_rng().gen::<[u8; 16]>()));
}
Masklinn
  • 34,759
  • 3
  • 38
  • 57
  • Yes, you did write that and I'm thankful you took the time to write the above. Please have a bit patience with me as I am a bit slow in this. Will try it in the editor. – Slow but learning Mar 20 '23 at 08:37
  • Apparently `data-encoding` is available in the playground and can do hex encoding, if you don't want to try things out locally you can give it a shot, I've never used it but I expect it's easy enough if you look at the docs. – Masklinn Mar 20 '23 at 08:40
  • Did try the above suggestion in my editor and after some changes I got it to work pretty well. Thanks – Slow but learning Mar 20 '23 at 09:00
  • rustc-serialize gives a warning that it will be rejected by a future version of Rust – Slow but learning Mar 20 '23 at 09:49
  • note that Python's `secrets` module is specified to provide random values directly from the OS (e.g. via `urandom` under linux). AFAICT, equivalent under Rust would be [`OsRng.fill_bytes`](https://docs.rs/rand/latest/rand/rngs/struct.OsRng.html). – Sam Mason Mar 22 '23 at 19:05
0

This seems to be a solution. Just change 16 to desired number of hexadecimal. 32 will give 64 hexadecimal.

use rand::RngCore;
//use rustc_serialize::hex::ToHex;

fn main() {
    // compile-time length, use `vec![0;len]` for runtime
    let mut bytes = [0; 16];
    rand::thread_rng().fill_bytes(&mut bytes);
    println!("{}", hex::encode(&bytes));
    //println!("{}", bytes.to_hex());
}
cafce25
  • 15,907
  • 4
  • 25
  • 31