Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Randomness Through Radio: Creating a SDR Random Number Generator

DZone 's Guide to

Randomness Through Radio: Creating a SDR Random Number Generator

Learn more about random number generation in Java.

· Java Zone ·
Free Resource

Problem

Many programming languages provide random number generators (RNGs) that generate pseudo-random numbers, not truly random. A seed value is either externally-provided or internally-generated, from which the random numbers are calculated.

The Java class java.util.Random takes the seed and scrambles it with some bit magic.

public Random(long seed) {
    this.haveNextNextGaussian = false;
    if (this.getClass() == Random.class) {
        this.seed = new AtomicLong(initialScramble(seed));
    } else {
        this.seed = new AtomicLong();
        this.setSeed(seed);
    }
}

private static long initialScramble(long seed) {
    return (seed ^ 25214903917L) & 281474976710655L;
} 


A random number is generated by returning the number of bits required for the specific data type while also updating the seed value for the next request.

protected int next(int bits) {
    AtomicLong seed = this.seed;

    long oldseed;
    long nextseed;
    do {
        oldseed = seed.get();
        nextseed = oldseed * 25214903917L + 11L & 281474976710655L;
    } while(!seed.compareAndSet(oldseed, nextseed));

    return (int)(nextseed >>> 48 - bits);
}


Though impressive looking, identical random numbers are repeatedly returned when using the same seed and making identical requests. While fine for shuffling your iTunes playlist, it's not cool when security or privacy is required: financial transactions, medical records, legal documents, bitcoin wallets.

True random numbers require that the underlying data used to be unique, non-deterministic, difficult (nearly impossible) to repeat. Nature can provide this, e.g., atmospheric noise or radioactive decay, but requires Internet access. Commercial hardware solutions exist but are black-boxes in understanding how the true randomness is achieved.

So what about using software-defined radio?

Software-Defined Radio

Software-defined radio (SDR) is a digital implementation of a radio receiver, using modern electronics, computer hardware, and software that replace the hardware components of an analog radio: detectors, amplifiers, mixers, filters, and modulators/demodulators.

The flexibility and configurability of SDR provide many advantages:

  • Receive a wide range of frequencies, including super-low 
  • Adjust bandwidth depending on the frequency
  • Filter out noise caused by external factors, e.g. weather, interference, bleed;
  • Processes both analog and digital broadcast

A common SDR component is the RTL2832U, a USB dongle that is recognized by most operating systems. There is a variety of software solutions available, from full-blown GUI applications that scan frequencies to command-line apps that receive air traffic control information.

SDR Random Number Generator

My implementation uses a Raspberry Pi Model 3 running Raspian, though most *nix implementations should work.

Initial Setup

  1. Install Raspian. Download the Raspian image and copy to the micro SD card. Insert the micro SD card into the Raspberry Pi and boot, following the instruction set up. More detailed instructions are here.
  2. Add Packages. There are two Raspbian packages required: rtl-sdr contains a series of command line programs for interacting with the RTL2832U; sox does digital-to-analog conversion to play the audio received. Install using the command sudo apt-get rtl-sdr sox and follow the prompts

Receive the Broadcast

The command-line program rtl_fm is tuned to an FM frequency and writes the bytes to stdout. The bytes can be used for random number generation, audio playback, or both.

I use a *nix FIFO file to pass the raw data generated by rtl_fm to the random number generator. Using tee, it's possible to also hear the broadcasts being received.

mkfifo /tmp/sdr-random
/usr/local/bin/rtl_fm -g 50 -f 94.5M -M wfm -s 180k -E deemp | /usr/bin/tee /tmp/sdr-random | /usr/bin/play -q -r 180k -t raw -e s -b 16 -c 1 -V1 - lowpass 16k &


By using a FIFO file, nothing actually happens until there's a process reading. Therefore, no audio is heard until the random number generator is started.

Generate Random Numbers

The SDR Random Number Generator is a Spring Boot application reads from a file and stores the bytes in a circular buffer. By extending the Java-standard Random class, the bytes used are coming from the circular buffer rather than an original seed value.

package com.buddhadata.projects.jukebox.random.supplier;

import java.util.Random;
import java.util.function.LongSupplier;

/**
 * Generates random numbers by using bits generated through whatever external long provider is supplied
 */
public class LongSupplierRandom extends Random {

  /**
   * Provides the next seed value to use, however the producer wants to supply it.
   */
  private final LongSupplier seedProducer;

  /**
   * Constructor
   * @param seedProducer instance of class which can generate a seed to use.
   */
  public LongSupplierRandom(LongSupplier seedProducer) {
    this.seedProducer = seedProducer;
  }

  /**
   * All methods in java.util.Random call this method to get a series of bits, from which the next int, long,
   * double, whatever is generated.  Based on this presumed source: http://developer.classpath.org/doc/java/util/Random-source.html
   * @param bits  the number of random bits to generate, in the range 1..32
   * @return the next random value
   */
  @Override
  protected int next (int bits) {
    long l = seedProducer.getAsLong() & ((1L << 48) - 1);
    return (int) (l >>> (48 - bits));
  }
}


The LongSupplier defines a standard Java interface for providing longs, in our case from the software-defined radio output stored in the circular buffer. As random number requests are made, a pointer in the circular buffer is incremented to a new location in the buffer.

The Spring Boot application defines RESTful methods to request new random numbers, i.e. curl http://localhost:8080/random/double.

How Random Is It?

Looking at the possible variables that could be changed, it's pretty damn random:

  • Broadcast Frequency. FM stations typically broadcast between 88MHz and 108MHz, separated by at least .1MHz, for a potential of 200 different stations. Realistically, the actual number of stations is much smaller: depending on location, you might only receive 30 different stations, substantially less in rural areas.
  • Reception Quality. FM broadcasts are analog, so reception is impacted by external factors, e.g. distance from the transmitter, weather conditions, type/placement of the antenna, building construction, solar flares. No two receptions are the same: If it sounds different, the bytes generated from the SDR dongle are different. Different bytes, different random numbers.
  • Uniqueness. As most FM broadcasts are live and unscripted, the raw data produced by the SDR dongle is different from any other point of time: the ultimate one-time pad. Interviews and news reports might be replayed but could have been edited between occurrences, and the encompassing programs might have changed. Complete pre-recorded shows are rare on radio
  • Timing. The underlying buffer into which the raw data is written is continually overwritten by new data provided by the SDR dongle. It's not enough to request random numbers in the same order with the same radio broadcast and reception quality, it also requires identical timings. The underlying circular buffer is always being rewritten/refreshed, so if the underlying raw data doesn't match, then the random numbers generated won't match. The ultimate race condition.

Notes

  • The random number generator itself doesn't know that the data is supplied by the SDR dongle; anything process writing to the same file could be used.
  • The repo is configured to create a Docker image. Unfortunately, FIFO files are not supported by Docker at this time, and therefore, a different way is required to pass data to the random number generator.
  • The random number generator has implemented creating the file and starting rtl_fm with a specific frequency, but it doesn't always work, e.g. putting in rc.local to automatically start at boot.
  • The source for this is on GitHub.

Conclusion

If you need true random number generation, it's very easy to do so without a lot of expense or hassle.

Topics:
sdr ,random number generation ,java ,rtl sdr ,raspberry pi 3 ,raspian ,spring boot ,tutorial

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}