summaryrefslogtreecommitdiff
path: root/cipher/ecc-eddsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'cipher/ecc-eddsa.c')
-rw-r--r--cipher/ecc-eddsa.c135
1 files changed, 85 insertions, 50 deletions
diff --git a/cipher/ecc-eddsa.c b/cipher/ecc-eddsa.c
index 4a9fe0a5..22f27023 100644
--- a/cipher/ecc-eddsa.c
+++ b/cipher/ecc-eddsa.c
@@ -46,6 +46,20 @@ reverse_buffer (unsigned char *buffer, unsigned int length)
}
+/* Helper to scan a hex string. */
+static gcry_mpi_t
+scanval (const char *string)
+{
+ gpg_error_t err;
+ gcry_mpi_t val;
+
+ err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
+ if (err)
+ log_fatal ("scanning ECC parameter failed: %s\n", gpg_strerror (err));
+ return val;
+}
+
+
/* Encode MPI using the EdDSA scheme. MINLEN specifies the required
length of the buffer in bytes. On success 0 is returned an a
@@ -122,61 +136,82 @@ _gcry_ecc_eddsa_encodepoint (mpi_point_t point, mpi_ec_t ec,
}
-/* Recover X from Y and SIGN . */
-void
+/* Recover X from Y and SIGN (which actually is a parity bit). */
+gpg_err_code_t
_gcry_ecc_eddsa_recover_x (gcry_mpi_t x, gcry_mpi_t y, int sign, mpi_ec_t ec)
{
- /* FIXME: This algorithm can be improved - see the paper.
- sqrt(-1) mod ed255519_p:
- 2B8324804FC1DF0B2B4D00993DFBD7A72F431806AD2FE478C4EE1B274A0EA0B0 */
- gcry_mpi_t yy, t, p1, p2, p3;
-
- /* t = (y^2-1) ยท ((b*y^2+1)^{p-2} mod p) */
- yy = mpi_new (0);
- mpi_mul (yy, y, y);
- t = mpi_copy (yy);
- mpi_mul (t, t, ec->b);
- mpi_add_ui (t, t, 1);
- p2 = mpi_copy (ec->p);
- mpi_sub_ui (p2, p2, 2);
- mpi_powm (t, t, p2, ec->p);
-
- mpi_sub_ui (yy, yy, 1);
- mpi_mul (t, yy, t);
-
- /* x = t^{(p+3)/8} mod p */
- p3 = mpi_copy (ec->p);
- mpi_add_ui (p3, p3, 3);
- mpi_fdiv_q (p3, p3, mpi_const (MPI_C_EIGHT));
- mpi_powm (x, t, p3, ec->p);
-
- /* (x^2 - t) % p != 0 ? x = (x*(2^{(p-1)/4} mod p)) % p */
- mpi_mul (yy, x, x);
- mpi_subm (yy, yy, t, ec->p);
- if (mpi_cmp_ui (yy, 0))
+ gpg_err_code_t rc = 0;
+ gcry_mpi_t u, v, v3, t;
+ static gcry_mpi_t p58, seven;
+
+ if (ec->dialect != ECC_DIALECT_ED25519)
+ return GPG_ERR_NOT_IMPLEMENTED;
+
+ if (!p58)
+ p58 = scanval ("0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD");
+ if (!seven)
+ seven = mpi_set_ui (NULL, 7);
+
+ u = mpi_new (0);
+ v = mpi_new (0);
+ v3 = mpi_new (0);
+ t = mpi_new (0);
+
+ /* Compute u and v */
+ /* u = y^2 */
+ mpi_mulm (u, y, y, ec->p);
+ /* v = b*y^2 */
+ mpi_mulm (v, ec->b, u, ec->p);
+ /* u = y^2-1 */
+ mpi_sub_ui (u, u, 1);
+ /* v = b*y^2+1 */
+ mpi_add_ui (v, v, 1);
+
+ /* Compute sqrt(u/v) */
+ /* v3 = v^3 */
+ mpi_powm (v3, v, mpi_const (MPI_C_THREE), ec->p);
+ /* t = v3 * v3 * u * v = u * v^7 */
+ mpi_powm (t, v, seven, ec->p);
+ mpi_mulm (t, t, u, ec->p);
+ /* t = t^((p-5)/8) = (u * v^7)^((p-5)/8) */
+ mpi_powm (t, t, p58, ec->p);
+ /* x = t * u * v^3 = (u * v^3) * (u * v^7)^((p-5)/8) */
+ mpi_mulm (t, t, u, ec->p);
+ mpi_mulm (x, t, v3, ec->p);
+
+ /* Adjust if needed. */
+ /* t = v * x^2 */
+ mpi_mulm (t, x, x, ec->p);
+ mpi_mulm (t, t, v, ec->p);
+ /* -t == u ? x = x * sqrt(-1) */
+ gcry_mpi_neg (t, t);
+ if (!mpi_cmp (t, u))
{
- p1 = mpi_copy (ec->p);
- mpi_sub_ui (p1, p1, 1);
- mpi_fdiv_q (p1, p1, mpi_const (MPI_C_FOUR));
- mpi_powm (yy, mpi_const (MPI_C_TWO), p1, ec->p);
- mpi_mulm (x, x, yy, ec->p);
+ static gcry_mpi_t m1; /* Fixme: this is not thread-safe. */
+ if (!m1)
+ m1 = scanval ("2B8324804FC1DF0B2B4D00993DFBD7A7"
+ "2F431806AD2FE478C4EE1B274A0EA0B0");
+ mpi_mulm (x, x, m1, ec->p);
+ /* t = v * x^2 */
+ mpi_mulm (t, x, x, ec->p);
+ mpi_mulm (t, t, v, ec->p);
+ /* -t == u ? x = x * sqrt(-1) */
+ gcry_mpi_neg (t, t);
+ if (!mpi_cmp (t, u))
+ rc = GPG_ERR_INV_OBJ;
}
- else
- p1 = NULL;
- /* is_odd(x) ? x = p-x */
- if (mpi_test_bit (x, 0))
- mpi_sub (x, ec->p, x);
+ /* Choose the desired square root according to parity */
+ if (mpi_test_bit (x, 0) != !!sign)
+ gcry_mpi_neg (x, x);
- /* lowbit(x) != sign ? x = p-x */
- if (mpi_test_bit (x, 0) != sign)
- mpi_sub (x, ec->p, x);
+ mpi_free (t);
+ mpi_free (v3);
+ mpi_free (v);
+ mpi_free (u);
- gcry_mpi_release (yy);
- gcry_mpi_release (t);
- gcry_mpi_release (p3);
- gcry_mpi_release (p2);
- gcry_mpi_release (p1);
+ return rc;
}
@@ -278,10 +313,10 @@ _gcry_ecc_eddsa_decodepoint (gcry_mpi_t pk, mpi_ec_t ctx, mpi_point_t result,
else
gcry_free (rawmpi);
- _gcry_ecc_eddsa_recover_x (result->x, result->y, sign, ctx);
+ rc = _gcry_ecc_eddsa_recover_x (result->x, result->y, sign, ctx);
mpi_set_ui (result->z, 1);
- return 0;
+ return rc;
}