After power-up, the ENTROPY_SRC block is disabled.
For simplicity of initialization, only a single register write is needed to start functional operation of the ENTROPY_SRC block. This assumes that proper defaults are chosen for thresholds, sampling rate, and other registers.
For security reasons, a configuration and control register locking function is performed by the REGEN
register. Clearing the bit in this register will prevent future modification of the CONF
register or other writeable registers by firmware.
When enabled, the ENTROPY_SRC block will generate entropy bits continuously. The es_entropy_valid
bit in the ENTROPY_SRC_INTR_STATE
register will indicate to the firmware when entropy bits can read from the ENTROPY_DATA
register. The firmware will do 32-bit register reads of the ENTROPY_DATA
register to retrieve the entropy bits. Each read will automatically pop an entry from the entropy unpacker block. A full twelve 32-bit words need to be read at a time.
The hardware entropy interface will move entropy bits out of the ENTROPY FIFO when it is not empty, and the downstream hardware is ready. If firmware is not currently reading entropy bits, all processed entropy bits will flow to the hardware entropy interface.
All module assets and countermeasures performed by hardware are listed in the hjson countermeasures section. Labels for each instance of asset and countermeasure are located throughout the RTL source code.
For all of the health test threshold registers, these registers could be protected with shadow registers. A design choice was made here to not use shadow registers and save on silicon cost. The threshold registers are protected by software. It is expected that software will read the threshold registers on a periodic basis, and compare these values to what was originally programmed into the threshold registers.
Bus integrity checking is performed for the final seed delivery to CSRNG. This is done to make sure repeated values are not occurring. Only 64 bits (out of 384 bits) are checked, since this is statistically significant, and more checking would cost more silicon.
The ENTROPY_SRC module has several interrupts: es_entropy_valid
, es_health_test_failed
, and es_fifo_err
.
The es_entropy_valid
interrupt should be asserted when an entropy source has been implemented that is relatively slow.
The es_health_test_failed
interrupt will trigger when the internal health test fails and exceeds the alert threshold.
The es_fifo_err
interrupt will fire when an internal FIFO has a malfunction. The conditions that cause this to happen are either when there is a push to a full FIFO or a pull from an empty FIFO.
The following diagram shows how the main state machine state is constructed. The larger circles show the how the overall state machine transitions. The sub-state machines with smaller circles show more detail about how the large circles operate.
The following waveform shows an example of how the entropy source hardware interface works, which is much like a FIFO.
{signal: [ {name: 'clk' , wave: 'p...|.........|.......'}, {name: 'es_req' , wave: '0..1|..01.0..1|.....0.'}, {name: 'es_ack' , wave: '0...|.10.10...|....10.'}, {name: 'es_bus[383:0]' , wave: '0...|.30.30...|....30.', data: ['es0','es1','es2']}, {name: 'es_fips' , wave: '0...|....10...|....10.'}, ]}
The following waveform shows an example of what the PTRNG timing looks like.
{signal: [ {name: 'clk' , wave: 'p.|......|......|......'}, {name: 'rng_enable' , wave: '01|......|......|......'}, {name: 'rng_valid' , wave: '0.|..10..|..10..|..10..'}, {name: 'rng_b' , wave: 'x.|..3...|..4...|..5.....', data: ['es0','es1','es2']}, ]}
The following waveform shows how a sampling of a data pattern will be tested by the Repetition Count test. Operating on each bit stream, this test will count when a signal is at a stuck level. This NIST test is intended to signal a catastrophic failure with the PTRNG noise source.
{signal: [ {name: 'rng_valid' , wave: 'p...............'}, ['rng bits', {name: 'rng_bus[3]' , wave: '1.0.10..1...0101'}, {name: 'rng_bus[2]' , wave: '01.0.10..1...010'}, {name: 'rng_bus[1]' , wave: '101.0.10..1...01'}, {name: 'rng_bus[0]' , wave: '10.10..1...0101.'}, ], {name: 'thresh_i (hex)' , wave: '3...............',data: ['3']}, {name: 'rep_cntr_q[3] (hex)' , wave: '4444444444444444',data: ['0','0','1','0','1','0','0','1','2','0','1','2','3','0','0','0']}, {name: 'rep_cntr_q[2] (hex)' , wave: '4444444444444444',data: ['0','1','0','1','0','1','0','0','1','2','0','1','2','3','0','0']}, {name: 'rep_cntr_q[1] (hex)' , wave: '4444444444444444',data: ['0','0','0','0','1','0','1','0','0','1','2','0','1','2','3','0']}, {name: 'rep_cntr_q[0] (hex)' , wave: '4444444444444444',data: ['0','0','0','1','0','0','1','2','0','1','2','3','0','0','0','0']}, {name: 'test_cnt_q (hex)' , wave: '4444444444444444',data: ['0','0','0','0','0','0','0','0','0','0','0','1','2','3','4','0']}, {name: 'window_cnt_q (hex)' , wave: '5555555555555555',data: ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']}, ], head:{ text:'Repetition Count Test', tick:0, },}
This NIST-defined test is intended to detect statistical bias in the raw entropy data. The test counts the number of 1's in a given sample, and applies thresholds to reject samples which deviate too far from the ideal mean of 50%.
Depending on the value of the CONF.THRESHOLD_SCOPE
field, the thresholds can either be applied collectively to the all RNG inputs, or the thresholds can be applied on a line-by-line basis. Setting CONF.THRESHOLD_SCOPE
to kMuBi4True
will apply the thresholds to the aggregated RNG stream. This can be useful for lowering the likelihood of coincidental test failures (higher α). Meanwhile, setting CONF.THRESHOLD_SCOPE
to kMuBi4False
will apply thresholds on a line-by-line basis which allows the ENTROPY_SRC to detect single line failures.
The following waveform shows how a sampling of a data pattern will be tested by the Adaptive Proportion test. In this example, the sum is taken over all RNG lines (i.e., CONF.THRESHOLD_SCOPE
is True).
{signal: [ {name: 'rng_valid' , wave: 'p...............'}, ['rng bits', {name: 'rng_bus[3]' , wave: '1.0.10..1...0101'}, {name: 'rng_bus[2]' , wave: '01.0.10..1...010'}, {name: 'rng_bus[1]' , wave: '101.0.10..1...01'}, {name: 'rng_bus[0]' , wave: '10.10..1...0101.'}, ], {name: 'Column-wise sum' , wave: '3333333333333333',data: ['3','2','2','2','1','1','1','1','2','3', '4', '3', '3', '2', '2','3']}, {name: 'test_cnt_q (hex)' , wave: '4444444444444444',data: ['0','3','5','7','9','a','b','c','d','f','12','16','19','1c','1e','20']}, {name: 'window_cnt_q (hex)' , wave: '5555555555555555',data: ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']}, ], head:{ text:'Adaptive Proportion Test', tick:0, },}
The following waveform shows how a sampling of a data pattern will be tested by the Bucket test. Operating on all four bit streams, this test will identify the symbol and sort it into bin counters, or “buckets”. This test is intended to find bias with a symbol or symbols.
{signal: [ {name: 'rng_valid' , wave: 'p...............'}, ['rng bits', {name: 'rng_bus[3]' , wave: '1.0.10..1...0101'}, {name: 'rng_bus[2]' , wave: '01.0.10..1...010'}, {name: 'rng_bus[1]' , wave: '101.0.10..1...01'}, {name: 'rng_bus[0]' , wave: '10.10..1...0101.'}, ], {name: 'thresh_i (hex)' , wave: '3...............',data: ['3']}, {name: 'bin_cntr_q[0] (hex)' , wave: '4...............',data: ['0']}, {name: 'bin_cntr_q[1] (hex)' , wave: '4........4......',data: ['0','1']}, {name: 'bin_cntr_q[2] (hex)' , wave: '4.......4.......',data: ['0','1']}, {name: 'bin_cntr_q[13] (hex)' , wave: '4..........4....',data: ['0','1']}, {name: 'bin_cntr_q[14] (hex)' , wave: '4............4..',data: ['0','1']}, {name: 'bin_cntr_q[15] (hex)' , wave: '4...........4...',data: ['0','1']}, {name: 'test_cnt_q (hex)' , wave: '4...............',data: ['0']}, {name: 'window_cnt_q (hex)' , wave: '5555555555555555',data: ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']}, ], head:{ text:'Bucket Test', tick:0, },}
The following waveform shows how a sampling of a data pattern will be tested by the Markov test.
The test aims to detect either:
Oversampling of AST/RNG outputs leading to “clustered” input values that eventually change, but often are just repeats of the previous sample. For example the string: “00111111000011000111000111000001111” has roughly equal numbers of 1‘s and 0’s, but no good entropy source should generate such strings, because each bit is likely just a repeat of the previous one.
Wild oscillations of the RNG, in a distinctly non-random way. For instance the string: “010101010101010101” has almost zero entropy, even though the number of 1‘s and 0’s appears unbiased.
The test counts the number of changes in the a fixed number of RNG samples, and comparing the number of “01”/“10” pairs to the number of “00”/“11” pairs. On average, the number of switching (e.g., “01”) vs. non-switching (e.g., “00”) pairs should be 50% of the total, with a variance proportional to the sample size.
Like the Adaptive Proportion test, the Markov Test can be computed either cumulatively (summing the results over all RNG lines) or on a per-line basis. In this example, the RNG lines are scored individually (i.e., CONF.THRESHOLD_SCOPE
is False).
{signal: [ {name: 'rng_valid' , wave: 'p...............'}, ['rng bits', {name: 'rng_bus[3]' , wave: '1.0.10..1...0101'}, {name: 'rng_bus[2]' , wave: '01.0.10..1...010'}, {name: 'rng_bus[1]' , wave: '101.0.10..1...01'}, {name: 'rng_bus[0]' , wave: '10.10..1...0101.'}, ], {name: 'pair_cntr_q[3] (hex)', wave: '4.4.4.4.4.4.4.4.',data: ['0','0','0','1','1','1','1','2']}, {name: 'pair_cntr_q[2] (hex)', wave: '4.4.4.4.4.4.4.4.',data: ['0','1','2','3','3','4','4','5']}, {name: 'pair_cntr_q[1] (hex)', wave: '4.4.4.4.4.4.4.4.',data: ['0','1','1','1','2','2','2','2']}, {name: 'pair_cntr_q[0] (hex)', wave: '4.4.4.4.4.4.4.4.',data: ['0','1','2','2','3','3','4','5']}, {name: 'window_cnt_q (hex)' , wave: '5555555555555555',data: ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']}, ], head:{ text:'Markov Test', tick:0, },}
To initialize the ENTROPY_SRC block, see the Device Interface Functions (DIFs) section.
Once entropy has been prepared for delivery, it can be consumed by either hardware (CSRNG block hardware instance) or by a software interface (CSRNG software instance).
Note that when software makes frequent re-seed requests to CSRNG, any stored up entropy seeds in the final entropy FIFO will quickly consumed. Once the FIFO is empty, subsequent entropy seed requests will have to wait the worst case latency time while new entropy is being created.
A useful feature for the ENTROPY_SRC block is the ability to disable it in a graceful matter. Since there exists another feature to avoid power spikes between ENTROPY_SRC and CSRNG, software needs to monitor the disabling process. Bit 16 in the DEBUG_STATUS
should be polled after the ENTROPY_SRC enable bits are cleared in the CONF
register. After the handshakes with CSRNG are finished, the above bit should be set and the ENTROPY_SRC block can be safely enabled again.
ENTROPY_SRC may only be disabled if CSRNG is disabled.
Need to alert the system of a FIFO overflow condition.