Skip to content

Replace the RNG criterion that latched healthy co-signers with one that catches partial fills - #1073

Merged
kwsantiago merged 3 commits into
mainfrom
the-rng-check-stops-latching-healthy-sources
Oct 18, 2026
Merged

kwsantiago merged 3 commits into
mainfrom
the-rng-check-stops-latching-healthy-sources

Conversation

@kwsantiago

@kwsantiago kwsantiago commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Both RNG health checks refused healthy randomness often enough to take a working co-signer out of service, and a refusal latches the node until an operator clears it. This replaces the criterion responsible with one that refuses more of what matters and does not fire on a sound source.

The criterion it replaces

It refused any byte position holding 0x00, or 0xff, in every sample. That is wrong in rate and in coverage.

Rate. A given position does that in three independent random samples with probability 1 in 256³, and there are 32 positions and two extreme values, so a sound source fails about once in 260,000 calls. Measured on the OS source:

Check Old criterion New criterion
Checked draw, per call 12 in 3,000,000 0 in 3,000,000
Periodic health check, per call 13 in 1,000,000 0 in 1,000,000

The checked draws are pure OS output and match the analytic 11.4 closely; the periodic figure, from two calls per check, is within ordinary variance of its expected 7.6. Two consequences in production:

It surfaced as a CI failure on Windows, in a test that generates up to 64 dealer keys.

Coverage. It caught positions frozen at an extreme value, any number of them, and never a position frozen at any other value. The failure worth catching is a source that fills only part of what it is asked for and leaves the rest as it was. That matters because several draws turn bytes straight into a scalar with no hash between: the dealer's key, every polynomial coefficient, refresh and repair deltas, and the DKG proof-of-knowledge nonce. Twelve frozen bytes there leave 160 bits in known positions, about 2^80 work to recover, and the remaining criteria (no all-zero sample, all distinct, every pair at least 64 bits apart) do not catch it until roughly half the bytes are frozen. Signing nonces are not exposed this way, since they are derived through a hash of the random bytes and the share.

The replacement

Count the byte positions that hold the same value, whatever it is, across every sample, and refuse at four or more. Applied in both the periodic check and the checked draw.

A position matches across three independent samples with probability 1 in 65,536, so four or more of 32 doing so is a binomial tail of about 2 × 10⁻¹⁵, the same order as the Hamming floor. No healthy node latches on it. What it lets through, one to three frozen positions, leaves at least 232 bits per sample.

It only runs across three or more samples. Across two, a position matches with probability 1 in 256 and four of 32 matching becomes about 8 × 10⁻⁶ per call, the rate this exists to get away from. Both sites already judge at least three.

Tests

  • A source filling twenty bytes per block and leaving twelve at 0x00 is refused, in the checked draw and in the periodic check. Every pair is still distinct, nonzero and far apart, so nothing else sees it.
  • The same with the unfilled bytes left at 0x5a, which the old criterion never caught.
  • Three frozen positions pass and four are refused, pinning the threshold from both sides. These are built rather than drawn: with random unfrozen bytes, any one matching across the samples by chance tips three into four, which would fail on healthy input about once in 2,260 runs.
  • A single position repeating across blocks is not a fault.

Each fails if the count is removed. Every existing degraded-source test still refuses: stuck, barely moving, alternating, all-zero, wide fills, and group keys from a stuck or alternating source. A stale doc saying the probe draws "until two have been judged", when it draws until three, is corrected.

@coderabbitai

coderabbitai Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 6 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 0562e339-6cff-45bd-9b32-3e86eb0c4d69
📥 Commits

Reviewing files that changed from the base of the PR and between 451bbb7 and 60dafe2.

📒 Files selected for processing: 2
  • keep-core/src/entropy.rs
  • keep-core/src/frost/checked_rng.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kwsantiago kwsantiago changed the title Drop the byte-position RNG criterion that latched healthy co-signers Replace the RNG criterion that latched healthy co-signers with one that catches partial fills Oct 18, 2026
@kwsantiago
kwsantiago merged commit 8b74a28 into main Oct 18, 2026
13 checks passed
@kwsantiago
kwsantiago deleted the the-rng-check-stops-latching-healthy-sources branch October 18, 2026 17:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant