Public keys
Two keys, two jobs. Keeping them separate is the point: whoever holds this server cannot sign a release, and whoever holds the release key does not need access to this server.
Release key — SLH-DSA-SHA2-128s
Signs every manifest, bundle and report. Kept offline; it never touches this host. Your router already has the public half baked into its image at /etc/gadnet/release-public-key-slhdsa.pem, which is why pointing a device at a hostile update server produces a failed update rather than a compromised one.
Hash-based signatures (NIST FIPS 205) rest on hash preimage resistance alone, which a quantum computer only halves. That is why release provenance uses SLH-DSA rather than the classical GPG key that ships alongside it for compatibility.
Server-side copy in use: release-public-key-slhdsa.pem
Published key set
Routers learn a replacement signing key from this document, which is itself signed by the key they already trust. That is what makes a rotation an ordinary background event instead of a new image on every device - and why a server that is taken over still cannot introduce a key of its own.
Sequence 1, published 2026-09-22.
| Fingerprint (SHA-256) | Status | Valid |
|---|---|---|
66b2 74b0 ca6b 3153 c6dd 1496 ad29 5114 5925 b13c c5b4 14ad 857f 24cb b3c4 1431 |
current | 2026-09-22 – 2028-09-21 |
52db 3adc d469 d1af ce92 5d73 793f 58c6 50af 5ee0 43e3 2c9d 3396 fbd3 f80a 99ea |
next | 2026-09-22 – 2028-09-21 |
If a router asks you to confirm a new release key, compare its fingerprint with the one listed here, character for character.
Machine-readable, and its detached signature:
Reproduce a fingerprint from a public key yourself:
openssl pkey -pubin -in release-public-key-slhdsa.pem -outform DER | openssl dgst -sha256
Transport identity key — Ed25519
Signs key-exchange transcripts, and nothing else. Pin it in a client and a substituted server is detected even when its TLS certificate validates - which is the normal situation behind a corporate proxy or a captive portal.
- Public key (base64url)
tDvaWjcAqgAev3fxt2wagFEvhM5uXbRXpY01KR-zIag- Fingerprint
b43b da5a 3700 aa00 1ebf 77f1 b76c 1a80 512f 84ce 6e5d b457 a58d 3529 1fb3 21a8
Compromise of this key lets an attacker impersonate the transport. It does not let them forge a release, and it does not reveal past sessions: the session secrets come from ephemeral keys that exist only for the duration of one handshake.
Key exchange
Suite:
X25519MLKEM768 — X25519 combined with ML-KEM-768 (FIPS 203), in classical || PQ order. The classical leg survives a break of ML-KEM; the post-quantum leg defends against an adversary recording traffic now to decrypt later.
Handshake endpoint: POST https://updates.gadnet.pl/api/v1/kex/init
{
"version": 1,
"x25519_public": "<32 bytes, base64url>",
"mlkem768_public": "<PEM SubjectPublicKeyInfo, base64url>"
}
The reply carries the server's ephemeral X25519 public key, the ML-KEM ciphertext, a session id, and an Ed25519 signature over the transcript hash. Both sides then run HKDF-SHA-384 over x25519_shared || mlkem_shared with the transcript hash as salt, so a tampered handshake yields different keys and the first authenticated request fails.