How to generate Random N bit hex numbers?

Dennis Clarke dclarke at blastwave.org
Mon Apr 19 19:13:10 CEST 2010


> All,
>     I am rather new to the GMP. With this said, I am attempting to
> generate a random N bit (where N can be any integer ex. 1024)
> hexadecimal number using the c++ interface.  Below is a simple test
> where I generate a random '6' bit number in decimal.
>
> gmp_randclass r (gmp_randinit_lc_2exp_size, 32);
> mpz_class z;
> z=r.get_z_bits(6);  //z stores value of random integer.
>
> However, I have not been able to find a function to do this similar
> process and produce hexadecimal random number.
>
> If this is not possible, how would I go about converting an mpz_class
> integer to hexadecimal? For example if
>
> mpz_class z;
> z=10;
>
> how would I then convert z to hexadecimal?
>

I know that I'll get slammed by someone for saying this. Regardless of
what you do to get a "random" number you need to draw that number from a
process or source. Unless your system has crypto hardware with some crypto
drivers then you probably will have a PRNG = Pseudo Random Number
Generator.  That means, pretty damn random but no promises.

As for hex.  Well, isn't it in bits in the computers memory anyways? Just
print it out via printf.  You lost me there.

Here is a quick hack to read from /dev/random :

/*
 * Quick hack to read bytes from /dev/random
 */

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

/* Macros */
#define TRUE 1
#define FALSE 0
#define MAXFILENAMELEN 512
#define MAXERRMSGLEN 256

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

        int     i,j;
        double  rval;
        char    *prog = argv[0];
        char    error_buff[255];

        FILE    * fp;

        if ((fp = fopen("/dev/random", "r")) == NULL) {
            fprintf(stderr, "%s: can't read /dev/random \n", prog);
            fprintf(stderr, "%s: ABORTING\n", prog);
            perror(error_buff);
            exit(EXIT_FAILURE);
        } else {
            for (i = 0; i < 16; ++i) {
                j = getc(fp);
                printf ( "Byte %02i is %03id", i, j );
                printf ( " and Hex = 0x%02xh", ( uint8_t )( j ) );
                rval = ((double) j / (double) 256);
                printf ( " and float on [0, 255] is %.8f\n", rval );
            } /* end for i */
        } /* if */
    return (0);
} /* End of main */

On Solaris I see this :

bash-4.1$ echo $CFLAGS
-xstrconst -xildoff -xarch=v8 -xnolibmil -Xa -xcode=pic32 -xregs=no%appl
-xlibmieee -g -Qy -xdebugformat=dwarf -xs -D_TS_ERRNO

bash-4.1$ cc $CFLAGS -c -o prng_hardware.o prng_hardware.c
bash-4.1$ cc $CFLAGS -o prng_hardware prng_hardware.o
bash-4.1$ file ./prng_hardware
./prng_hardware:        ELF 32-bit MSB executable SPARC Version 1,
dynamically linked, not stripped

bash-4.1$ ./prng_hardware
Byte 00 is 092d and Hex = 0x5ch and float on [0, 255] is 0.35937500
Byte 01 is 238d and Hex = 0xeeh and float on [0, 255] is 0.92968750
Byte 02 is 151d and Hex = 0x97h and float on [0, 255] is 0.58984375
Byte 03 is 151d and Hex = 0x97h and float on [0, 255] is 0.58984375
Byte 04 is 151d and Hex = 0x97h and float on [0, 255] is 0.58984375
Byte 05 is 201d and Hex = 0xc9h and float on [0, 255] is 0.78515625
Byte 06 is 252d and Hex = 0xfch and float on [0, 255] is 0.98437500
Byte 07 is 218d and Hex = 0xdah and float on [0, 255] is 0.85156250
Byte 08 is 206d and Hex = 0xceh and float on [0, 255] is 0.80468750
Byte 09 is 026d and Hex = 0x1ah and float on [0, 255] is 0.10156250
Byte 10 is 238d and Hex = 0xeeh and float on [0, 255] is 0.92968750
Byte 11 is 204d and Hex = 0xcch and float on [0, 255] is 0.79687500
Byte 12 is 115d and Hex = 0x73h and float on [0, 255] is 0.44921875
Byte 13 is 031d and Hex = 0x1fh and float on [0, 255] is 0.12109375
Byte 14 is 253d and Hex = 0xfdh and float on [0, 255] is 0.98828125
Byte 15 is 158d and Hex = 0x9eh and float on [0, 255] is 0.61718750
bash-4.1$

