Curve25519 public key format in ECDHSessionKey

The response sent to a call to get_ecdh_session_key is an ECDHSessionKey which contains both the shared secret from the ECDH computation and the public key of the provided identity.

The test data from SLIP-0010 seem to indicate that the curve25519 public keys start with 0x00, but the public key present in the ECDHSessionKey has a 0x01 prefix, so the question is what is the format of the returned public key?

I assumed the key was in Montgomery format, even though it should then have had a 0x40 prefix, but performing an ECDH after having converted the public key to Weierstrass short form did not lead to the same shared secret as the one in the ECDHSessionKey, so I am kind of stuck in my understanding of the correct key format to consider.

Any help would be appreciated.

1 Like

The public key prefix was recently changed from 0x01 to 0x00 to comply with the spec. See Public key prefixes rework by onvej-sl · Pull Request #4093 · trezor/trezor-firmware · GitHub. That pull request was merged on August 21st. Unfortunately the only firmware that has been released since then is for Trezor Safe 5, so unless you have a TS5, you will need to wait for the next firmware release.

As for the point format, the remaining 32 bytes should be the u-coordinate on a Montgomery curve. Could it be an issue with endianity? If it’s any help, here is the function which computes the public key from the private key: trezor-firmware/crypto/ed25519-donna/ed25519.c at ef02c4de5d492a5c5d562984ec65a302d093dfd0 · trezor/trezor-firmware · GitHub. From what I can tell, this results in a little-endian encoding of the u-coordinate.

2 Likes

Looking at this again, you mention converting the public key to “Weierstrass short form”. I am not sure why you would do that rather than use the formulas for point addition on the Montgomery curve, see RFC 7748 - Elliptic Curves for Security. Nevertheless, I suppose it could still work. Assuming you mapped the public key to the Weierstrass curve and did the ECDH using that curve, then did you map the resulting point back to the Montgomery curve and take its u-coordinate? You certainly can’t use the x-coordinate from the Weierstrass curve, because as RFC 7748 states the X25519 function “produce[s] a u-coordinate as output”.

Thanks for the feedback, I’ll wait for the next firmware for TS3.

Regarding the ECDH I managed to make it work, the issue was a one off in my key extraction.

Though now I am stuck with another issue, still related to curve25519, SLIP-0017 states that the HD Node is derived using BIP32 from the computed m/17’/A’/B’/C’/D’ derivation path, but from looking at the code it seems the “Bitcoin seed” BIP32 HmacSHA512 key is not used but instead replaced by a curve specific key, namely “curve25519 seed”. Even by changing that key I don’t seem to be able to recompute the correct public key (as returned by get_ecdh_session_key) from an input URI (proto://user@host:port) and index.

Is there some subtlety that eludes me?

SLIP-17 is inaccurate when referring to BIP-32, because BIP-32 doesn’t define key derivation for curve25519 keys. So the reference should be SLIP-10, which means not only using the string “curve25519 seed”, but also the different (simpler) child key derivation process, see step 4 here. Perhaps that is the problem.

I guess this is the problem yes, I figured it out in the mean time but I would gladly have avoided digging into the firmware’s source code :slight_smile:

I’ve file PR (satoshilabs/slips/pull/1835) so others (if any) don’t go down the same rabbit hole.

Merged. Thank you for your contribution.