Not really random?

Published on Sat May 22 2021

I just ran into some very interesting in my own Go code.

It turns out that random numbers aren’t always really random.

Check out this code:

package main

import (
	"encoding/base64"
	"fmt"
	"math/rand"
)

func main() {
	data := make([]byte, 16)
	rand.Read(data)
	fmt.Println(base64.StdEncoding.EncodeToString(data))
}

If I run the code (check it out on the Go playground) it will produce this result:

Uv38ByGCZU8WP18PmmIdcg==

The interesting part is that it produces the same result every time it runs!

But this is not a bug! This is a feature!

It is because the math/rand package is made like this. It will produce the same random number sequence every time it runs. It is because the package uses a seed to produce the random numbers! Every time it runs without specifying a seed it used the default seed and will therefore produce the same result.

This could be fixed by adding a line like rand.Seed(time.Now().UnixNano()) but this is treating the symptoms. Instead, you should only be using the math/rand package if you need to reproduce (the same) seed-based sequences. If it is truly random number sequences you need – especially for cryptographic applications – you should use the crypto/rand package instead.

The example now looks like this (try it on the Go playground):

package main

import (
	"crypto/rand"
	"encoding/base64"
	"fmt"
)

func main() {
	data := make([]byte, 16)
	rand.Read(data)
	fmt.Println(base64.StdEncoding.EncodeToString(data))
}

This will produce a new output on every run.

Simple 🥳