On RHEL 5.5 I see this :

[dclarke at icarus random]$ uname -a
Linux icarus 2.6.18-194.el5 #1 SMP Tue Mar 16 21:52:39 EDT 2010 x86_64
x86_64 x86_64 GNU/Linux
[dclarke at icarus random]$ gcc -dumpmachine
x86_64-redhat-linux
[dclarke at icarus random]$ gcc --version
gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-48)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

[dclarke at icarus random]$ CFLAGS='-march=pentiumpro -mmmx -mno-sse
-malign-double -mpreferred-stack-boundary=8 -m32'
[dclarke at icarus random]$ export CFLAGS

[dclarke at icarus random]$ gcc $CFLAGS -c -o prng_hardware.o prng_hardware.c
prng_hardware.c: In function 'main':
prng_hardware.c:36: error: 'uint8_t' undeclared (first use in this function)
prng_hardware.c:36: error: (Each undeclared identifier is reported only once
prng_hardware.c:36: error: for each function it appears in.)


Well, I guess Linux doesn't grok the ISO/JTC1/SC22/WG14 C committee's
working draft for types like uint8_t or similar.

So insert this :

/* Linux seems to need this */
#include <stdint.h>

[dclarke at icarus random]$ gcc $CFLAGS -c -o prng_hardware.o prng_hardware.c
[dclarke at icarus random]$ gcc $CFLAGS -o prng_hardware prng_hardware.o
[dclarke at icarus random]$ file prng_hardware
prng_hardware: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
for GNU/Linux 2.6.9, dynamically linked (uses shared libs), for GNU/Linux
2.6.9, not stripped

[dclarke at icarus random]$ ./prng_hardware
Byte 00 is 244d and Hex = 0xf4h and float on [0, 255] is 0.95312500
Byte 01 is 141d and Hex = 0x8dh and float on [0, 255] is 0.55078125
Byte 02 is 200d and Hex = 0xc8h and float on [0, 255] is 0.78125000
Byte 03 is 038d and Hex = 0x26h and float on [0, 255] is 0.14843750
Byte 04 is 079d and Hex = 0x4fh and float on [0, 255] is 0.30859375
Byte 05 is 065d and Hex = 0x41h and float on [0, 255] is 0.25390625
Byte 06 is 240d and Hex = 0xf0h and float on [0, 255] is 0.93750000
Byte 07 is 084d and Hex = 0x54h and float on [0, 255] is 0.32812500
Byte 08 is 073d and Hex = 0x49h and float on [0, 255] is 0.28515625
Byte 09 is 168d and Hex = 0xa8h and float on [0, 255] is 0.65625000
Byte 10 is 230d and Hex = 0xe6h and float on [0, 255] is 0.89843750
Byte 11 is 225d and Hex = 0xe1h and float on [0, 255] is 0.87890625
Byte 12 is 024d and Hex = 0x18h and float on [0, 255] is 0.09375000
Byte 13 is 151d and Hex = 0x97h and float on [0, 255] is 0.58984375
Byte 14 is 004d and Hex = 0x04h and float on [0, 255] is 0.01562500
Byte 15 is 238d and Hex = 0xeeh and float on [0, 255] is 0.92968750

So for random numbers try to use a PRNG and get bytes that way. If you can
not do that then you're stuck with something like the SIMD-oriented Fast
Mersenne Twister (SFMT) :

http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/

That is *very* good.


-- 
Dennis Clarke
dclarke at opensolaris.ca  <- Email related to the open source Solaris
dclarke at blastwave.org   <- Email related to open source for Solaris




More information about the gmp-discuss mailing list