Generating random numbers from a lava lamp using .NET Core

Photo by @marcszeglat / Unsplash.com

I used to have a lava lamp when I was young. I mean, I’m still relatively young, but I haven’t had a lava lamp in decades anymore. I think it was a fad of the 1990s, and when everyone realized the lamps actually broke rather easily, the hype died quickly. Our family also had a bread machine around the same time. We don’t have that either, anymore.

When I read about Cloudflare’s random number generator solution with their distributed randomness beacon, and especially the LavaRand solution, I figured I can just as well build my own. Because what’s better than spending a few evenings of quality time fiddling with something, that will inevitably break, but during the process teach you a lot about life and make you question your life choices?

Cloudflare has built a very impressive solution with arrays and rows of lava lamps, and additional logic into considering image noise from the capture device. I don’t have time for all that, but I wanted to build something akin, yet a bit more.. ghetto?

Random number generators

I first spent a bit of time reading about random number generators, or RNGs. In short, it’s a device or an algorithm that produces numbers that are not reasonably predicted. You could use a pair of dice, and with Cognitive Services in Azure, it would be trivial to read the values automatically. But, I want the lava lamp to be part of this setup!

Using .NET Core and C#, I can use the Random class to generate pseudo-random numbers. They are pseudo because that class uses a finite set of numbers. See D. E. Knuth. The Art of Computer Programming, Volume 2: Seminumerical Algorithms. Addison-Wesley, Reading, MA, third edition, 1997 for the internals of this.

Thus, making this easy, I could just do this in C#:

Random rnd = new Random(); 
Console.WriteLine(“{0}”, Rnd.Next()); 

And this would produce me with a random number, such as 42. Typically, this is good enough for many purposes.

You can also use System.Security.Cryptography.RNGCryptoServiceProvider to generate cryptographically strong random values. It’s a bit more complex, but also it doesn’t involve a fancy gizmo, like a lava lamp.

The setup

I started to build my setup by sourcing a good webcam, that can capture data from a lava lamp. Back in the day, I used a USB-connected Logitech webcam, the one that looks like a golf ball. The API used the atrocious Win32 APIs, and calling that from managed code, such as C#, was painful.

Thankfully, I happened to purchase a set of 5 cameras (for some reason), and I haven’t had much use for them yet.

They are the Ubiquiti Networks’ Unifi UVC-G3 surveillance cameras. They can be powered with Power over Ethernet, and they look badass. A box of 5 costs around $800. Definitely not the cheapest, but they are meant for ‘real’ surveillance, not just for hacking around in your basement with a lava lamp trying to generate random numbers.

The cameras expose a REST API, which is super easy to use. Simply call:

GET http://unifiserver/api/2.0/snapshot/camera/{CameraID}

And it returns a static .JPG file! So by using this setup, I purchased the cheapest lava lamp I could find (about $15) and captured a few images.

Processing the image

And now all that’s left is to use a bit of C# again to process the image. I found interesting research papers on how exactly to do this. They were very complex and full of algorithms and math I wasn’t familiar with. I wanted to get this thing working, so I started hacking around a bit and ended up with a simple approach:

Bitmap img = new Bitmap(@"c:\temp\lava-closeup.jpg");
for (int i = 0; i < img.Width; i++)
{
	for (int j = 0; j < img.Height; j++)
	{
		Color pixel = img.GetPixel(i, j);

		if (pixel.R < 255 && pixel.G < 255 && pixel.B < 255)
		{
			sb.Append(pixel.R + pixel.G + pixel.B);
		}
	}
}

Random rnd = new Random();
string randomNumber = sb.ToString().Substring(rnd.Next(1, sb.Length -1), 6);

First, I’m reading the image file as a bitmap. I’m then looping each pixel of the image and randomly pick one pixel. From that pixel, I store the R, G and B values in numerical forms – thus, I end up with three values, that I add together. Finally, I generate a pseudo-random number and generate my final random number with aid from that.

Admittedly, this isn’t cryptographically secure. Also, the code is far from great, but it works as an initial proof of concept.

In conclusion

This was a fun little exercise. Adding physical devices – the lava lamp, and a camera – brought in some extra challenges, in a good way. Reading the image file was very simple, and it opened up all sorts of opportunities to enhance the logic later on.

I opted to generate 6 figure numbers, but perhaps I should optimize this at a later date to produce longer, or shorter numbers as needed. This could also be wrapped in an Azure Function to produce an API for generating these numbers.