Raw 32-byte keys on the wire, X.509 SubjectPublicKeyInfo in the JCA -- so
every crossing needs the 12-byte DER prefix added or stripped. Written out
as a constant rather than parsed: a DER parser here would be more code than
the thing it parses, and one more place to get a length wrong.
Refuses an all-zero shared secret. X25519 produces all zeros for a
small-order peer key, and a peer that sends one forces both sides to a
secret it already knows. RFC 7748 says implementations MAY check; when the
peer's key arrives over a relay nobody trusts, MAY is not the right reading.
All four small-order points from §6.1 are tested.
⚠️ XDH is API 33+ on Android. Older devices throw NoSuchAlgorithmException
at the first call, and the app must either bundle a provider or refuse to
run -- a decision nobody has made, so it is documented rather than papered
over.
⚠️ These run on the JVM against SunEC. Android routes the same calls through
Conscrypt. Passing here says the encoding is right and nothing about a
device.
Kotlin engine: 27 tests -> 33.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>