Hi,
Nikos pointed out to me that there's a slight difference between
curve25519 as implemented by Nettle and the spec in RFC 7748.
As far as I see, the difference is that RFC 7748 says that bit 255 of an
encoded x coordinates is ignored. Or more precisely, the high bit of the
31:st octet in the x input string is cleared before convertion into an
integer. While nettle's curve25519_mul includes it in the computation,
with the usual wrap-around, 2^255 = 19 (mod p). I don't see any
difference in handling scalars. Do you agree?
So I'm considering this change,
diff --git a/curve25519-mul.c b/curve25519-mul.c
index adb20cb..f5127d7 100644
--- a/curve25519-mul.c
+++ b/curve25519-mul.c
@@ -72,7 +72,11 @@ curve25519_mul (uint8_t *q, const uint8_t *n, const uint8_t *p)
itch = ecc->p.size * 12;
scratch = gmp_alloc_limbs (itch);
+ /* Note that 255 % GMP_NUMB_BITS == 0 isn't supported, so x1 always
+ holds at least 256 bits. */
mpn_set_base256_le (x1, ecc->p.size, p, CURVE25519_SIZE);
+ /* Clear bit 255, as required by RFC 7748. */
+ x1[255/GMP_NUMB_BITS] &= ~((mp_limb_t) 1 << (255 % GMP_NUMB_BITS));
/* Initialize, x2 = x1, z2 = 1 */
mpn_copyi (x2, x1, ecc->p.size);
I wouldn't expect any problems from this, its a corner case with input
values which are arguably invalid.
The motivation in the RFC, as I understand it, is to leave open for
protocols to use the top bit for their own, without bothering to clear
it before invoking curve25519. Which at first seems a bit silly, but
there's some value in not leaving corner cases implementation defined,
and it would maybe have been even more silly to require that
implementations do wraparound of that improper high bit.
This change would also need some updates of testcases and documentation.
Regards,
/Niels
--
Niels Möller. PGP-encrypted email is preferred. Keyid C0B98E26.
Internet email is subject to wholesale government surveillance.