No v5 support in hockeypuck (Was: Undocumented novel Ed448 point encoding breaks interoperability)

Andrew Gallagher andrewg at andrewg.com
Sun May 3 14:17:24 CEST 2026


Hi, all.

In reply to my previous email to gnupg-devel [0], but cross-posting for 
maximum audience:

On 05/01/2026 13:55, Andrew Gallagher via Gnupg-devel wrote:
> It has been brought to my attention that Ed448 keys are being encoded 
> without prefix octets in their MPIs/SOSes, which breaks compatibility 
> with go-crypto (and perhaps others) and is not documented anywhere that 
> I can find. The librepgp specification requires prefix octets for all 
> ECC curve point representations.

After (finally!) enabling support for v5 keys in hockeypuck, I have 
discovered that ECDH curve448 encryption subkeys have the same curve 
point encoding issue as Ed448 signing (sub)keys. protonmail/go-crypto, 
the OpenPGP library that hockeypuck relies on, implemented v5 support 
according to the latest rfc4880bis [1] draft, which consistently 
specifies prefix octets of 0x04 or 0x40 for all ECC point curves, 
whether ECDSA, ECDH, or EdDSA.

(protonmail/go-crypto was an early adopter of the rfc4880bis draft, and 
as such it is the only library available to hockeypuck that provides 
production v5 support of any kind; most of the alternatives never 
officially released v5 support)

The change in the Ed448 point encoding since rfc4880bis, as mentioned in 
my previous email, has been (belatedly) acknowledged in the most recent 
version of draft-librepgp [2]. The discrepancy in the ECDH point 
encoding still has not.

As a result, it is not now possible for hockeypuck to process *any* v5 
key material that GnuPG generates, even if we include support for the v5 
packet format as planned, since v5 is only generated in practice for 
x448 and type 8 kyber algorithms, neither of which are parseable.

Note also that x448 key generation is gated behind expert mode in gnupg 
and type 8 "kyber" keys are not. This means that only a small fraction 
of the wild population of v5 keys would be fully usable even if this 
encoding discrepancy was addressed. Type 8 will not be implemented in 
pm/gc as the library is prioritising support for the upcoming standard 
draft-ietf-openpgp-pqc [3] and draft-ietf-openpgp-nist-bp-comp [4] PQC 
keys instead.

At this point, even though it would be easy for me to claim a 
theoretical "v5 support" in hockeypuck 2.4, it would be a cruel and 
misleading prank on our users because none of them would be able to 
upload a real v5 key to any of the keyservers. Even if we were to patch 
in a hotfix for prefix-less code points (which would not be 
prohibitively difficult) it would still only serve a small number of 
expert users, and expert users are much more likely to prefer PQC 
encryption.

So I am (as of today) dropping v5 support as a design goal of 
hockeypuck, and pausing work on it indefinitely. If and when a 
meaningful fraction of GnuPG-compatible algorithm code points are added 
to pm/gc, or if GnuPG added support for interoperable PQC algorithms 
[3][4], I would happily reconsider.

I'm sorry that it has taken me three years to come to this conclusion. I 
could (in theory) have spotted this incompatibility earlier and saved 
users the false hope that v5 and v6 keys could coexist on the keyservers 
in the current state of the ecosystem.

Thanks once again to Liz Fong-Jones for finding this issue and bringing 
it to my attention.

A

[0] https://lists.gnupg.org/pipermail/gnupg-devel/2026-January/036128.html
[1] 
https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-rfc4880bis#name-ecdsa-and-ecdh-conversion-p
[2] 
https://author-tools.ietf.org/iddiff?url1=draft-koch-librepgp-04&url2=draft-koch-librepgp-05&difftype=--html#part-10
[3] https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-pqc
[4] https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-nist-bp-comp

PS here's a hexdump of a v5 curve448 ECDH subkey that I generated this 
morning using gnupg 2.5.18 from macports, showing that there is no 0x40 
or 0x04 octet present. The prefix octet would be expected at byte 0x12, 
immediately following the x448 curve OID 0x2b656f and the MPI length 
0x01be. (It's an MPI length BTW, not an SOS length - SOS lengths are 
rounded up to the nearest multiple of 8)

```
     00000000  b8                                                 CTB
     00000001     4c                                              length
     00000002        05                                           version
     00000003           69 f7 0a 31 12  00 00 00 42 03 2b 65 6f
     00000010  01 be 37 69 62 e9 a7 a7  81 c5 7b c5 c7 5d da f6
     00000020  d2 aa 26 e1 7e fc 35 ce  3c 11 d9 50 b9 c9 71 84
     00000030  5d 61 60 84 93 af 60 fa  db 59 aa 15 68 b4 3f 65
     00000040  cd 1d fc 3d d6 34 c3 64  1a 49 03 01 0a 09
```



More information about the Gnupg-devel mailing list