Commit 05624cde authored by Wim Lewis's avatar Wim Lewis

First draft at reconstructing points from their compact representation

(X + sign(Y)). Implementations of sqrt in P-256, P-384, and P-521.
parent dc28cadb
......@@ -179,7 +179,9 @@ hogweed_SOURCES = sexp.c sexp-format.c \
ecc-dup-eh.c ecc-add-eh.c ecc-add-ehh.c \
ecc-mul-g-eh.c ecc-mul-a-eh.c \
ecc-mul-g.c ecc-mul-a.c ecc-hash.c ecc-random.c \
ecc-point.c ecc-scalar.c ecc-point-mul.c ecc-point-mul-g.c \
ecc-point.c ecc-point-from-octets.c ecc-point-compact.c \
ecc-point-recover.c \
ecc-scalar.c ecc-point-mul.c ecc-point-mul-g.c \
ecc-ecdsa-sign.c ecdsa-sign.c \
ecc-ecdsa-verify.c ecdsa-verify.c ecdsa-keygen.c \
curve25519-mul-g.c curve25519-mul.c curve25519-eh-to-x.c \
......
......@@ -130,6 +130,7 @@ const struct ecc_curve _nettle_secp_192r1 =
ecc_192_modp,
ecc_mod_inv,
NULL,
NULL,
},
{
192,
......@@ -149,6 +150,7 @@ const struct ecc_curve _nettle_secp_192r1 =
ecc_mod,
ecc_mod_inv,
NULL,
NULL,
},
USE_REDC,
......
......@@ -82,6 +82,7 @@ const struct ecc_curve _nettle_secp_224r1 =
USE_REDC ? ecc_224_redc : ecc_224_modp,
ecc_mod_inv,
NULL,
NULL,
},
{
224,
......@@ -101,6 +102,7 @@ const struct ecc_curve _nettle_secp_224r1 =
ecc_mod,
ecc_mod_inv,
NULL,
NULL,
},
USE_REDC,
......
......@@ -310,6 +310,7 @@ const struct ecc_curve _nettle_curve25519 =
ecc_25519_modp,
ecc_25519_inv,
ecc_25519_sqrt,
NULL,
},
{
253,
......@@ -329,6 +330,7 @@ const struct ecc_curve _nettle_curve25519 =
ecc_25519_modq,
ecc_mod_inv,
NULL,
NULL,
},
0, /* No redc */
......
......@@ -239,6 +239,40 @@ ecc_256_modq (const struct ecc_modulo *q, mp_limb_t *rp)
#error Unsupported parameters
#endif
static void
ecc_256_sqrt (const struct ecc_modulo *m,
mp_limb_t *rp,
const mp_limb_t *cp,
mp_limb_t *scratch)
{
mp_size_t size = m->size;
/* This computes the square root modulo p256 using the identity:
sqrt(c) = c^(2^254 − 2^222 + 2^190 + 2^94) (mod P-256)
*/
/* We use our scratch space for three temporaries (TA, TB, TC) all of
which are 2*size long to allow for multiplication/squaring */
#define TA scratch
#define TB (scratch + 2*size)
#define TC (scratch + 4*size)
ecc_mod_pow2n_mul(m, TB, cp, cp, TC, 1); /* [1] TB <-- c^3 */
ecc_mod_pow2n_mul(m, TA, TB, TB, TC, 2); /* [2] TA <-- c^(2^4 - 1) */
ecc_mod_pow2n_mul(m, TB, TA, TA, TC, 4); /* [3] TB <-- c^(2^8 - 1) */
ecc_mod_pow2n_mul(m, TC, TB, TB, TA, 8); /* [4] TC <-- c^(2^16 - 1) */
ecc_mod_pow2n_mul(m, TA, TC, TC, TB, 16); /* [5] TA <-- c^(2^32 - 1) */
ecc_mod_pow2n_mul(m, TB, TA, cp, TC, 32); /* [6] TB <-- c^(2^64 - 2^32 + 1) */
ecc_mod_pow2n_mul(m, TC, TB, cp, TA, 96); /* [7] TC <-- c^(2^160 - 2^128 + 2^96 + 1) */
ecc_mod_pow2n (m, rp, TC, TA, 94); /* [8] TB <-- c^(2^254 - 2^222 + 2^190 + 2^94) */
#undef TA
#undef TB
#undef TC
}
const struct ecc_curve _nettle_secp_256r1 =
{
{
......@@ -247,7 +281,7 @@ const struct ecc_curve _nettle_secp_256r1 =
ECC_BMODP_SIZE,
ECC_REDC_SIZE,
ECC_MOD_INV_ITCH (ECC_LIMB_SIZE),
0,
6 * ECC_LIMB_SIZE,
ecc_p,
ecc_Bmodp,
......@@ -259,6 +293,7 @@ const struct ecc_curve _nettle_secp_256r1 =
USE_REDC ? ecc_256_redc : ecc_256_modp,
ecc_mod_inv,
NULL,
ecc_256_sqrt,
},
{
256,
......@@ -278,6 +313,7 @@ const struct ecc_curve _nettle_secp_256r1 =
ecc_256_modq,
ecc_mod_inv,
NULL,
NULL,
},
USE_REDC,
......
......@@ -146,7 +146,58 @@ ecc_384_modp (const struct ecc_modulo *p, mp_limb_t *rp)
#else
#define ecc_384_modp ecc_mod
#endif
static void
ecc_384_sqrt (const struct ecc_modulo *m,
mp_limb_t *rp,
const mp_limb_t *cp,
mp_limb_t *scratch)
{
mp_size_t size = ECC_LIMB_SIZE;
/* This computes the square root modulo p256 using the identity:
sqrt(c) = c^(2^382 − 2^126 - 2^94 + 2^30) (mod P-384)
which is from Routine 3.2.12 of "Mathematical routines for the NIST prime elliptic curves", April 5, 2010, author unknown.
*/
/* We use our scratch space for several temporaries, all of
which are 2*size long to allow for multiplication/squaring */
#define T1 scratch
#define T2 (scratch + 2*size)
#define T3 (scratch + 4*size)
#define T4 (scratch + 6*size)
#define Tr T2 /* T2 and R are not live at the same time */
#define Tx (scratch + 8*size)
ecc_mod_pow2n_mul(m, T1, cp, cp, T2, 1); /* [ 1] T1 <- c^(2^1 - 1) */
ecc_mod_pow2n_mul(m, Tx, T1, T1, T3, 2); /* [ 2] T2 <- c^(2^4 - 1) */
ecc_mod_pow2n_mul(m, T2, Tx, cp, T3, 1); /* [ 3] T2 <- c^(2^5 - 1) */
ecc_mod_pow2n_mul(m, T3, T2, T2, Tx, 5); /* [ 4] T3 <- c^(2^10 - 1) */
ecc_mod_pow2n_mul(m, T4, T3, T2, Tx, 5); /* [ 5] T4 <- c^(2^15 - 1) */
ecc_mod_pow2n_mul(m, T2, T4, T4, Tx, 15); /* [ 6] T2 <- c^(2^30 - 1) */
ecc_mod_pow2n (m, T3, T2, Tx, 2); /* [ 7] T3 <- c^(2^32 - 4) */
ecc_mod_inplc_mul(m, T1, T3, Tx); /* [ 8] T1 <- c^(2^32 - 1) */
ecc_mod_pow2n (m, T3, T3, Tx, 28); /* [ 9] T3 <- c^(2^60 - 2^30) */
ecc_mod_inplc_mul(m, T2, T3, Tx); /* T2 <- c^(2^60 - 1) */
ecc_mod_pow2n_mul(m, T3, T2, T2, Tx, 60); /* [10] T3 <- c^(2^120 - 1) */
ecc_mod_pow2n_mul(m, Tr, T3, T3, Tx, 120); /* [11] r <- c^(2^240 - 1) */
ecc_mod_pow2n_mul(m, T3, Tr, T4, Tx, 15); /* [12] r <- c^(2^255 - 1) */
ecc_mod_pow2n_mul(m, Tr, T3, T1, Tx, 33); /* [13] r <- c^(2^288 - 2^32 - 1) */
ecc_mod_pow2n_mul(m, T3, Tr, cp, T1, 64); /* [14] r <- c^(2^352 - 2^96 - 2^64 + 1) */
ecc_mod_pow2n (m, rp, T3, T1, 30); /* [15] r <- c^(2^382 - 2^126 - 2^94 + 2^30) */
#undef T1
#undef T2
#undef T3
#undef T4
#undef Tr
#undef Tx
}
const struct ecc_curve _nettle_secp_384r1 =
{
{
......@@ -155,7 +206,7 @@ const struct ecc_curve _nettle_secp_384r1 =
ECC_BMODP_SIZE,
ECC_REDC_SIZE,
ECC_MOD_INV_ITCH (ECC_LIMB_SIZE),
0,
10 * ECC_LIMB_SIZE,
ecc_p,
ecc_Bmodp,
......@@ -167,6 +218,7 @@ const struct ecc_curve _nettle_secp_384r1 =
ecc_384_modp,
ecc_mod_inv,
NULL,
ecc_384_sqrt,
},
{
384,
......@@ -186,6 +238,7 @@ const struct ecc_curve _nettle_secp_384r1 =
ecc_mod,
ecc_mod_inv,
NULL,
NULL,
},
USE_REDC,
......
......@@ -75,6 +75,22 @@ ecc_521_modp (const struct ecc_modulo *m UNUSED, mp_limb_t *rp)
}
#endif
static void
ecc_521_sqrt (const struct ecc_modulo *m,
mp_limb_t *rp,
const mp_limb_t *cp,
mp_limb_t *scratch)
{
/* This computes the square root modulo p256 using the identity:
sqrt(c) = c^(2^519) (mod P-521)
*/
mpn_copyi(scratch, cp, m->size);
ecc_mod_pow2n(m, rp, scratch, scratch+m->size, 519);
}
const struct ecc_curve _nettle_secp_521r1 =
{
{
......@@ -83,7 +99,7 @@ const struct ecc_curve _nettle_secp_521r1 =
ECC_BMODP_SIZE,
ECC_REDC_SIZE,
ECC_MOD_INV_ITCH (ECC_LIMB_SIZE),
0,
3 * ECC_LIMB_SIZE,
ecc_p,
ecc_Bmodp,
......@@ -95,6 +111,7 @@ const struct ecc_curve _nettle_secp_521r1 =
ecc_521_modp,
ecc_mod_inv,
NULL,
ecc_521_sqrt,
},
{
521,
......@@ -114,6 +131,7 @@ const struct ecc_curve _nettle_secp_521r1 =
ecc_mod,
ecc_mod_inv,
NULL,
NULL,
},
USE_REDC,
......
......@@ -49,6 +49,9 @@
#define ecc_mod_submul_1 _nettle_ecc_mod_submul_1
#define ecc_mod_mul _nettle_ecc_mod_mul
#define ecc_mod_sqr _nettle_ecc_mod_sqr
#define ecc_mod_pow2n_mul _nettle_ecc_mod_pow2n_mul
#define ecc_mod_pow2n _nettle_ecc_mod_pow2n
#define ecc_mod_inplc_mul _nettle_ecc_mod_inplc_mul
#define ecc_mod_random _nettle_ecc_mod_random
#define ecc_mod _nettle_ecc_mod
#define ecc_mod_inv _nettle_ecc_mod_inv
......@@ -56,6 +59,7 @@
#define ecc_a_to_j _nettle_ecc_a_to_j
#define ecc_j_to_a _nettle_ecc_j_to_a
#define ecc_eh_to_a _nettle_ecc_eh_to_a
#define ecc_point_recover_y _nettle_ecc_point_recover_y
#define ecc_dup_jj _nettle_ecc_dup_jj
#define ecc_add_jja _nettle_ecc_add_jja
#define ecc_add_jjj _nettle_ecc_add_jjj
......@@ -97,6 +101,7 @@ extern const struct ecc_curve _nettle_curve25519;
#define ECC_MUL_A_EH_WBITS 4
struct ecc_modulo;
struct ecc_point;
/* Reduces from 2*ecc->size to ecc->size. */
/* Required to return a result < 2q. This property is inherited by
......@@ -113,6 +118,13 @@ typedef int ecc_mod_sqrt_func (const struct ecc_modulo *m,
const mp_limb_t *up, const mp_limb_t *vp,
mp_limb_t *scratch);
/* Computes the square root of u (mod p).
2*size space must be available at rp. up and rp may overlap, but must not overlap with scratch. */
typedef void ecc_mod_sqrt_func2 (const struct ecc_modulo *m,
mp_limb_t *rp,
const mp_limb_t *up,
mp_limb_t *scratch);
typedef void ecc_add_func (const struct ecc_curve *ecc,
mp_limb_t *r,
const mp_limb_t *p, const mp_limb_t *q,
......@@ -155,6 +167,7 @@ struct ecc_modulo
ecc_mod_func *reduce;
ecc_mod_inv_func *invert;
ecc_mod_sqrt_func *sqrt;
ecc_mod_sqrt_func2 *sqrt2;
};
/* Represents an elliptic curve of the form
......@@ -234,7 +247,7 @@ void
ecc_mod_submul_1 (const struct ecc_modulo *m, mp_limb_t *rp,
const mp_limb_t *ap, mp_limb_t b);
/* NOTE: mul and sqr needs 2*ecc->size limbs at rp */
/* NOTE: mul, sqr, pow2n[_mul] all need 2*ecc->size limbs at rp */
void
ecc_mod_mul (const struct ecc_modulo *m, mp_limb_t *rp,
const mp_limb_t *ap, const mp_limb_t *bp);
......@@ -243,6 +256,20 @@ void
ecc_mod_sqr (const struct ecc_modulo *m, mp_limb_t *rp,
const mp_limb_t *ap);
void
ecc_mod_pow2n_mul (const struct ecc_modulo *m,
mp_limb_t *dst, const mp_limb_t *src1, const mp_limb_t *src2,
mp_limb_t *scratch, unsigned scount);
void
ecc_mod_pow2n (const struct ecc_modulo *m,
mp_limb_t *dst, const mp_limb_t *src,
mp_limb_t *scratch, unsigned scount);
void
ecc_mod_inplc_mul(const struct ecc_modulo *m,
mp_limb_t *srcdst,
const mp_limb_t *src2,
mp_limb_t *scratch);
#define ecc_modp_add(ecc, r, a, b) \
ecc_mod_add (&(ecc)->p, (r), (a), (b))
#define ecc_modp_sub(ecc, r, a, b) \
......@@ -298,6 +325,12 @@ ecc_eh_to_a (const struct ecc_curve *ecc,
mp_limb_t *r, const mp_limb_t *p,
mp_limb_t *scratch);
/* Reconstructs the y-coordinate of a curve point in affine
coordinates, based on its x-value and ~y (which indicates the
parity/sign of the y-coordinate) */
int
ecc_point_recover_y(struct ecc_point *p, int y_sign);
/* Group operations */
/* Point doubling, with jacobian input and output. Corner cases:
......
......@@ -125,3 +125,60 @@ ecc_mod_sqr (const struct ecc_modulo *m, mp_limb_t *rp,
mpn_sqr (rp, ap, m->size);
m->reduce (m, rp);
}
/* Computes src1 ^ ( 2 ^ scount ) * src2 */
/* dst and scratch must both have 2*size space */
void
ecc_mod_pow2n_mul (const struct ecc_modulo *m,
mp_limb_t * dst,
const mp_limb_t * src1,
const mp_limb_t * src2,
mp_limb_t * scratch, unsigned scount)
{
ecc_mod_pow2n (m, scratch, src1, dst, scount);
mpn_mul (dst, scratch, m->size, src2, m->size);
m->reduce (m, dst);
}
/* computes x <- x * y; performs an extra copy since mpn_mul can't share src and dst buffers */
void
ecc_mod_inplc_mul (const struct ecc_modulo *m,
mp_limb_t * srcdst,
const mp_limb_t * src2, mp_limb_t * scratch)
{
mpn_mul (scratch, srcdst, m->size, src2, m->size);
m->reduce (m, scratch);
mpn_copyi (srcdst, scratch, m->size);
}
void
ecc_mod_pow2n (const struct ecc_modulo *m,
mp_limb_t * dst,
const mp_limb_t * src, mp_limb_t * scratch, unsigned scount)
{
mp_size_t size = m->size;
if (scount & 1)
{
mpn_sqr (dst, src, size);
m->reduce (m, dst);
scount -= 1;
}
else
{
mpn_sqr (scratch, src, size);
m->reduce (m, scratch);
mpn_sqr (dst, scratch, size);
m->reduce (m, dst);
scount -= 2;
}
while (scount)
{
mpn_sqr (scratch, dst, size);
m->reduce (m, scratch);
mpn_sqr (dst, scratch, size);
m->reduce (m, dst);
scount -= 2;
}
}
/* ecc-point-compact.c
Copyright (C) 2019 Wim Lewis
This file is part of GNU Nettle.
GNU Nettle is free software: you can redistribute it and/or
modify it under the terms of either:
* the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your
option) any later version.
or
* the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your
option) any later version.
or both in parallel, as here.
GNU Nettle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received copies of the GNU General Public License and
the GNU Lesser General Public License along with this program. If
not, see http://www.gnu.org/licenses/.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "ecc.h"
#include "ecc-internal.h"
int
ecc_point_set_compact (struct ecc_point *p, const mpz_t x, int y_sign)
{
const struct ecc_curve *curve = p->ecc;
mp_size_t size = curve->p.size;
if (mpz_sgn (x) < 0 || mpz_limbs_cmp (x, curve->p.m, size) >= 0)
return 0;
mpz_limbs_copy (p->p, x, size);
return ecc_point_recover_y (p, y_sign);
}
/* ecc-point-from-octets.c
Copyright (C) 2019 Wim Lewis
This file is part of GNU Nettle.
GNU Nettle is free software: you can redistribute it and/or
modify it under the terms of either:
* the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your
option) any later version.
or
* the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your
option) any later version.
or both in parallel, as here.
GNU Nettle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received copies of the GNU General Public License and
the GNU Lesser General Public License along with this program. If
not, see http://www.gnu.org/licenses/.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "ecc.h"
#include "ecc-internal.h"
static int
import_mp (const struct ecc_modulo *m, mp_limb_t * dst, size_t len,
const uint8_t * buf)
{
mp_size_t sz = mpn_set_str (dst, buf, len, 256);
mp_size_t msize = m->size;
if (sz < msize)
{
mpn_zero (dst + sz, msize - sz);
}
if (mpn_cmp (dst, m->m, msize) >= 0)
return 0;
else
return 1;
}
int
ecc_point_set_from_octets (struct ecc_point *p, size_t len,
const uint8_t * buf)
{
const struct ecc_curve *curve = p->ecc;
size_t byte_size = (7 + curve->p.bit_size) / 8;
int res;
if (len < 1 + byte_size)
{
/* This might be the point at infinity (which is represented as
just the octet 0x00), but we can't represent that in affine
coordinates */
return 0;
}
if (buf[0] == 0x02 || buf[0] == 0x03)
{
/* Compressed point */
if (len != 1 + byte_size)
return 0;
if (!import_mp (&(curve->p), p->p, len, buf))
return 0;
return ecc_point_recover_y (p, (buf[0] == 0x02 ? 0 : 1));
}
if (buf[0] == 0x04 || buf[0] == 0x06 || buf[0] == 0x07)
{
/* Uncompressed point, or hybrid point */
if (len != 1 + 2 * byte_size)
return 0;
mpz_t x, y;
nettle_mpz_init_set_str_256_u (x, byte_size, buf + 1);
nettle_mpz_init_set_str_256_u (y, byte_size, buf + 1 + byte_size);
res = ecc_point_set (p, x, y);
mpz_clear (x);
mpz_clear (y);
/* If this was a "hybrid" point, check that the y-sign flag was
consistent */
if (buf[0] == ((p->p[curve->p.size] & 1) ? 0x06 : 0x07))
return 0;
return res;
}
/* Unrecognized point format */
return 0;
}
/* ecc-point-recover.c
Copyright (C) 2019 Wim Lewis
This file is part of GNU Nettle.
GNU Nettle is free software: you can redistribute it and/or
modify it under the terms of either:
* the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your
option) any later version.
or
* the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your
option) any later version.
or both in parallel, as here.
GNU Nettle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received copies of the GNU General Public License and
the GNU Lesser General Public License along with this program. If
not, see http://www.gnu.org/licenses/.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <assert.h>
#include "ecc.h"
#include "ecc-internal.h"
#include "gmp-glue.h"
#define MAX(a, b) ((a) > (b) ? (a) : (b))
static int
ecc_recover_y_weierstrass_itch (const struct ecc_curve *c)
{
const struct ecc_modulo *m = &(c->p);
mp_size_t size = m->size;
return 3 * (m->size) + MAX (2 * size, m->sqrt_itch);
}
/* Test whether a and b are congruent.
"a" and "b" may be in the range [0, 2p) (that is, almost modulo-reduced,
but may contain one multiple of p).
The "b" input is clobbered.
*/
static int
congruent (const struct ecc_modulo *p, const mp_limb_t * a, mp_limb_t * b)
{
mp_size_t size = p->size;
int cy;
cy = mpn_sub_n (b, b, a, size);
if (cy == 0)
{
/* b was larger than or equal to a; if they were congruent, b now contains either 0 or p. */
return (mpn_zero_p (b, size) || (mpn_cmp (b, p->m, size) == 0));
}
else
{
/* b was smaller than a; if they were congruent, b now contains -p. */
cy = mpn_add_n (b, b, p->m, size);
if (!cy)
return 0;
if (mpn_zero_p (b, size))
return 1;
return 0;
}
}
static int
ecc_recover_y_weierstrass (const struct ecc_curve *c,
mp_limb_t * x_y, int y_sign, mp_limb_t * scratch)
{
const struct ecc_modulo *m = &(c->p);
mp_size_t size = m->size;
mp_limb_t *rp = x_y + size; /* result buffer: second half of X || Y */
mp_limb_t cy;
/* Compute y^2 = x^3 - 3*x + b (mod p) */
mpn_sqr (scratch, x_y, size);
m->mod (m, scratch);
if (mpn_sub_1 (scratch, scratch, size, (mp_limb_t) 3))
{
mpn_add (scratch, scratch, size, m->m, size);
}