What happened
On 19 August 2026 the Stratum V2 reference implementation merged
pull request 2283, 27 commits to
noise_sv2, the crate that encrypts the link between a miner and its pool, and to the codec
that frames its messages. The pull request
closes six issues in the project's own tracker and twelve findings from an audit
repository, project-loupe/audit-stratum, which is not publicly readable. Nothing in it
repairs a broken cipher. Every part of it is about what the implementation does with key
material and counters on either side of the cipher.
What it changes
Stratum V2 wraps the miner-to-pool link in an authenticated encrypted session, and the specification is blunt about why: "Any intelligence about submitted shares can be directly converted to estimations of a miner's earnings and can be associated with a particular username." The session uses ChaCha20-Poly1305, with a 32-byte key and an 8-byte nonce that starts at zero and is incremented after every message.
Four of the changes are worth following.
A counter that could have gone round. Under this kind of authenticated encryption, one key must never encrypt two messages under the same nonce. The code incremented the counter unconditionally, so at its maximum value the addition would wrap and the same key would begin again at nonce zero. Encryption and decryption now fail instead, with a test that sets the counter to its last value and checks that both refuse (commit 02630c9c).
Copies of a cipher are copies of a nonce. Initiator, Responder and the codec derived
Clone, so a duplicate carried the same key and the same counter and could encrypt different
messages under both. The derives are gone. The issue that asked for it puts the reasoning in
one line: "This leads to nonce reuse which is particularly undesirable."
Secrets that outlived the handshake. When the handshake completes, its ephemeral, static
and authority keypairs, the chaining key and the handshake hash are now erased rather than
left in the object
(commit 25194461),
and the intermediate buffers used to derive the session keys, previously built with
.concat() on the heap and never cleaned, are a fixed stack buffer that gets wiped. The
hand-written volatile zero-writes were replaced by the zeroize crate
(commit caf81de8).
A key you have deleted cannot be recovered from a crash dump, a swapped page or a process
somebody reads later, which is the entire argument for wiping it.
A signed field nobody read. A pool proves its identity with a certificate signed by an
authority key, and the signed message is SHA-256(version || valid_from || not_valid_after || server_public_key). The version was covered by the signature and never compared, so a
certificate written for a later format would verify and then be read under today's layout.
Verification now rejects any version other than the one the crate implements
(commit 15e5969c).
What it does not change
Nobody's hashrate was stolen and no encrypted session is known to have been read. The counter case in particular needs a single session to send more than eighteen quintillion messages, which no mining connection will do. What it fixes is the shape of the mistake, an increment with nothing checking it, not a loss anyone suffered.
Erasure is also best-effort. zeroize stops the compiler from deleting a write nobody appears
to read; it cannot follow a copy the allocator, the operating system or a page file made
earlier. The change narrows the window in which key material sits in memory. It does not
promise the window is closed.
None of it is about who controls mining. Encryption stops the network between a miner and a pool from reading or rewriting the work, and by the specification it is "optional on the local network" and "mandatory for remote access to the upstream nodes". Which transactions go into the block is a different protocol entirely, the one that put a miner-built template in block 955,318 in June.
And nothing here is installed. The most recent tagged release, v1.11.1, is from 22 July 2026, before any of this work; these commits are on the main branch.
Context
The interesting part is where the findings came from. Bitcoin's implementations are being read this year at a rate they have not been read at before, by audits that file specific, small, well-described issues rather than announcing an incident. Six numbered issues in this project's own tracker, twelve findings in an audit repository, and a pull request that closes them together is what that process looks like from the inside.
It is worth being precise about what an audit of this kind produces. Not one dramatic hole, but a list of places where the code was correct in the case that happens and undefined in the case that does not: the counter nobody expected to reach its limit, the field nobody expected to change, the buffer nobody expected to be read. The distance between "cannot happen" and "is checked" is the entire subject, and it is the same distance a miner trusts when it points a machine at a pool it cannot see inside.
