Urandom Wrapper

The problem

Some years ago I discovered /dev/urandom as built in pseudo random generator in a lot of linux distributions and I wanted to use it to generate random numbers.

Internet communities (as fraction of mankind) generate normally a lot of, let's say, destructive contributions but from time to time there are also a lot - of useful contributions give out for free (aside from the cost of the connection). Although the useful contributions are a small fraction of the total contributions - or at least I perceive so - normally a person can find often that someone already worked on the wanted solution if the context of the solution is very recent.

Well, maybe my search skills were not so high, but I did not find any clean solution to use /dev/urandom with a little additional programs as possible. This is helpful to port the solution in small linux distributions, like openwrt. Most of the solutions use awk, perl, python while I would have liked to get a random integer of (almost) arbitrary length.

The solutions.

One can search online solutions, there are plenty of approximative solutions (without using awk, perl, python or other programming languages) that nevertheless do work. For example one is the following

bytes_to_read_int=1
bytes_per_unsigned_integer=1
od -v -A n -N $bytes_to_read_int -t u$bytes_per_unsigned_integer < /dev/urandom

And this works quite well until 64 bits (8 bytes) unsigned integers, that are, well, quite long. Up to $18446744073709551615$ and would cover most of the needs.

But I like ideas like bc , that allows arbitrary precision arithmetic. I'm already super happy when I hit 50 digits for simple operations.

My rough solution

Rough because so far there are very little checks to avoid input errors and what not.

Since /dev/urandom outputs bytes, I thought to code those bytes back in numbers (like od does ), and then use the result to build a number. Since is better to start an action and proceeds slowly than being overwhelmed by a grandiose plan, I decided to use od until I substitute it with bitwise operations. od is quite a basic tool in linux and does not have a big footprint, so even in environments with few hundreds of kilobytes of memory free should be possible to install it. Then I assumed, as shell interpreter, busybox, that is quite "packed" compared to bash, using a stripped version of ash/dash interpreters.

numbers from 0 to 199

So I realized that if I get from /dev/urandom 1 byte as unsigned integer, I can likely use the numbers from 000 to 199 because those have the digit for the unit and for the tens equally distributed (the hundreds are not because those have only 0 and 1, if I go up to 255 I get also 2). One has to throw away the numbers 200 to 255 because those would modify the distribution of the digits for units and tens since, say, a 9 would appear less than a 4 then.

Actually I could have used an unsigned integer up to 2 or 3 bytes, to throw away less digits per byte but still be manageable by basic shell commands. In fact I'm not sure whtever the busbox commands can handle numbers over 16 millions (2 to the power of 16). I will check this in possible future iterations.

Building numbers and throwing them away

Since I want numbers that could be possibly very long, I treat them as strings, so I do not have numerical limitations for the commands that one can find in busybox. How do I build a number though?

Given a byte from /dev/urandom transformed by od in a number, when this is smaller than 200, I extract the digit in the unit position and in the ten position, to append it to my result string. The string may be as long as the maximum value in the input range (the parameters are: min_value and max_value ). At first I also checked the boundaries while building the string, implementing an idea like "if the result build so far will be surely bigger than the max value (comparison digit by digit), throw the last digit away and find a new one" (same checks for the min value) but this produced problems.

For example assume that the max value is 100. The random generator will pick as first digit either 0 or 1, throwing away all the rest. But if 1 is chosen, then all the other digits are forced to be 0, therefore skewing the distribution in the result.

So I settled that I build a string of the length of maxvalue as strong, and then I check if it is valid or not, checking digit by digit. If it is not valid, a new number is build.

This may be not a fast solution as od (actually finding a sort of extended od would solve all the problems, building a number bit by bit, or octal by octal, hex by hex and other multiples of 2), but first comes correctness, in every action, then speed.

So far the iteration was focused on the correctness and after a test of 100 thousand draws, for a range 1 to 999 (with 999 the selection is pretty fast because all the digits are valid, so none is thrown away) is giving back an eyeballed equal distribution (analyzed with perl). The same for 1 to 100.

Of course eyeballed equal distributions do not help, more tests are needed, but those will be for the next iterations. At the moment I do believe that the solution is somewhat usable, of course not for encrypted transactions.

Code

here on assembla.

Usage (a next iteration would have to include the help in the code, damn me):

chmod +x urandom_wrapper.sh
  # so it is executable, or use 'sh urandom_wrapper.sh'
./urandom_wrapper.sh 1 100
  # to get a number between 1 and 100, randomly.

Tools used

  • openwrt
  • busybox
  • od
  • internet man pages
  • wikidot
  • perl
  • libreoffice draw
  • notepad++
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License