My fictional user only has knowledge of an unclamped Ed25519 public key. He wants to calculate the same X25519 public key that I myself got from my Ed25519 secret.
So, given an Ed25519 key pair, I am looking for a way to get to the same X25519 public key in both of these two scenarios:
- when converting an unclamped Ed25519 public key to X25519
- when deriving the X25519 public key from the Ed25519 secret
It works with clamped
I have a Ed25519 key pair ed_pk
and ed_sk
where the public key is clamped:
// ed_sk=5BAA0D..
// ed_pk=466EC8..
... and I derive an X25519 public key x_pk
from the Ed25519 secret:
crypto_scalarmult_base(x_pk, ed_sk);
// x_pk=1321BF..
Note the value of x_pk. It matches what I get when converting over from the Ed25519 public key:
crypto_sign_ed25519_pk_to_curve25519(x_pk, ed_pk);
// x_pk=1321BF..
1321BF.. either way - Great!
But when I have an unclamped Ed25519 public key to begin with:
crypto_scalarmult_ed25519_base_noclamp(ed_pk, ed_sk);
... the conversion creates a different number for x_pk:
// ed_pk=A63B27..
crypto_sign_ed25519_pk_to_curve25519(x_pk, ed_pk);
// x_pk=B9FD38..
Can I (A) convert a public key that wasn't clamped to its clamped version? or (B) amend the Ed25519-X25519 conversion in a way that gets me matching results when working with unclamped variants?
If you absolutely want to use the same key for both operations, you can use Edwards25519 for key exchange instead of complicating the protocol with Curve25519 conversions.
What is often confused as the Ed25519 secret is the seed. The actual secret scalar is usually not exposed in APIs, and handled internally by computing
SHA-512(seed)
, and truncating the output to the first 256 bits.Here's simple Zig code that does what you want: