##Overview
drnglib (Digital Random Number Generator Library) is a Java 7 library that provides access to Intel Secure Key,
the hardware random number generator introduced in the Ivy Bridge microarchitecture. This library retrieves
cryptographically secure random values directly from the CPU using the rdrand
instruction. Access to rdrand
is
implemented by a small native library embedded as a resource in the .jar file.
The DigitalRandom class is provided as a drop-in replacement for
SecureRandom. It is thread-safe and
stateless. All thread synchronization occurs in the hardware implementation of rdrand
.
For more information see:
- Wikipedia: RdRand
- Intel DRNG Software Implementation Guide
- Analysis of Intel's Ivy Bridge Digital Random Number Generator
PDF
##Usage
Follow these two steps to start generating random numbers:
- Add the following dependency to your project (published on Maven Central):
<dependency>
<groupId>net.nullschool</groupId>
<artifactId>drnglib</artifactId>
<version>1.0.0</version>
</dependency>
- Create an instance of
DigitalRandom
located in thenet.nullschool.util
package:
DigitalRandom random = new DigitalRandom();
System.out.println(random.nextInt());
Your project will need Java 7 and an
Intel Ivy Bridge (or newer) CPU. If the CPU does not contain
a hardware random number generator, instantiation of DigitalRandom
will throw UnsupportedOperationException
.
drnglib runs on Windows, Mac OSX, and Linux. (Adding support for other operation systems simply requires building the native library code on the desired platform.)
##Performance
The following micro-benchmarks show the relative performance of the JRE's implementations of Random
compared with DigitalRandom
. These numbers were gathered using the benchmark harness contained in the test
class PerformanceTest
under the following conditions:
- Intel Core i7 3770S (quad core with hyper-threading enabled)
- Windows 7
- Java 1.7.0_11 64-bit
- -Xms1G -Xmx2G -XX:+PrintCompilation -XX:+PrintGCDetails
- Each thread provided its own RNG instance; no sharing.
MiB/sec Mean (Standard Deviation) over 20 trials after JVM warm up
+---------++-----------+-------------------++--------------+---------------+--------+
| Threads || Random | ThreadLocalRandom || SecureRandom | DigitalRandom | Speed* |
+---------++-----------+-------------------++--------------+---------------+--------+
| 1 || 379 (0) | 2965 (0) || 40 (0) | 192 (2) | 4.8x |
| 2 || 528 (263) | 5929 (0) || 75 (3) | 382 (2) | 5.0x |
| 3 || 340 (69) | 8836 (32) || 100 (6) | 569 (4) | 5.7x |
| 4 || 414 (118) | 11654 (78) || 129 (6) | 747 (4) | 5.8x |
| 5 || 422 (29) | 14193 (103) || 141 (5) | 760 (0) | 5.4x |
| 6 || 478 (37) | 16812 (462) || 147 (3) | 760 (0) | 5.2x |
| 7 || 515 (29) | 19482 (812) || 158 (3) | 760 (0) | 4.8x |
| 8 || 561 (43) | 21528 (911) || 167 (2) | 758 (0) | 4.5x |
+---------++-----------+-------------------++--------------+---------------+--------+
*speed improvement of DigitalRandom over SecureRandom
MiB/sec Mean (Standard Deviation) over 20 trials after JVM warm up
+---------++-----------+-------------------++--------------+---------------+--------+
| Threads || Random | ThreadLocalRandom || SecureRandom | DigitalRandom | Speed* |
+---------++-----------+-------------------++--------------+---------------+--------+
| 1 || 370 (0) | 644 (0) || 59 (0) | 205 (2) | 3.5x |
| 2 || 652 (203) | 1287 (0) || 114 (6) | 400 (3) | 3.5x |
| 3 || 841 (342) | 1791 (59) || 155 (11) | 576 (8) | 3.7x |
| 4 || 910 (435) | 2092 (114) || 174 (11) | 669 (6) | 3.8x |
| 5 || 935 (470) | 2224 (129) || 185 (11) | 673 (7) | 3.6x |
| 6 || 750 (375) | 2324 (64) || 200 (8) | 686 (8) | 3.4x |
| 7 || 854 (378) | 2460 (41) || 213 (7) | 702 (6) | 3.3x |
| 8 || 694 (107) | 2508 (37) || 229 (6) | 743 (8) | 3.2x |
+---------++-----------+-------------------++--------------+---------------+--------+
*speed improvement of DigitalRandom over SecureRandom
Millions UUID/sec Mean (Standard Deviation) over 20 trials after JVM warm up
+---------+-----------------+------------------------+---------+
| Threads | UUID.randomUUID | DigitalRandom.nextUUID | Speed* |
+---------+-----------------+------------------------+---------+
| 1 | 3.4 (0.0) | 12.4 (0.2) | 3.6x |
| 2 | 2.5 (0.1) | 18.5 (3.4) | 7.4x |
| 3 | 2.4 (0.1) | 26.8 (3.8) | 11.2x |
| 4 | 2.3 (0.0) | 34.7 (3.7) | 15.1x |
| 5 | 2.3 (0.0) | 41.8 (2.7) | 18.2x |
| 6 | 2.3 (0.0) | 44.5 (1.3) | 19.3x |
| 7 | 2.3 (0.0) | 45.7 (0.7) | 19.9x |
| 8 | 2.3 (0.0) | 46.7 (0.7) | 20.3x |
+---------+-----------------+------------------------+---------+
*speed improvement of DigitalRandom over SecureRandom
DigitalRandom
significantly outperforms SecureRandom
, and even Random
in some scenarios. SecureRandom
on
Windows defaults to the SHA1PRNG algorithm, but its implementation suffers from fairly trivial issues, such as the
need to generate all values into byte[]
buffers, even when a simple int
or long
is requested. Linux machines
suffer further because SecureRandom
's default algorithm gathers entropy from /dev/random
, which can be very slow.
Java 7 clearly benefits from the introduction of ThreadLocalRandom
, but it is important to note it does not produce
randomness of cryptographic quality. It is an excellent replacement for Random
, not SecureRandom
.
The performance improvement DigitalRandom
provides when generating UUID
s is particularly striking. This is because
UUID.randomUUID()
, which is the JRE garden path method for generating UUIDs, uses exactly one static instance of
SecureRandom
. Sharing one instance of SecureRandom
causes severe thread contention, whereas DigitalRandom
needs no thread synchronization.
##Build Requirements
###To build drnglib jar:
###To build drnglib's native libraries:
- gcc 4.2 or greater (Unix/Mac OSX)
- Visual Studio 2012 any flavor (Windows)
##Build Instructions
To build the Java jar:
- get the source:
git clone git@github.com:cambecc/drnglib.git
- from the
drnglib/
directory, do a maven build:mvn clean install
To build the native libraries:
NOTE: It is not necessary to build the native libraries unless you have made changes to the C code in the
drnglib/src/main/c/
directory. Building the native libraries is somewhat tedious because each library flavor
must be built from a toolset for the associated operating system. This usually means a Windows install for .dll,
Mac OSX for .dylib, and Linux for .so. To build one particular flavor:
- make sure the
JAVA_HOME
environment variable is defined to point to your Java 7 JDK - from the
drnglib/src/main/c/
directory, invoke the appropriate build script, e.g.,./build-macosx.sh
- rebuild the java jar to incorporate your native library. From the
drnglib/
directory, do a maven build:mvn clean install
On Ubuntu, needed to get the following packages in order to build:
sudo apt-get install libc6-dev-i386
sudo apt-get install g++-multilib