### Implementations of sqrt in P-192 and P-224.

`Documentation, formatting, additional test cases, general cleanup.`
parent 05624cde
 ... ... @@ -180,7 +180,7 @@ hogweed_SOURCES = sexp.c sexp-format.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-point-from-octets.c ecc-point-compact.c \ ecc-point-recover.c \ ecc-point-recover.c tonelli-shanks.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 \ ... ...
 ... ... @@ -110,6 +110,42 @@ ecc_192_modp (const struct ecc_modulo *m UNUSED, mp_limb_t *rp) #define ecc_192_modp ecc_mod #endif static void ecc_192_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 p192 using the identity: sqrt(c) = c^(2^190 - 2^62) (mod P-192) which can be seen as a special case of Tonelli-Shanks with e=1. */ /* 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, TA, cp, cp, TB, 1); /*  TA <-- c^3 */ ecc_mod_pow2n_mul(m, TB, TA, TA, TC, 2); /*  TB <-- c^(2^4 - 1) */ ecc_mod_pow2n_mul(m, TA, TB, TB, TC, 4); /*  TA <-- c^(2^8 - 1) */ ecc_mod_pow2n_mul(m, TB, TA, TA, TC, 8); /*  TB <-- c^(2^16 - 1) */ ecc_mod_pow2n_mul(m, TA, TB, TB, TC, 16); /*  TA <-- c^(2^32 - 1) */ ecc_mod_pow2n_mul(m, TB, TA, TA, TC, 32); /*  TB <-- c^(2^64 - 1) */ ecc_mod_pow2n_mul(m, TC, TB, TB, TA, 64); /*  TC <-- c^(2^128 - 1) */ ecc_mod_pow2n (m, rp, TC, TA, 62); /*  r <-- c^(2^190 - 2^62) */ #undef TA #undef TB #undef TC } const struct ecc_curve _nettle_secp_192r1 = { { ... ... @@ -118,7 +154,7 @@ const struct ecc_curve _nettle_secp_192r1 = ECC_BMODP_SIZE, ECC_REDC_SIZE, ECC_MOD_INV_ITCH (ECC_LIMB_SIZE), 0, 6 * ECC_LIMB_SIZE, ecc_p, ecc_Bmodp, ... ... @@ -130,7 +166,7 @@ const struct ecc_curve _nettle_secp_192r1 = ecc_192_modp, ecc_mod_inv, NULL, NULL, ecc_192_sqrt, }, { 192, ... ...
 ... ... @@ -62,6 +62,75 @@ ecc_224_modp (const struct ecc_modulo *m, mp_limb_t *rp); # error Configuration error #endif static void ecc_224_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; unsigned int i; #define S1 (scratch) #define S1a (scratch + size) #define S2 (scratch + 2*size) #define S3 (scratch + 4*size) /* Setup for the Tonelli-Shanks algorithm */ /* scratch is assumed to have space for XXX */ /* The algorithm starts by decomposing p (the modulus) into e and s s.t. (p-1) = s*2^e */ /* These are precomputed for us as e = ECC_SQRT_E = 96, and s = 2^128 - 1 */ /* We also have a precomputed ecc_sqrt_z = z^s where z is an arbitrary quadratic nonresidue in p */ /* compute S1 = c^(2^64 - 1), S1a = c^(2^32 - 1) */ const mp_limb_t *f = cp; for (i = 0; i < 6; i++) { if (f == S1) { mpn_copyi (S3, S1, size); f = S3; } ecc_mod_pow2n_mul (m, S1, f, f, S2, 1 << i); f = S1; } /* compute S2 = c^(2^127 - 1) */ mpn_copyi (S1a, S3, size); ecc_mod_pow2n_mul (m, S2, S1, S1a, S3, 32); /* S2 = c^(2^96 - 1) */ for (i = 0; i < 31; i++) { ecc_mod_sqr (m, S3, S2); ecc_mod_mul (m, S2, S3, cp); } /* Finish up with: R <-- c^( (s+1) / 2 ) = c^(2^127) c <-- z^s (precomputed) t <-- c^s = c^(2^128 - 1) */ ecc_mod_mul (m, S1, S2, cp); ecc_mod_sqr (m, S3, S2); ecc_mod_mul (m, S1a, S3, cp); mpn_copyi (rp, S1, size); mpn_copyi (S1, ecc_sqrt_z, size); /* We are now set up for the Tonelli-Shanks inner loop: R is in *rp c is at S1 t is at S1 + size */ if (!ecc_tonelli_shanks (m, rp, ECC_SQRT_E, ecc_unit, S1)) return; /* Our caller will notice that we didn't find an actual sqrt */ #undef S1 #undef S2 #undef S3 } const struct ecc_curve _nettle_secp_224r1 = { { ... ... @@ -70,7 +139,7 @@ const struct ecc_curve _nettle_secp_224r1 = ECC_BMODP_SIZE, -ECC_REDC_SIZE, ECC_MOD_INV_ITCH (ECC_LIMB_SIZE), 0, 6 * ECC_LIMB_SIZE, ecc_p, ecc_Bmodp, ... ... @@ -82,7 +151,7 @@ const struct ecc_curve _nettle_secp_224r1 = USE_REDC ? ecc_224_redc : ecc_224_modp, ecc_mod_inv, NULL, NULL, ecc_224_sqrt, }, { 224, ... ...
 ... ... @@ -250,6 +250,8 @@ ecc_256_sqrt (const struct ecc_modulo *m, /* This computes the square root modulo p256 using the identity: sqrt(c) = c^(2^254 − 2^222 + 2^190 + 2^94) (mod P-256) which can be seen as a special case of Tonelli-Shanks with e=1. */ /* We use our scratch space for three temporaries (TA, TB, TC) all of ... ...
 ... ... @@ -159,7 +159,11 @@ ecc_384_sqrt (const struct ecc_modulo *m, 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. which can be seen as a special case of Tonelli-Shanks with e=1. The specific sqr/mul schedule 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 ... ...
 ... ... @@ -84,6 +84,8 @@ ecc_521_sqrt (const struct ecc_modulo *m, /* This computes the square root modulo p256 using the identity: sqrt(c) = c^(2^519) (mod P-521) which can be seen as a special case of Tonelli-Shanks with e=1. */ mpn_copyi(scratch, cp, m->size); ... ...
 ... ... @@ -52,6 +52,7 @@ #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_tonelli_shanks _nettle_ecc_tonelli_shanks #define ecc_mod_random _nettle_ecc_mod_random #define ecc_mod _nettle_ecc_mod #define ecc_mod_inv _nettle_ecc_mod_inv ... ... @@ -270,6 +271,13 @@ ecc_mod_inplc_mul(const struct ecc_modulo *m, const mp_limb_t *src2, mp_limb_t *scratch); int ecc_tonelli_shanks(const struct ecc_modulo *m, mp_limb_t *rp, unsigned int M, const mp_limb_t *unit, 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) \ ... ...
 ... ... @@ -158,7 +158,12 @@ ecc_mod_pow2n (const struct ecc_modulo *m, { mp_size_t size = m->size; if (scount & 1) if (scount == 0) { mpn_copyi(dst, src, size); return; } else if (scount & 1) { mpn_sqr (dst, src, size); m->reduce (m, dst); ... ...
 ... ... @@ -147,7 +147,8 @@ ecc_recover_y_weierstrass (const struct ecc_curve *c, if ((rp & 1) ? !y_sign : y_sign) { /* Zero is its own negation, which means we can't satisfy this request */ /* TODO: Check whether any of our curves intersect y=0? P-256 doesn't. */ /* (This shouldn't be reachable with any of our NIST curves, since none of them have a solution for Y=0) */ if (mpn_zero_p (rp, size)) return 0; ... ...
 ... ... @@ -1137,7 +1137,7 @@ output_curve (const struct ecc_curve *ecc, unsigned bits_per_limb) mpz_fdiv_q_2exp (s, s, e); /* Find a non-square g, g^{(p-1)/2} = -1, and z = g^{(p-1)/4 */ and z = g^s */ for (g = 2; ; g++) { mpz_set_ui (z, g); ... ... @@ -1155,6 +1155,7 @@ output_curve (const struct ecc_curve *ecc, unsigned bits_per_limb) } mpz_add_ui (t, t, 1); assert (mpz_cmp (t, ecc->p) == 0); printf ("/* g = %u */\n", g); output_bignum ("ecc_sqrt_z", z, limb_size, bits_per_limb); mpz_fdiv_q_2exp (t, s, 1); ... ...
 ... ... @@ -4811,6 +4811,32 @@ the function returns 1. Otherwise, it returns 0. Currently, the infinity point (or zero point, with additive notation) is not allowed. @end deftypefun @cindex Compact point representation @deftypefun int ecc_point_set_compact (struct ecc_point *@var{p}, const mpz_t @var{x}, int @var{y}) Recover a point's coordinates from a compact representation consisting of its @math{x} coordinate and a single bit of information about its @math{y} coordinate (see @cite{RFC 6090}). @var{y} should contain the least significant bit (0 or 1) of the actual coordinate. If the parameters correspond to a valid point on the curve other than the point at infinity, it copies the point to @var{p} and returns 1. Otherwise, it returns 0. Currently, this function is only supported for the @abbr{NIST} curves (@code{secp256r1}, @i{etc.}). For other curves, such as @code{Curve25519}, it always returns 0. This function is not side-channel silent. @end deftypefun @cindex @code{ECPoint} @deftypefun int ecc_point_set_from_octets (struct ecc_point *@var{p}, size_t @var{len}, const uint8_t *@var{buf}) Check that the given octet string, interpreted according to the format used by standards such as @cite{RFC 5480} and @cite{X9.62}, represents a point on the curve. If so, the coordinates are copied and converted to internal representation, by calling @code{ecc_point_set} or @code{ecc_point_set_compact} as appropriate. If successful, returns 1. Otherwise, it returns 0. @end deftypefun @deftypefun void ecc_point_get (const struct ecc_point *@var{p}, mpz_t @var{x}, mpz_t @var{y}) Extracts the coordinate of the point @var{p}. The output parameters @var{x} or @var{y} may be NULL if the caller doesn't want that ... ...
 ... ... @@ -241,6 +241,12 @@ ecc-redc-test\$(EXEEXT): ecc-redc-test.\$(OBJEXT) ecc-sqrt-test\$(EXEEXT): ecc-sqrt-test.\$(OBJEXT) \$(LINK) ecc-sqrt-test.\$(OBJEXT) \$(TEST_OBJS) -o ecc-sqrt-test\$(EXEEXT) ecc-point-compact-test\$(EXEEXT): ecc-point-compact-test.\$(OBJEXT) \$(LINK) ecc-point-compact-test.\$(OBJEXT) \$(TEST_OBJS) -o ecc-point-compact-test\$(EXEEXT) ecc-point-from-octets-test\$(EXEEXT): ecc-point-from-octets-test.\$(OBJEXT) \$(LINK) ecc-point-from-octets-test.\$(OBJEXT) \$(TEST_OBJS) -o ecc-point-from-octets-test\$(EXEEXT) ecc-dup-test\$(EXEEXT): ecc-dup-test.\$(OBJEXT) \$(LINK) ecc-dup-test.\$(OBJEXT) \$(TEST_OBJS) -o ecc-dup-test\$(EXEEXT) ... ...
 ... ... @@ -143,6 +143,80 @@ test_point_reconstruction (const struct ecc_curve *ecc, mpz_clear (y_in); } static void test_secp192r1_compact (void) { const struct ecc_curve *ecc = &_nettle_secp_192r1; /* The generator point */ test_point_reconstruction (ecc, "188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012", 1, "07192b95ffc8da78631011ed6b24cdd573f977a11e794811"); /* Misc points */ test_point_reconstruction (ecc, "1faee4205a4f669d2d0a8f25e3bcec9a62a6952965bf6d31", 0, "5ff2cdfa508a2581892367087c696f179e7a4d7e8260fb06"); test_point_reconstruction (ecc, "3afc9fe857c9cac94b333b0e0c2f5eaca8352670472e6c9a", 1, "fffffffffffffffeffffffffffffffffffffffffffffffff"); test_point_reconstruction (ecc, "6640909960af1640197342c0c58b40406b56a622c1258431", 0, "000000000000000000000001000000000000000000000000"); } static void test_secp224r1_compact (void) { const struct ecc_curve *ecc = &_nettle_secp_224r1; /* The generator point */ test_point_reconstruction (ecc, "b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", 0, "bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"); /* Special cases, eg to increase branch coverage in our implementation (thanks to SageMath / Pari for computations) */ test_point_reconstruction (ecc, /* Y = 1 */ "3b5889352ddf7468bf8c0729212aa1b2a3fcb1a844b8be91abb753d5", 1, "00000000000000000000000000000000000000000000000000000001"); test_point_reconstruction (ecc, /* Y = -1 */ "3b5889352ddf7468bf8c0729212aa1b2a3fcb1a844b8be91abb753d5", 0, "ffffffffffffffffffffffffffffffff000000000000000000000000"); test_point_reconstruction (ecc, /* Y^2 intermediate is 2^98-1 */ "760737a5a69ba5f84740bcafca96f6cc3049d98fa95a45c9d159126b", 1, "86d5a7d677bc09173bd94be84efb59936faca004c9bada763b39a531"); /* From Google Wycheproof */ test_point_reconstruction (ecc, /* testcase 21 - edge cases for ephemeral key */ "00000000000000ffffffffffffff0000000000000100000000000000", 0, "73ca5f8f104997a2399e0c7f25e72a75ec29fc4542533d3fea89a33a"); test_point_reconstruction (ecc, /* testcase 26 - edge cases for ephemeral key */ "0a15c112ff784b1445e889f955be7e3ffdf451a2c0e76ab5cb32cf41", 0, "3d4df973c563c6decdd435e4f864557e4c273096d9941ca4260a266e"); test_point_reconstruction (ecc, /* testcase 28 - edge cases for ephemeral key */ "661ac958c0febbc718ccf39cefc6b66c4231fbb9a76f35228a3bf5c3", 1, "103b8040e3cb41966fc64a68cacb0c14053f87d27e8ed7bf2d7fe51b"); test_point_reconstruction (ecc, /* testcase 65 - invalid public key */ "0ca753db5ddeca474241f8d2dafc0844343fd0e37eded2f0192d51b2", 0, NULL); } static void test_secp256r1_compact (void) { ... ... @@ -172,7 +246,7 @@ test_secp256r1_compact (void) "efdde3b32872a9effcf3b94cbf73aa7b39f9683ece9121b9852167f4e3da609b", 1, NULL); /* Special cses tailored to our implementation (thanks to Wolfram Alpha for computations) */ /* Special cases tailored to our implementation (thanks to Wolfram Alpha for computations) */ /* Incur an annoying underflow in computation of Y */ test_point_reconstruction (ecc, ... ... @@ -299,10 +373,58 @@ test_secp521r1_compact (void) } static void test_out_of_range (void) { mpz_t x; struct ecc_point pt; int res; mpz_init (x); mpz_set_si (x, -1); ecc_point_init (&pt, &_nettle_secp_521r1); res = ecc_point_set_compact (&pt, x, 0); if (res != 0) { fprintf (stderr, "Failed to reject X<0\n"); dump_result_point (&pt); abort (); } ecc_point_clear (&pt); mpz_set_si (x, 0); ecc_point_init (&pt, &_nettle_secp_256r1); res = ecc_point_set_compact (&pt, x, 0); if (res == 0) { fprintf (stderr, "Failed to accept X==0 on P-256\n"); abort (); } ecc_point_clear (&pt); mpz_ui_pow_ui (x, 2, 521); mpz_sub_ui (x, x, 1); ecc_point_init (&pt, &_nettle_secp_521r1); res = ecc_point_set_compact (&pt, x, 0); if (res != 0) { fprintf (stderr, "Failed to reject X==p\n"); dump_result_point (&pt); abort (); } ecc_point_clear (&pt); mpz_clear (x); } void test_main (void) { test_secp192r1_compact (); test_secp224r1_compact (); test_secp256r1_compact (); test_secp384r1_compact (); test_secp521r1_compact (); test_out_of_range (); }
 ... ... @@ -122,10 +122,15 @@ test_main (void) which isn't a valid public key. */ test_point_from_octets (&_nettle_secp_256r1, "00", NULL, NULL); /* Strings with invalid lengths */ test_point_from_octets (&_nettle_secp_256r1, "02", NULL, NULL); test_point_from_octets (&_nettle_secp_256r1, "04", NULL, NULL); test_point_from_octets (&_nettle_secp_256r1, "06", NULL, NULL); test_point_from_octets (&_nettle_secp_224r1, "01AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", NULL, NULL); /* A valid point */ test_point_from_octets (&_nettle_secp_256r1, "04" ... ... @@ -145,6 +150,10 @@ test_main (void) "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff" "0000000000000000000000000000000000000000000000000000000000000000", NULL, NULL); test_point_from_octets (&_nettle_secp_224r1, /* X > p */ "02" "ffffffffffffffffffffffffffffffffffffffffffffffffffff0000", NULL, NULL); /* Compressed points */ test_point_from_octets (&_nettle_secp_256r1, ... ... @@ -184,6 +193,10 @@ test_main (void) "58fd4168a87795603e2b04390285bdca6e57de6027fe211dd9d25e2212d29e62" "080d36bd224d7405509295eed02a17150e03b314f96da37445b0d1d29377d12c", NULL, NULL); test_point_from_octets (&_nettle_secp_256r1, "06" "58fd4168a87795603e2b04390285bdca6e57de6027fe211dd9d25e2212d29e62", NULL, NULL); test_point_from_octets (&_nettle_secp_256r1, "07" "e9484e58f3331b66ffed6d90cb1c78065fa28cfba5c7dd4352013d3252ee4277" ... ...
tonelli-shanks.c 0 → 100644