NIST SP 800-90B · section 6.2 · ten estimators, minimum taken
The Battery That Can't Tell
Your browser's clock is deliberately blunt. Count how many loop iterations fit between two of its ticks and you have a noise source your own machine is generating right now. Run the ten estimators that a federal standard says shall be calculated, take the minimum as it says you must, and you get a min-entropy in bits per sample for your hardware. Then run the identical battery on a cryptographic generator and on a piece of arithmetic whose whole state is 31 bits. All three land on top of each other, inside the scatter a single one of them shows when you simply run it again.
01 · the apertureYour clock does not tick as finely as you think
Every browser rounds performance.now() to a quantum, on purpose, to blunt timing side channels. Documentation disagrees about what the quantum is; on this build machine the three engines gave two answers between them, and one of those two came out ten times coarser than the figure this page had predicted for it from the documentation, which is recorded below as a prediction that died. So the page does not look the quantum up. It measures it, by calling the clock in a tight loop and keeping the smallest step it ever takes.
not yet measured
The second figure matters as much as the first. If every step the clock takes is a whole multiple of the smallest one, the clock is a clean lattice and the coarseness is pure rounding. If the steps land off that lattice, the engine is adding noise to the clock deliberately, and any entropy measured downstream is partly the browser's own generator rather than your machine. That would not be a measurement of anything physical, so the page checks and says so.
02 · the noise sourceThe coarseness is not the obstacle, it is the instrument
The usual instinct is to treat a coarse clock as a broken ruler. Do the opposite: use it as a gate. Spin a counting loop from one clock edge to the next and record how many iterations fit. The count is large, and it will not sit still, because underneath your tab there are interrupts, a scheduler, frequency scaling, other cores contending for cache. Section 6.4 of the Recommendation describes this exact case and endorses this exact reduction: take the low four bits, and credit the source with at most four bits per sample.
no samples yet
The histogram shows how often each of the sixteen possible four-bit samples came up. A noise source makes it flat and restless; a broken one makes it a spike.
This is where the page is allowed to refuse. If the counter barely moves, or averages too few iterations for its bottom four bits to mean anything, or the tab was backgrounded mid-collection, there is no honest number to print and the instrument declines to print one. A page that always produces a figure will eventually produce a wrong one.
03 · the mandated batteryTen estimators, and the standard says take the smallest
For non-IID data, the following estimators shall be calculated on the outputs of the noise source and outputs of any conditioning component that is not listed in Section 3.1.5.1.1, and the minimum of all the estimates is taken as the entropy assessment of the entropy source for this Recommendation: SP 800-90B, section 6.2, printed page 41
Three of the ten carry a restriction one sentence later: The Collision, Markov and Compression estimates are only applied to binary inputs. So they run on the bitstring and not on the four-bit samples, and the table below says which ran on what rather than quietly averaging the two. The minimum is not a summary statistic chosen for effect. It is the rule.
collect samples first
| estimator | section | H (bits/bit) | detail |
|---|
Two quantities come out, and confusing them is the commonest way to misreport a source. H_bitstring is per bit of the flattened bitstring; H_original is per four-bit sample. Section 3.1.3 says the per-sample estimate is min(H_original, n × H_bitstring), and that the initial entropy estimate also takes the minimum with H_submitter, the developer's own documented figure. There is no H_submitter for a web page, so what this page prints is not H_I and never can be.
04 · the comparisonNow run the identical battery on things with no entropy in them at all
Here is the sophisticated objection, and it is correct as far as it goes: you are just measuring your operating system's scheduler, and any decent generator would score the same. Right. Here is the number. The same ten estimators, the same minimum rule, the same sample count, on your live capture, on crypto.getRandomValues, and on a linear congruential generator with the old glibc constants, whose entire state is 31 bits and whose state is its output: hand anyone one full output of it and they have everything it will ever produce, forwards and backwards. The battery is handed the top four bits of each, which is a harder problem, and that is the point of feeding it this one.
| source | what is inside it | battery minimum | caught by |
|---|
Whatever order those four came out in, do not read it yet. These estimators have scatter of their own, and a single run of each cannot tell a real gap from that scatter. So the page ships the control that decides it: the same battery, at spec scale, over five repeated captures of each source. If one source varies from run to run by more than the sources differ from each other, then the ordering above is not a fact about the sources. It is the instrument's own wobble, arranged in a line.
| source | runs | mean | lowest | highest | spread |
|---|
05 · the controlsThe battery is not blind, and here is it working
So the four sources above are, as far as this battery can see, the same source. The obvious next thought is that the tests must simply be weak. They are not, and this is where you can watch them work. Feed them things that are definitely not random and see which of the ten notices. This is also where the minimum rule earns its keep: on an alternating bit stream the Most Common Value estimate is completely fooled, because the stream is perfectly balanced, and it takes a predictor to see the obvious.
| control | MCV alone | battery minimum | which of the ten caught it | verdict |
|---|
The pair to look at hardest is the two ends of one generator. The top four bits and the bottom four bits of the same linear congruential generator carry the identical internal state, and the battery treats them completely differently, because the low bits of an LCG have short periods and the predictors find them. Nothing about the amount of unpredictability changed between those two rows. Only whether this particular family of statistics happens to have a model for it.
06 · calibrationThe one source whose true answer is known in closed form
Everything above is a comparison between measurements. This is the row where there is a right answer to compare against. For independent bits that come up zero with probability p, the most likely outcome has probability p, so the min-entropy is exactly −log₂(p). The Recommendation gives a figure for how far short an estimate may fall, in footnote 11, printed at the foot of page 40: the underestimation is believed likely not to exceed one bit. Note where that footnote sits, because the page had it wrong at first. Its anchor is in section 6.1, the IID track, and its subject is the most common value estimate on its own, not the minimum over all ten, which can only be smaller. So it is a yardstick borrowed from the standard rather than a bound the standard places on this battery. Drag p and watch whether it holds anyway.
| p | analytic truth | battery minimum | conservative by | held? |
|---|
07 · the published tableRe-deriving a printed table, and finding it moved
Four of the ten estimators need a quantity called P_local: the success rate at which a run of correct predictions as long as the one observed would sit at the one per cent tail. Appendix G.2 prints a table of it, 136 rows, for a sequence of a million. That table is a published number the page can recompute from scratch, which makes it the only figure here that can be checked against something other than itself.
not yet run
| r | printed | recomputed at r | recomputed at r−5 |
|---|
The disagreement is not scattered, which is what an implementation error looks like. It is one unbroken block, every row of it equal to the value belonging to the row above, and it snaps back into alignment afterwards. The printed table gives that away without any help from this page, as long as you measure the climb per unit of r rather than per printed row: the table steps by one up to 49 and then by five, so a raw difference across that jump is not comparable with the one before it. Per unit of r, P_local climbs smoothly and its rate shrinks steadily, yet the rate into the start of that block is a fraction of the rate before it, and the rate out of it is nearly double the rates either side. Both anomalies sit exactly at the two ends.
There is a second one, and NIST has already published it. The worked example in section 6.3.1 never was self-consistent, and the errata of 29 May 2025 resolves it in the direction that disagrees with the formula printed directly above the example, and with the divisor in NIST's own reference implementation.
| divisor | radicand | p_u | min-entropy | who prints this |
|---|
what it meansThe battery is right. It is answering a different question.
Nothing above shows the estimators to be broken. They catch a shift register with one byte of state instantly; they are calibrated against closed-form truth in the conservative direction; and this implementation of all ten agrees with NIST's own compiled reference tool to within four millionths of a bit on every one of the thirty comparisons, which is four orders of magnitude below the gaps this page is arguing about. It is not agreement to the final printed digit of that tool, and the check panel says so in as many words. The result is not about test quality. It is about what min-entropy is a property of, and the Recommendation says that in its first paragraph on the subject.
Entropy is defined relative to one's knowledge of an experiment's output prior to observation, and reflects the uncertainty associated with predicting its value. SP 800-90B, section 2.1, printed page 4
… whose output values are effectively indistinguishable from those of a random process as long as the internal states and internal actions of the process are unknown. SP 800-90B, glossary, definition of Pseudorandom
A battery of statistics is an observer with no knowledge of internal state. Handed the outputs of a generator whose seed it cannot see, it is in exactly the position the glossary describes, and it returns the answer that position entails. That is not a failure of the tests. It is the definition doing what definitions do.
Which is why the Recommendation never leaves the decision to the statistics. It disqualifies generators by documentation, in a requirement no statistic could enforce:
Although the noise source is not required to produce unbiased and independent outputs, it shall exhibit random behavior; i.e., the output shall not be definable by any known algorithmic rule. SP 800-90B, section 3.2.2, requirement 5, printed page 19
An LCG is definable by a known algorithmic rule; that is practically its definition. It is disqualified as a noise source by that sentence, and by nothing in section 6. The battery was never the gate. Section 3.1.1 demands the raw data from the noise source, section 3.2.2 demands a technical argument for why that source provides the entropy claimed, and section 6.2 says only, of its own ten tests, that a large and diverse battery minimizes the probability that such a source's entropy is greatly overestimated. Minimizes. Not establishes.
So the honest reading of your own number, above, is this. It is a real measurement of a real physical process on your machine, and it is not an entropy assessment of anything, because an assessment under this standard is a claim about what an adversary outside a documented security boundary cannot know, and neither this page nor these ten tests are in a position to make that claim about your laptop. Your hardware and a 31-bit formula came out within a few hundredths of a bit of each other, which is less than either of them moves when you simply measure it twice. The figure is true. The thing it is a figure of is smaller than it looks.
The check
Running the checks…