Random number generator (device)

Revision as of 18:19, 19 April 2011 by rosettacode>Kernigh (→‎{{header|C}}: Add alternate solution for Windows using CryptGenRandom.)

If your system has a means to generate random numbers involving not only a software algorithm (like the /dev/random devices in Unix), show how to obtain a random 32-bit number from that mechanism.

Task
Random number generator (device)
You are encouraged to solve this task according to the task description, using any language you may know.

Ada

random.adb: <lang Ada>with Ada.Streams.Stream_IO; with Ada.Text_IO; procedure Random is

  Number : Integer;
  Random_File : Ada.Streams.Stream_IO.File_Type;

begin

  Ada.Streams.Stream_IO.Open (File => Random_File,
                              Mode => Ada.Streams.Stream_IO.In_File,
                              Name => "/dev/random");
  Integer'Read (Ada.Streams.Stream_IO.Stream (Random_File), Number);
  Ada.Streams.Stream_IO.Close (Random_File);
  Ada.Text_IO.Put_Line ("Number:" & Integer'Image (Number));

end Random;</lang>

C

It works on systems having /dev/urandom, like GNU/Linux.

<lang c>#include <inttypes.h>

  1. include <stdio.h>
  2. include <stdint.h>

int main(int argc, char **argv) {

   uint32_t v;
   FILE *r = fopen("/dev/urandom", "r");
   if (r == NULL)
   {

perror("/dev/urandom"); return 1;

   }
   size_t br = fread(&v, sizeof(uint32_t), 1, r);
   if (br < 1)
   {

fputs("/dev/urandom: Not enough bytes\n", stderr); return 1;

   }
   printf("%" PRIu32 "\n", v);
   fclose(r);
   return 0;

}</lang>

Library: BSD libc

arc4random() appeared in OpenBSD 2.1 and has spread to many BSD systems. This function runs an ARC4 random number generator that takes entropy from a kernel device. (This kernel device is sysctl kern.arandom in OpenBSD, or /dev/urandom in some other systems.)

<lang c>#include <inttypes.h> /* PRIu32 */

  1. include <stdlib.h> /* arc4random */
  2. include <stdio.h> /* printf */

int main() { printf("%" PRIu32 "\n", arc4random()); return 0; }</lang>

Library: OpenSSL

OpenSSL can generate random numbers. The default generator uses SHA1. For Unix systems, OpenSSL will gather entropy by reading a kernel device like /dev/urandom, or by using EGD, the Entropy Gathering Daemon. For other systems, OpenSSL might use a different source of entropy.

<lang c>#include <inttypes.h>

  1. include <stdio.h>
  1. include <openssl/err.h>
  2. include <openssl/rand.h>

int main() { uint32_t v;

if (RAND_bytes((unsigned char *)&v, sizeof(uint32_t)) == 0) { ERR_print_errors_fp(stderr); return 1; } printf("%" PRIu32 "\n", v); return 0; }</lang>

Windows

Works with: MinGW

<lang c>#include <stdio.h> /* printf */

  1. include <windows.h>
  2. include <wincrypt.h> /* CryptAcquireContext, CryptGenRandom */

int main() { HCRYPTPROV p; ULONG i;

if (CryptAcquireContext(&p, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) == FALSE) { fputs("CryptAcquireContext failed.\n", stderr); return 1; } if (CryptGenRandom(p, sizeof i, (BYTE *)&i) == FALSE) { fputs("CryptGenRandom failed.\n", stderr); return 1; } printf("%lu\n", i); CryptReleaseContext(p, 0); return 0; }</lang>

C#

<lang csharp>using System; using System.Security.Cryptography;

private static int GetRandomInt() {

 int result = 0;
 var rng = new RNGCryptoServiceProvider();
 var buffer = new byte[4];
 rng.GetBytes(buffer);
 result = BitConverter.ToInt32(buffer, 0);
 return result;

}</lang>

Forth

<lang forth>variable rnd

randoms ( n -- )
 s" /dev/random" r/o open-file throw
 swap 0 do
   dup rnd 1 cells rot read-file throw drop
   rnd @ .
 loop
 close-file throw ;</lang>

Go

In the Go library is crypto/rand, a source specified to use dev/urandom on Unix-like systems and the CryptGenRandom API on Windows. Also implemented here is a source using dev/random, if you really want it. On my system it would print a few numbers then hang until I moved the mouse or pressed some keys on the keyboard. <lang go>package main

import (

   "crypto/rand"
   "encoding/binary"
   "fmt"
   "io"
   "os"

)

func main() {

   testRandom("crypto/rand", rand.Reader)
   testRandom("dev/random", newDevRandom())

}

func newDevRandom() (f *os.File) {

   var err os.Error
   if f, err = os.Open("/dev/random"); err != nil {
       panic(err)
   }
   return

}

func testRandom(label string, src io.Reader) {

   fmt.Printf("%s:\n", label)
   var r int32
   for i := 0; i < 10; i++ {
       if err := binary.Read(src, binary.LittleEndian, &r); err != nil {
           panic(err)
       }
       fmt.Print(r, " ")
   }
   fmt.Println()

}</lang>

J

Untested: <lang j>256#.a.i.1!:11'/dev/urandom';0 4</lang>

Fallback: <lang j>256#.a.i.4{.host'dd if=/dev/urandom bs=4 count=1'</lang>

Note: this assumes that J is running on linux.

PicoLisp

<lang PicoLisp>: (in "/dev/urandom" (rd 4)) -> 2917110327</lang>

PureBasic

PureBasic has the source for the random data is the "/dev/urandom" device on Linux or Mac OSX and the "Microsoft Cryptography API" on Windows. <lang PureBasic>If OpenCryptRandom()

 MyRandom = CryptRandom(#MAXLONG)
 CloseCryptRandom()

EndIf</lang>

Python

<lang Python>import random rand = random.SystemRandom() rand.randint(1,10)</lang>

Ruby

<lang Ruby> require 'securerandom' SecureRandom.random_number(1 << 31) </lang>


Tcl

<lang tcl>package require Tcl 8.5

  1. Allow override of device name

proc systemRandomInteger Template:Device "/dev/random" {

   set f [open $device "rb"]
   binary scan [read $f 4] "I" x
   close $f
   return $x

}</lang> Usage: <lang tcl>% puts [systemRandomInteger] 636131349</lang>