mirror of
https://github.com/monero-project/monero.git
synced 2026-07-28 14:47:15 -07:00
crypto: add Ed25519->X25519 conversion functions
Reviewed-by: koe <ukoe@protonmail.com> Reviewed-by: j-berman <justinberman@protonmail.com>
This commit is contained in:
+34
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2014-2024, The Monero Project
|
||||
// Copyright (c) 2014-2026, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
@@ -3905,6 +3905,39 @@ int sc_isnonzero(const unsigned char *s) {
|
||||
s[27] | s[28] | s[29] | s[30] | s[31]) - 1) >> 8) + 1;
|
||||
}
|
||||
|
||||
static int edwardsYZ_to_x25519(unsigned char *xbytes, const fe Y, const fe Z) {
|
||||
//! @see Section 4.1 of RFC 7748: https://www.rfc-editor.org/rfc/rfc7748.html#section-4.1
|
||||
//
|
||||
// y = Y/Z
|
||||
// x_mont = (1 + y) / (1 - y)
|
||||
// = (1 + Y/Z) / (1 - Y/Z)
|
||||
// = (Z + Y) / (Z - Y)
|
||||
|
||||
fe tmp0;
|
||||
fe tmp1;
|
||||
int r;
|
||||
fe_add(tmp0, Z, Y); // Z + Y
|
||||
fe_sub(tmp1, Z, Y); // Z - Y
|
||||
r = -!fe_isnonzero(tmp1); // succeed iff 0 != (Z - Y). AKA fail if identity point or some invalid reprs
|
||||
fe_invert(tmp1, tmp1); // 1/(Z - Y)
|
||||
fe_mul(tmp0, tmp0, tmp1); // (Z + Y) / (Z - Y)
|
||||
fe_tobytes(xbytes, tmp0); // tobytes((Z + Y) / (Z - Y))
|
||||
return r; // 0 on success, otherwise -1
|
||||
}
|
||||
|
||||
int ge_p3_to_x25519(unsigned char *xbytes, const ge_p3 *h) {
|
||||
return edwardsYZ_to_x25519(xbytes, h->Y, h->Z);
|
||||
}
|
||||
|
||||
int edwards_bytes_to_x25519_vartime(unsigned char *xbytes, const unsigned char *s) {
|
||||
ge_p3 h;
|
||||
const int r = ge_frombytes_vartime(&h, s);
|
||||
if (0 != r)
|
||||
return r;
|
||||
|
||||
return edwardsYZ_to_x25519(xbytes, h.Y, h.Z);
|
||||
}
|
||||
|
||||
int ge_p3_is_point_at_infinity_vartime(const ge_p3 *p) {
|
||||
// https://eprint.iacr.org/2008/522
|
||||
// X == T == 0 and Y/Z == 1
|
||||
|
||||
@@ -162,6 +162,30 @@ void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b,
|
||||
int sc_check(const unsigned char *);
|
||||
int sc_isnonzero(const unsigned char *); /* Doesn't normalize */
|
||||
|
||||
/**
|
||||
* @brief Convert Ed25519 y-coord to X25519 x-coord, AKA "ConvertPointE()" in the Carrot spec
|
||||
* @param[out] xbytes X25519 x-coord as a 255-bit little endian integer
|
||||
* @param h Ed25519 point in projective representation
|
||||
* @return 0 on success, otherwise non-0 on failure
|
||||
*
|
||||
* Returns failure on Ed25519's identity point. Assumes `h` has valid field element representations,
|
||||
* that Z != 0, and that Y/Z is a valid y-coordinate for Ed25519. Returns success iff Y != Z (Y == Z
|
||||
* corresponds with the identity point in valid point representations). The runtime is constant.
|
||||
*/
|
||||
int ge_p3_to_x25519(unsigned char *xbytes, const ge_p3 *h);
|
||||
/**
|
||||
* @brief Convert Ed25519 y-coord to X25519 x-coord, AKA "ConvertPointE()" in the Carrot spec
|
||||
* @param[out] xbytes X25519 x-coord as a 255-bit little endian integer
|
||||
* @param s Ed25519 point in compressed Y representation
|
||||
* @return 0 on success, otherwise non-0 on failure
|
||||
*
|
||||
* Returns failure on Ed25519's identity point (repr {1, 0, 0, ...}). Otherwise, returns success iff
|
||||
* `s` is a valid compressed Y representation of an Ed25519 point. The runtime is variable *only* in
|
||||
* whether `s` is a valid representation. In other words, for all valid Ed25519 points, the runtime
|
||||
* is constant.
|
||||
*/
|
||||
int edwards_bytes_to_x25519_vartime(unsigned char *xbytes, const unsigned char *s);
|
||||
|
||||
// internal
|
||||
uint64_t load_3(const unsigned char *in);
|
||||
uint64_t load_4(const unsigned char *in);
|
||||
|
||||
Reference in New Issue
Block a user