Compare commits
10 Commits
09beb03631
...
9f5c69c9cc
Author | SHA1 | Date |
---|---|---|
Joris van Rantwijk | 9f5c69c9cc | |
Joris van Rantwijk | d8acfbe985 | |
Joris van Rantwijk | 3acd8b3043 | |
Joris van Rantwijk | fc70f906b3 | |
Joris van Rantwijk | 9c5e076644 | |
Joris van Rantwijk | 2085470db4 | |
Joris van Rantwijk | e92ed9ea54 | |
Joris van Rantwijk | e5cbb260cd | |
Joris van Rantwijk | 317db19e2f | |
Joris van Rantwijk | c695860db8 |
115
README.txt
115
README.txt
|
@ -16,21 +16,55 @@ These PRNGs are a good alternative to linear feedback shift registers (LFSR).
|
|||
Although LFSRs are commonly used, their output exhibits strong correlations.
|
||||
Furthermore, correctly generating multi-bit random words with LFSRs is tricky.
|
||||
|
||||
NOTE: None of the RNGs in this package are cryptographic random number
|
||||
generators. These generators are not suitable for cryptography.
|
||||
NOTE: This library is not designed for cryptographic applications
|
||||
(such as generating passwords, encryption keys).
|
||||
Most of the RNGs in this library are cryptographically weak.
|
||||
|
||||
|
||||
Xoshiro128++ RNG
|
||||
----------------
|
||||
|
||||
Xoshiro128++ is a random number generator developed in 2019 by
|
||||
David Blackman and Sebastiano Vigna. The Xoshiro construction is
|
||||
based on the Xorshift concept invented by George Marsaglia.
|
||||
|
||||
See also http://prng.di.unimi.it/
|
||||
|
||||
This RNG produces a sequence of 32-bit words. It passes all known
|
||||
statistical tests and has a relatively long period (2**128 - 1).
|
||||
|
||||
The VHDL implementation produces 32 new random bits on every (enabled)
|
||||
clock cycle. It is quite efficient in terms of FPGA resources, but it
|
||||
requires two cascaded 32-bit adders which limit its speed. An optional
|
||||
pipeline stage can be inserted between the adders to improve the timing
|
||||
performance of the circuit.
|
||||
|
||||
Output word length: 32 bits
|
||||
Seed length: 128 bits
|
||||
Period: 2**128 - 1
|
||||
|
||||
FPGA resources: general logic and two 32-bit adders
|
||||
Synthesis results: 201 LUTs, 194 registers on Spartan-6
|
||||
149 LUTs, 194 registers on Spartan-7
|
||||
Timing results: 400 MHz on Spartan-6 LX45-3
|
||||
350 MHz on Spartan-7 S25-1
|
||||
|
||||
|
||||
Xoroshiro128+ RNG
|
||||
------------------
|
||||
-----------------
|
||||
|
||||
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)
|
||||
|
@ -42,7 +76,7 @@ Seed length: 128 bits
|
|||
Period: 2**128 - 1
|
||||
|
||||
FPGA resources: general logic and 64-bit adder
|
||||
Sythesis 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
|
||||
|
||||
|
||||
|
@ -79,31 +113,72 @@ Seed length: 32 bits
|
|||
Period: 2**19937 - 1
|
||||
|
||||
FPGA resources: RAM block, 32 bits x 1024 elements
|
||||
Sythesis results: 279 LUTs, 297 registers, 2x RAMB16 on Spartan-6
|
||||
Synthesis results: 279 LUTs, 297 registers, 2x RAMB16 on Spartan-6
|
||||
Timing results: 300 MHz on Spartan-6 LX45-3
|
||||
|
||||
|
||||
Trivium RNG
|
||||
-----------
|
||||
|
||||
Trivium is a stream cipher published in 2005 by Christophe De Canniere
|
||||
and Bart Preneel as part of the eSTREAM project.
|
||||
|
||||
See also C. De Canniere, B. Preneel, "Trivium Specifications",
|
||||
http://www.ecrypt.eu.org/stream/p3ciphers/trivium/trivium_p3.pdf
|
||||
|
||||
See also the eSTREAM portfolio page for Trivium:
|
||||
http://www.ecrypt.eu.org/stream/e2-trivium.html
|
||||
|
||||
This library uses the key stream of the Trivium cipher as a sequence
|
||||
of random bits. The VHDL implementation produces up to 64 new random bits
|
||||
on every (enabled) clock cycle. The number of bits per clock cycle is
|
||||
configurade as a synthesis parameter.
|
||||
|
||||
This RNG passes all known statistical tests. However, little is known
|
||||
about its period. The period depends on the seed value, and is believed
|
||||
to be long (at least 2**80) for the vast majority of seed choices.
|
||||
|
||||
After reset and after each reseeding, the RNG must process 1152 bits
|
||||
to initialize its state. This takes up to 1152 clock cycles, depending
|
||||
on the configured number of bits per cycle. The RNG can not provide random
|
||||
data during this time.
|
||||
|
||||
Output word length: configurable from 1 to 64 bits (must be power-of-2)
|
||||
Seed length: 80 bits key + 80 bits IV
|
||||
Period: unknown, depends on seed
|
||||
|
||||
FPGA resources: only general logic (AND, XOR ports, registers)
|
||||
Synthesis results: 202 LUTs, 332 registers on Spartan-6 (32 bits output)
|
||||
145 LUTs, 332 registers on Spartan-7 (32 bits output)
|
||||
Timing results: 380 MHz on Spartan-6 LX45-3 (32 bits output)
|
||||
440 MHz on Spartan-7 S25-1 (32 bits output)
|
||||
|
||||
|
||||
Code organization
|
||||
-----------------
|
||||
|
||||
rtl/ Synthesizable VHDL code
|
||||
rtl/rng_xoroshiro128plus.vhdl Implementation of Xoroshiro128+ RNG
|
||||
rtl/rng_mt19937.vhdl Implementation of Mersenne Twister RNG
|
||||
rtl/ Synthesizable VHDL code
|
||||
rtl/rng_xoshiro128plusplus.vhdl Implementation of Xoshiro128++ RNG
|
||||
rtl/rng_xoroshiro128plus.vhdl Implementation of Xoroshiro128+ RNG
|
||||
rtl/rng_mt19937.vhdl Implementation of Mersenne Twister RNG
|
||||
rtl/rng_trivium.vhdl Implementation of Trivium RNG
|
||||
|
||||
sim/ Test benches
|
||||
sim/Makefile Makefile for building test benches with GHDL
|
||||
sim/tb_xoroshiro128plus.vhdl Test bench for Xoroshiro128+ RNG
|
||||
sim/tb_mt19937.vhdl Test bench for Mersenne Twister RNG
|
||||
sim/ Test benches
|
||||
sim/Makefile Makefile for building test benches with GHDL
|
||||
sim/tb_xoshiro128plusplus.vhdl Test bench for Xoshiro128++ RNG
|
||||
sim/tb_xoroshiro128plus.vhdl Test bench for Xoroshiro128+ RNG
|
||||
sim/tb_mt19937.vhdl Test bench for Mersenne Twister RNG
|
||||
sim/tb_trivium.vhdl Test bench for Trivium RNG
|
||||
|
||||
refimpl/ Reference software implementations of RNGs
|
||||
refimpl/ Reference software implementations of RNGs
|
||||
|
||||
synth/ Top-level wrappers for synthesis testruns
|
||||
synth/ Top-level wrappers for synthesis testruns
|
||||
|
||||
|
||||
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
|
||||
|
|
|
@ -4,19 +4,28 @@
|
|||
# This makefile works with GCC under Linux.
|
||||
#
|
||||
|
||||
.PHONY: all
|
||||
all: ref_xoroshiro ref_mt19937 ref_trivium
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
CFLAGS = -std=c11 -Wall -O2
|
||||
CXXFLAGS = -std=c++11 -Wall -O2
|
||||
|
||||
ref_xoroshiro: ref_xoroshiro.c
|
||||
$(CC) -std=c11 -Wall -O2 -o $@ $<
|
||||
.PHONY: all
|
||||
all: ref_xoshiro128plusplus \
|
||||
ref_xoroshiro128plus \
|
||||
ref_mt19937 \
|
||||
ref_trivium
|
||||
|
||||
ref_xoshiro128plusplus: ref_xoshiro128plusplus.c
|
||||
ref_xoroshiro128plus: ref_xoroshiro128plus.c
|
||||
|
||||
ref_mt19937: ref_mt19937.cpp
|
||||
$(CXX) -std=c++11 -Wall -O2 -o $@ $<
|
||||
|
||||
ref_trivium: ref_trivium.cpp
|
||||
$(CXX) -std=c++11 -Wall -O2 -o $@ $<
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(RM) ref_xoroshiro ref_mt19937 ref_trivium
|
||||
$(RM) ref_xoshiro128plusplus
|
||||
$(RM) ref_xoroshiro128plus
|
||||
$(RM) ref_mt19937
|
||||
$(RM) ref_trivium
|
||||
|
||||
|
|
|
@ -13,14 +13,13 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/* ========== 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 <http://creativecommons.org/publicdomain/zero/1.0/>. */
|
||||
|
||||
int64_t s[2];
|
||||
#include <stdint.h>
|
||||
|
||||
/* 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);
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Reference implementation of "xoshiro128++" in C.
|
||||
*
|
||||
* Algorithm code by David Blackman and Sebastiano Vigna <vigna@acm.org>
|
||||
* Main program wrapper by Joris van Rantwijk <joris@jorisvr.nl>
|
||||
*
|
||||
* To the extent possible under law, the author has dedicated all copyright
|
||||
* and related and neighboring rights to this software to the public domain
|
||||
* worldwide. This software is distributed without any warranty.
|
||||
*
|
||||
* See <http://creativecommons.org/publicdomain/zero/1.0/>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
/* ========== BEGIN of reference implementation of xoshiro128++ ==========
|
||||
* Source: http://prng.di.unimi.it/
|
||||
*/
|
||||
|
||||
/* Written in 2019 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
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* This is xoshiro128++ 1.0, one of our 32-bit all-purpose, rock-solid
|
||||
generators. It has excellent speed, a state size (128 bits) that is
|
||||
large enough for mild parallelism, and it passes all tests we are aware
|
||||
of.
|
||||
|
||||
For generating just single-precision (i.e., 32-bit) floating-point
|
||||
numbers, xoshiro128+ is even faster.
|
||||
|
||||
The state must be seeded so that it is not everywhere zero. */
|
||||
|
||||
|
||||
static inline uint32_t rotl(const uint32_t x, int k) {
|
||||
return (x << k) | (x >> (32 - k));
|
||||
}
|
||||
|
||||
|
||||
static uint32_t s[4];
|
||||
|
||||
uint32_t next(void) {
|
||||
const uint32_t result = rotl(s[0] + s[3], 7) + s[0];
|
||||
|
||||
const uint32_t t = s[1] << 9;
|
||||
|
||||
s[2] ^= s[0];
|
||||
s[3] ^= s[1];
|
||||
s[1] ^= s[2];
|
||||
s[0] ^= s[3];
|
||||
|
||||
s[2] ^= t;
|
||||
|
||||
s[3] = rotl(s[3], 11);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ========== END of reference implementation of xoshiro128++ ========== */
|
||||
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
char *p;
|
||||
unsigned long numval;
|
||||
unsigned long k;
|
||||
unsigned long long seed_tmp;
|
||||
|
||||
if (argc != 4) {
|
||||
fprintf(stderr, "Reference implementation of RNG xoshiro128++\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Usage: ref_xoshiro128plusplus SEED0 SEED1 NVALUE\n");
|
||||
fprintf(stderr, " SEEDn seed value in range 0 .. (2**64-1)\n");
|
||||
fprintf(stderr, " NVALUE number of values to get from generator\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Example: ref_xoshiro128plusplus 0x3141592653589793 "
|
||||
"0x0123456789abcdef 100\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
seed_tmp = strtoull(argv[1], &p, 0);
|
||||
if (p == argv[1] || *p != '\0') {
|
||||
fprintf(stderr, "ERROR: Invalid value for SEED0\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
s[0] = (uint32_t)seed_tmp;
|
||||
s[1] = (uint32_t)(seed_tmp >> 32);
|
||||
|
||||
seed_tmp = strtoull(argv[2], &p, 0);
|
||||
if (p == argv[2] || *p != '\0') {
|
||||
fprintf(stderr, "ERROR: Invalid value for SEED1\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
s[2] = (uint32_t)seed_tmp;
|
||||
s[3] = (uint32_t)(seed_tmp >> 32);
|
||||
|
||||
numval = strtoul(argv[3], &p, 0);
|
||||
if (p == argv[3] || *p != '\0') {
|
||||
fprintf(stderr, "ERROR: Invalid value for NVALUE\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (k = 0; k < numval; k++) {
|
||||
printf("0x%08lx\n", (unsigned long) next());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
--
|
||||
-- Pseudo Random Number Generator "xoroshiro128+".
|
||||
-- Pseudo Random Number Generator "xoroshiro128+ 1.0".
|
||||
--
|
||||
-- Author: Joris van Rantwijk <joris@jorisvr.nl>
|
||||
--
|
||||
|
@ -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;
|
||||
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
--
|
||||
-- Pseudo Random Number Generator "xoshiro128++ 1.0".
|
||||
--
|
||||
-- Author: Joris van Rantwijk <joris@jorisvr.nl>
|
||||
--
|
||||
-- This is a 32-bit random number generator in synthesizable VHDL.
|
||||
-- The generator can produce 32 new random bits on every clock cycle.
|
||||
--
|
||||
-- The algorithm "xoshiro128++" is by David Blackman and Sebastiano Vigna.
|
||||
-- See also http://prng.di.unimi.it/
|
||||
--
|
||||
-- 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.
|
||||
--
|
||||
-- After reset and after re-seeding, one or two clock cycles are needed
|
||||
-- before valid random data appears on the output. The exact delay
|
||||
-- depends on the setting of the "pipeline" parameter.
|
||||
--
|
||||
-- NOTE: This is not a cryptographic random number generator.
|
||||
--
|
||||
|
||||
--
|
||||
-- Copyright (C) 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
|
||||
-- License as published by the Free Software Foundation; either
|
||||
-- version 2.1 of the License, or (at your option) any later version.
|
||||
--
|
||||
-- See <https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html>
|
||||
--
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
|
||||
entity rng_xoshiro128plusplus is
|
||||
|
||||
generic (
|
||||
-- Default seed value.
|
||||
init_seed: std_logic_vector(127 downto 0);
|
||||
|
||||
-- Enable optional pipeline stage in output calculation.
|
||||
-- This uses an extra 32-bit register but tends to improve
|
||||
-- the timing performance of the circuit.
|
||||
-- If the pipeline stage is enabled, two clock cycles are needed
|
||||
-- before valid output appears after reset and after re-seeding.
|
||||
-- If the pipeline stage is disabled, just one clock cycle is needed.
|
||||
pipeline: boolean := true );
|
||||
|
||||
port (
|
||||
|
||||
-- Clock, rising edge active.
|
||||
clk: in std_logic;
|
||||
|
||||
-- Synchronous reset, active high.
|
||||
rst: in std_logic;
|
||||
|
||||
-- High to request re-seeding of the generator.
|
||||
reseed: in std_logic;
|
||||
|
||||
-- New seed value (must be valid when reseed = '1').
|
||||
newseed: in std_logic_vector(127 downto 0);
|
||||
|
||||
-- High when the user accepts the current random data word
|
||||
-- and requests new random data for the next clock cycle.
|
||||
out_ready: in std_logic;
|
||||
|
||||
-- High when valid random data is available on the output.
|
||||
-- This signal is low for 1 or 2 clock cycles after reset and
|
||||
-- after re-seeding, and high in all other cases.
|
||||
out_valid: out std_logic;
|
||||
|
||||
-- Random output data (valid when out_valid = '1').
|
||||
-- A new random word appears after every rising clock edge
|
||||
-- where out_ready = '1'.
|
||||
out_data: out std_logic_vector(31 downto 0) );
|
||||
|
||||
end entity;
|
||||
|
||||
|
||||
architecture xoshiro128plusplus_arch of rng_xoshiro128plusplus is
|
||||
|
||||
-- Internal state of RNG.
|
||||
signal reg_state_s0: std_logic_vector(31 downto 0) := init_seed(31 downto 0);
|
||||
signal reg_state_s1: std_logic_vector(31 downto 0) := init_seed(63 downto 32);
|
||||
signal reg_state_s2: std_logic_vector(31 downto 0) := init_seed(95 downto 64);
|
||||
signal reg_state_s3: std_logic_vector(31 downto 0) := init_seed(127 downto 96);
|
||||
|
||||
-- Optional pipeline register.
|
||||
signal reg_sum_s0s3: std_logic_vector(31 downto 0) := (others => '0');
|
||||
|
||||
-- Output register.
|
||||
signal reg_valid: std_logic := '0';
|
||||
signal reg_nvalid: std_logic := '0';
|
||||
signal reg_output: std_logic_vector(31 downto 0) := (others => '0');
|
||||
|
||||
begin
|
||||
|
||||
-- Drive output signal.
|
||||
out_valid <= reg_valid;
|
||||
out_data <= reg_output;
|
||||
|
||||
-- Synchronous process.
|
||||
process (clk) is
|
||||
variable v_prev_s0: std_logic_vector(31 downto 0) := (others => '0');
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
|
||||
if out_ready = '1' or reg_valid = '0' then
|
||||
|
||||
-- Prepare output word.
|
||||
if pipeline then
|
||||
|
||||
-- Use a pipelined output stage.
|
||||
reg_valid <= reg_nvalid;
|
||||
reg_nvalid <= '1';
|
||||
|
||||
-- Calculate the previous value of s0.
|
||||
v_prev_s0 := reg_state_s0 xor
|
||||
std_logic_vector(
|
||||
rotate_right(unsigned(reg_state_s3),
|
||||
11));
|
||||
|
||||
-- Derive output from prev_s0 and intermediate result
|
||||
-- (prev_s0 + prev_s3) calculated in the previous cycle.
|
||||
reg_output <= std_logic_vector(
|
||||
unsigned(v_prev_s0) +
|
||||
rotate_left(unsigned(reg_sum_s0s3),
|
||||
7));
|
||||
|
||||
-- Update the intermediate register (s0 + s3).
|
||||
reg_sum_s0s3 <= std_logic_vector(
|
||||
unsigned(reg_state_s0) +
|
||||
unsigned(reg_state_s3));
|
||||
|
||||
else
|
||||
|
||||
-- Derive output directly from s0 and s3.
|
||||
-- This requires two cascaded 32-bit adders and
|
||||
-- may limit the timing performance of the circuit.
|
||||
reg_valid <= '1';
|
||||
reg_output <= std_logic_vector(
|
||||
rotate_left(
|
||||
unsigned(reg_state_s0) +
|
||||
unsigned(reg_state_s3), 7) +
|
||||
unsigned(reg_state_s0));
|
||||
|
||||
end if;
|
||||
|
||||
-- Update internal state.
|
||||
reg_state_s0 <= reg_state_s0 xor
|
||||
reg_state_s1 xor
|
||||
reg_state_s3;
|
||||
|
||||
reg_state_s1 <= reg_state_s0 xor
|
||||
reg_state_s1 xor
|
||||
reg_state_s2;
|
||||
|
||||
reg_state_s2 <= reg_state_s0 xor
|
||||
reg_state_s2 xor
|
||||
std_logic_vector(
|
||||
shift_left(unsigned(reg_state_s1), 9));
|
||||
|
||||
reg_state_s3 <= std_logic_vector(
|
||||
rotate_left(
|
||||
unsigned(reg_state_s1 xor
|
||||
reg_state_s3), 11));
|
||||
|
||||
end if;
|
||||
|
||||
-- Re-seed function.
|
||||
if reseed = '1' then
|
||||
reg_state_s0 <= newseed(31 downto 0);
|
||||
reg_state_s1 <= newseed(63 downto 32);
|
||||
reg_state_s2 <= newseed(95 downto 64);
|
||||
reg_state_s3 <= newseed(127 downto 96);
|
||||
reg_valid <= '0';
|
||||
reg_nvalid <= '0';
|
||||
end if;
|
||||
|
||||
-- Synchronous reset.
|
||||
if rst = '1' then
|
||||
reg_state_s0 <= init_seed(31 downto 0);
|
||||
reg_state_s1 <= init_seed(63 downto 32);
|
||||
reg_state_s2 <= init_seed(95 downto 64);
|
||||
reg_state_s3 <= init_seed(127 downto 96);
|
||||
reg_valid <= '0';
|
||||
reg_nvalid <= '0';
|
||||
reg_output <= (others => '0');
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end architecture;
|
||||
|
|
@ -6,7 +6,14 @@ GHDL = ghdl
|
|||
GHDLFLAGS =
|
||||
|
||||
.PHONY: all
|
||||
all: tb_xoroshiro128plus tb_mt19937 tb_trivium
|
||||
all: tb_xoshiro128plusplus \
|
||||
tb_xoroshiro128plus \
|
||||
tb_mt19937 \
|
||||
tb_trivium
|
||||
|
||||
tb_xoshiro128plusplus: tb_xoshiro128plusplus.o rng_xoshiro128plusplus.o
|
||||
tb_xoshiro128plusplus.o: tb_xoshiro128plusplus.vhdl rng_xoshiro128plusplus.o
|
||||
rng_xoshiro128plusplus.o: ../rtl/rng_xoshiro128plusplus.vhdl
|
||||
|
||||
tb_xoroshiro128plus: tb_xoroshiro128plus.o rng_xoroshiro128plus.o
|
||||
tb_xoroshiro128plus.o: tb_xoroshiro128plus.vhdl rng_xoroshiro128plus.o
|
||||
|
|
|
@ -28,6 +28,8 @@ architecture arch of tb_trivium is
|
|||
|
||||
type test_vectors is array (natural range <>) of test_vector;
|
||||
|
||||
-- This is a small subset of the test vectors from
|
||||
-- the ECRYPT stream cipher project.
|
||||
constant testvec: test_vectors(0 to 4) := (
|
||||
0 => ( key => x"0053A6F94C9FF24598EB",
|
||||
iv => x"0D74DB42A91077DE45AC",
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
--
|
||||
-- Test bench for PRNG "xoshiro128++".
|
||||
--
|
||||
|
||||
use std.textio.all;
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
entity tb_xoshiro128plusplus is
|
||||
end entity;
|
||||
|
||||
architecture arch of tb_xoshiro128plusplus is
|
||||
|
||||
signal clk: std_logic;
|
||||
signal clock_active: boolean := false;
|
||||
|
||||
signal s_rst: std_logic;
|
||||
signal s_reseed: std_logic;
|
||||
signal s_newseed: std_logic_vector(127 downto 0);
|
||||
signal s_ready: std_logic;
|
||||
signal s_valid: std_logic;
|
||||
signal s_data: std_logic_vector(31 downto 0);
|
||||
|
||||
function to_hex_string(s: std_logic_vector)
|
||||
return string
|
||||
is
|
||||
constant alphabet: string(1 to 16) := "0123456789abcdef";
|
||||
variable y: string(1 to s'length/4);
|
||||
begin
|
||||
for i in y'range loop
|
||||
y(i) := alphabet(to_integer(unsigned(s(s'high+4-4*i downto s'high+1-4*i))) + 1);
|
||||
end loop;
|
||||
return y;
|
||||
end function;
|
||||
|
||||
begin
|
||||
|
||||
-- Instantiate PRNG.
|
||||
inst_prng: entity work.rng_xoshiro128plusplus
|
||||
generic map (
|
||||
init_seed => x"0123456789abcdef3141592653589793" )
|
||||
port map (
|
||||
clk => clk,
|
||||
rst => s_rst,
|
||||
reseed => s_reseed,
|
||||
newseed => s_newseed,
|
||||
out_ready => s_ready,
|
||||
out_valid => s_valid,
|
||||
out_data => s_data );
|
||||
|
||||
-- Generate clock.
|
||||
clk <= (not clk) after 10 ns when clock_active else '0';
|
||||
|
||||
-- Main simulation process.
|
||||
process is
|
||||
file outf1: text is out "sim_xoshiro128plusplus_seed1.dat";
|
||||
file outf2: text is out "sim_xoshiro128plusplus_seed2.dat";
|
||||
variable lin: line;
|
||||
variable nskip: integer;
|
||||
variable v: std_logic_vector(31 downto 0);
|
||||
begin
|
||||
|
||||
report "Start test bench";
|
||||
|
||||
-- Reset.
|
||||
s_rst <= '1';
|
||||
s_reseed <= '0';
|
||||
s_newseed <= (others => '0');
|
||||
s_ready <= '0';
|
||||
|
||||
-- Start clock.
|
||||
clock_active <= true;
|
||||
|
||||
-- Wait 2 clock cycles, then end reset.
|
||||
wait for 30 ns;
|
||||
wait until falling_edge(clk);
|
||||
s_rst <= '0';
|
||||
|
||||
-- Wait 1 clock cycle to initialize generator.
|
||||
wait until falling_edge(clk);
|
||||
s_ready <= '1';
|
||||
|
||||
-- Optionally wait an additional pipeline cycle.
|
||||
if s_valid = '0' then
|
||||
report "Detected pipeline delay";
|
||||
wait until falling_edge(clk);
|
||||
end if;
|
||||
|
||||
-- Produce numbers
|
||||
for i in 0 to 999 loop
|
||||
|
||||
-- Check that output is valid.
|
||||
assert s_valid = '1' report "Output not valid";
|
||||
|
||||
-- Write output to file.
|
||||
write(lin, "0x" & to_hex_string(s_data));
|
||||
writeline(outf1, lin);
|
||||
|
||||
-- Sometimes skip cycles.
|
||||
if i mod 5 = 1 then
|
||||
nskip := 1;
|
||||
if i mod 3 = 0 then
|
||||
nskip := nskip + 1;
|
||||
end if;
|
||||
if i mod 11 = 0 then
|
||||
nskip := nskip + 1;
|
||||
end if;
|
||||
|
||||
v := s_data;
|
||||
s_ready <= '0';
|
||||
for t in 1 to nskip loop
|
||||
wait until falling_edge(clk);
|
||||
assert s_valid = '1' report "Output not valid";
|
||||
assert s_data = v report "Output changed while not ready";
|
||||
end loop;
|
||||
s_ready <= '1';
|
||||
end if;
|
||||
|
||||
-- Go to next cycle.
|
||||
wait until falling_edge(clk);
|
||||
|
||||
end loop;
|
||||
|
||||
-- Re-seed generator.
|
||||
report "Re-seed generator";
|
||||
s_reseed <= '1';
|
||||
s_newseed <= x"3141592653589793fedcba9876543210";
|
||||
s_ready <= '0';
|
||||
wait until falling_edge(clk);
|
||||
s_reseed <= '0';
|
||||
s_newseed <= (others => '0');
|
||||
|
||||
-- Wait 1 clock cycle to re-seed generator.
|
||||
wait until falling_edge(clk);
|
||||
s_ready <= '1';
|
||||
|
||||
-- Optionally wait an additional pipeline cycle.
|
||||
if s_valid = '0' then
|
||||
report "Detected pipeline delay";
|
||||
wait until falling_edge(clk);
|
||||
end if;
|
||||
|
||||
-- Produce numbers
|
||||
for i in 0 to 999 loop
|
||||
|
||||
-- Check that output is valid.
|
||||
assert s_valid = '1' report "Output not valid";
|
||||
|
||||
-- Write output to file.
|
||||
write(lin, "0x" & to_hex_string(s_data));
|
||||
writeline(outf2, lin);
|
||||
|
||||
-- Sometimes skip cycles.
|
||||
if i mod 5 = 2 then
|
||||
nskip := 1;
|
||||
if i mod 3 = 0 then
|
||||
nskip := nskip + 1;
|
||||
end if;
|
||||
if i mod 11 = 0 then
|
||||
nskip := nskip + 1;
|
||||
end if;
|
||||
|
||||
v := s_data;
|
||||
s_ready <= '0';
|
||||
for t in 1 to nskip loop
|
||||
wait until falling_edge(clk);
|
||||
assert s_valid = '1' report "Output not valid";
|
||||
assert s_data = v report "Output changed while not ready";
|
||||
end loop;
|
||||
s_ready <= '1';
|
||||
end if;
|
||||
|
||||
-- Go to next cycle.
|
||||
wait until falling_edge(clk);
|
||||
|
||||
end loop;
|
||||
|
||||
-- End simulation.
|
||||
report "End testbench";
|
||||
|
||||
clock_active <= false;
|
||||
wait;
|
||||
|
||||
end process;
|
||||
|
||||
end architecture;
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
|
||||
entity toptriv is
|
||||
port (
|
||||
clk : in std_logic;
|
||||
rst : in std_logic;
|
||||
ready: in std_logic;
|
||||
valid: out std_logic;
|
||||
data: out std_logic_vector(31 downto 0) );
|
||||
end toptriv;
|
||||
|
||||
architecture arch of toptriv is
|
||||
begin
|
||||
|
||||
inst_prng: entity work.rng_trivium
|
||||
generic map (
|
||||
num_bits => 32,
|
||||
init_key => x"31415926535897932384",
|
||||
init_iv => x"0123456789abcdefa50f" )
|
||||
port map (
|
||||
clk => clk,
|
||||
rst => rst,
|
||||
reseed => '0',
|
||||
newkey => (others => '0'),
|
||||
newiv => (others => '0'),
|
||||
out_ready => ready,
|
||||
out_valid => valid,
|
||||
out_data => data );
|
||||
|
||||
end arch;
|
||||
|
|
@ -2,16 +2,16 @@
|
|||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
|
||||
entity topxs is
|
||||
entity top_xoroshiro128plus is
|
||||
port (
|
||||
clk : in std_logic;
|
||||
rst : in std_logic;
|
||||
ready: in std_logic;
|
||||
valid: out std_logic;
|
||||
data: out std_logic_vector(63 downto 0) );
|
||||
end topxs;
|
||||
end top_xoroshiro128plus;
|
||||
|
||||
architecture arch of topxs is
|
||||
architecture arch of top_xoroshiro128plus is
|
||||
begin
|
||||
|
||||
inst_prng: entity work.rng_xoroshiro128plus
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
|
||||
entity top_xoshiro128plusplus is
|
||||
port (
|
||||
clk : in std_logic;
|
||||
rst : in std_logic;
|
||||
ready: in std_logic;
|
||||
valid: out std_logic;
|
||||
data: out std_logic_vector(31 downto 0) );
|
||||
end top_xoshiro128plusplus;
|
||||
|
||||
architecture arch of top_xoshiro128plusplus is
|
||||
begin
|
||||
|
||||
inst_prng: entity work.rng_xoshiro128plusplus
|
||||
generic map (
|
||||
init_seed => x"0123456789abcdef3141592653589793" )
|
||||
port map (
|
||||
clk => clk,
|
||||
rst => rst,
|
||||
reseed => '0',
|
||||
newseed => (others => '0'),
|
||||
out_ready => ready,
|
||||
out_valid => valid,
|
||||
out_data => data );
|
||||
|
||||
end arch;
|
||||
|
Loading…
Reference in New Issue