original key verifies signature: true
bytes == bytes2: false
original bytes: [aa, 57, 71, d7, 94, 34, ba, 8a, 3e, 0f, 44, 20, 11, 36, 85, 5d, aa, d0, e8, 84, 86, b9, 8b, 0b, 91, cd, 21, 60, de, db, 52, 78, d4, 59, 1f, 97, 04, f6, b7, c4, d3, 16, c7, dc, d3, ed, c1, 89, eb, 8c, 13, 72, 66, 7a, ae, a8, 80]
round-tripped bytes: [45, 52, 37, 50, 42, e8, 51, d9, 79, 8a, dd, d6, 38, b4, 2f, 68, bf, ff, ac, dc, 6a, e9, 77, d1, 40, e7, 4c, bf, a9, d9, ae, 44, 78, a9, 68, b5, dc, 6d, 03, 58, d3, a7, 8a, 10, db, 34, af, 69, 25, a4, 95, 95, 93, 89, cb, 5b, 00]
round-tripped key verifies the SAME signature: false
thread 'main' panicked at src/main.rs:30:5:
assertion `left == right` failed: PublicKey should round-trip through as_byte()/try_from() unchanged
PublicKey::as_byte()followed byPublicKey::try_from(&bytes[..])producesa different key that no longer verifies a signature the original in-memory
key verifies correctly. The parsed-back key isn't equivalent to the one that
was serialized — this makes any round trip through the public wire format
(the whole point of
as_byte()/TryFrom) silently produce a broken key.Repro (deterministic, no RNG needed)
Output
Environment
Impact
This makes the crate unsafe to use anywhere a public key needs to survive
serialisation — e.g. loading a key from a config file, a DNSSEC DNSKEY
record, or any wire protocol — since TryFrom<&[u8]> silently produces a
key that looks valid (parses without error) but doesn't actually correspond
to the bytes it was built from, and will reject signatures the real key
would accept.
I ran into this while evaluating ed448-rust as an Ed448 backend for a
DNSSEC (RFC 8080) implementation and had to switch to a different crate as a
result. My guess for the root cause, not
yet confirmed, is somewhere in
Point::encode/decodeor the TryFromconversion path in
src/public_key.rs.