# Post-quantum counter-signatures

**Every published release's `SHA256SUMS` carries a second signature under a post-quantum algorithm,
in addition to the OpenPGP one.** This page explains what it is for and how to check it. **It changes
nothing about the existing GPG signatures — it sits beside them.**

> **Applied retroactively on 10 August 2026, and that works for a reason worth stating.** A
> counter-signature made today protects a release published earlier, because what matters is not when
> it was *signed* but that its OpenTimestamps anchor **predates any cryptographic break**. All twelve
> published manifests were counter-signed in one batch and anchored in **Bitcoin block 961879**.
>
> Each was fetched **from its published release** before signing, so the signature covers the bytes
> the world can actually download rather than a local copy.
>
> *(`satoshi-onchain` v1.0.0 has no published assets, so there is no manifest to cover — a property
> of that release, not a gap here.)*

## Why

The OpenPGP release key is **Ed25519**. Elliptic-curve signatures do not survive a cryptographically
relevant quantum computer: given the public key, the private key becomes recoverable, and **anyone
could then produce signatures indistinguishable from ours.**

**SHA-256 is not in that position.** Grover's algorithm offers at most a quadratic speedup against a
hash, leaving ~128 bits of effective security. So:

```
GPG signature (Ed25519)      forgeable after a break
published SHA-256 manifests  unaffected
OpenTimestamps anchors       unaffected -- and they are what dates a release
```

**Our timestamps already outlive our signatures.** A forger who could mint a fake signature still
could not produce a **pre-break Bitcoin anchor**, so genuine releases stay distinguishable by
*precedence*. **The counter-signature closes the remaining gap: it answers *who*, where the anchor
answers *which came first*.**

## The algorithm

**SLH-DSA-SHA2-128s** — NIST FIPS 205, the standardised form of SPHINCS+. Its security rests **only
on hash functions**, so it stands in the same place SHA-256 does.

```
public key   126 bytes      parthod0x-pq-countersign.pem
signature  7,856 bytes      <release>.SHA256SUMS.slhdsa
```

**It is stateless.** LMS and XMSS were considered and rejected: they are *stateful*, and reusing a
one-time key index — restoring a backup, copying a key, rolling back a snapshot — destroys their
security. A stateless scheme has no such failure mode.

## Verify a release

Two routes. **Step 3 is the only one that differs between them**, and they check the same thing.

> ### ⮕ THE ROUTE WITH NO DEPENDENCIES — added 6 September 2026
>
> ```bash
> python verify/verify_slhdsa.py parthod0x-pq-countersign.pem SHA256SUMS SHA256SUMS.slhdsa
> ```
>
> **Pure Python, `hashlib` only.** No OpenSSL, no build step, no package, no network.
>
> ⛔ **This exists because the version below made the durable signature depend on the fragile
> tool.** The whole argument for counter-signing is that SLH-DSA outlives elliptic curves — and
> the only published way to check it required a particular release of one program. A signature
> meant to be verifiable in fifty years should not assume what will be installed then.
>
> Check the checker with `python verify/verify_slhdsa.py --selftest --corpus docs`, and — while an
> independent implementation is still available — `--crosscheck`, which requires this file and
> OpenSSL to agree on **every** verdict, accepts and rejects alike.
>
> ⚠️ Not validated against NIST ACVP test vectors; see
> [`../verify/README.md`](../verify/README.md) for exactly what it has and has not been checked
> against.

**The OpenSSL route requires OpenSSL 3.5 or later**, which ships SLH-DSA natively — no extra
libraries.

```bash
openssl version                                        # must be 3.5+

# 1. the manifest still matches the tarball  (unchanged, the primary check)
sha256sum -c SHA256SUMS

# 2. the OpenPGP signature                    (unchanged)
gpg --verify SHA256SUMS.asc SHA256SUMS

# 3. the post-quantum counter-signature       (new)
openssl pkeyutl -verify -pubin -inkey parthod0x-pq-countersign.pem \
  -rawin -in SHA256SUMS -sigfile SHA256SUMS.slhdsa
#   -> Signature Verified Successfully

# 4. the counter-signature's own timestamp    (what makes it pre-dated)
ots verify SHA256SUMS.slhdsa.ots
```

**Step 4 is the one that matters most and is easiest to skip.** A counter-signature made at any time
proves authorship; a counter-signature **anchored in a Bitcoin block** proves it was made *before*
that block — which is what a forgery cannot reproduce.

## Scope, stated plainly

- **This is authenticity, not authority.** It proves who published these bytes. It proves nothing
  about any claim the bytes make. **Not money, not financial advice.**
- **The public key here is dated by its own OpenTimestamps proof.** Compare it against a second
  source before relying on it, exactly as with the OpenPGP fingerprint — a key and its own claimed
  provenance are not independent. **The key is published byte-identically on the two sites that
  actually publish signed releases, and on the releases themselves:**

  ```bash
  for h in satoshioncha.in bitcoin-lab.org; do
    curl -sL "https://$h/parthod0x-pq-countersign.pem" | sha256sum
  done
  # both -> 0624d2c7149d4af09e25b558e76f5e6b1a8855d60723c45333829c46488ceda4
  ```

  **Two hosts agreeing is weak evidence and should be treated as such** — one publisher controls
  both. It rules out a single substituted file, not a substituted publisher. **The OpenTimestamps
  proof on the key is what a compromised host cannot backdate**, and it is the reason the key was
  stamped at all. *(For the OpenPGP key there is a genuinely independent route — the public
  keyservers. There is no equivalent for a raw SLH-DSA key, which is precisely why its timestamp
  carries the weight here.)*
- **Old releases can still be covered.** A counter-signature made today and anchored today protects a
  release published earlier, because the anchor proves it predates any break. **The deadline is
  "before a break", not "at release."**
