diff --git a/README.txt b/README.txt index 87a0497..c43e438 100644 --- a/README.txt +++ b/README.txt @@ -25,13 +25,17 @@ NOTE: This library is not designed for cryptographic applications ------------------ Xoroshiro128+ is an RNG algorithm developed in 2016 by David Blackman -and Sebastiano Vigna. It is a further development of the Xorshift algorithm -invented by George Marsaglia +and Sebastiano Vigna. The VHDL code matches an updated version of +the algorithm called "xoroshiro128+ 1.0", released in 2018. +The Xoroshiro algorithm is based on the Xorshift concept invented +by George Marsaglia. -See also http://xoroshiro.di.unimi.it/ +See also http://prng.di.unimi.it/ -This RNG passes many statistical tests. Its period, 2**128 - 1, is long -compared to a typical LFSR, but much shorter than the Mersenne Twister. +This RNG passes many statistical tests, but the least significant +output bits are known to be not fully random and fail certain tests. +The generator has a long period (2**128 - 1) compared to a typical LFSR, +but much shorter than the Mersenne Twister. The output is 1-dimensionally equidistributed. The VHDL implementation produces 64 new random bits on every (enabled) @@ -43,7 +47,7 @@ Seed length: 128 bits Period: 2**128 - 1 FPGA resources: general logic and 64-bit adder -Synthesis results: 194 LUTs, 192 registers on Spartan-6 +Synthesis results: 198 LUTs, 193 registers on Spartan-6 Timing results: 333 MHz on Spartan-6 LX45-3 @@ -141,7 +145,7 @@ Timing results: 380 MHz on Spartan-6 LX45-3 (32 bits output) License ------- -Copyright (C) 2016 Joris van Rantwijk +Copyright (C) 2016-2020 Joris van Rantwijk This VHDL library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License diff --git a/refimpl/Makefile b/refimpl/Makefile index 8276870..7eecf17 100644 --- a/refimpl/Makefile +++ b/refimpl/Makefile @@ -10,9 +10,9 @@ CFLAGS = -std=c11 -Wall -O2 CXXFLAGS = -std=c++11 -Wall -O2 .PHONY: all -all: ref_xoroshiro ref_mt19937 ref_trivium +all: ref_xoroshiro128plus ref_mt19937 ref_trivium -ref_xoroshiro: ref_xoroshiro.c +ref_xoroshiro128plus: ref_xoroshiro128plus.c ref_mt19937: ref_mt19937.cpp @@ -20,5 +20,5 @@ ref_trivium: ref_trivium.cpp .PHONY: clean clean: - $(RM) ref_xoroshiro ref_mt19937 ref_trivium + $(RM) ref_xoroshiro128plus ref_mt19937 ref_trivium diff --git a/refimpl/ref_xoroshiro.c b/refimpl/ref_xoroshiro128plus.c similarity index 56% rename from refimpl/ref_xoroshiro.c rename to refimpl/ref_xoroshiro128plus.c index a23694e..2be6856 100644 --- a/refimpl/ref_xoroshiro.c +++ b/refimpl/ref_xoroshiro128plus.c @@ -13,14 +13,13 @@ #include #include -#include /* ========== BEGIN of reference implementation of xoroshiro128+ ========== - * Source: http://xoroshiro.di.unimi.it/ + * Source: http://prng.di.unimi.it/ */ -/* Written in 2016 by David Blackman and Sebastiano Vigna (vigna@acm.org) +/* Written in 2016-2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) To the extent possible under law, the author has dedicated all copyright and related and neighboring rights to this software to the public domain @@ -28,22 +27,48 @@ worldwide. This software is distributed without any warranty. See . */ -int64_t s[2]; +#include + +/* This is xoroshiro128+ 1.0, our best and fastest small-state generator + for floating-point numbers. We suggest to use its upper bits for + floating-point generation, as it is slightly faster than + xoroshiro128++/xoroshiro128**. It passes all tests we are aware of + except for the four lower bits, which might fail linearity tests (and + just those), so if low linear complexity is not considered an issue (as + it is usually the case) it can be used to generate 64-bit outputs, too; + moreover, this generator has a very mild Hamming-weight dependency + making our test (http://prng.di.unimi.it/hwd.php) fail after 5 TB of + output; we believe this slight bias cannot affect any application. If + you are concerned, use xoroshiro128++, xoroshiro128** or xoshiro256+. + + We suggest to use a sign test to extract a random Boolean value, and + right shifts to extract subsets of bits. + + The state must be seeded so that it is not everywhere zero. If you have + a 64-bit seed, we suggest to seed a splitmix64 generator and use its + output to fill s. + + NOTE: the parameters (a=24, b=16, b=37) of this version give slightly + better results in our test than the 2016 version (a=55, b=14, c=36). +*/ static inline uint64_t rotl(const uint64_t x, int k) { - return (x << k) | (x >> (64 - k)); + return (x << k) | (x >> (64 - k)); } + +static uint64_t s[2]; + uint64_t next(void) { - const uint64_t s0 = s[0]; - uint64_t s1 = s[1]; - const uint64_t result = s0 + s1; + const uint64_t s0 = s[0]; + uint64_t s1 = s[1]; + const uint64_t result = s0 + s1; - s1 ^= s0; - s[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b - s[1] = rotl(s1, 36); // c + s1 ^= s0; + s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b + s[1] = rotl(s1, 37); // c - return result; + return result; } /* ========== END of reference implementation of xoroshiro128+ ========== */ @@ -58,12 +83,12 @@ int main(int argc, const char **argv) if (argc != 4) { fprintf(stderr, "Reference implementation of RNG xoroshiro128+\n"); fprintf(stderr, "\n"); - fprintf(stderr, "Usage: ref_xoroshiro SEED0 SEED1 NUMVALUE\n"); + fprintf(stderr, "Usage: ref_xoroshiro128plus SEED0 SEED1 NUMVALUE\n"); fprintf(stderr, " SEED0 seed value in range 0 .. (2**64-1)\n"); fprintf(stderr, " SEED1 seed value in range 0 .. (2**64-1)\n"); fprintf(stderr, " NUMVALUE number of values to get from generator\n"); fprintf(stderr, "\n"); - fprintf(stderr, "Example: ref_xoroshiro 0x3141592653589793 " + fprintf(stderr, "Example: ref_xoroshiro128plus 0x3141592653589793 " "0x0123456789abcdef 100\n"); exit(1); } diff --git a/rtl/rng_xoroshiro128plus.vhdl b/rtl/rng_xoroshiro128plus.vhdl index fa46bbc..9db816c 100644 --- a/rtl/rng_xoroshiro128plus.vhdl +++ b/rtl/rng_xoroshiro128plus.vhdl @@ -1,5 +1,5 @@ -- --- Pseudo Random Number Generator "xoroshiro128+". +-- Pseudo Random Number Generator "xoroshiro128+ 1.0". -- -- Author: Joris van Rantwijk -- @@ -7,9 +7,9 @@ -- The generator can produce 64 new random bits on every clock cycle. -- -- The algorithm "xoroshiro128+" is by David Blackman and Sebastiano Vigna. --- See also http://xoroshiro.di.unimi.it/ +-- See also http://prng.di.unimi.it/ -- --- The generator requires a 128-bit seed value, not equal to zero. +-- The generator requires a 128-bit seed value, not equal to all zeros. -- A default seed must be supplied at compile time and will be used -- to initialize the generator at reset. The generator also supports -- re-seeding at run time. @@ -19,12 +19,12 @@ -- -- NOTE: This is not a cryptographic random number generator. -- --- NOTE: The least significant output bit is less random than --- all other output bits. +-- NOTE: The least significant output bits are not fully random and +-- fail certain statistical tests. -- -- --- Copyright (C) 2016 Joris van Rantwijk +-- Copyright (C) 2016-2020 Joris van Rantwijk -- -- This code is free software; you can redistribute it and/or -- modify it under the terms of the GNU Lesser General Public @@ -131,12 +131,12 @@ begin -- Update internal state. reg_state_s0 <= reg_state_s0 xor reg_state_s1 xor - shiftl(reg_state_s0, 14) xor - shiftl(reg_state_s1, 14) xor - rotl(reg_state_s0, 55); + rotl(reg_state_s0, 24) xor + shiftl(reg_state_s0, 16) xor + shiftl(reg_state_s1, 16); - reg_state_s1 <= rotl(reg_state_s0, 36) xor - rotl(reg_state_s1, 36); + reg_state_s1 <= rotl(reg_state_s0, 37) xor + rotl(reg_state_s1, 37); end if;