diff --git a/ChangeLog b/ChangeLog index aab10bb1aa776f3fb36f45b8ba650a296db78e15..3fde054b6d475f23551bfe31592475f4e689aa4c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,284 @@ +2014-08-27 Niels Möller <nisse@lysator.liu.se> + + Merged camellia-reorg changes (starting at 2014-07-04). + * Makefile.in (clean-here): Added ecc-25519.h. + +2014-08-26 Niels Möller <nisse@lysator.liu.se> + + * examples/ecc-benchmark.c (bench_mul_g, bench_mul_a): Use struct + ecc_curve function pointers. + (bench_mul_g_eh, bench_mul_a_eh): Deleted. + (bench_curve): Make modq benchmark unconditional. Use bench_mul_g + and bench_mul_a also for curve25519. + + * testsuite/ecc-mod-test.c (test_curve): Make modq test + unconditional, partially reverting 2014-07-04 change. + + * ecc-25519.c (ecc_25519_modq): New function. + + * eccdata.c (output_curve): Precomputation for curve25519 mod q. + + * mini-gmp.c (mpz_abs_sub_bit): Do full normalization, needed in + case the most significant bit is cleared. + +2014-08-25 Niels Möller <nisse@lysator.liu.se> + + * testsuite/ecdh-test.c (set_point): Check return value of + ecc_point_set. + (test_main): Enable curve25519 test. + + * ecc-point-mul-g.c (ecc_point_mul_g): Use ecc->mul_g and + ecc->h_to_a function pointers. + * ecc-point-mul.c (ecc_point_mul): Use the ecc->mul and + ecc->h_to_a function pointers. + + * ecc-internal.h (ecc_mul_g_func, ecc_mul_func, ecc_h_to_a_func): + New typedefs. + (struct ecc_curve): New function pointers mul, mul_g, h_to_a, and + constans for their scratch requirements. Updated all instances. + + * ecc-point.c (ecc_point_set): Handle curve25519 as a special + case, when checking if the point is on the curve. + +2014-08-24 Niels Möller <nisse@lysator.liu.se> + + * testsuite/ecdh-test.c: Test ecc_point_mul and ecc_point_mul_g, + using test data generated by ecc-ref.gp. Tests for all curves + except curve25519, which doesn't yet work with the general + ecc_point interface. + + * testsuite/Makefile.in (TS_HOGWEED_SOURCES): Added ecdh-test.c. + + * misc/ecc-ref.gp: Script to generate ECDH test data. + +2014-08-23 Niels Möller <nisse@lysator.liu.se> + + * ecc-a-to-j.c (ecc_a_to_j): Deleted INITIAL argument. + * ecc.h (ecc_a_to_j): Updated prototype. + * ecc-mul-a.c (ecc_mul_a, table_init): Updated calls to ecc_a_to_j. + + * ecc-mul-a.c (ecc_mul_a): Deleted INITIAL argument, all callers, + except the tests, pass 1. Updated all callers. + (table_init): Likewise deleted INITIAL. + * ecc.h (ecc_mul_a): Updated prototype. + * testsuite/ecc-mul-a-test.c (test_main): Deleted tests for + ecc_mul_a with INITIAL == 0. + + * ecc-internal.h (struct ecc_curve): Reordered struct, moved + function pointers before pointers to bignum constants. + + * sec-modinv.c (sec_modinv): Document that for a == 0 (mod m), we + should produce the "inverse" 0. + + * testsuite/ecc-modinv-test.c (test_main): Check that ecc_modp_inv + produces 0 if a == 0 or a == p. + +2014-08-22 Niels Möller <nisse@lysator.liu.se> + + * x86_64/ecc-25519-modp.asm: New file. Assembly implementation, + initial version yields 30% speedup of ecc_25519_modp. Early + folding eliminates one pass of carry propagation, and yields + almost 20% additional speedup. + + * ecc-25519.c [HAVE_NATIVE_ecc_25519_modp]: Use assembly version + if available. + + * configure.ac (asm_hogweed_optional_list): Added ecc-25519-modp.asm. + Also add HAVE_NATIVE_ecc_25519_modp to config.h.in. + +2014-08-19 Niels Möller <nisse@lysator.liu.se> + + * examples/ecc-benchmark.c (bench_curve): Support benchmarking of + curve25519, for now handled as a special case. + (curves): Added nettle_curve25519. + (bench_dup_eh, bench_add_eh, bench_add_ehh, bench_mul_g_eh): New + functions. + +2014-08-18 Niels Möller <nisse@lysator.liu.se> + + * testsuite/curve25519-dh-test.c (test_a): Use curve25519_mul. + (test_main): Use little-endian inputs for test_a. + (curve25519_sqrt, curve_25519): Deleted static helper functions, + no longer needed. + + * curve25519-mul.c (curve25519_mul): New file and function. + * curve25519.h (curve25519_mul): Declare it. + * Makefile.in (hogweed_SOURCES): Added curve25519-mul.c. + + * curve25519-mul-g.c (curve25519_mul_g): Renamed file and + function, updated callers. + * curve25519-base.c (curve25519_base): ... old names. + * Makefile.in (hogweed_SOURCES): Updated for rename. + + * eccdata.c (output_curve): Compute constants needed for + Shanks-Tonelli. + * ecc-25519.c (ecc_modp_powm_2kp1, ecc_25519_sqrt): New functions. + * ecc-internal.h (ecc_25519_sqrt): Declare it. + +2014-08-06 Niels Möller <nisse@lysator.liu.se> + + * testsuite/curve25519-dh-test.c (test_g): Use curve25519_base. + (test_main): Use little-endian inputs for test_g. + + * curve25519-base.c (curve25519_base): New file, new function. + Analogous to NaCl's crypto_scalarmult_base. + * curve25519.h: New file. + * Makefile.in (hogweed_SOURCES): Added curve25519-base.c. + (HEADERS): Added curve25519.h. + + * gmp-glue.c (mpn_set_base256_le, mpn_get_base256_le): New functions. + * gmp-glue.h: Declare them. + +2014-08-02 Niels Möller <nisse@lysator.liu.se> + + * testsuite/curve25519-dh-test.c (curve25519_sqrt): Fixed memory + leak, a mpz_clear call was missing. + + * ecc-internal.h (ECC_MUL_A_EH_WBITS): Set to 4, to enable + window-based scalar multiplication. + + * ecc-mul-a-eh.c (table_init) [ECC_MUL_A_EH_WBITS > 0]: Fixed + initialization of TABLE(1). + +2014-07-29 Niels Möller <nisse@lysator.liu.se> + + * ecc-internal.h (ECC_MUL_A_EH_WBITS): New constant. + (ECC_A_TO_EH_ITCH, ECC_MUL_A_EH_ITCH): New macros. + * ecc-a-to-eh.c (ecc_a_to_eh, ecc_a_to_eh_itch): New file, new + functions. + * ecc-mul-a-eh.c: New file. + (ecc_mul_a_eh): New function. The case [ECC_MUL_A_EH_WBITS > 0] + not yet working). + (ecc_mul_a_eh_itch): New function. + * ecc.h: Declare new functions. + * Makefile.in (hogweed_SOURCES): Added ecc-a-to-eh.c and + ecc-mul-a-eh.c. + + * testsuite/curve25519-dh-test.c (curve25519_sqrt): New function. + (curve_25519): Use ecc_mul_a_eh. + (test_a): New function. + (test_main): Test construction of shared secret, using scalar + multiplication with points other than the fix generator. + +2014-07-26 Niels Möller <nisse@lysator.liu.se> + + * ecc-add-ehh.c (ecc_add_ehh): Reduce scratch need. + * ecc-internal.h (ECC_ADD_EHH_ITCH): Reduced to 7*size. + +2014-07-23 Niels Möller <nisse@lysator.liu.se> + + * testsuite/curve25519-dh-test.c: New test case, based on + draft-josefsson-tls-curve25519-05 test vectors. + * testsuite/Makefile.in (TS_HOGWEED_SOURCES): Added curve25519-dh-test.c. + +2014-07-18 Niels Möller <nisse@lysator.liu.se> + + * ecc-mul-g-eh.c (ecc_mul_g_eh, ecc_mul_g_eh_itch): New file and + functions. Untested. + * ecc.h (ecc_mul_g_eh_itch): Declare new functions. + * ecc-internal.h (ECC_MUL_G_EH_ITCH): New macro. + * Makefile.in (hogweed_SOURCES): Added ecc-mul-g-eh.c. + +2014-07-17 Niels Möller <nisse@lysator.liu.se> + + * ecc-add-eh.c (ecc_add_eh): Reduce scratch need. + * ecc-internal.h (ECC_ADD_EH_ITCH): Reduced to 6*size. + + * testsuite/curve25519-dup-test.c (test_main): Free allocated + storage. + +2014-07-15 Niels Möller <nisse@lysator.liu.se> + + * ecc-add-eh.c (ecc_add_eh, ecc_add_eh_itch): New file, new + functions. + * ecc.h: Declare new functions. + * ecc-internal.h (ECC_ADD_EH_ITCH): New macro. + * Makefile.in (hogweed_SOURCES): Added ecc-add-eh.c. + * testsuite/curve25519-add-test.c (test_main): Test ecc_add_eh. + Additional test for g2+g2. Free allocated storage. + +2014-07-14 Niels Möller <nisse@lysator.liu.se> + + * testsuite/curve25519-add-test.c: New test case. + * testsuite/Makefile.in (TS_HOGWEED_SOURCES): Added + curve25519-add-test.c. + + * ecc-add-ehh.c (ecc_add_ehh, ecc_add_ehh_itch): New file, new + functions. + * ecc.h (ecc_add_ehh, ecc_add_ehh_itch): Declare them. + * ecc-internal.h (ECC_ADD_EHH_ITCH): New macro. + * Makefile.in (hogweed_SOURCES): Added ecc-add-ehh.c. + + * ecc-25519.c (nettle_curve25519): Use ecc_d instead of ecc_b. + + * eccdata.c: For curve25519, output the Edwards curve constant, + ecc_d = (121665/121666) mod p. + + * testsuite/curve25519-dup-test.c (test_main): Add test for 4g. + Delete some left-over debug output. + +2014-07-11 Niels Möller <nisse@lysator.liu.se> + + * misc/ecc-formulas.tex: Some ECC notes. + + * testsuite/curve25519-dup-test.c: New testcase. + * testsuite/Makefile.in (TS_HOGWEED_SOURCES): Added + curve25519-dup-test.c. + + * testsuite/testutils.c (test_ecc_point): Made non-static. + * testsuite/testutils.h (struct ecc_ref_point): Moved here, from + testutils.h. + (test_ecc_point): Declare it. + + * ecc-dup-eh.c (ecc_dup_eh, ecc_dup_eh_itch): New file, new functions. + * ecc-eh-to-a.c (ecc_eh_to_a, ecc_eh_to_a_itch): New file, new + functions. + * ecc.h: Declare new functions. + * ecc-internal.h (ECC_EH_TO_A_ITCH, ECC_DUP_EH_ITCH): New macros. + * Makefile.in (hogweed_SOURCES): Added ecc-dup-eh.c and + ecc-eh-to-a.c. + + * ecc-internal.h (struct ecc_curve): New constant edwards_root. + * ecc-192.c (nettle_secp_192r1): Updated accordingly, additional + NULL pointer. + * ecc-224.c (nettle_secp_224r1): Likewise. + * ecc-256.c (nettle_secp_256r1): Likewise. + * ecc-384.c (nettle_secp_384r1): Likewise. + * ecc-521.c (nettle_secp_521r1): Likewise. + * ecc-25519.c (nettle_curve25519): Initialize new constant. + + * eccdata.c (ecc_curve_init): For curve 25519, use correct + constant for edwards coordinate transform, and output the constant + as ecc_edwards. + +2014-07-06 Niels Möller <nisse@lysator.liu.se> + + * eccdata.c: Use separate is_zero flag to represent the neutral + element. + (output_point, output_point_redc): Unified to a single function, + with a use_redc flag argument. Also support conversion to Edwards + form. + (ecc_curve_init_str): New argument for Edwards curve conversion + constant. + +2014-07-04 Niels Möller <nisse@lysator.liu.se> + + Started curve25519 branch. + * ecc-25519.c: New file. + (ecc_25519_modp): New function. + (nettle_curve25519): New curve. + + * ecc-curve.h (nettle_curve25519): Declare it. + + * Makefile.in (hogweed_SOURCES): Added ecc-25519.c. + (ecc-25519.h): New generated file. Add as explicit dependency for + ecc-25519.o. + + * testsuite/ecc-mod-test.c (test_curve): New function, extracted + from test_main. Tolerate NULL modq function pointer. + (test_main): Use test_curve, iterate over supported curves, and + also test curve_25519 for the new modp function. + 2014-08-23 Niels Möller <nisse@lysator.liu.se> * ecc-modp.c (ecc_modp_sub_1): Deleted unused function. diff --git a/Makefile.in b/Makefile.in index b4082110a9dcdd43f4cc7eb89a7dfbfbd19696c7..d637087262676440bb349de605234efec69e39c2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -164,18 +164,23 @@ hogweed_SOURCES = sexp.c sexp-format.c \ ecc-mod.c ecc-generic-modp.c ecc-generic-modq.c \ ecc-modp.c ecc-modq.c ecc-generic-redc.c \ ecc-192.c ecc-224.c ecc-256.c ecc-384.c ecc-521.c \ + ecc-25519.c \ ecc-size.c ecc-j-to-a.c ecc-a-to-j.c \ ecc-dup-jj.c ecc-add-jja.c ecc-add-jjj.c \ + ecc-a-to-eh.c ecc-eh-to-a.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-ecdsa-sign.c ecdsa-sign.c \ ecc-ecdsa-verify.c ecdsa-verify.c ecdsa-keygen.c \ + curve25519-mul-g.c curve25519-mul.c \ $(OPT_HOGWEED_SOURCES) HEADERS = aes.h arcfour.h arctwo.h asn1.h blowfish.h \ base16.h base64.h buffer.h camellia.h cast128.h \ cbc.h ccm.h chacha.h chacha-poly1305.h ctr.h \ - des.h des-compat.h dsa.h dsa-compat.h eax.h \ + curve25519.h des.h des-compat.h dsa.h dsa-compat.h eax.h \ ecc-curve.h ecc.h ecdsa.h \ gcm.h gosthash94.h hmac.h \ knuth-lfib.h \ @@ -347,6 +352,9 @@ ecc-384.h: eccdata.stamp ecc-521.h: eccdata.stamp ./eccdata$(EXEEXT_FOR_BUILD) 521 56 6 $(GMP_NUMB_BITS) > $@T && mv $@T $@ +ecc-25519.h: eccdata.stamp + ./eccdata$(EXEEXT_FOR_BUILD) 255 14 6 $(GMP_NUMB_BITS) > $@T && mv $@T $@ + eccdata.stamp: eccdata.c $(MAKE) eccdata$(EXEEXT_FOR_BUILD) echo stamp > eccdata.stamp @@ -356,12 +364,14 @@ ecc-224.$(OBJEXT): ecc-224.h ecc-256.$(OBJEXT): ecc-256.h ecc-384.$(OBJEXT): ecc-384.h ecc-521.$(OBJEXT): ecc-521.h +ecc-25519.$(OBJEXT): ecc-25519.h ecc-192.p$(OBJEXT): ecc-192.h ecc-224.p$(OBJEXT): ecc-224.h ecc-256.p$(OBJEXT): ecc-256.h ecc-384.p$(OBJEXT): ecc-384.h ecc-521.p$(OBJEXT): ecc-521.h +ecc-25519.p$(OBJEXT): ecc-25519.h .asm.s: $(srcdir)/asm.m4 machine.m4 config.m4 $(M4) $(srcdir)/asm.m4 machine.m4 config.m4 $< >$@T \ @@ -619,7 +629,7 @@ distcheck: dist clean-here: -rm -f $(TARGETS) $(IMPLICIT_TARGETS) *.$(OBJEXT) *.p$(OBJEXT) *.s \ - ecc-192.h ecc-224.h ecc-256.h ecc-384.h ecc-521.h \ + ecc-192.h ecc-224.h ecc-256.h ecc-384.h ecc-521.h ecc-25519.h \ eccdata$(EXEEXT_FOR_BUILD) eccdata.stamp -rm -rf .lib libnettle.stamp libhogweed.stamp diff --git a/configure.ac b/configure.ac index 6923d3a3514fba48e359d407f018db20f1f5e4b1..ddee35c775c2314ab28ec9084212d2d6a4bf7767 100644 --- a/configure.ac +++ b/configure.ac @@ -285,7 +285,7 @@ asm_nettle_optional_list="gcm-hash8.asm" asm_hogweed_optional_list="" if test "x$enable_public_key" = "xyes" ; then asm_hogweed_optional_list="ecc-192-modp.asm ecc-224-modp.asm \ - ecc-256-redc.asm ecc-384-modp.asm ecc-521-modp.asm" + ecc-25519-modp.asm ecc-256-redc.asm ecc-384-modp.asm ecc-521-modp.asm" fi OPT_ASM_NETTLE_SOURCES="" @@ -365,6 +365,7 @@ AH_VERBATIM([HAVE_NATIVE], #undef HAVE_NATIVE_ecc_192_redc #undef HAVE_NATIVE_ecc_224_modp #undef HAVE_NATIVE_ecc_224_redc +#undef HAVE_NATIVE_ecc_25519_modp #undef HAVE_NATIVE_ecc_256_modp #undef HAVE_NATIVE_ecc_256_redc #undef HAVE_NATIVE_ecc_384_modp diff --git a/curve25519-mul-g.c b/curve25519-mul-g.c new file mode 100644 index 0000000000000000000000000000000000000000..f98bee3d4198c755f33d12612ec109160b6b8558 --- /dev/null +++ b/curve25519-mul-g.c @@ -0,0 +1,71 @@ +/* curve25519-mul-g.c + + Copyright (C) 2014 Niels Möller + + 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 <string.h> + +#include "curve25519.h" + +#include "ecc.h" +#include "ecc-internal.h" + +/* Intended to be compatible with NaCl's crypto_scalarmult_base. */ +void +curve25519_mul_g (uint8_t *r, const uint8_t *n) +{ + uint8_t t[CURVE25519_SIZE]; + mp_limb_t *scratch; + mp_size_t ecc_size; + mp_size_t itch; + +#define p scratch +#define x (scratch + 3*ecc_size) +#define scratch_out (scratch + 4*ecc_size) + + memcpy (t, n, sizeof(t)); + t[0] &= ~7; + t[CURVE25519_SIZE-1] = (t[CURVE25519_SIZE-1] & 0x3f) | 0x40; + + ecc_size = nettle_curve25519.size; + itch = 4*ecc_size + ECC_MUL_G_EH_ITCH(ecc_size); + scratch = gmp_alloc_limbs (itch); + + mpn_set_base256_le (x, ecc_size, t, CURVE25519_SIZE); + + ecc_mul_g_eh (&nettle_curve25519, p, x, scratch_out); + ecc_eh_to_a (&nettle_curve25519, 2, x, p, scratch_out); + + mpn_get_base256_le (r, CURVE25519_SIZE, x, ecc_size); + gmp_free_limbs (scratch, itch); +} diff --git a/curve25519-mul.c b/curve25519-mul.c new file mode 100644 index 0000000000000000000000000000000000000000..ddc50eb5e5922e84639821bf9fbd34ab6f4652e5 --- /dev/null +++ b/curve25519-mul.c @@ -0,0 +1,90 @@ +/* curve25519-mul.c + + Copyright (C) 2014 Niels Möller + + 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 <string.h> + +#include "curve25519.h" + +#include "ecc.h" +#include "ecc-internal.h" + +/* Intended to be compatible with NaCl's crypto_scalarmult. NOTE: Not + side-channel silent, due to the sqrt. */ +int +curve25519_mul (uint8_t *q, const uint8_t *n, const uint8_t *p) +{ + uint8_t t[CURVE25519_SIZE]; + mp_size_t itch; + mp_limb_t *scratch; + const struct ecc_curve *ecc = &nettle_curve25519; + +#define x scratch +#define y (scratch + ecc->size) +#define s (scratch + 3*ecc->size) +#define scratch_out (scratch + 4*ecc->size) + + itch = 5*ecc->size + ECC_MUL_A_EH_ITCH (ecc->size); + scratch = gmp_alloc_limbs (itch); + + mpn_set_base256_le (x, ecc->size, p, CURVE25519_SIZE); + + /* First compute y coordinate, from + + y^2 = x^3 + b x^2 + x = (x^2 + bx + 1) x + */ + ecc_modp_sqr (&nettle_curve25519, y, x); + ecc_modp_addmul_1 (&nettle_curve25519, y, x, 0x76d06ULL); + ecc_modp_add (ecc, s, y, ecc->unit); + ecc_modp_mul (ecc, y, s, x); + + /* FIXME: Pass s as scratch space to ecc_25519_sqrt */ + if (!ecc_25519_sqrt (y, y)) + /* y-coordinate doesn't belong to base field F_p. FIXME: Implement + case of y in F_{p^2}? */ + return 0; + + memcpy (t, n, sizeof(t)); + t[0] &= ~7; + t[CURVE25519_SIZE-1] = (t[CURVE25519_SIZE-1] & 0x3f) | 0x40; + + mpn_set_base256_le (s, ecc->size, t, CURVE25519_SIZE); + + ecc_mul_a_eh (ecc, x, s, x, scratch_out); + ecc_eh_to_a (ecc, 2, s, x, scratch_out); + mpn_get_base256_le (q, CURVE25519_SIZE, s, ecc->size); + + gmp_free_limbs (scratch, itch); + return 1; +} diff --git a/curve25519.h b/curve25519.h new file mode 100644 index 0000000000000000000000000000000000000000..bcf579d7ca2e41be1d59379ed7b0792217b77855 --- /dev/null +++ b/curve25519.h @@ -0,0 +1,53 @@ +/* curve25519.h + + Copyright (C) 2014 Niels Möller + + 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/. +*/ + +#ifndef NETTLE_CURVE25519_H +#define NETTLE_CURVE25519_H + +#include "nettle-types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Name mangling */ +#define curve25519_mul_g nettle_curve25519_mul_g +#define curve25519_mul nettle_curve25519_mul + +#define CURVE25519_SIZE 32 + +void +curve25519_mul_g (uint8_t *q, const uint8_t *n); + +int +curve25519_mul (uint8_t *q, const uint8_t *n, const uint8_t *p); + +#endif /* NETTLE_CURVE25519_H */ diff --git a/ecc-192.c b/ecc-192.c index 2af501fa32503bc690d92c602dfbe41ad88d1196..29ff7f6a2ee00aff90ea2fae4905d052e3583790 100644 --- a/ecc-192.c +++ b/ecc-192.c @@ -39,6 +39,9 @@ #include <assert.h> +/* FIXME: Remove ecc.h include, once prototypes of more internal + functions are moved to ecc-internal.h */ +#include "ecc.h" #include "ecc-internal.h" #define USE_REDC 0 @@ -117,15 +120,26 @@ const struct ecc_curve nettle_secp_192r1 = ECC_REDC_SIZE, ECC_PIPPENGER_K, ECC_PIPPENGER_C, + + ECC_MUL_A_ITCH (ECC_LIMB_SIZE), + ECC_MUL_G_ITCH (ECC_LIMB_SIZE), + ECC_J_TO_A_ITCH (ECC_LIMB_SIZE), + + ecc_192_modp, + ecc_generic_redc, + ecc_192_modp, + ecc_generic_modq, + + ecc_mul_a, + ecc_mul_g, + ecc_j_to_a, + ecc_p, ecc_b, ecc_q, ecc_g, ecc_redc_g, - ecc_192_modp, - ecc_generic_redc, - ecc_192_modp, - ecc_generic_modq, + NULL, ecc_Bmodp, ecc_Bmodp_shifted, ecc_pp1h, diff --git a/ecc-224.c b/ecc-224.c index 6ed2365b1e75947065272775389d1b46c8c99599..8a99f0e38ad0ca5894d024e3e7c85e733c21948f 100644 --- a/ecc-224.c +++ b/ecc-224.c @@ -37,6 +37,7 @@ # include "config.h" #endif +#include "ecc.h" #include "ecc-internal.h" #if HAVE_NATIVE_ecc_224_modp @@ -63,15 +64,26 @@ const struct ecc_curve nettle_secp_224r1 = ECC_REDC_SIZE, ECC_PIPPENGER_K, ECC_PIPPENGER_C, + + ECC_MUL_A_ITCH (ECC_LIMB_SIZE), + ECC_MUL_G_ITCH (ECC_LIMB_SIZE), + ECC_J_TO_A_ITCH (ECC_LIMB_SIZE), + + ecc_224_modp, + ecc_generic_redc, + USE_REDC ? ecc_generic_redc : ecc_224_modp, + ecc_generic_modq, + + ecc_mul_a, + ecc_mul_g, + ecc_j_to_a, + ecc_p, ecc_b, ecc_q, ecc_g, ecc_redc_g, - ecc_224_modp, - ecc_generic_redc, - USE_REDC ? ecc_generic_redc : ecc_224_modp, - ecc_generic_modq, + NULL, ecc_Bmodp, ecc_Bmodp_shifted, ecc_pp1h, diff --git a/ecc-25519.c b/ecc-25519.c new file mode 100644 index 0000000000000000000000000000000000000000..3cbc60edee3024e94c5bed407c99edaab7118f49 --- /dev/null +++ b/ecc-25519.c @@ -0,0 +1,275 @@ +/* ecc-25519.c + + Arithmetic and tables for curve25519, + + Copyright (C) 2014 Niels Möller + + 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" + +#define USE_REDC 0 + +#include "ecc-25519.h" + +#if HAVE_NATIVE_ecc_25519_modp + +#define ecc_25519_modp nettle_ecc_25519_modp +void +ecc_25519_modp (const struct ecc_curve *ecc, mp_limb_t *rp); +#else + +#define PHIGH_BITS (GMP_NUMB_BITS * ECC_LIMB_SIZE - 255) + +#if PHIGH_BITS == 0 +#error Unsupported limb size */ +#endif + +static void +ecc_25519_modp(const struct ecc_curve *ecc UNUSED, mp_limb_t *rp) +{ + mp_limb_t hi, cy; + + cy = mpn_addmul_1 (rp, rp + ECC_LIMB_SIZE, ECC_LIMB_SIZE, + (mp_limb_t) 19 << PHIGH_BITS); + hi = rp[ECC_LIMB_SIZE-1]; + cy = (cy << PHIGH_BITS) + (hi >> (GMP_NUMB_BITS - PHIGH_BITS)); + rp[ECC_LIMB_SIZE-1] = (hi & (GMP_NUMB_MASK >> PHIGH_BITS)) + + sec_add_1 (rp, rp, ECC_LIMB_SIZE - 1, 19 * cy); +} +#endif /* HAVE_NATIVE_ecc_25519_modp */ + +#define QHIGH_BITS (GMP_NUMB_BITS * ECC_LIMB_SIZE - 252) + +#if QHIGH_BITS == 0 +#error Unsupported limb size */ +#endif + +static void +ecc_25519_modq (const struct ecc_curve *ecc, mp_limb_t *rp) +{ + mp_size_t n; + mp_limb_t cy; + + /* n is the offset where we add in the next term */ + for (n = ECC_LIMB_SIZE; n-- > 0;) + { + mp_limb_t cy; + + cy = mpn_submul_1 (rp + n, + ecc->Bmodq_shifted, ECC_LIMB_SIZE, + rp[n + ECC_LIMB_SIZE]); + /* Top limb of mBmodq_shifted is zero, so we get cy == 0 or 1 */ + assert (cy < 2); + cnd_add_n (cy, rp+n, ecc_q, ECC_LIMB_SIZE); + } + + cy = mpn_submul_1 (rp, ecc_q, ECC_LIMB_SIZE, + rp[ECC_LIMB_SIZE-1] >> (GMP_NUMB_BITS - QHIGH_BITS)); + assert (cy < 2); + cnd_add_n (cy, rp, ecc_q, ECC_LIMB_SIZE); +} + +/* Needs 2*ecc->size limbs at rp, and 2*ecc->size additional limbs of + scratch space. No overlap allowed. */ +static void +ecc_modp_powm_2kp1 (const struct ecc_curve *ecc, + mp_limb_t *rp, const mp_limb_t *xp, + unsigned k, mp_limb_t *tp) +{ + if (k & 1) + { + ecc_modp_sqr (ecc, tp, xp); + k--; + } + else + { + ecc_modp_sqr (ecc, rp, xp); + ecc_modp_sqr (ecc, tp, rp); + k -= 2; + } + while (k > 0) + { + ecc_modp_sqr (ecc, rp, tp); + ecc_modp_sqr (ecc, tp, rp); + k -= 2; + } + ecc_modp_mul (ecc, rp, tp, xp); +#undef t1 +#undef t2 +} + +/* Compute x such that x^2 = a (mod p). Returns one on success, zero + on failure. using the e == 2 special case of the Shanks-Tonelli + algorithm (see http://www.math.vt.edu/people/brown/doc/sqrts.pdf, + or Henri Cohen, Computational Algebraic Number Theory, 1.5.1. + + NOTE: Not side-channel silent. FIXME: Compute square root in the + extended field if a isn't a square (mod p)? FIXME: Accept scratch + space from caller (could allow scratch == rp). */ +#if ECC_SQRT_E != 2 +#error Broken curve25519 parameters +#endif +int +ecc_25519_sqrt(mp_limb_t *rp, const mp_limb_t *ap) +{ + mp_size_t itch; + mp_limb_t *scratch; + int res; + const struct ecc_curve *ecc = &nettle_curve25519; + + itch = 7*ECC_LIMB_SIZE; + scratch = gmp_alloc_limbs (itch); + +#define t0 scratch +#define a7 (scratch + 2*ECC_LIMB_SIZE) +#define t1 (scratch + 3*ECC_LIMB_SIZE) +#define t2 (scratch + 5*ECC_LIMB_SIZE) +#define scratch_out (scratch + 3*ECC_LIMB_SIZE) /* overlap t1, t2 */ + +#define xp (scratch + ECC_LIMB_SIZE) +#define bp (scratch + 2*ECC_LIMB_SIZE) + + /* a^{2^252 - 3} = a^{(p-5)/8}, using the addition chain + 2^252 - 3 + = 1 + (2^252-4) + = 1 + 4 (2^250-1) + = 1 + 4 (2^125+1)(2^125-1) + = 1 + 4 (2^125+1)(1+2(2^124-1)) + = 1 + 4 (2^125+1)(1+2(2^62+1)(2^62-1)) + = 1 + 4 (2^125+1)(1+2(2^62+1)(2^31+1)(2^31-1)) + = 1 + 4 (2^125+1)(1+2(2^62+1)(2^31+1)(7+8(2^28-1))) + = 1 + 4 (2^125+1)(1+2(2^62+1)(2^31+1)(7+8(2^14+1)(2^14-1))) + = 1 + 4 (2^125+1)(1+2(2^62+1)(2^31+1)(7+8(2^14+1)(2^7+1)(2^7-1))) + = 1 + 4 (2^125+1)(1+2(2^62+1)(2^31+1)(7+8(2^14+1)(2^7+1)(1+2(2^6-1)))) + = 1 + 4 (2^125+1)(1+2(2^62+1)(2^31+1)(7+8(2^14+1)(2^7+1)(1+2(2^3+1)*7))) + */ + + ecc_modp_powm_2kp1 (ecc, t1, ap, 1, t2); /* a^3 */ + ecc_modp_sqr (ecc, t0, t1); /* a^6 */ + ecc_modp_mul (ecc, a7, t0, ap); /* a^7 */ + ecc_modp_powm_2kp1 (ecc, t0, a7, 3, t1); /* a^63 = a^{2^6-1} */ + ecc_modp_sqr (ecc, t1, t0); /* a^{2^7-2} */ + ecc_modp_mul (ecc, t0, t1, ap); /* a^{2^7-1} */ + ecc_modp_powm_2kp1 (ecc, t1, t0, 7, t2); /* a^{2^14-1}*/ + ecc_modp_powm_2kp1 (ecc, t0, t1, 14, t2); /* a^{2^28-1} */ + ecc_modp_sqr (ecc, t1, t0); /* a^{2^29-2} */ + ecc_modp_sqr (ecc, t2, t1); /* a^{2^30-4} */ + ecc_modp_sqr (ecc, t1, t2); /* a^{2^31-8} */ + ecc_modp_mul (ecc, t0, t1, a7); /* a^{2^31-1} */ + ecc_modp_powm_2kp1 (ecc, t1, t0, 31, t2); /* a^{2^62-1} */ + ecc_modp_powm_2kp1 (ecc, t0, t1, 62, t2); /* a^{2^124-1}*/ + ecc_modp_sqr (ecc, t1, t0); /* a^{2^125-2} */ + ecc_modp_mul (ecc, t0, t1, ap); /* a^{2^125-1} */ + ecc_modp_powm_2kp1 (ecc, t1, t0, 125, t2); /* a^{2^250-1} */ + ecc_modp_sqr (ecc, t0, t1); /* a^{2^251-2} */ + ecc_modp_sqr (ecc, t1, t0); /* a^{2^252-4} */ + ecc_modp_mul (ecc, t0, t1, ap); /* a^{2^252-3} */ + + /* Compute candidate root x and fudgefactor b. */ + ecc_modp_mul (ecc, xp, t0, ap); /* a^{(p+3)/8 */ + ecc_modp_mul (ecc, bp, t0, xp); /* a^{(p-1)/4} */ + /* Check if b == 1 (mod p) */ + if (mpn_cmp (bp, ecc->p, ECC_LIMB_SIZE) >= 0) + mpn_sub_n (bp, bp, ecc->p, ECC_LIMB_SIZE); + if (mpn_cmp (bp, ecc->unit, ECC_LIMB_SIZE) == 0) + { + mpn_copyi (rp, xp, ECC_LIMB_SIZE); + res = 1; + } + else + { + mpn_add_1 (bp, bp, ECC_LIMB_SIZE, 1); + if (mpn_cmp (bp, ecc->p, ECC_LIMB_SIZE) == 0) + { + ecc_modp_mul (&nettle_curve25519, bp, xp, ecc_sqrt_z); + mpn_copyi (rp, bp, ECC_LIMB_SIZE); + res = 1; + } + else + res = 0; + } + gmp_free_limbs (scratch, itch); + return res; +#undef t0 +#undef t1 +#undef t2 +#undef a7 +#undef xp +#undef bp +#undef scratch_out +} + +const struct ecc_curve nettle_curve25519 = +{ + 255, + ECC_LIMB_SIZE, + ECC_BMODP_SIZE, + ECC_BMODQ_SIZE, + 0, /* No redc */ + 0, + ECC_PIPPENGER_K, + ECC_PIPPENGER_C, + + ECC_MUL_A_EH_ITCH (ECC_LIMB_SIZE), + ECC_MUL_G_EH_ITCH (ECC_LIMB_SIZE), + ECC_EH_TO_A_ITCH (ECC_LIMB_SIZE), + + ecc_25519_modp, + NULL, + ecc_25519_modp, + ecc_25519_modq, + + + ecc_mul_a_eh, + ecc_mul_g_eh, + ecc_eh_to_a, + + ecc_p, + ecc_d, /* Use the Edwards curve constant. */ + ecc_q, + ecc_g, + ecc_redc_g, + ecc_edwards, + ecc_Bmodp, + ecc_Bmodp_shifted, + ecc_pp1h, + ecc_redc_ppm1, + ecc_unit, + ecc_Bmodq, + ecc_mBmodq_shifted, /* Use q - 2^{252} instead. */ + ecc_qp1h, + ecc_table +}; diff --git a/ecc-256.c b/ecc-256.c index 2f2297e67c4d6d20c6958983d6e04e2d0c4e15f1..f888aafef92510ae555fad9e547ed5598ef4ec30 100644 --- a/ecc-256.c +++ b/ecc-256.c @@ -39,6 +39,7 @@ #include <assert.h> +#include "ecc.h" #include "ecc-internal.h" #if HAVE_NATIVE_ecc_256_redc @@ -228,15 +229,26 @@ const struct ecc_curve nettle_secp_256r1 = ECC_REDC_SIZE, ECC_PIPPENGER_K, ECC_PIPPENGER_C, + + ECC_MUL_A_ITCH (ECC_LIMB_SIZE), + ECC_MUL_G_ITCH (ECC_LIMB_SIZE), + ECC_J_TO_A_ITCH (ECC_LIMB_SIZE), + + ecc_256_modp, + ecc_256_redc, + USE_REDC ? ecc_256_redc : ecc_256_modp, + ecc_256_modq, + + ecc_mul_a, + ecc_mul_g, + ecc_j_to_a, + ecc_p, ecc_b, ecc_q, ecc_g, ecc_redc_g, - ecc_256_modp, - ecc_256_redc, - USE_REDC ? ecc_256_redc : ecc_256_modp, - ecc_256_modq, + NULL, ecc_Bmodp, ecc_Bmodp_shifted, ecc_pp1h, diff --git a/ecc-384.c b/ecc-384.c index 8bfcb2145e6d2ca55db79d407cf4669798e9cf59..c20d8ab425dce7073e314b912a81e0911568b029 100644 --- a/ecc-384.c +++ b/ecc-384.c @@ -39,6 +39,7 @@ #include <assert.h> +#include "ecc.h" #include "ecc-internal.h" #define USE_REDC 0 @@ -156,15 +157,26 @@ const struct ecc_curve nettle_secp_384r1 = ECC_REDC_SIZE, ECC_PIPPENGER_K, ECC_PIPPENGER_C, + + ECC_MUL_A_ITCH (ECC_LIMB_SIZE), + ECC_MUL_G_ITCH (ECC_LIMB_SIZE), + ECC_J_TO_A_ITCH (ECC_LIMB_SIZE), + + ecc_384_modp, + ECC_REDC_SIZE != 0 ? ecc_generic_redc : NULL, + ecc_384_modp, + ecc_generic_modq, + + ecc_mul_a, + ecc_mul_g, + ecc_j_to_a, + ecc_p, ecc_b, ecc_q, ecc_g, ecc_redc_g, - ecc_384_modp, - ECC_REDC_SIZE != 0 ? ecc_generic_redc : NULL, - ecc_384_modp, - ecc_generic_modq, + NULL, ecc_Bmodp, ecc_Bmodp_shifted, ecc_pp1h, diff --git a/ecc-521.c b/ecc-521.c index fc84dfe6501acec0c52f1d1e7252c0349a630bee..821c77c769681d7760cc0ea3bbfc9fe27187b7f1 100644 --- a/ecc-521.c +++ b/ecc-521.c @@ -37,6 +37,7 @@ # include "config.h" #endif +#include "ecc.h" #include "ecc-internal.h" #define USE_REDC 0 @@ -84,15 +85,26 @@ const struct ecc_curve nettle_secp_521r1 = ECC_REDC_SIZE, ECC_PIPPENGER_K, ECC_PIPPENGER_C, + + ECC_MUL_A_ITCH (ECC_LIMB_SIZE), + ECC_MUL_G_ITCH (ECC_LIMB_SIZE), + ECC_J_TO_A_ITCH (ECC_LIMB_SIZE), + + ecc_521_modp, + ecc_generic_redc, + ecc_521_modp, + ecc_generic_modq, + + ecc_mul_a, + ecc_mul_g, + ecc_j_to_a, + ecc_p, ecc_b, ecc_q, ecc_g, ecc_redc_g, - ecc_521_modp, - ecc_generic_redc, - ecc_521_modp, - ecc_generic_modq, + NULL, ecc_Bmodp, ecc_Bmodp_shifted, ecc_pp1h, diff --git a/ecc-a-to-eh.c b/ecc-a-to-eh.c new file mode 100644 index 0000000000000000000000000000000000000000..7f77394efa9d54618c24a3d96d1d6c8cea2094bd --- /dev/null +++ b/ecc-a-to-eh.c @@ -0,0 +1,77 @@ +/* ecc-a-to-eh.c + + Copyright (C) 2014 Niels Möller + + 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" + +mp_size_t +ecc_a_to_eh_itch (const struct ecc_curve *ecc) +{ + return ECC_A_TO_EH_ITCH (ecc->size); +} + +/* Convert from affine coordinates to homogeneous coordinates on the + corresponding Edwards curve. */ +void +ecc_a_to_eh (const struct ecc_curve *ecc, + mp_limb_t *r, const mp_limb_t *p, + mp_limb_t *scratch) +{ +#define xp p +#define yp (p + ecc->size) + +#define up r +#define vp (r + ecc->size) +#define wp (r + 2*ecc->size) + + /* u = t x / y + v = (x-1) / (x+1) + + or in homogeneous coordinates + + U = t x (x+1) + V = (x-1) y + W = (x+1) y + */ + + ecc_modp_mul (ecc, scratch, xp, yp); + ecc_modp_add (ecc, wp, scratch, yp); + ecc_modp_sub (ecc, vp, scratch, yp); + + ecc_modp_sqr (ecc, scratch, xp); + ecc_modp_add (ecc, up, scratch, xp); + ecc_modp_mul (ecc, scratch, up, ecc->edwards_root); + mpn_copyi (up, scratch, ecc->size); +} diff --git a/ecc-a-to-j.c b/ecc-a-to-j.c index 5f7cc6877c0905ab70c859ed609c4014cb1ae8d0..36e4d150383bb4be6b3ea6650f9be7ce83a71716 100644 --- a/ecc-a-to-j.c +++ b/ecc-a-to-j.c @@ -40,10 +40,9 @@ void ecc_a_to_j (const struct ecc_curve *ecc, - int initial, mp_limb_t *r, const mp_limb_t *p) { - if (ecc->use_redc && initial) + if (ecc->use_redc) { mpn_copyd (r + ecc->size, p, 2*ecc->size); diff --git a/ecc-add-eh.c b/ecc-add-eh.c new file mode 100644 index 0000000000000000000000000000000000000000..a3471b268378f8724d7136214cee78e127823bd9 --- /dev/null +++ b/ecc-add-eh.c @@ -0,0 +1,113 @@ +/* ecc-add-eh.c + + Copyright (C) 2014 Niels Möller + + 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" + +mp_size_t +ecc_add_eh_itch (const struct ecc_curve *ecc) +{ + return ECC_ADD_EH_ITCH (ecc->size); +} + +/* Add two points on an Edwards curve, with result and first point in + homogeneous coordinates. */ +void +ecc_add_eh (const struct ecc_curve *ecc, + mp_limb_t *r, const mp_limb_t *p, const mp_limb_t *q, + mp_limb_t *scratch) +{ +#define x1 p +#define y1 (p + ecc->size) +#define z1 (p + 2*ecc->size) + +#define x2 q +#define y2 (q + ecc->size) + +#define x3 r +#define y3 (r + ecc->size) +#define z3 (r + 2*ecc->size) + + /* Formulas (from djb, + http://www.hyperelliptic.org/EFD/g1p/auto-edwards-projective.html#doubling-dbl-2007-bl): + + Computation Operation Live variables + + C = x1*x2 mul C + D = y1*y2 mul C, D + T = (x1+y1)(x2+y2) - C - D C, D, T + E = b*C*D 2 mul C, E, T (Replace C <-- D - C) + B = z1^2 sqr B, C, E, T + F = B - E B, C, E, F, T + G = B + E C, F, G, T + x3 = z1*F*T 3 mul C, F, G, T + y3 = z1*G*(D-C) 2 mul F, G + z3 = F*G mul + */ +#define C (scratch) +#define D (scratch + 1*ecc->size) +#define T (scratch + 2*ecc->size) +#define E (scratch + 3*ecc->size) +#define B (scratch + 4*ecc->size) +#define F D +#define G E + + ecc_modp_mul (ecc, C, x1, x2); + ecc_modp_mul (ecc, D, y1, y2); + ecc_modp_add (ecc, x3, x1, y1); + ecc_modp_add (ecc, y3, x2, y2); + ecc_modp_mul (ecc, T, x3, y3); + ecc_modp_sub (ecc, T, T, C); + ecc_modp_sub (ecc, T, T, D); + ecc_modp_mul (ecc, x3, C, D); + ecc_modp_mul (ecc, E, x3, ecc->b); + + ecc_modp_sub (ecc, C, D, C); + ecc_modp_sqr (ecc, B, z1); + ecc_modp_sub (ecc, F, B, E); + ecc_modp_add (ecc, G, B, E); + + /* x3 */ + ecc_modp_mul (ecc, B, F, T); + ecc_modp_mul (ecc, x3, B, z1); + + /* y3 */ + ecc_modp_mul (ecc, B, G, C); + ecc_modp_mul (ecc, y3, B, z1); + + /* z3 */ + ecc_modp_mul (ecc, B, F, G); + mpn_copyi (z3, B, ecc->size); +} diff --git a/ecc-add-ehh.c b/ecc-add-ehh.c new file mode 100644 index 0000000000000000000000000000000000000000..b009d84f98b7ebb23464f11fe75252c1cfa03b6b --- /dev/null +++ b/ecc-add-ehh.c @@ -0,0 +1,117 @@ +/* ecc-add-ehh.c + + Copyright (C) 2014 Niels Möller + + 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" + +mp_size_t +ecc_add_ehh_itch (const struct ecc_curve *ecc) +{ + return ECC_ADD_EHH_ITCH (ecc->size); +} + +/* Add two points on an Edwards curve, in homogeneous coordinates */ +void +ecc_add_ehh (const struct ecc_curve *ecc, + mp_limb_t *r, const mp_limb_t *p, const mp_limb_t *q, + mp_limb_t *scratch) +{ +#define x1 p +#define y1 (p + ecc->size) +#define z1 (p + 2*ecc->size) + +#define x2 q +#define y2 (q + ecc->size) +#define z2 (q + 2*ecc->size) + +#define x3 r +#define y3 (r + ecc->size) +#define z3 (r + 2*ecc->size) + + /* Formulas (from djb, + http://www.hyperelliptic.org/EFD/g1p/auto-edwards-projective.html#doubling-dbl-2007-bl): + + Computation Operation Live variables + + C = x1*x2 mul C + D = y1*y2 mul C, D + T = (x1+y1)(x2+y2) - C - D C, D, T + E = b*C*D 2 mul C, E, T (Replace C <-- D - C) + A = z1*z2 mul A, C, E, T + B = A^2 sqr A, B, C, E, T + F = B - E A, B, C, E, F, T + G = B + E A, C, F, G, T + x3 = A*F*T 3 mul A, C, G + y3 = A*G*(D-C) 2 mul F, G + z3 = F*G mul + */ +#define C scratch +#define D (scratch + ecc->size) +#define T (scratch + 2*ecc->size) +#define E (scratch + 3*ecc->size) +#define A (scratch + 4*ecc->size) +#define B (scratch + 5*ecc->size) +#define F D +#define G E + + ecc_modp_mul (ecc, C, x1, x2); + ecc_modp_mul (ecc, D, y1, y2); + ecc_modp_add (ecc, A, x1, y1); + ecc_modp_add (ecc, B, x2, y2); + ecc_modp_mul (ecc, T, A, B); + ecc_modp_sub (ecc, T, T, C); + ecc_modp_sub (ecc, T, T, D); + ecc_modp_mul (ecc, x3, C, D); + ecc_modp_mul (ecc, E, x3, ecc->b); + ecc_modp_sub (ecc, C, D, C); + + ecc_modp_mul (ecc, A, z1, z2); + ecc_modp_sqr (ecc, B, A); + + ecc_modp_sub (ecc, F, B, E); + ecc_modp_add (ecc, G, B, E); + + /* x3 */ + ecc_modp_mul (ecc, B, F, T); + ecc_modp_mul (ecc, x3, B, A); + + /* y3 */ + ecc_modp_mul (ecc, B, G, C); + ecc_modp_mul (ecc, y3, B, A); + + /* z3 */ + ecc_modp_mul (ecc, B, F, G); + mpn_copyi (z3, B, ecc->size); +} diff --git a/ecc-curve.h b/ecc-curve.h index b5f0f975dfd8f3a28f313d097b6da106582f68ea..df72569c01da39095bdf8147b4ad4b571c61c6af 100644 --- a/ecc-curve.h +++ b/ecc-curve.h @@ -46,6 +46,7 @@ extern const struct ecc_curve nettle_secp_224r1; extern const struct ecc_curve nettle_secp_256r1; extern const struct ecc_curve nettle_secp_384r1; extern const struct ecc_curve nettle_secp_521r1; +extern const struct ecc_curve nettle_curve25519; #ifdef __cplusplus } diff --git a/ecc-dup-eh.c b/ecc-dup-eh.c new file mode 100644 index 0000000000000000000000000000000000000000..7065063113c98bd7f1a6ef10bdad39c4ec590bb6 --- /dev/null +++ b/ecc-dup-eh.c @@ -0,0 +1,98 @@ +/* ecc-dup-eh.c + + Copyright (C) 2014 Niels Möller + + 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" + +mp_size_t +ecc_dup_eh_itch (const struct ecc_curve *ecc) +{ + return ECC_DUP_EH_ITCH (ecc->size); +} + +/* Double a point on an Edwards curve, in homogeneous coordinates */ +void +ecc_dup_eh (const struct ecc_curve *ecc, + mp_limb_t *r, const mp_limb_t *p, + mp_limb_t *scratch) +{ + /* Formulas (from djb, + http://www.hyperelliptic.org/EFD/g1p/auto-edwards-projective.html#doubling-dbl-2007-bl): + + Computation Operation Live variables + + b = (x+y)^2 sqr b + c = x^2 sqr b, c + d = y^2 sqr b, c, d + e = c+d b, c, d, e + h = z^2 sqr b, c, d, e, h + j = e-2*h b, c, d, e, j + x' = (b-e)*j mul c, d, e, j + y' = e*(c-d) mul e, j + z' = e*j mul + */ +#define b scratch +#define c (scratch + ecc->size) +#define d (scratch + 2*ecc->size) +#define e (scratch + 3*ecc->size) +#define j (scratch + 4*ecc->size) + + /* b */ + ecc_modp_add (ecc, e, p, p + ecc->size); + ecc_modp_sqr (ecc, b, e); + + /* c */ + ecc_modp_sqr (ecc, c, p); + /* d */ + ecc_modp_sqr (ecc, d, p + ecc->size); + /* h, can use r as scratch, even for in-place operation. */ + ecc_modp_sqr (ecc, r, p + 2*ecc->size); + /* e, */ + ecc_modp_add (ecc, e, c, d); + /* b - e */ + ecc_modp_sub (ecc, b, b, e); + /* j */ + ecc_modp_add (ecc, r, r, r); + ecc_modp_sub (ecc, j, e, r); + + /* x' */ + ecc_modp_mul (ecc, r, b, j); + /* y' */ + ecc_modp_sub (ecc, c, c, d); + ecc_modp_mul (ecc, r + ecc->size, e, c); + /* z' */ + ecc_modp_mul (ecc, b, e, j); + mpn_copyi (r + 2*ecc->size, b, ecc->size); +} diff --git a/ecc-ecdsa-verify.c b/ecc-ecdsa-verify.c index 6337d7bad24e0cc30f250b9507788438835a412e..1310b3125c206ad1ae9ba6135b3fc0bcbd0ca2a4 100644 --- a/ecc-ecdsa-verify.c +++ b/ecc-ecdsa-verify.c @@ -114,7 +114,7 @@ ecc_ecdsa_verify (const struct ecc_curve *ecc, ecc_modq_mul (ecc, u2, rp, sinv); /* Total storage: 5*ecc->size + ECC_MUL_A_ITCH (ecc->size) */ - ecc_mul_a (ecc, 1, P2, u2, pp, u2 + ecc->size); + ecc_mul_a (ecc, P2, u2, pp, u2 + ecc->size); /* u1 = h / s, P1 = u1 * G */ ecc_hash (ecc, hp, length, digest); diff --git a/ecc-eh-to-a.c b/ecc-eh-to-a.c new file mode 100644 index 0000000000000000000000000000000000000000..fd953bf34d16fdc21aa4266adbb4f9ab74dc0869 --- /dev/null +++ b/ecc-eh-to-a.c @@ -0,0 +1,105 @@ +/* ecc-eh-to-a.c + + Copyright (C) 2014 Niels Möller + + 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" + +mp_size_t +ecc_eh_to_a_itch (const struct ecc_curve *ecc) +{ + /* Needs 2*ecc->size + scratch for ecc_modq_inv */ + return ECC_EH_TO_A_ITCH (ecc->size); +} + +/* Convert from homogeneous coordinates on the Edwards curve to affine + coordinates on the corresponding Montgomery curve. */ +void +ecc_eh_to_a (const struct ecc_curve *ecc, + int flags, + mp_limb_t *r, const mp_limb_t *p, + mp_limb_t *scratch) +{ +#define izp scratch +#define sp (scratch + ecc->size) +#define tp (scratch + 2*ecc->size) + +#define xp r +#define yp (r + ecc->size) +#define up p +#define vp (p + ecc->size) +#define wp (p + 2*ecc->size) + /* x = (v+1)/(v-1), y = t x / u (with t = sqrt(b+2)) + + In homogeneous coordinates, + + X = (W + V) U + Y = t (W + V) W + Z = (W - V) U + */ + /* FIXME: Simplify for common case that only x-coordinate is wanted. */ + + mp_limb_t cy; + + /* NOTE: For the infinity point, this subtraction gives zero (mod + p), which isn't invertible. For curve25519, the desired output is + x = 0, and we should be fine, since ecc_modp_inv returns 0 + in this case. */ + ecc_modp_sub (ecc, izp, wp, vp); + ecc_modp_mul (ecc, izp + ecc->size, izp, up); + /* Needs 3*size scratch */ + ecc_modp_inv (ecc, izp, izp + ecc->size, izp + 2*ecc->size); + + ecc_modp_add (ecc, sp, wp, vp); + ecc_modp_mul (ecc, tp, sp, up); + mpn_copyi (sp, tp, ecc->size); /* FIXME: Eliminate copy */ + ecc_modp_mul (ecc, tp, sp, izp); + cy = mpn_sub_n (xp, tp, ecc->p, ecc->size); + cnd_copy (cy, xp, tp, ecc->size); + + if (flags & 2) + /* Skip y coordinate */ + return; + + ecc_modp_add (ecc, sp, wp, vp); /* FIXME: Redundant. Also the (W + + V) Z^-1 multiplication is + redundant. */ + ecc_modp_mul (ecc, tp, sp, wp); + mpn_copyi (sp, tp, ecc->size); /* FIXME: Eliminate copy */ + ecc_modp_mul (ecc, tp, sp, ecc->edwards_root); + mpn_copyi (sp, tp, ecc->size); /* FIXME: Eliminate copy */ + ecc_modp_mul (ecc, tp, sp, izp); + cy = mpn_sub_n (yp, tp, ecc->p, ecc->size); + cnd_copy (cy, yp, tp, ecc->size); +} diff --git a/ecc-internal.h b/ecc-internal.h index aae2fba4aea6bb6e77304d36790b481cef2574a0..d9e107303d092b722bf8cf5103c43dac28c84c14 100644 --- a/ecc-internal.h +++ b/ecc-internal.h @@ -62,21 +62,38 @@ #define sec_sub_1 _nettle_sec_sub_1 #define sec_tabselect _nettle_sec_tabselect #define sec_modinv _nettle_sec_modinv +#define ecc_25519_sqrt _nettle_ecc_25519_sqrt #define ECC_MAX_SIZE ((521 + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS) /* Window size for ecc_mul_a. Using 4 bits seems like a good choice, for both Intel x86_64 and ARM Cortex A9. For the larger curves, of - 384 and 521 bits, we could improve seepd by a few percent if we go + 384 and 521 bits, we could improve speed by a few percent if we go up to 5 bits, but I don't think that's worth doubling the storage. */ #define ECC_MUL_A_WBITS 4 +/* And for ecc_mul_a_eh */ +#define ECC_MUL_A_EH_WBITS 4 + /* Reduces from 2*ecc->size to ecc->size. */ /* Required to return a result < 2q. This property is inherited by modp_mul and modp_add. */ typedef void ecc_mod_func (const struct ecc_curve *ecc, mp_limb_t *rp); +typedef void ecc_mul_g_func (const struct ecc_curve *ecc, mp_limb_t *r, + const mp_limb_t *np, mp_limb_t *scratch); + +typedef void ecc_mul_func (const struct ecc_curve *ecc, + mp_limb_t *r, + const mp_limb_t *np, const mp_limb_t *p, + mp_limb_t *scratch); + +typedef void ecc_h_to_a_func (const struct ecc_curve *ecc, + int flags, + mp_limb_t *r, const mp_limb_t *p, + mp_limb_t *scratch); + /* Represents an elliptic curve of the form y^2 = x^3 - 3x + b (mod p) @@ -97,6 +114,19 @@ struct ecc_curve unsigned short pippenger_k; unsigned short pippenger_c; + unsigned short mul_itch; + unsigned short mul_g_itch; + unsigned short h_to_a_itch; + + ecc_mod_func *modp; + ecc_mod_func *redc; + ecc_mod_func *reduce; + ecc_mod_func *modq; + + ecc_mul_func *mul; + ecc_mul_g_func *mul_g; + ecc_h_to_a_func *h_to_a; + /* The prime p. */ const mp_limb_t *p; const mp_limb_t *b; @@ -106,11 +136,9 @@ struct ecc_curve const mp_limb_t *g; /* Generator with coordinates in Montgomery form. */ const mp_limb_t *redc_g; - - ecc_mod_func *modp; - ecc_mod_func *redc; - ecc_mod_func *reduce; - ecc_mod_func *modq; + /* If non-NULL, the constant needed for transformation to the + equivalent Edwards curve. */ + const mp_limb_t *edwards_root; /* B^size mod p. Expected to have at least 32 leading zeros (equality for secp_256r1). */ @@ -226,20 +254,34 @@ sec_modinv (mp_limb_t *vp, mp_limb_t *ap, mp_size_t n, const mp_limb_t *mp, const mp_limb_t *mp1h, mp_size_t bit_size, mp_limb_t *scratch); +int +ecc_25519_sqrt(mp_limb_t *rp, const mp_limb_t *ap); + /* Current scratch needs: */ #define ECC_MODINV_ITCH(size) (3*(size)) #define ECC_J_TO_A_ITCH(size) (5*(size)) -#define ECC_DUP_JA_ITCH(size) (5*(size)) +#define ECC_EH_TO_A_ITCH(size) (5*(size)) +#define ECC_A_TO_EH_ITCH(size) (2*(size)) #define ECC_DUP_JJ_ITCH(size) (5*(size)) +#define ECC_DUP_EH_ITCH(size) (5*(size)) #define ECC_ADD_JJA_ITCH(size) (6*(size)) #define ECC_ADD_JJJ_ITCH(size) (8*(size)) +#define ECC_ADD_EH_ITCH(size) (6*(size)) +#define ECC_ADD_EHH_ITCH(size) (7*(size)) #define ECC_MUL_G_ITCH(size) (9*(size)) +#define ECC_MUL_G_EH_ITCH(size) (9*(size)) #if ECC_MUL_A_WBITS == 0 #define ECC_MUL_A_ITCH(size) (12*(size)) #else #define ECC_MUL_A_ITCH(size) \ (((3 << ECC_MUL_A_WBITS) + 11) * (size)) #endif +#if ECC_MUL_A_EH_WBITS == 0 +#define ECC_MUL_A_EH_ITCH(size) (13*(size)) +#else +#define ECC_MUL_A_EH_ITCH(size) \ + (((3 << ECC_MUL_A_EH_WBITS) + 10) * (size)) +#endif #define ECC_ECDSA_SIGN_ITCH(size) (12*(size)) #define ECC_ECDSA_VERIFY_ITCH(size) \ (6*(size) + ECC_MUL_A_ITCH ((size))) diff --git a/ecc-mul-a-eh.c b/ecc-mul-a-eh.c new file mode 100644 index 0000000000000000000000000000000000000000..1e9f4fc762927f9391380fd05a6c2cb68064f7ec --- /dev/null +++ b/ecc-mul-a-eh.c @@ -0,0 +1,181 @@ +/* ecc-mul-a-eh.c + + Copyright (C) 2013, 2014 Niels Möller + + 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" + +mp_size_t +ecc_mul_a_eh_itch (const struct ecc_curve *ecc) +{ + /* Binary algorithm needs 6*ecc->size + scratch for ecc_add_ehh, + total 13 ecc->size + + Window algorithm needs (3<<w) * ecc->size for the table, + 3*ecc->size for a temporary point, and scratch for + ecc_add_ehh. */ + return ECC_MUL_A_EH_ITCH (ecc->size); +} + +#if ECC_MUL_A_EH_WBITS == 0 +void +ecc_mul_a_eh (const struct ecc_curve *ecc, + mp_limb_t *r, + const mp_limb_t *np, const mp_limb_t *p, + mp_limb_t *scratch) +{ +#define pe scratch +#define tp (scratch + 3*ecc->size) +#define scratch_out (scratch + 6*ecc->size) + + unsigned i; + + ecc_a_to_eh (ecc, pe, p, pe + 3*ecc->size); + + /* x = 0, y = 1, z = 1 */ + mpn_zero (r, 3*ecc->size); + r[ecc->size] = r[2*ecc->size] = 1; + + for (i = ecc->size; i-- > 0; ) + { + mp_limb_t w = np[i]; + mp_limb_t bit; + + for (bit = (mp_limb_t) 1 << (GMP_NUMB_BITS - 1); + bit > 0; + bit >>= 1) + { + int digit; + + ecc_dup_eh (ecc, r, r, scratch_out); + ecc_add_ehh (ecc, tp, r, pe, scratch_out); + + digit = (w & bit) > 0; + /* If we had a one-bit, use the sum. */ + cnd_copy (digit, r, tp, 3*ecc->size); + } + } +} +#else /* ECC_MUL_A_EH_WBITS > 1 */ + +#define TABLE_SIZE (1U << ECC_MUL_A_EH_WBITS) +#define TABLE_MASK (TABLE_SIZE - 1) + +#define TABLE(j) (table + (j) * 3*ecc->size) + +static void +table_init (const struct ecc_curve *ecc, + mp_limb_t *table, unsigned bits, + const mp_limb_t *p, + mp_limb_t *scratch) +{ + unsigned size = 1 << bits; + unsigned j; + + mpn_zero (TABLE(0), 3*ecc->size); + TABLE(0)[ecc->size] = TABLE(0)[2*ecc->size] = 1; + + ecc_a_to_eh (ecc, TABLE(1), p, scratch); + + for (j = 2; j < size; j += 2) + { + ecc_dup_eh (ecc, TABLE(j), TABLE(j/2), scratch); + ecc_add_ehh (ecc, TABLE(j+1), TABLE(j), TABLE(1), scratch); + } +} + +void +ecc_mul_a_eh (const struct ecc_curve *ecc, + mp_limb_t *r, + const mp_limb_t *np, const mp_limb_t *p, + mp_limb_t *scratch) +{ +#define tp scratch +#define table (scratch + 3*ecc->size) + mp_limb_t *scratch_out = table + (3*ecc->size << ECC_MUL_A_EH_WBITS); + + /* Avoid the mp_bitcnt_t type for compatibility with older GMP + versions. */ + unsigned blocks = (ecc->bit_size + ECC_MUL_A_EH_WBITS - 1) / ECC_MUL_A_EH_WBITS; + unsigned bit_index = (blocks-1) * ECC_MUL_A_EH_WBITS; + + mp_size_t limb_index = bit_index / GMP_NUMB_BITS; + unsigned shift = bit_index % GMP_NUMB_BITS; + mp_limb_t w, bits; + + table_init (ecc, table, ECC_MUL_A_EH_WBITS, p, scratch_out); + + w = np[limb_index]; + bits = w >> shift; + if (limb_index < ecc->size - 1) + bits |= np[limb_index + 1] << (GMP_NUMB_BITS - shift); + + assert (bits < TABLE_SIZE); + + sec_tabselect (r, 3*ecc->size, table, TABLE_SIZE, bits); + + for (;;) + { + unsigned j; + if (shift >= ECC_MUL_A_EH_WBITS) + { + shift -= ECC_MUL_A_EH_WBITS; + bits = w >> shift; + } + else + { + if (limb_index == 0) + { + assert (shift == 0); + break; + } + bits = w << (ECC_MUL_A_EH_WBITS - shift); + w = np[--limb_index]; + shift = shift + GMP_NUMB_BITS - ECC_MUL_A_EH_WBITS; + bits |= w >> shift; + } + for (j = 0; j < ECC_MUL_A_EH_WBITS; j++) + ecc_dup_eh (ecc, r, r, scratch_out); + + bits &= TABLE_MASK; + sec_tabselect (tp, 3*ecc->size, table, TABLE_SIZE, bits); + ecc_add_ehh (ecc, r, tp, r, scratch_out); + } +#undef table +#undef tp +} + +#endif /* ECC_MUL_A_EH_WBITS > 1 */ diff --git a/ecc-mul-a.c b/ecc-mul-a.c index 17bc6d2585f8a11dcb3f7a55aff5aee16bdb3f9c..82f72e65540ad35317040a38b5aaffb36bdacfd3 100644 --- a/ecc-mul-a.c +++ b/ecc-mul-a.c @@ -55,7 +55,7 @@ ecc_mul_a_itch (const struct ecc_curve *ecc) #if ECC_MUL_A_WBITS == 0 void ecc_mul_a (const struct ecc_curve *ecc, - int initial, mp_limb_t *r, + mp_limb_t *r, const mp_limb_t *np, const mp_limb_t *p, mp_limb_t *scratch) { @@ -67,7 +67,7 @@ ecc_mul_a (const struct ecc_curve *ecc, unsigned i; - ecc_a_to_j (ecc, initial, pj, p); + ecc_a_to_j (ecc, pj, p); mpn_zero (r, 3*ecc->size); for (i = ecc->size, is_zero = 1; i-- > 0; ) @@ -104,14 +104,14 @@ ecc_mul_a (const struct ecc_curve *ecc, static void table_init (const struct ecc_curve *ecc, mp_limb_t *table, unsigned bits, - int initial, const mp_limb_t *p, + const mp_limb_t *p, mp_limb_t *scratch) { unsigned size = 1 << bits; unsigned j; mpn_zero (TABLE(0), 3*ecc->size); - ecc_a_to_j (ecc, initial, TABLE(1), p); + ecc_a_to_j (ecc, TABLE(1), p); for (j = 2; j < size; j += 2) { @@ -122,7 +122,7 @@ table_init (const struct ecc_curve *ecc, void ecc_mul_a (const struct ecc_curve *ecc, - int initial, mp_limb_t *r, + mp_limb_t *r, const mp_limb_t *np, const mp_limb_t *p, mp_limb_t *scratch) { @@ -140,7 +140,7 @@ ecc_mul_a (const struct ecc_curve *ecc, unsigned shift = bit_index % GMP_NUMB_BITS; mp_limb_t w, bits; - table_init (ecc, table, ECC_MUL_A_WBITS, initial, p, scratch_out); + table_init (ecc, table, ECC_MUL_A_WBITS, p, scratch_out); w = np[limb_index]; bits = w >> shift; diff --git a/ecc-mul-g-eh.c b/ecc-mul-g-eh.c new file mode 100644 index 0000000000000000000000000000000000000000..4242479c9bfb88ea9392cffd5eb730a0bdd62c58 --- /dev/null +++ b/ecc-mul-g-eh.c @@ -0,0 +1,108 @@ +/* ecc-mul-g-eh.c + + Copyright (C) 2013, 2014 Niels Möller + + 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/. +*/ + +/* Development of Nettle's ECC support was funded by the .SE Internet Fund. */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <assert.h> + +#include "ecc.h" +#include "ecc-internal.h" + +mp_size_t +ecc_mul_g_eh_itch (const struct ecc_curve *ecc) +{ + /* Needs 3*ecc->size + scratch for ecc_add_jja. */ + return ECC_MUL_G_EH_ITCH (ecc->size); +} + +void +ecc_mul_g_eh (const struct ecc_curve *ecc, mp_limb_t *r, + const mp_limb_t *np, mp_limb_t *scratch) +{ + /* Scratch need determined by the ecc_add_eh call. Current total is + 9 * ecc->size, at most 648 bytes. */ +#define tp scratch +#define scratch_out (scratch + 3*ecc->size) + + unsigned k, c; + unsigned i, j; + unsigned bit_rows; + + k = ecc->pippenger_k; + c = ecc->pippenger_c; + + bit_rows = (ecc->bit_size + k - 1) / k; + + /* x = 0, y = 1, z = 1 */ + mpn_zero (r, 3*ecc->size); + r[ecc->size] = r[2*ecc->size] = 1; + + for (i = k; i-- > 0; ) + { + ecc_dup_eh (ecc, r, r, scratch); + for (j = 0; j * c < bit_rows; j++) + { + unsigned bits; + /* Avoid the mp_bitcnt_t type for compatibility with older GMP + versions. */ + unsigned bit_index; + + /* Extract c bits from n, stride k, starting at i + kcj, + ending at i + k (cj + c - 1)*/ + for (bits = 0, bit_index = i + k*(c*j+c); bit_index > i + k*c*j; ) + { + mp_size_t limb_index; + unsigned shift; + + bit_index -= k; + + limb_index = bit_index / GMP_NUMB_BITS; + if (limb_index >= ecc->size) + continue; + + shift = bit_index % GMP_NUMB_BITS; + bits = (bits << 1) | ((np[limb_index] >> shift) & 1); + } + sec_tabselect (tp, 2*ecc->size, + (ecc->pippenger_table + + (2*ecc->size * (mp_size_t) j << c)), + 1<<c, bits); + + ecc_add_eh (ecc, r, r, tp, scratch_out); + } + } +#undef tp +#undef scratch_out +} diff --git a/ecc-point-mul-g.c b/ecc-point-mul-g.c index 8186bf2c9746453161f2d0460c44b7ff657ea071..bb9a2d760f48174ccb7903b2b1c967bc532773dc 100644 --- a/ecc-point-mul-g.c +++ b/ecc-point-mul-g.c @@ -45,13 +45,14 @@ void ecc_point_mul_g (struct ecc_point *r, const struct ecc_scalar *n) { TMP_DECL(scratch, mp_limb_t, 3*ECC_MAX_SIZE + ECC_MUL_G_ITCH (ECC_MAX_SIZE)); - mp_limb_t size = r->ecc->size; - mp_size_t itch = 3*size + ECC_MUL_G_ITCH (size); + const struct ecc_curve *ecc = r->ecc; + mp_limb_t size = ecc->size; + mp_size_t itch = 3*size + ecc->mul_g_itch; - assert (r->ecc == n->ecc); + assert (n->ecc == ecc); TMP_ALLOC (scratch, itch); - ecc_mul_g (r->ecc, scratch, n->p, scratch + 3*size); - ecc_j_to_a (r->ecc, 1, r->p, scratch, scratch + 3*size); + ecc->mul_g (ecc, scratch, n->p, scratch + 3*size); + ecc->h_to_a (ecc, 1, r->p, scratch, scratch + 3*size); } diff --git a/ecc-point-mul.c b/ecc-point-mul.c index d8329cf5112538e342dac44bed03c860b74c7923..2080b60815bcadeb1d91e615c91dd03f3e32b87a 100644 --- a/ecc-point-mul.c +++ b/ecc-point-mul.c @@ -44,14 +44,15 @@ void ecc_point_mul (struct ecc_point *r, const struct ecc_scalar *n, const struct ecc_point *p) { - mp_limb_t size = p->ecc->size; - mp_size_t itch = 3*size + ECC_MUL_A_ITCH (size); + const struct ecc_curve *ecc = r->ecc; + mp_limb_t size = ecc->size; + mp_size_t itch = 3*size + ecc->mul_itch; mp_limb_t *scratch = gmp_alloc_limbs (itch); - assert (n->ecc == p->ecc); - assert (r->ecc == p->ecc); + assert (n->ecc == ecc); + assert (p->ecc == ecc); - ecc_mul_a (p->ecc, 1, scratch, n->p, p->p, scratch + 3*size); - ecc_j_to_a (r->ecc, 1, r->p, scratch, scratch + 3*size); + ecc->mul (ecc, scratch, n->p, p->p, scratch + 3*size); + ecc->h_to_a (ecc, 1, r->p, scratch, scratch + 3*size); gmp_free_limbs (scratch, itch); } diff --git a/ecc-point.c b/ecc-point.c index 448b17b16e524e4e755a625d739c44392178dd86..60fbd080c22b3f8f37c12789d8df792c25c1393d 100644 --- a/ecc-point.c +++ b/ecc-point.c @@ -68,12 +68,26 @@ ecc_point_set (struct ecc_point *p, const mpz_t x, const mpz_t y) mpz_init (lhs); mpz_init (rhs); - /* Check that y^2 = x^3 - 3*x + b (mod p) */ + if (p->ecc->bit_size == 255) + { + /* curve25519 special case. FIXME: Do in some cleaner way? */ + + /* Check that y^2 = x^3 + 486662 x^2 + x (mod p)*/ + mpz_mul (lhs, x, x); /* Reuse lhs as a temporary */ + mpz_add_ui (rhs, x, 486662); + mpz_mul (rhs, rhs, lhs); + mpz_add (rhs, rhs, x); + } + else + { + /* Check that y^2 = x^3 - 3*x + b (mod p) */ + mpz_mul (rhs, x, x); + mpz_sub_ui (rhs, rhs, 3); + mpz_mul (rhs, rhs, x); + mpz_add (rhs, rhs, mpz_roinit_n (t, p->ecc->b, size)); + } + mpz_mul (lhs, y, y); - mpz_mul (rhs, x, x); - mpz_sub_ui (rhs, rhs, 3); - mpz_mul (rhs, rhs, x); - mpz_add (rhs, rhs, mpz_roinit_n (t, p->ecc->b, size)); res = mpz_congruent_p (lhs, rhs, mpz_roinit_n (t, p->ecc->p, size)); diff --git a/ecc.h b/ecc.h index 7293186b14997a3ca4f042b87726505c214e01b9..360d60b102195f94ece96a07bfa9f4466f10b319 100644 --- a/ecc.h +++ b/ecc.h @@ -58,23 +58,33 @@ extern "C" { #define ecc_size nettle_ecc_size #define ecc_size_a nettle_ecc_size_a #define ecc_size_j nettle_ecc_size_j -#define ecc_a_to_a_itch nettle_ecc_a_to_a_itch -#define ecc_a_to_a nettle_ecc_a_to_a #define ecc_a_to_j nettle_ecc_a_to_j #define ecc_j_to_a_itch nettle_ecc_j_to_a_itch #define ecc_j_to_a nettle_ecc_j_to_a -#define ecc_dup_ja_itch nettle_ecc_dup_ja_itch -#define ecc_dup_ja nettle_ecc_dup_ja +#define ecc_eh_to_a_itch nettle_ecc_eh_to_a_itch +#define ecc_eh_to_a nettle_ecc_eh_to_a +#define ecc_a_to_eh_itch nettle_ecc_a_to_eh_itch +#define ecc_a_to_eh nettle_ecc_a_to_eh #define ecc_dup_jj_itch nettle_ecc_dup_jj_itch #define ecc_dup_jj nettle_ecc_dup_jj #define ecc_add_jja_itch nettle_ecc_add_jja_itch #define ecc_add_jja nettle_ecc_add_jja #define ecc_add_jjj_itch nettle_ecc_add_jjj_itch #define ecc_add_jjj nettle_ecc_add_jjj +#define ecc_dup_eh_itch nettle_ecc_dup_eh_itch +#define ecc_dup_eh nettle_ecc_dup_eh +#define ecc_add_eh_itch nettle_ecc_add_eh_itch +#define ecc_add_eh nettle_ecc_add_eh +#define ecc_add_ehh_itch nettle_ecc_add_ehh_itch +#define ecc_add_ehh nettle_ecc_add_ehh #define ecc_mul_g_itch nettle_ecc_mul_g_itch #define ecc_mul_g nettle_ecc_mul_g #define ecc_mul_a_itch nettle_ecc_mul_a_itch #define ecc_mul_a nettle_ecc_mul_a +#define ecc_mul_g_eh_itch nettle_ecc_mul_g_eh_itch +#define ecc_mul_g_eh nettle_ecc_mul_g_eh +#define ecc_mul_a_eh_itch nettle_ecc_mul_a_eh_itch +#define ecc_mul_a_eh nettle_ecc_mul_a_eh struct ecc_curve; @@ -168,21 +178,10 @@ ecc_size_j (const struct ecc_curve *ecc); _ecc_*, and provide public ecc_* functions which handle the infinity points properly? */ -/* Converts the affine coordinates of a point into montgomery form, if - used for this curve. */ -mp_size_t -ecc_a_to_a_itch (const struct ecc_curve *ecc); -void -ecc_a_to_a (const struct ecc_curve *ecc, - mp_limb_t *r, const mp_limb_t *p, - mp_limb_t *scratch); - /* Converts a point P in affine coordinates into a point R in jacobian - coordinates. If INITIAL is non-zero, and the curve uses montgomery - coordinates, also convert coordinates to montgomery form. */ + coordinates. */ void ecc_a_to_j (const struct ecc_curve *ecc, - int initial, mp_limb_t *r, const mp_limb_t *p); /* Converts a point P in jacobian coordinates into a point R in affine @@ -197,17 +196,25 @@ ecc_j_to_a (const struct ecc_curve *ecc, mp_limb_t *r, const mp_limb_t *p, mp_limb_t *scratch); -/* Group operations */ +/* Converts a point P on an Edwards curve to affine coordinates on + the corresponding Montgomery curve. */ +mp_size_t +ecc_eh_to_a_itch (const struct ecc_curve *ecc); +void +ecc_eh_to_a (const struct ecc_curve *ecc, + int flags, + mp_limb_t *r, const mp_limb_t *p, + mp_limb_t *scratch); -/* Point doubling, with jacobian output and affine input. Corner - cases: Correctly sets R = 0 (r_Z = 0) if p = 0 or 2p = 0. */ mp_size_t -ecc_dup_ja_itch (const struct ecc_curve *ecc); +ecc_a_to_eh_itch (const struct ecc_curve *ecc); void -ecc_dup_ja (const struct ecc_curve *ecc, - mp_limb_t *r, const mp_limb_t *p, - mp_limb_t *scratch); +ecc_a_to_eh (const struct ecc_curve *ecc, + mp_limb_t *r, const mp_limb_t *p, + mp_limb_t *scratch); + +/* Group operations */ /* Point doubling, with jacobian input and output. Corner cases: Correctly sets R = 0 (r_Z = 0) if p = 0 or 2p = 0. */ @@ -241,6 +248,29 @@ ecc_add_jjj (const struct ecc_curve *ecc, mp_limb_t *r, const mp_limb_t *p, const mp_limb_t *q, mp_limb_t *scratch); +/* FIXME: Use a generic ecc_dup, ecc_add, for any type of curve. */ +/* Point doubling on an Edwards curve, with homogeneous + cooordinates. */ +mp_size_t +ecc_dup_eh_itch (const struct ecc_curve *ecc); +void +ecc_dup_eh (const struct ecc_curve *ecc, + mp_limb_t *r, const mp_limb_t *p, + mp_limb_t *scratch); + +mp_size_t +ecc_add_eh_itch (const struct ecc_curve *ecc); +void +ecc_add_eh (const struct ecc_curve *ecc, + mp_limb_t *r, const mp_limb_t *p, const mp_limb_t *q, + mp_limb_t *scratch); + +mp_size_t +ecc_add_ehh_itch (const struct ecc_curve *ecc); +void +ecc_add_ehh (const struct ecc_curve *ecc, + mp_limb_t *r, const mp_limb_t *p, const mp_limb_t *q, + mp_limb_t *scratch); /* Computes N * the group generator. N is an array of ecc_size() limbs. It must be in the range 0 < N < group order, then R != 0, @@ -253,18 +283,31 @@ ecc_mul_g (const struct ecc_curve *ecc, mp_limb_t *r, const mp_limb_t *np, mp_limb_t *scratch); /* Computes N * P. The scalar N is the same as for ecc_mul_g. P is a - non-zero point on the curve, in affine coordinates. Pass a non-zero - INITIAL if the point coordinates have not previously been converted - to Montgomery representation. Output R is a non-zero point, in - Jacobian coordinates. */ + non-zero point on the curve, in affine coordinates. Output R is a + non-zero point, in Jacobian coordinates. */ mp_size_t ecc_mul_a_itch (const struct ecc_curve *ecc); void ecc_mul_a (const struct ecc_curve *ecc, - int initial, mp_limb_t *r, + mp_limb_t *r, const mp_limb_t *np, const mp_limb_t *p, mp_limb_t *scratch); +mp_size_t +ecc_mul_g_eh_itch (const struct ecc_curve *ecc); +void +ecc_mul_g_eh (const struct ecc_curve *ecc, mp_limb_t *r, + const mp_limb_t *np, mp_limb_t *scratch); + +mp_size_t +ecc_mul_a_eh_itch (const struct ecc_curve *ecc); +void +ecc_mul_a_eh (const struct ecc_curve *ecc, + mp_limb_t *r, + const mp_limb_t *np, const mp_limb_t *p, + mp_limb_t *scratch); + + #ifdef __cplusplus } #endif diff --git a/eccdata.c b/eccdata.c index 4e17f9ac64b9db8a9600a026d6b78f7a8fe7ddc3..9069e61082467bb099788373755bb1f9b9d71737 100644 --- a/eccdata.c +++ b/eccdata.c @@ -2,7 +2,7 @@ Generate compile time constant (but machine dependent) tables. - Copyright (C) 2013 Niels Möller + Copyright (C) 2013, 2014 Niels Möller This file is part of GNU Nettle. @@ -40,12 +40,11 @@ #include "mini-gmp.c" -/* Affine coordinates, for simplicity. Infinity point represented as x - == y == 0. FIXME: Doesn't quite work for Montgomery curves, where - (0,0) is a normal finite point. Shouldn't occur in these - computations, though. */ +/* Affine coordinates, for simplicity. Infinity point, i.e., te + neutral group element, is represented using the is_zero flag. */ struct ecc_point { + int is_zero; mpz_t x; mpz_t y; }; @@ -74,6 +73,16 @@ struct ecc_curve mpz_t q; struct ecc_point g; + /* Non-zero if we want elements represented as point s(u, v) on an + equivalent Edwards curve, using + + u = t x / y + v = (x-1) / (x+1) + */ + int use_edwards; + mpz_t d; + mpz_t t; + /* Table for pippenger's algorithm. Element @@ -107,25 +116,26 @@ ecc_clear (struct ecc_point *p) static int ecc_zero_p (const struct ecc_point *p) { - return mpz_sgn (p->x) == 0 && mpz_sgn (p->y) == 0; + return p->is_zero; } static int ecc_equal_p (const struct ecc_point *p, const struct ecc_point *q) { - return mpz_cmp (p->x, q->x) == 0 && mpz_cmp (p->y, q->y) == 0; + return p->is_zero ? q->is_zero + : !q->is_zero && mpz_cmp (p->x, q->x) == 0 && mpz_cmp (p->y, q->y) == 0; } static void ecc_set_zero (struct ecc_point *r) { - mpz_set_ui (r->x, 0); - mpz_set_ui (r->y, 0); + r->is_zero = 1; } static void ecc_set (struct ecc_point *r, const struct ecc_point *p) { + r->is_zero = p->is_zero; mpz_set (r->x, p->x); mpz_set (r->y, p->y); } @@ -186,9 +196,10 @@ ecc_dup (const struct ecc_curve *ecc, mpz_sub (y, y, p->y); mpz_mod (y, y, ecc->p); + r->is_zero = 0; mpz_swap (x, r->x); mpz_swap (y, r->y); - + mpz_clear (m); mpz_clear (t); mpz_clear (x); @@ -243,6 +254,7 @@ ecc_add (const struct ecc_curve *ecc, mpz_sub (y, y, p->y); mpz_mod (y, y, ecc->p); + r->is_zero = 0; mpz_swap (x, r->x); mpz_swap (y, r->y); @@ -296,6 +308,7 @@ static void ecc_set_str (struct ecc_point *p, const char *x, const char *y) { + p->is_zero = 0; mpz_set_str (p->x, x, 16); mpz_set_str (p->y, y, 16); } @@ -303,7 +316,8 @@ ecc_set_str (struct ecc_point *p, static void ecc_curve_init_str (struct ecc_curve *ecc, enum ecc_type type, const char *p, const char *b, const char *q, - const char *gx, const char *gy) + const char *gx, const char *gy, + const char *d, const char *t) { ecc->type = type; @@ -318,6 +332,16 @@ ecc_curve_init_str (struct ecc_curve *ecc, enum ecc_type type, ecc->table = NULL; ecc->ref = NULL; + + mpz_init (ecc->d); + mpz_init (ecc->t); + + ecc->use_edwards = (t != NULL); + if (ecc->use_edwards) + { + mpz_set_str (ecc->t, t, 16); + mpz_set_str (ecc->d, d, 16); + } } static void @@ -341,7 +365,8 @@ ecc_curve_init (struct ecc_curve *ecc, unsigned bit_size) "f4ff0afd82ff1012", "07192b95ffc8da78631011ed6b24cdd5" - "73f977a11e794811"); + "73f977a11e794811", + NULL, NULL); ecc->ref = ecc_alloc (3); ecc_set_str (&ecc->ref[0], /* 2 g */ "dafebf5828783f2ad35534631588a3f629a70fb16982a888", @@ -372,7 +397,8 @@ ecc_curve_init (struct ecc_curve *ecc, unsigned bit_size) "56c21122343280d6115c1d21", "bd376388b5f723fb4c22dfe6cd4375a0" - "5a07476444d5819985007e34"); + "5a07476444d5819985007e34", + NULL, NULL); ecc->ref = ecc_alloc (3); ecc_set_str (&ecc->ref[0], /* 2 g */ @@ -404,7 +430,8 @@ ecc_curve_init (struct ecc_curve *ecc, unsigned bit_size) "77037D812DEB33A0F4A13945D898C296", "4FE342E2FE1A7F9B8EE7EB4A7C0F9E16" - "2BCE33576B315ECECBB6406837BF51F5"); + "2BCE33576B315ECECBB6406837BF51F5", + NULL, NULL); ecc->ref = ecc_alloc (3); ecc_set_str (&ecc->ref[0], /* 2 g */ @@ -441,7 +468,8 @@ ecc_curve_init (struct ecc_curve *ecc, unsigned bit_size) "3617de4a96262c6f5d9e98bf9292dc29" "f8f41dbd289a147ce9da3113b5f0b8c0" - "0a60b1ce1d7e819d7a431d7c90ea0e5f"); + "0a60b1ce1d7e819d7a431d7c90ea0e5f", + NULL, NULL); ecc->ref = ecc_alloc (3); ecc_set_str (&ecc->ref[0], /* 2 g */ @@ -487,7 +515,8 @@ ecc_curve_init (struct ecc_curve *ecc, unsigned bit_size) "39296a789a3bc0045c8a5fb42c7d1bd9" "98f54449579b446817afbd17273e662c" "97ee72995ef42640c550b9013fad0761" - "353c7086a272c24088be94769fd16650"); + "353c7086a272c24088be94769fd16650", + NULL, NULL); ecc->ref = ecc_alloc (3); ecc_set_str (&ecc->ref[0], /* 2 g */ @@ -506,7 +535,7 @@ ecc_curve_init (struct ecc_curve *ecc, unsigned bit_size) case 255: /* curve25519, y^2 = x^3 + 486662 x^2 + x (mod p), with p = 2^{255} - 19. - Acccording to http://cr.yp.to/papers.html#newelliptic, this + According to http://cr.yp.to/papers.html#newelliptic, this is birationally equivalent to the Edwards curve x^2 + y^2 = 1 + (121665/121666) x^2 y^2 (mod p). @@ -529,8 +558,10 @@ ecc_curve_init (struct ecc_curve *ecc, unsigned bit_size) "7fffffffffffffffffffffffffffffff" "ffffffffffffffffffffffffffffffed", "76d06", - /* Order of the subgroup is 2^252 + - 27742317777372353535851937790883648493 */ + /* Order of the subgroup is 2^252 + q_0, where + q_0 = 27742317777372353535851937790883648493, + 125 bits. + */ "10000000000000000000000000000000" "14def9dea2f79cd65812631a5cf5d3ed", "9", @@ -538,7 +569,16 @@ ecc_curve_init (struct ecc_curve *ecc, unsigned bit_size) x = Mod(9, 2^255-19); sqrt(x^3 + 486662*x^2 + x) */ "20ae19a1b8a086b4e01edd2c7748d14c" - "923d4d7e6d7c61b229e9c5a27eced3d9"); + "923d4d7e6d7c61b229e9c5a27eced3d9", + /* (121665/121666) mod p, from PARI/GP + c = Mod(121665, p); c / (c+1) + */ + "2dfc9311d490018c7338bf8688861767" + "ff8ff5b2bebe27548a14b235eca6874a", + /* sqrt(486664) mod p, from PARI/GP + sqrt(Mod(486664, p)) */ + "141b0b6806563d503de05885280b5910" + "9ca5ee38d7b56c9c165db7106377bbd8"); ecc->ref = ecc_alloc (3); ecc_set_str (&ecc->ref[0], /* 2 g */ "20d342d51873f1b7d9750c687d157114" @@ -642,20 +682,30 @@ ecc_mul_pippenger (const struct ecc_curve *ecc, mpz_clear (n); } +static void +ecc_point_out (FILE *f, const struct ecc_point *p) +{ + if (p->is_zero) + fprintf (f, "zero"); + else + { + fprintf (stderr, "("); + mpz_out_str (stderr, 16, p->x); + fprintf (stderr, ",\n "); + mpz_out_str (stderr, 16, (p)->y); + fprintf (stderr, ")"); + } +} #define ASSERT_EQUAL(p, q) do { \ if (!ecc_equal_p (p, q)) \ { \ fprintf (stderr, "%s:%d: ASSERT_EQUAL (%s, %s) failed.\n", \ __FILE__, __LINE__, #p, #q); \ - fprintf (stderr, "p = ("); \ - mpz_out_str (stderr, 16, (p)->x); \ - fprintf (stderr, ",\n "); \ - mpz_out_str (stderr, 16, (p)->y); \ - fprintf (stderr, ")\nq = ("); \ - mpz_out_str (stderr, 16, (q)->x); \ - fprintf (stderr, ",\n "); \ - mpz_out_str (stderr, 16, (q)->y); \ - fprintf (stderr, ")\n"); \ + fprintf (stderr, "p = "); \ + ecc_point_out (stderr, (p)); \ + fprintf (stderr, "\nq = "); \ + ecc_point_out (stderr, (q)); \ + fprintf (stderr, "\n"); \ abort(); \ } \ } while (0) @@ -665,11 +715,9 @@ ecc_mul_pippenger (const struct ecc_curve *ecc, { \ fprintf (stderr, "%s:%d: ASSERT_ZERO (%s) failed.\n", \ __FILE__, __LINE__, #p); \ - fprintf (stderr, "p = ("); \ - mpz_out_str (stderr, 16, (p)->x); \ - fprintf (stderr, ",\n "); \ - mpz_out_str (stderr, 16, (p)->y); \ - fprintf (stderr, ")\n"); \ + fprintf (stderr, "p = "); \ + ecc_point_out (stderr, (p)); \ + fprintf (stderr, "\n"); \ abort(); \ } \ } while (0) @@ -790,43 +838,67 @@ output_bignum (const char *name, const mpz_t x, } static void -output_point (const char *name, const struct ecc_point *p, +output_point (const char *name, const struct ecc_curve *ecc, + const struct ecc_point *p, int use_redc, unsigned size, unsigned bits_per_limb) { - if (name) - printf("static const mp_limb_t %s[%u] = {", name, 2*size); - - output_digits (p->x, size, bits_per_limb); - output_digits (p->y, size, bits_per_limb); + mpz_t x, y, t; - if (name) - printf("\n};\n"); -} - -static void -output_point_redc (const char *name, const struct ecc_curve *ecc, - const struct ecc_point *p, - unsigned size, unsigned bits_per_limb) -{ - mpz_t t; + mpz_init (x); + mpz_init (y); mpz_init (t); - + if (name) printf("static const mp_limb_t %s[%u] = {", name, 2*size); - - mpz_mul_2exp (t, p->x, size * bits_per_limb); - mpz_mod (t, t, ecc->p); - - output_digits (t, size, bits_per_limb); - mpz_mul_2exp (t, p->y, size * bits_per_limb); - mpz_mod (t, t, ecc->p); + if (ecc->use_edwards) + { + if (ecc_zero_p (p)) + { + mpz_set_si (x, 0); + mpz_set_si (y, 1); + } + else if (!mpz_sgn (p->y)) + { + assert (!mpz_sgn (p->x)); + mpz_set_si (x, 0); + mpz_set_si (y, -1); + } + else + { + mpz_invert (x, p->y, ecc->p); + mpz_mul (x, x, p->x); + mpz_mul (x, x, ecc->t); + mpz_mod (x, x, ecc->p); + + mpz_sub_ui (y, p->x, 1); + mpz_add_ui (t, p->x, 1); + mpz_invert (t, t, ecc->p); + mpz_mul (y, y, t); + mpz_mod (y, y, ecc->p); + } + } + else + { + mpz_set (x, p->x); + mpz_set (y, p->y); + } + if (use_redc) + { + mpz_mul_2exp (x, x, size * bits_per_limb); + mpz_mod (x, x, ecc->p); + mpz_mul_2exp (y, y, size * bits_per_limb); + mpz_mod (y, y, ecc->p); + } - output_digits (t, size, bits_per_limb); + output_digits (x, size, bits_per_limb); + output_digits (y, size, bits_per_limb); if (name) printf("\n};\n"); + mpz_clear (x); + mpz_clear (y); mpz_clear (t); } @@ -854,7 +926,7 @@ output_curve (const struct ecc_curve *ecc, unsigned bits_per_limb) { unsigned limb_size = (ecc->bit_size + bits_per_limb - 1)/bits_per_limb; unsigned i; - unsigned bits; + unsigned bits, e; int redc_limbs; mpz_t t; @@ -868,9 +940,11 @@ output_curve (const struct ecc_curve *ecc, unsigned bits_per_limb) output_bignum ("ecc_p", ecc->p, limb_size, bits_per_limb); output_bignum ("ecc_b", ecc->b, limb_size, bits_per_limb); + if (ecc->use_edwards) + output_bignum ("ecc_d", ecc->d, limb_size, bits_per_limb); output_bignum ("ecc_q", ecc->q, limb_size, bits_per_limb); - output_point ("ecc_g", &ecc->g, limb_size, bits_per_limb); - output_point_redc ("ecc_redc_g", ecc, &ecc->g, limb_size, bits_per_limb); + output_point ("ecc_g", ecc, &ecc->g, 0, limb_size, bits_per_limb); + output_point ("ecc_redc_g", ecc, &ecc->g, 1, limb_size, bits_per_limb); bits = output_modulo ("ecc_Bmodp", ecc->p, limb_size, bits_per_limb); printf ("#define ECC_BMODP_SIZE %u\n", @@ -878,6 +952,28 @@ output_curve (const struct ecc_curve *ecc, unsigned bits_per_limb) bits = output_modulo ("ecc_Bmodq", ecc->q, limb_size, bits_per_limb); printf ("#define ECC_BMODQ_SIZE %u\n", (bits + bits_per_limb - 1) / bits_per_limb); + bits = mpz_sizeinbase (ecc->q, 2); + if (bits < ecc->bit_size) + { + /* for curve25519, with q = 2^k + q', with a much smaller q' */ + unsigned mbits; + unsigned shift; + + /* Shift to align the one bit at B */ + shift = bits_per_limb * limb_size + 1 - bits; + + mpz_set (t, ecc->q); + mpz_clrbit (t, bits-1); + mbits = mpz_sizeinbase (t, 2); + + /* The shifted value must be a limb smaller than q. */ + if (mbits + shift + bits_per_limb <= bits) + { + /* q of the form 2^k + q', with q' a limb smaller */ + mpz_mul_2exp (t, t, shift); + output_bignum ("ecc_mBmodq_shifted", t, limb_size, bits_per_limb); + } + } if (ecc->bit_size < limb_size * bits_per_limb) { @@ -932,7 +1028,10 @@ output_curve (const struct ecc_curve *ecc, unsigned bits_per_limb) mpz_add_ui (t, ecc->q, 1); mpz_fdiv_q_2exp (t, t, 1); output_bignum ("ecc_qp1h", t, limb_size, bits_per_limb); - + + if (ecc->use_edwards) + output_bignum ("ecc_edwards", ecc->t, limb_size, bits_per_limb); + /* Trailing zeros in p+1 correspond to trailing ones in p. */ redc_limbs = mpz_scan0 (ecc->p, 0) / bits_per_limb; if (redc_limbs > 0) @@ -957,13 +1056,69 @@ output_curve (const struct ecc_curve *ecc, unsigned bits_per_limb) } printf ("#define ECC_REDC_SIZE %d\n", redc_limbs); + /* For mod p square root computation. */ + if (mpz_fdiv_ui (ecc->p, 4) == 3) + { + /* x = a^{(p+1)/4} gives square root of a (if it exists, + otherwise the square root of -a). */ + e = 1; + mpz_add_ui (t, ecc->p, 1); + mpz_fdiv_q_2exp (t, t, 2); + } + else + { + /* p-1 = 2^e s, s odd, t = (s-1)/2*/ + unsigned g, i; + mpz_t s; + mpz_t z; + + mpz_init (s); + mpz_init (z); + + mpz_sub_ui (s, ecc->p, 1); + e = mpz_scan1 (s, 0); + assert (e > 1); + + mpz_fdiv_q_2exp (s, s, e); + + /* Find a non-square g, g^{(p-1)/2} = -1, + and z = g^{(p-1)/4 */ + for (g = 2; ; g++) + { + mpz_set_ui (z, g); + mpz_powm (z, z, s, ecc->p); + mpz_mul (t, z, z); + mpz_mod (t, t, ecc->p); + + for (i = 2; i < e; i++) + { + mpz_mul (t, t, t); + mpz_mod (t, t, ecc->p); + } + if (mpz_cmp_ui (t, 1) != 0) + break; + } + mpz_add_ui (t, t, 1); + assert (mpz_cmp (t, ecc->p) == 0); + output_bignum ("ecc_sqrt_z", z, limb_size, bits_per_limb); + + mpz_fdiv_q_2exp (t, s, 1); + + mpz_clear (s); + mpz_clear (z); + } + printf ("#define ECC_SQRT_E %u\n", e); + printf ("#define ECC_SQRT_T_BITS %u\n", + (unsigned) mpz_sizeinbase (t, 2)); + output_bignum ("ecc_sqrt_t", t, limb_size, bits_per_limb); + printf ("#if USE_REDC\n"); printf ("#define ecc_unit ecc_Bmodp\n"); printf ("static const mp_limb_t ecc_table[%lu] = {", (unsigned long) (2*ecc->table_size * limb_size)); for (i = 0; i < ecc->table_size; i++) - output_point_redc (NULL, ecc, &ecc->table[i], limb_size, bits_per_limb); + output_point (NULL, ecc, &ecc->table[i], 1, limb_size, bits_per_limb); printf("\n};\n"); @@ -975,7 +1130,7 @@ output_curve (const struct ecc_curve *ecc, unsigned bits_per_limb) printf ("static const mp_limb_t ecc_table[%lu] = {", (unsigned long) (2*ecc->table_size * limb_size)); for (i = 0; i < ecc->table_size; i++) - output_point (NULL, &ecc->table[i], limb_size, bits_per_limb); + output_point (NULL, ecc, &ecc->table[i], 0, limb_size, bits_per_limb); printf("\n};\n"); printf ("#endif\n"); diff --git a/examples/ecc-benchmark.c b/examples/ecc-benchmark.c index 0153b74460c5a0b2e8bcd4d44f698725cda942b3..6fc4860d3659df8b453c5f9056170dffd29350e0 100644 --- a/examples/ecc-benchmark.c +++ b/examples/ecc-benchmark.c @@ -227,14 +227,35 @@ static void bench_mul_g (void *p) { struct ecc_ctx *ctx = (struct ecc_ctx *) p; - ecc_mul_g (ctx->ecc, ctx->rp, ctx->ap, ctx->tp); + ctx->ecc->mul_g (ctx->ecc, ctx->rp, ctx->ap, ctx->tp); } static void bench_mul_a (void *p) { struct ecc_ctx *ctx = (struct ecc_ctx *) p; - ecc_mul_a (ctx->ecc, 1, ctx->rp, ctx->ap, ctx->bp, ctx->tp); + ctx->ecc->mul (ctx->ecc, ctx->rp, ctx->ap, ctx->bp, ctx->tp); +} + +static void +bench_dup_eh (void *p) +{ + struct ecc_ctx *ctx = (struct ecc_ctx *) p; + ecc_dup_eh (ctx->ecc, ctx->rp, ctx->ap, ctx->tp); +} + +static void +bench_add_eh (void *p) +{ + struct ecc_ctx *ctx = (struct ecc_ctx *) p; + ecc_add_eh (ctx->ecc, ctx->rp, ctx->ap, ctx->bp, ctx->tp); +} + +static void +bench_add_ehh (void *p) +{ + struct ecc_ctx *ctx = (struct ecc_ctx *) p; + ecc_add_ehh (ctx->ecc, ctx->rp, ctx->ap, ctx->bp, ctx->tp); } #if NETTLE_USE_MINI_GMP @@ -300,9 +321,19 @@ bench_curve (const struct ecc_curve *ecc) #else modinv_powm = 0; #endif - dup_jj = time_function (bench_dup_jj, &ctx); - add_jja = time_function (bench_add_jja, &ctx); - add_jjj = time_function (bench_add_jjj, &ctx); + if (ecc->bit_size == 255) + { + /* For now, curve25519 is a special case */ + dup_jj = time_function (bench_dup_eh, &ctx); + add_jja = time_function (bench_add_eh, &ctx); + add_jjj = time_function (bench_add_ehh, &ctx); + } + else + { + dup_jj = time_function (bench_dup_jj, &ctx); + add_jja = time_function (bench_add_jja, &ctx); + add_jjj = time_function (bench_add_jjj, &ctx); + } mul_g = time_function (bench_mul_g, &ctx); mul_a = time_function (bench_mul_a, &ctx); @@ -321,6 +352,7 @@ bench_curve (const struct ecc_curve *ecc) const struct ecc_curve * const curves[] = { &nettle_secp_192r1, &nettle_secp_224r1, + &nettle_curve25519, &nettle_secp_256r1, &nettle_secp_384r1, &nettle_secp_521r1, diff --git a/gmp-glue.c b/gmp-glue.c index 754a849b5ec3b19bddeae70c24feccc80bc009c1..013c4cfa0dd60a8af3d12604538665749570fd4e 100644 --- a/gmp-glue.c +++ b/gmp-glue.c @@ -227,6 +227,68 @@ mpn_set_base256 (mp_limb_t *rp, mp_size_t rn, } } +void +mpn_set_base256_le (mp_limb_t *rp, mp_size_t rn, + const uint8_t *xp, size_t xn) +{ + size_t xi; + mp_limb_t out; + unsigned bits; + for (xi = 0, out = bits = 0; xi < xn && rn > 0; ) + { + mp_limb_t in = xp[xi++]; + out |= (in << bits) & GMP_NUMB_MASK; + bits += 8; + if (bits >= GMP_NUMB_BITS) + { + *rp++ = out; + rn--; + + bits -= GMP_NUMB_BITS; + out = in >> (8 - bits); + } + } + if (rn > 0) + { + *rp++ = out; + if (--rn > 0) + mpn_zero (rp, rn); + } +} + +void +mpn_get_base256_le (uint8_t *rp, size_t rn, + const mp_limb_t *xp, mp_size_t xn) +{ + unsigned bits; + mp_limb_t in; + for (bits = in = 0; xn > 0 && rn > 0; ) + { + if (bits >= 8) + { + *rp++ = in; + rn--; + in >>= 8; + bits -= 8; + } + else + { + uint8_t old = in; + in = *xp++; + xn--; + *rp++ = old | (in << bits); + in >>= (8 - bits); + bits += GMP_NUMB_BITS - 8; + } + } + while (rn > 0) + { + *rp++ = in; + rn--; + in >>= 8; + } +} + mp_limb_t * gmp_alloc_limbs (mp_size_t n) { diff --git a/gmp-glue.h b/gmp-glue.h index 69663de695251e31004df83b69d33c3aa2ab172a..f9e149ada64b92b18ede13aeb81e39d332422aeb 100644 --- a/gmp-glue.h +++ b/gmp-glue.h @@ -71,6 +71,8 @@ #define mpz_limbs_copy _nettle_mpz_limbs_copy #define mpz_set_n _nettle_mpz_set_n #define mpn_set_base256 _nettle_mpn_set_base256 +#define mpn_set_base256_le _nettle_mpn_set_base256_le +#define mpn_get_base256_le _nettle_mpn_get_base256_le #define gmp_alloc_limbs _nettle_gmp_alloc_limbs #define gmp_free_limbs _nettle_gmp_free_limbs #define gmp_free _nettle_gmp_free @@ -153,7 +155,7 @@ mpz_limbs_read_n (mpz_ptr x, mp_size_t n); /* Copy limbs, with zero-padding. */ /* FIXME: Reorder arguments, on the theory that the first argument of - an _mpz_* fucntion should be an mpz_t? Or rename to _mpz_get_limbs, + an _mpz_* function should be an mpz_t? Or rename to _mpz_get_limbs, with argument order consistent with mpz_get_*. */ void mpz_limbs_copy (mp_limb_t *xp, mpz_srcptr x, mp_size_t n); @@ -167,6 +169,14 @@ void mpn_set_base256 (mp_limb_t *rp, mp_size_t rn, const uint8_t *xp, size_t xn); +void +mpn_set_base256_le (mp_limb_t *rp, mp_size_t rn, + const uint8_t *xp, size_t xn); + +void +mpn_get_base256_le (uint8_t *rp, size_t rn, + const mp_limb_t *xp, mp_size_t xn); + mp_limb_t * gmp_alloc_limbs (mp_size_t n); diff --git a/mini-gmp.c b/mini-gmp.c index b9186951cbb5f8039d60a43cde33b9ab2ae06325..acbe1becd8718cc2fa4f39241b8c5efeae8f44a6 100644 --- a/mini-gmp.c +++ b/mini-gmp.c @@ -3569,7 +3569,7 @@ mpz_abs_sub_bit (mpz_t d, mp_bitcnt_t bit_index) gmp_assert_nocarry (mpn_sub_1 (dp + limb_index, dp + limb_index, dn - limb_index, bit)); - dn -= (dp[dn-1] == 0); + dn = mpn_normalized_size (dp, dn); d->_mp_size = (d->_mp_size < 0) ? - dn : dn; } diff --git a/misc/.gitignore b/misc/.gitignore index 2bd18fa44c50410f251ef0996354f6ef19fcd381..81c83739da1c867d63bc801fa28079c3c3151f1b 100644 --- a/misc/.gitignore +++ b/misc/.gitignore @@ -1 +1,5 @@ /*.pdf +/*.dvi +/*.log +/*.aux +/auto diff --git a/misc/ecc-formulas.tex b/misc/ecc-formulas.tex new file mode 100644 index 0000000000000000000000000000000000000000..46740d1cf26dad0a893af4f963c1f93de30512d3 --- /dev/null +++ b/misc/ecc-formulas.tex @@ -0,0 +1,225 @@ +\documentclass[a4paper]{article} +\usepackage[utf8]{inputenc} +\usepackage{amsmath} +\usepackage{url} + +\author{Niels Möller} +\title{Notes on ECC formulas} + +\begin{document} + +\maketitle + +\section{Weierstrass curve} + +Consider only the special case +\begin{equation*} + y^2 = x^3 - 3x + b \pmod{p} +\end{equation*} +See \url{http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html}. + +Affine formulas for duplication, $(x_2, y_2) = 2(x_1, y_1)$: +\begin{align*} + t &= (2y)^{-1} 3 (x_1^2 - 1) \\ + x_2 &= t^2 - 2 x_1 \\ + y_2 &= (x_1 - x_2) * t - y_1 +\end{align*} +Affine formulas for addition, $(x_3, y_3) = (x_1, y_1) + (x_2, +y_2)$: +\begin{align*} + t &= (x_2 - x_1)^{-1} (y_2 - y_1) \\ + x_3 &= t^2 - x_1 - x_2 \\ + y_3 &= (x_1 - x_3) t - y_1 +\end{align*} + +\section{Montgomery curve} + +Consider the special case +\begin{equation*} + y^2 = x^3 + b x^2 + x +\end{equation*} +See \url{http://www.hyperelliptic.org/EFD/g1p/auto-montgom.html}. + +Affine formulas for duplication, $(x_2, y_2) = 2(x_1, y_1)$: +\begin{align*} + t &= (2 y_1)^{-1} (3 x_1^2 + 2b x_1 + 1) \\ + x_2 &= t^2 - b - 2 x_1 \\ + y_2 &= (3 x_1 + b) t - t^3 - y_1 \\ + &= (3 x_1 + b - t^2) t - y_1 \\ + &= (x_1 - x_2) t - y_1 +\end{align*} +So the computation is very similar to the Weierstraß case, differing +only in the formula for $t$, and the $b$ term in $x_2$. + +Affine formulas for addition, $(x_3, y_3) = (x_1, y_1) + (x_2, +y_2)$: +\begin{align*} + t &= (x_2 - x_1)^{-1} (y_2 - y_1) \\ + x_3 &= t^2 - b - x_1 - x_2 \\ + y_3 &= (2 x_1 + x_2 + b) t - t^3 - y_1 \\ + &= (2 x_1 + x_2 + b - t^2) t - y_1 \\ + &= (x_1 - x_3) t - y_1 +\end{align*} +Again, very similar to the Weierstraß formulas, with only an +additional $b$ term in the formula for $x_3$. + +\section{Edwards curve} + +For an Edwards curve, we consider the special case +\begin{equation*} + x^2 + y^2 = 1 + d x^2 y^2 +\end{equation*} +See \url{http://cr.yp.to/papers.html#newelliptic}. + +Affine formulas for addition, $(x_3, y_3) = (x_1, y_1) + (x_2, +y_2)$: +\begin{align*} + t &= d x_1 x_2 y_1 y_2 \\ + x_3 &= (1 + t)^{-1} (x_1 y_2 + y_1 x_2) \\ + y_3 &= (1 - t)^{-1} (y_1 y_2 - x_1 x_2) +\end{align*} +With homogeneous coordinates $(X_1, Y_1, Z_1)$ etc., D.~J.~Bernstein +suggests the formulas +\begin{align*} + A &= Z_1 Z_2 \\ + B &= A^2 \\ + C &= X_1 X_2 \\ + D &= Y_1 Y_2 \\ + E &= d C D \\ + F &= B - E \\ + G &= B + E \\ + X_3 &= A F [(X_1 + Y_1)(X_2 + Y_2) - C - D] \\ + Y_3 &= A G (D - C) \\ + Z_3 &= F G +\end{align*} +This works also for doubling, but a more efficient variant is +\begin{align*} + B &= (X_1 + Y_1)^2 \\ + C &= X_1^2 \\ + D &= Y_1^2 \\ + E &= C + D \\ + H &= Z_1^2 \\ + J &= E - 2H \\ + X_3 &= (B - E) J \\ + Y_3 &= E (C - D) \\ + Z_3 &= E J +\end{align*} + +\section{EdDSA} + +The EdDSA paper (\url{http://ed25519.cr.yp.to/ed25519-20110926.pdf}) +suggests using the twisted Edwards curve, +\begin{equation*} + -x^2 + y^2 = 1 + d x^2 y^2 \pmod{p} +\end{equation*} +Assuming -1 has a square root modulo $p$, a point $(x, y)$ lies on +this curve if and only if $(\sqrt{-1} x, p)$ lies of the non-twisted +Edwards curve. The point additin formulas for the twisted Edwards +curve are +\begin{align*} + t &= d x_1 x_2 y_1 y_2 \\ + x_3 &= (1 + t)^{-1} (x_1 y_2 + y_1 x_2) \\ + y_3 &= (1 - t)^{-1} (y_1 y_2 + x_1 x_2) +\end{align*} +For the other formulas, it should be fine to just switch the sign of +terms involving $x_1 x_2$ or $x_1^2$. The paper suggests further +optimizations: For precomputed points, use the representation $(x-y, +x+y, dxy)$. And for temporary points, maintain an additional redundant +coordinate $T$, with $Z T = X Y$ (see +\url{http://eprint.iacr.org/2008/522.pdf}). + +\section{Curve25519} + +Curve25519 is defined as the Montgomery curve +\begin{equation*} + y^2 = x^3 + b x^2 + x \pmod p +\end{equation*} +with $b = 486662$ and $p = 2^{255} -19$. It is equivalent to the +Edwards curve +\begin{equation*} + u^2 + v^2 = 1 + d u^2 v^2 \pmod p +\end{equation*} +with $d = (121665/121666) \bmod p$. The equivalence is given by +mapping $P = (x,y)$ to $P' = (u, v)$, as follows. +\begin{itemize} +\item $P = \infty$ corresponds to $P' = (0, 1)$ +\item $P = (0, 0)$ corresponds to $P' = (0, -1)$ +\item Otherwise, for all other points on the curve. First note that $x + \neq -1$ (since then the right hand side is a not a quadratic + residue), and that $y \neq 0$ (since $y = 0$ and $x \neq 0$ implies + that $x^2 + bx + 1 = 0$, or $(x + b/2)^2 = (b/2)^2 - 1$, which also + isn't a quadratic residue). The correspondence is then given by + \begin{align*} + u &= \sqrt{b+2} \, x / y \\ + v &= (x-1) / (x+1) + \end{align*} +\end{itemize} + +The inverse transformation is +\begin{align*} + x &= (1+v) / (1-v) \\ + y &= \sqrt{b+2} \, x / u +\end{align*} +If the Edwards coordinates are represented using homogeneous +coordinates, $u = U/W$ and $v = V/W$, then +\begin{align*} + x &= \frac{W+V}{W-V} \\ + y &= \sqrt{b} \frac{(W+V) W}{(W-V) U} +\end{align*} +so we need to invert the value $(W-V) U$. + +\subsection{Transforms for the twisted Edwards Curve} + +If we use the twisted Edwards curve instead, let $\alpha = \sqrt{-1} +\pmod{p}$. Then we work with coordinates $(u', v)$, where $u' = \alpha +u$. The transform from Montgomery form $(x, y)$ is then +\begin{align*} + u &= (\alpha \sqrt{b+2}) \, x / y\\ + v &= (x-1) / (x+1) +\end{align*} +And the inverse transform is similarly +\begin{align*} + x &= (1+v) / (1-v) \\ + y &= (\alpha \sqrt{b+2}) \, x / u +\end{align*} +so it's just a change of the transform constant, effectively using +$\sqrt{-(b+2)}$ instead. + +\subsection{Coordinates outside of the base field} + +The curve25519 function is defined with an input point represented by +the $x$-coordinate only, and is specified as allowing any value. The +corresponding $y$ coordinate is given by +\begin{equation*} + y = \sqrt{x^3 + b x^2 + x} \pmod p +\end{equation*} +whenever this square root exists. But what if it doesn't? Then we work +with the curve over the extended field $F_{p^2}$. Let $n$ by any +non-square, then $(x^3 + b x^2 + x) n$ is a square, and we get the +$y = y' / \sqrt{n}$ with +\begin{equation*} + y' = \sqrt{(x^3 + b x^2 + x) n} +\end{equation*} +It happens that for all multiples of such a point, this same factor is +tacked on to all the $y$-coordinates, while all the $x$-coordinates +remain in the base field $F_p$. It's the ``twist'' curve $y'^2 / n = +x^3 + bx^2 + x$. On the corresponding Edwards curve, we +get $u = \sqrt{n} u'$ with +\begin{equation*} + u' = \sqrt{b+2} \, x / y' +\end{equation*} +and the addition formula +\begin{align*} + t &= d n u'_1 u'_2 v_1 v_2 \\ + u'_3 &= (1+t)^{-1}(u'_1v_2 + v_1 u'_2) \\ + v_3 &= (1-t)^{-1}(v_1 v_2 - n u'_1 u'_2) +\end{align*} +It seems a bit tricky to handle both types of point in a single +function without speed penalty, due to the conditional factor of $n$ +in the formula for $v_3$. +\end{document} + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: t +%%% End: diff --git a/misc/ecc-ref.gp b/misc/ecc-ref.gp new file mode 100644 index 0000000000000000000000000000000000000000..7ef732593350dc353f6a6779f088f62bdcd535d7 --- /dev/null +++ b/misc/ecc-ref.gp @@ -0,0 +1,121 @@ +/* Script for pari/gp. Run as gp -q ecc-ref.gp */ + +out(apriv, A, bpriv, B, S) = print( \ + "/* a_s */ \"", apriv, "\",\n", \ + "/* a_x */ \"", component(A[1], 2), "\",\n", \ + "/* a_y */ \"", component(A[2], 2), "\",\n", \ + "/* b_s */ \"", bpriv, "\",\n", \ + "/* b_x */ \"", component(B[1], 2), "\",\n", \ + "/* b_y */ \"", component(B[2], 2), "\",\n", \ + "/* s_x */ \"", component(S[1], 2), "\",\n", \ + "/* s_y */ \"", component(S[2], 2), "\","); + +p192 = 2^192 - 2^64 - 1; +b192 = 2455155546008943817740293915197451784769108058161191238065; +g = Mod([602046282375688656758213480587526111916698976636884684818, \ + 174050332293622031404857552280219410364023488927386650641], p192); +secp192 = ellinit(Mod([0,0,0,-3, b192], p192)); +q = 6277101735386680763835789423176059013767194773182842284081; +if (ellpow(secp192, g, q) != [0], error("secp192 parameter error")); + +a = 1+random(q-1); +b = 1+random(q-1); +A = ellpow(secp192, g, a); +B = ellpow(secp192, g, b); +S = ellpow(secp192, A, b); +if (S != ellpow(secp192, B, a), error("secp192 dh error")); +print("secp192"); +out(a, A, b, B, S); + +p224 = 2^224 - 2^96 + 1; +b224 = 18958286285566608000408668544493926415504680968679321075787234672564; +g = Mod([19277929113566293071110308034699488026831934219452440156649784352033,\ + 19926808758034470970197974370888749184205991990603949537637343198772], p224); + +secp224 = ellinit(Mod([0,0,0,-3, b224], p224)); +q = 26959946667150639794667015087019625940457807714424391721682722368061; +if (ellpow(secp224, g, q) != [0], error("secp224 parameter error")); + +a = 1+random(q-1); +b = 1+random(q-1); +A = ellpow(secp224, g, a); +B = ellpow(secp224, g, b); +S = ellpow(secp224, A, b); +if (S != ellpow(secp224, B, a), error("secp224 dh error")); +print("secp224"); +out(a, A, b, B, S); + +p256 = 2^256 - 2^224 + 2^192 + 2^96 - 1; +b256 = 41058363725152142129326129780047268409114441015993725554835256314039467401291; +g = Mod([48439561293906451759052585252797914202762949526041747995844080717082404635286,\ + 36134250956749795798585127919587881956611106672985015071877198253568414405109], p256); + +secp256 = ellinit(Mod([0,0,0,-3, b256], p256)); +q = 115792089210356248762697446949407573529996955224135760342422259061068512044369; +if (ellpow(secp256, g, q) != [0], error("secp256 parameter error")); + +a = 1+random(q-1); +b = 1+random(q-1); +A = ellpow(secp256, g, a); +B = ellpow(secp256, g, b); +S = ellpow(secp256, A, b); +if (S != ellpow(secp256, B, a), error("secp256 dh error")); +print("secp256"); +out(a, A, b, B, S); + +p384 = 2^384 - 2^128 - 2^96 + 2^32 - 1; +b384 = 27580193559959705877849011840389048093056905856361568521428707301988689241309860865136260764883745107765439761230575; +g = Mod([26247035095799689268623156744566981891852923491109213387815615900925518854738050089022388053975719786650872476732087,\ + 8325710961489029985546751289520108179287853048861315594709205902480503199884419224438643760392947333078086511627871], p384); + +secp384 = ellinit(Mod([0,0,0,-3, b384], p384)); +q = 39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643; +if (ellpow(secp384, g, q) != [0], error("secp384 parameter error")); + +a = 1+random(q-1); +b = 1+random(q-1); +A = ellpow(secp384, g, a); +B = ellpow(secp384, g, b); +S = ellpow(secp384, A, b); +if (S != ellpow(secp384, B, a), error("secp384 dh error")); +print("secp384"); +out(a, A, b, B, S); + +p521 = 2^521 - 1; +b521 = 1093849038073734274511112390766805569936207598951683748994586394495953116150735016013708737573759623248592132296706313309438452531591012912142327488478985984; +g = Mod([2661740802050217063228768716723360960729859168756973147706671368418802944996427808491545080627771902352094241225065558662157113545570916814161637315895999846,\ + 3757180025770020463545507224491183603594455134769762486694567779615544477440556316691234405012945539562144444537289428522585666729196580810124344277578376784], p521); + +secp521 = ellinit(Mod([0,0,0,-3, b521], p521)); +q = 6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449; +if (ellpow(secp521, g, q) != [0], error("secp521 parameter error")); + +a = 1+random(q-1); +b = 1+random(q-1); +A = ellpow(secp521, g, a); +B = ellpow(secp521, g, b); +S = ellpow(secp521, A, b); +if (S != ellpow(secp521, B, a), error("secp521 dh error")); +print("secp521"); +out(a, A, b, B, S); + +p25519 = 2^255 - 19; +b25519 = 486662; +x = Mod(9, p25519); +y = sqrt(x^3 + b25519*x^2 + x); +g = [x, y]; + +curve25519 = ellinit(Mod([0, b25519, 0, 1, 0], p25519)); +q = 2^252 + 27742317777372353535851937790883648493; +if (ellpow(curve25519, g, q) != [0], error("curve25519 parameter error")); + +a = 1+random(q-1); +b = 1+random(q-1); +A = ellpow(curve25519, g, a); +B = ellpow(curve25519, g, b); +S = ellpow(curve25519, A, b); +if (S != ellpow(curve25519, B, a), error("curve25519 dh error")); +print("curve25519"); +out(a, A, b, B, S); + +quit diff --git a/sec-modinv.c b/sec-modinv.c index 6c7253df4ab6107af2d998c72b8387db0f771211..ea94abd3ac85810de14f264179221ecde99d5e30 100644 --- a/sec-modinv.c +++ b/sec-modinv.c @@ -71,6 +71,7 @@ cnd_swap (int cnd, mp_limb_t *ap, mp_limb_t *bp, mp_size_t n) } /* Compute a^{-1} mod m, with running time depending only on the size. + Returns zero if a == 0 (mod m), to be consistent with a^{phi(m)-1}. Also needs (m+1)/2, and m must be odd. */ void sec_modinv (mp_limb_t *vp, mp_limb_t *ap, mp_size_t n, diff --git a/testsuite/.test-rules.make b/testsuite/.test-rules.make index 8fc7ed415637f356605e453d2d700fd2d341c07c..59a9c0fa70c8d0445fb4c24c82fbbe48d7b88e03 100644 --- a/testsuite/.test-rules.make +++ b/testsuite/.test-rules.make @@ -187,6 +187,15 @@ dsa-test$(EXEEXT): dsa-test.$(OBJEXT) dsa-keygen-test$(EXEEXT): dsa-keygen-test.$(OBJEXT) $(LINK) dsa-keygen-test.$(OBJEXT) $(TEST_OBJS) -o dsa-keygen-test$(EXEEXT) +curve25519-dup-test$(EXEEXT): curve25519-dup-test.$(OBJEXT) + $(LINK) curve25519-dup-test.$(OBJEXT) $(TEST_OBJS) -o curve25519-dup-test$(EXEEXT) + +curve25519-add-test$(EXEEXT): curve25519-add-test.$(OBJEXT) + $(LINK) curve25519-add-test.$(OBJEXT) $(TEST_OBJS) -o curve25519-add-test$(EXEEXT) + +curve25519-dh-test$(EXEEXT): curve25519-dh-test.$(OBJEXT) + $(LINK) curve25519-dh-test.$(OBJEXT) $(TEST_OBJS) -o curve25519-dh-test$(EXEEXT) + ecc-mod-test$(EXEEXT): ecc-mod-test.$(OBJEXT) $(LINK) ecc-mod-test.$(OBJEXT) $(TEST_OBJS) -o ecc-mod-test$(EXEEXT) @@ -211,6 +220,9 @@ ecdsa-verify-test$(EXEEXT): ecdsa-verify-test.$(OBJEXT) ecdsa-keygen-test$(EXEEXT): ecdsa-keygen-test.$(OBJEXT) $(LINK) ecdsa-keygen-test.$(OBJEXT) $(TEST_OBJS) -o ecdsa-keygen-test$(EXEEXT) +ecdh-test$(EXEEXT): ecdh-test.$(OBJEXT) + $(LINK) ecdh-test.$(OBJEXT) $(TEST_OBJS) -o ecdh-test$(EXEEXT) + sha1-huge-test$(EXEEXT): sha1-huge-test.$(OBJEXT) $(LINK) sha1-huge-test.$(OBJEXT) $(TEST_OBJS) -o sha1-huge-test$(EXEEXT) diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in index 34c43087352198a134da532f5162645caed9a4b2..6109a669cc0dd6c5226fb678f4c236ff7dd5d093 100644 --- a/testsuite/Makefile.in +++ b/testsuite/Makefile.in @@ -38,9 +38,12 @@ TS_HOGWEED_SOURCES = sexp-test.c sexp-format-test.c \ pkcs1-test.c \ rsa-test.c rsa-encrypt-test.c rsa-keygen-test.c \ dsa-test.c dsa-keygen-test.c \ + curve25519-dup-test.c curve25519-add-test.c \ + curve25519-dh-test.c \ ecc-mod-test.c ecc-modinv-test.c ecc-redc-test.c \ ecc-mul-g-test.c ecc-mul-a-test.c \ - ecdsa-sign-test.c ecdsa-verify-test.c ecdsa-keygen-test.c + ecdsa-sign-test.c ecdsa-verify-test.c \ + ecdsa-keygen-test.c ecdh-test.c TS_SOURCES = $(TS_NETTLE_SOURCES) $(TS_HOGWEED_SOURCES) CXX_SOURCES = cxx-test.cxx diff --git a/testsuite/curve25519-add-test.c b/testsuite/curve25519-add-test.c new file mode 100644 index 0000000000000000000000000000000000000000..cee6b51df2ebed7a94be9c771128c72e57350284 --- /dev/null +++ b/testsuite/curve25519-add-test.c @@ -0,0 +1,136 @@ +#include "testutils.h" + +static int +point_zero_p (const struct ecc_curve *ecc, const mp_limb_t *p) +{ + mp_limb_t *d; + int ret; + mp_size_t i; + d = xalloc_limbs (ecc->size); + ecc_modp_sub (ecc, d, p + ecc->size, p + 2*ecc->size); + while (mpn_cmp (d, ecc->p, ecc->size) >= 0) + mpn_sub_n (d, d, ecc->p, ecc->size); + + for (i = 0, ret = 1; i < ecc->size; i++) + if (d[i]) + { + ret = 0; + break; + } + + free (d); + return ret; +} + +void +test_main (void) +{ + const struct ecc_curve *ecc = &nettle_curve25519; + mp_limb_t *g; + mp_limb_t *z; + mp_limb_t *g2; + mp_limb_t *g3; + mp_limb_t *g4; + mp_limb_t *pe; + mp_limb_t *pa; + mp_limb_t *scratch; + const struct ecc_ref_point rg = + { + "9", + "20ae19a1b8a086b4e01edd2c7748d14c923d4d7e6d7c61b229e9c5a27eced3d9" + }; + const struct ecc_ref_point rg2 = + { /* In Edwards coordinates: + x = 0x1a1c31f8665368131698fecfd54233fcdc638bb46d25cc61d8bc4bcdbfbb4459, + y = 0x2260cdf3092329c21da25ee8c9a21f5697390f51643851560e5f46ae6af8a3c9 + */ + "20d342d51873f1b7d9750c687d157114" + "8f3f5ced1e350b5c5cae469cdd684efb", + "13b57e011700e8ae050a00945d2ba2f3" + "77659eb28d8d391ebcd70465c72df563" + }; + const struct ecc_ref_point rg3 = + { + "1c12bc1a6d57abe645534d91c21bba64" + "f8824e67621c0859c00a03affb713c12", + "2986855cbe387eaeaceea446532c338c" + "536af570f71ef7cf75c665019c41222b" + }; + const struct ecc_ref_point rg4 = + { + "79ce98b7e0689d7de7d1d074a15b315f" + "fe1805dfcd5d2a230fee85e4550013ef", + "075af5bf4ebdc75c8fe26873427d275d" + "73c0fb13da361077a565539f46de1c30" + }; + + g = xalloc_limbs (ecc_size_j (ecc)); + z = xalloc_limbs (ecc_size_j (ecc)); + g2 = xalloc_limbs (ecc_size_j (ecc)); + g3 = xalloc_limbs (ecc_size_j (ecc)); + g4 = xalloc_limbs (ecc_size_j (ecc)); + pe = xalloc_limbs (ecc_size_j (ecc)); + pa = xalloc_limbs (ecc_size_j (ecc)); + scratch = xalloc_limbs (ECC_ADD_EHH_ITCH(ecc->size)); + + mpn_copyi (g, ecc->g, 2*ecc->size); + g[2*ecc->size] = 1; + mpn_zero (g+2*ecc->size + 1, ecc->size - 1); + + /* Zero point has x = 0, y = 1, z = 1 */ + mpn_zero (z, 3*ecc->size); + z[ecc->size] = z[2*ecc->size] = 1; + + ecc_add_ehh (ecc, pe, z, z, scratch); + if (!point_zero_p (ecc, pe)) + die ("dup of zero point failed.\n"); + + ecc_add_eh (ecc, pe, z, z, scratch); + if (!point_zero_p (ecc, pe)) + die ("dup of zero point failed.\n"); + + ecc_add_ehh (ecc, pe, g, pe, scratch); + ecc_eh_to_a (ecc, 0, pa, pe, scratch); + test_ecc_point (ecc, &rg, pa); + + ecc_add_eh (ecc, pe, z, g, scratch); + ecc_eh_to_a (ecc, 0, pa, pe, scratch); + test_ecc_point (ecc, &rg, pa); + + ecc_add_ehh (ecc, g2, g, pe, scratch); + ecc_eh_to_a (ecc, 0, pa, g2, scratch); + test_ecc_point (ecc, &rg2, pa); + + ecc_add_eh (ecc, g2, g, g, scratch); + ecc_eh_to_a (ecc, 0, pa, g2, scratch); + test_ecc_point (ecc, &rg2, pa); + + ecc_add_ehh (ecc, g3, g, g2, scratch); + ecc_eh_to_a (ecc, 0, pa, g3, scratch); + test_ecc_point (ecc, &rg3, pa); + + ecc_add_eh (ecc, g3, g2, g, scratch); + ecc_eh_to_a (ecc, 0, pa, g3, scratch); + test_ecc_point (ecc, &rg3, pa); + + ecc_add_ehh (ecc, g4, g, g3, scratch); + ecc_eh_to_a (ecc, 0, pa, g4, scratch); + test_ecc_point (ecc, &rg4, pa); + + ecc_add_eh (ecc, g4, g3, g, scratch); + ecc_eh_to_a (ecc, 0, pa, g4, scratch); + test_ecc_point (ecc, &rg4, pa); + + ecc_add_ehh (ecc, g4, g2, g2, scratch); + ecc_eh_to_a (ecc, 0, pa, g4, scratch); + test_ecc_point (ecc, &rg4, pa); + + free (g); + free (z); + free (g2); + free (g3); + free (g4); + free (pe); + free (pa); + free (scratch); +} diff --git a/testsuite/curve25519-dh-test.c b/testsuite/curve25519-dh-test.c new file mode 100644 index 0000000000000000000000000000000000000000..cd075d9952f76fedb7d424f3aabff3ecd2cf980c --- /dev/null +++ b/testsuite/curve25519-dh-test.c @@ -0,0 +1,111 @@ +/* curve25519-dh-test.c + + Copyright (C) 2014 Niels Möller + + 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/. +*/ + +#include "testutils.h" + +#include "curve25519.h" + +static void +test_g (const uint8_t *s, const uint8_t *r) +{ + uint8_t p[CURVE25519_SIZE]; + curve25519_mul_g (p, s); + if (!MEMEQ (CURVE25519_SIZE, p, r)) + { + printf ("curve25519_mul_g failure:\ns = "); + print_hex (CURVE25519_SIZE, s); + printf ("\np = "); + print_hex (CURVE25519_SIZE, p); + printf (" (bad)\nr = "); + print_hex (CURVE25519_SIZE, r); + printf (" (expected)\n"); + abort (); + } +} + +static void +test_a (const uint8_t *s, const uint8_t *b, const uint8_t *r) +{ + uint8_t p[CURVE25519_SIZE]; + if (!curve25519_mul (p, s, b)) + { + printf ("curve25519_mul returned 0:\ns = "); + print_hex (CURVE25519_SIZE, s); + printf ("\nb = "); + print_hex (CURVE25519_SIZE, b); + printf ("\n"); + abort (); + } + + if (!MEMEQ (CURVE25519_SIZE, p, r)) + { + printf ("curve25519_mul failure:\ns = "); + print_hex (CURVE25519_SIZE, s); + printf ("\nb = "); + print_hex (CURVE25519_SIZE, b); + printf ("\np = "); + print_hex (CURVE25519_SIZE, p); + printf (" (bad)\nr = "); + print_hex (CURVE25519_SIZE, r); + printf (" (expected)\n"); + abort (); + } +} + +void +test_main (void) +{ + /* From draft-turner-thecurve25519function-00 (same also in + draft-josefsson-tls-curve25519-05, but the latter uses different + endianness). */ + test_g (H("77076d0a7318a57d3c16c17251b26645" + "df4c2f87ebc0992ab177fba51db92c2a"), + H("8520f0098930a754748b7ddcb43ef75a" + "0dbf3a0d26381af4eba4a98eaa9b4e6a")); + test_g (H("5dab087e624a8a4b79e17f8b83800ee6" + "6f3bb1292618b6fd1c2f8b27ff88e0eb"), + H("de9edb7d7b7dc1b4d35b61c2ece43537" + "3f8343c85b78674dadfc7e146f882b4f")); + + test_a (H("77076d0a7318a57d3c16c17251b26645" + "df4c2f87ebc0992ab177fba51db92c2a"), + H("de9edb7d7b7dc1b4d35b61c2ece43537" + "3f8343c85b78674dadfc7e146f882b4f"), + H("4a5d9d5ba4ce2de1728e3bf480350f25" + "e07e21c947d19e3376f09b3c1e161742")); + + test_a (H("5dab087e624a8a4b79e17f8b83800ee6" + "6f3bb1292618b6fd1c2f8b27ff88e0eb"), + H("8520f0098930a754748b7ddcb43ef75a" + "0dbf3a0d26381af4eba4a98eaa9b4e6a"), + H("4a5d9d5ba4ce2de1728e3bf480350f25" + "e07e21c947d19e3376f09b3c1e161742")); +} diff --git a/testsuite/curve25519-dup-test.c b/testsuite/curve25519-dup-test.c new file mode 100644 index 0000000000000000000000000000000000000000..2490900b4637d66102b9922f35a30c0aecd1f2d8 --- /dev/null +++ b/testsuite/curve25519-dup-test.c @@ -0,0 +1,85 @@ +#include "testutils.h" + +static int +point_zero_p (const struct ecc_curve *ecc, const mp_limb_t *p) +{ + mp_limb_t *d; + int ret; + mp_size_t i; + d = xalloc_limbs (ecc->size); + ecc_modp_sub (ecc, d, p + ecc->size, p + 2*ecc->size); + while (mpn_cmp (d, ecc->p, ecc->size) >= 0) + mpn_sub_n (d, d, ecc->p, ecc->size); + + for (i = 0, ret = 1; i < ecc->size; i++) + if (d[i]) + { + ret = 0; + break; + } + + free (d); + return ret; +} + +void +test_main (void) +{ + const struct ecc_curve *ecc = &nettle_curve25519; + mp_limb_t *g; + mp_limb_t *z; + mp_limb_t *pe; + mp_limb_t *pa; + mp_limb_t *scratch; + const struct ecc_ref_point g2 = + { /* In Edwards coordinates: + x = 0x1a1c31f8665368131698fecfd54233fcdc638bb46d25cc61d8bc4bcdbfbb4459, + y = 0x2260cdf3092329c21da25ee8c9a21f5697390f51643851560e5f46ae6af8a3c9 + */ + "20d342d51873f1b7d9750c687d157114" + "8f3f5ced1e350b5c5cae469cdd684efb", + "13b57e011700e8ae050a00945d2ba2f3" + "77659eb28d8d391ebcd70465c72df563" + }; + const struct ecc_ref_point g4 = + { + "79ce98b7e0689d7de7d1d074a15b315f" + "fe1805dfcd5d2a230fee85e4550013ef", + "075af5bf4ebdc75c8fe26873427d275d" + "73c0fb13da361077a565539f46de1c30" + }; + + g = xalloc_limbs (ecc_size_j (ecc)); + z = xalloc_limbs (ecc_size_j (ecc)); + pe = xalloc_limbs (ecc_size_j (ecc)); + pa = xalloc_limbs (ecc_size_j (ecc)); + scratch = xalloc_limbs (ECC_DUP_EH_ITCH(ecc->size)); + + mpn_copyi (g, ecc->g, 2*ecc->size); + g[2*ecc->size] = 1; + mpn_zero (g+2*ecc->size + 1, ecc->size - 1); + + /* Zero point has x = 0, y = 1, z = 1 */ + mpn_zero (z, 3*ecc->size); + z[ecc->size] = z[2*ecc->size] = 1; + + ecc_dup_eh (ecc, pe, z, scratch); + if (!point_zero_p (ecc, pe)) + die ("dup of zero point failed.\n"); + + ecc_dup_eh (ecc, pe, g, scratch); + + ecc_eh_to_a (ecc, 0, pa, pe, scratch); + test_ecc_point (ecc, &g2, pa); + + ecc_dup_eh (ecc, pe, pe, scratch); + + ecc_eh_to_a (ecc, 0, pa, pe, scratch); + test_ecc_point (ecc, &g4, pa); + + free (g); + free (z); + free (pe); + free (pa); + free (scratch); +} diff --git a/testsuite/ecc-mod-test.c b/testsuite/ecc-mod-test.c index 5caee758081ee79c39e9de1e5576f116e590c7c6..c8af4a722b6a19fc4c1e04acb58a1decb9e3ade1 100644 --- a/testsuite/ecc-mod-test.c +++ b/testsuite/ecc-mod-test.c @@ -19,106 +19,110 @@ ref_mod (mp_limb_t *rp, const mp_limb_t *ap, const mp_limb_t *mp, mp_size_t mn) #define MAX_SIZE (2*MAX_ECC_SIZE) #define COUNT 50000 -void -test_main (void) +static void +test_curve (gmp_randstate_t rands, const struct ecc_curve *ecc) { - gmp_randstate_t rands; mp_limb_t a[MAX_SIZE]; mp_limb_t m[MAX_SIZE]; mp_limb_t ref[MAX_SIZE]; - unsigned i; mpz_t r; + unsigned j; - gmp_randinit_default (rands); - mpz_init (r); - for (i = 0; ecc_curves[i]; i++) + for (j = 0; j < COUNT; j++) { - const struct ecc_curve *ecc = ecc_curves[i]; - unsigned j; - for (j = 0; j < COUNT; j++) - { - if (j & 1) - mpz_rrandomb (r, rands, 2*ecc->size * GMP_NUMB_BITS); - else - mpz_urandomb (r, rands, 2*ecc->size * GMP_NUMB_BITS); + if (j & 1) + mpz_rrandomb (r, rands, 2*ecc->size * GMP_NUMB_BITS); + else + mpz_urandomb (r, rands, 2*ecc->size * GMP_NUMB_BITS); - mpz_limbs_copy (a, r, 2*ecc->size); + mpz_limbs_copy (a, r, 2*ecc->size); - ref_mod (ref, a, ecc->p, ecc->size); + ref_mod (ref, a, ecc->p, ecc->size); + mpn_copyi (m, a, 2*ecc->size); + ecc->modp (ecc, m); + if (mpn_cmp (m, ecc->p, ecc->size) >= 0) + mpn_sub_n (m, m, ecc->p, ecc->size); + + if (mpn_cmp (m, ref, ecc->size)) + { + fprintf (stderr, "ecc->modp failed: bit_size = %u\n", + ecc->bit_size); + gmp_fprintf (stderr, "a = %Nx\n", a, 2*ecc->size); + gmp_fprintf (stderr, "m = %Nx (bad)\n", m, ecc->size); + gmp_fprintf (stderr, "ref = %Nx\n", ref, ecc->size); + abort (); + } + + if (ecc->Bmodp_size < ecc->size) + { mpn_copyi (m, a, 2*ecc->size); - ecc->modp (ecc, m); + ecc_generic_modp (ecc, m); if (mpn_cmp (m, ecc->p, ecc->size) >= 0) mpn_sub_n (m, m, ecc->p, ecc->size); if (mpn_cmp (m, ref, ecc->size)) { - fprintf (stderr, "ecc->modp failed: bit_size = %u\n", + fprintf (stderr, "ecc_generic_modp failed: bit_size = %u\n", ecc->bit_size); gmp_fprintf (stderr, "a = %Nx\n", a, 2*ecc->size); gmp_fprintf (stderr, "m = %Nx (bad)\n", m, ecc->size); gmp_fprintf (stderr, "ref = %Nx\n", ref, ecc->size); abort (); } + } - if (ecc->Bmodp_size < ecc->size) - { - mpn_copyi (m, a, 2*ecc->size); - ecc_generic_modp (ecc, m); - if (mpn_cmp (m, ecc->p, ecc->size) >= 0) - mpn_sub_n (m, m, ecc->p, ecc->size); - - if (mpn_cmp (m, ref, ecc->size)) - { - fprintf (stderr, "ecc_generic_modp failed: bit_size = %u\n", - ecc->bit_size); - gmp_fprintf (stderr, "a = %Nx\n", a, 2*ecc->size); - gmp_fprintf (stderr, "m = %Nx (bad)\n", m, ecc->size); - gmp_fprintf (stderr, "ref = %Nx\n", ref, ecc->size); - abort (); - } - } + ref_mod (ref, a, ecc->q, ecc->size); - ref_mod (ref, a, ecc->q, ecc->size); + mpn_copyi (m, a, 2*ecc->size); + ecc->modq (ecc, m); + if (mpn_cmp (m, ecc->q, ecc->size) >= 0) + mpn_sub_n (m, m, ecc->q, ecc->size); + if (mpn_cmp (m, ref, ecc->size)) + { + fprintf (stderr, "ecc->modq failed: bit_size = %u\n", + ecc->bit_size); + gmp_fprintf (stderr, "a = %Nx\n", a, 2*ecc->size); + gmp_fprintf (stderr, "m = %Nx (bad)\n", m, ecc->size); + gmp_fprintf (stderr, "ref = %Nx\n", ref, ecc->size); + abort (); + } + if (ecc->Bmodq_size < ecc->size) + { mpn_copyi (m, a, 2*ecc->size); - ecc->modq (ecc, m); + ecc_generic_modq (ecc, m); if (mpn_cmp (m, ecc->q, ecc->size) >= 0) mpn_sub_n (m, m, ecc->q, ecc->size); if (mpn_cmp (m, ref, ecc->size)) { - fprintf (stderr, "ecc->modq failed: bit_size = %u\n", + fprintf (stderr, "ecc_generic_modp failed: bit_size = %u\n", ecc->bit_size); gmp_fprintf (stderr, "a = %Nx\n", a, 2*ecc->size); gmp_fprintf (stderr, "m = %Nx (bad)\n", m, ecc->size); gmp_fprintf (stderr, "ref = %Nx\n", ref, ecc->size); abort (); } - - if (ecc->Bmodq_size < ecc->size) - { - mpn_copyi (m, a, 2*ecc->size); - ecc_generic_modq (ecc, m); - if (mpn_cmp (m, ecc->q, ecc->size) >= 0) - mpn_sub_n (m, m, ecc->q, ecc->size); - - if (mpn_cmp (m, ref, ecc->size)) - { - fprintf (stderr, "ecc_generic_modp failed: bit_size = %u\n", - ecc->bit_size); - gmp_fprintf (stderr, "a = %Nx\n", a, 2*ecc->size); - gmp_fprintf (stderr, "m = %Nx (bad)\n", m, ecc->size); - gmp_fprintf (stderr, "ref = %Nx\n", ref, ecc->size); - abort (); - } - } } } - mpz_clear (r); +} + +void +test_main (void) +{ + gmp_randstate_t rands; + unsigned i; + + gmp_randinit_default (rands); + + for (i = 0; ecc_curves[i]; i++) + test_curve (rands, ecc_curves[i]); + + test_curve (rands, &nettle_curve25519); gmp_randclear (rands); } #endif /* ! NETTLE_USE_MINI_GMP */ diff --git a/testsuite/ecc-modinv-test.c b/testsuite/ecc-modinv-test.c index 31b5c27e934ecf72b0cd24e809bea55a1eaa6a76..ee4267dc811a6bbdb1bb47843f1292a7a79cb10d 100644 --- a/testsuite/ecc-modinv-test.c +++ b/testsuite/ecc-modinv-test.c @@ -37,6 +37,17 @@ ref_modinv (mp_limb_t *rp, const mp_limb_t *ap, const mp_limb_t *mp, mp_size_t m #define MAX_ECC_SIZE (1 + 521 / GMP_NUMB_BITS) #define COUNT 500 +static int +mpn_zero_p (mp_srcptr ap, mp_size_t n) +{ + while (--n >= 0) + { + if (ap[n] != 0) + return 0; + } + return 1; +} + void test_main (void) { @@ -55,6 +66,36 @@ test_main (void) { const struct ecc_curve *ecc = ecc_curves[i]; unsigned j; + /* Check behaviour for zero input */ + mpn_zero (a, ecc->size); + memset (ai, 17, ecc->size * sizeof(*ai)); + ecc_modp_inv (ecc, ai, a, scratch); + if (!mpn_zero_p (ai, ecc->size)) + { + fprintf (stderr, "ecc_modp_inv failed for zero input (bit size %u):\n", + ecc->bit_size); + gmp_fprintf (stderr, "p = %Nx\n" + "t = %Nx (bad)\n", + ecc->p, ecc->size, + ai, ecc->size); + abort (); + } + + /* Check behaviour for a = p */ + mpn_copyi (a, ecc->p, ecc->size); + memset (ai, 17, ecc->size * sizeof(*ai)); + ecc_modp_inv (ecc, ai, a, scratch); + if (!mpn_zero_p (ai, ecc->size)) + { + fprintf (stderr, "ecc_modp_inv failed for a = p input (bit size %u):\n", + ecc->bit_size); + gmp_fprintf (stderr, "p = %Nx\n" + "t = %Nx (bad)\n", + ecc->p, ecc->size, + ai, ecc->size); + abort (); + } + for (j = 0; j < COUNT; j++) { if (j & 1) diff --git a/testsuite/ecc-mul-a-test.c b/testsuite/ecc-mul-a-test.c index eef09c725f018721862ff142fb0ce9be9fb642c9..e182aacc44e45e0fe126590bf45ff1d95276d4e0 100644 --- a/testsuite/ecc-mul-a-test.c +++ b/testsuite/ecc-mul-a-test.c @@ -31,34 +31,21 @@ test_main (void) mpn_zero (n, size); n[0] = 1; - ecc_mul_a (ecc, 1, p, n, ecc->g, scratch); + ecc_mul_a (ecc, p, n, ecc->g, scratch); ecc_j_to_a (ecc, 1, p, p, scratch); if (mpn_cmp (p, ecc->g, 2*size != 0)) die ("curve %d: ecc_mul_a with n = 1 failed.\n", ecc->bit_size); - if (ecc->use_redc) - { - ecc_mul_a (ecc, 0, p, n, ecc->redc_g, scratch); - ecc_j_to_a (ecc, 1, p, p, scratch); - - if (mpn_cmp (p, ecc->g, 2*size != 0)) - die ("curve %d: ecc_mul_a with n = 1 and redc failed.\n", ecc->bit_size); - } for (n[0] = 2; n[0] <= 4; n[0]++) { - ecc_mul_a (ecc, 1, p, n, ecc->g, scratch); + ecc_mul_a (ecc, p, n, ecc->g, scratch); test_ecc_mul_j (i, n[0], p); - if (ecc->use_redc) - { - ecc_mul_a (ecc, 0, p, n, ecc->redc_g, scratch); - test_ecc_mul_j (i, n[0], p); - } } /* (order - 1) * g = - g */ mpn_sub_1 (n, ecc->q, size, 1); - ecc_mul_a (ecc, 1, p, n, ecc->g, scratch); + ecc_mul_a (ecc, p, n, ecc->g, scratch); ecc_j_to_a (ecc, 1, p, p, scratch); mpn_sub_n (p + size, ecc->p, p + size, size); if (mpn_cmp (p, ecc->g, 2*size) != 0) @@ -80,7 +67,7 @@ test_main (void) mpz_limbs_copy (n, r, size); n[size - 1] %= ecc->q[size - 1]; - ecc_mul_a (ecc, 1, p, n, ecc->g, scratch); + ecc_mul_a (ecc, p, n, ecc->g, scratch); ecc_j_to_a (ecc, 1, p, p, scratch); ecc_mul_g (ecc, q, n, scratch); diff --git a/testsuite/ecdh-test.c b/testsuite/ecdh-test.c new file mode 100644 index 0000000000000000000000000000000000000000..14f013993895eeb5ff9b2635869c5137ecc8709c --- /dev/null +++ b/testsuite/ecdh-test.c @@ -0,0 +1,203 @@ +/* ecdh-test.c + + Copyright (C) 2014 Niels Möller + + 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/. +*/ + +#include "testutils.h" + +static void +set_point (struct ecc_point *p, + const char *x, const char *y) +{ + mpz_t X, Y; + mpz_init_set_str (X, x, 0); + mpz_init_set_str (Y, y, 0); + if (!ecc_point_set (p, X, Y)) + die ("Test point not on curve!\n"); + + mpz_clear (X); + mpz_clear (Y); +} + +static void +set_scalar (struct ecc_scalar *s, + const char *x) +{ + mpz_t X; + mpz_init_set_str (X, x, 0); + ecc_scalar_set (s, X); + mpz_clear (X); +} + +static void +check_point (const char *name, const char *label, + const struct ecc_point *P, + const struct ecc_point *R) +{ + mpz_t px, py, rx, ry; + + mpz_init (px); + mpz_init (py); + mpz_init (rx); + mpz_init (ry); + + ecc_point_get (P, px, py); + ecc_point_get (R, rx, ry); + + /* FIXME: Should have a public point compare function */ + if (mpz_cmp (px, rx) != 0 || mpz_cmp (py, ry) != 0) + { + fprintf (stderr, "Failed %s %s\np_x = ", name, label); + mpz_out_str (stderr, 10, px); + fprintf (stderr, "\nr_x = "); + mpz_out_str (stderr, 10, rx); + fprintf (stderr, " (expected)\np_y = "); + mpz_out_str (stderr, 10, py); + fprintf (stderr, "\nr_y = "); + mpz_out_str (stderr, 10, ry); + fprintf (stderr, " (expected)\n"); + abort (); + } + mpz_clear (px); + mpz_clear (py); + mpz_clear (rx); + mpz_clear (ry); +} + +static void +test_dh (const char *name, const struct ecc_curve *ecc, + const char *a_priv, const char *ax, const char *ay, + const char *b_priv, const char *bx, const char *by, + const char *sx, const char *sy) +{ + struct ecc_point A, B, S, T; + struct ecc_scalar A_priv, B_priv; + + ecc_scalar_init (&A_priv, ecc); + set_scalar (&A_priv, a_priv); + ecc_point_init (&A, ecc); + set_point (&A, ax, ay); + + ecc_scalar_init (&B_priv, ecc); + set_scalar (&B_priv, b_priv); + ecc_point_init (&B, ecc); + set_point (&B, bx, by); + + ecc_point_init (&S, ecc); + set_point (&S, sx, sy); + + ecc_point_init (&T, ecc); + + ecc_point_mul_g (&T, &A_priv); + check_point (name, "a g", &T, &A); + + ecc_point_mul (&T, &B_priv, &T); + check_point (name, "b (a g)", &T, &S); + + ecc_point_mul_g (&T, &B_priv); + check_point (name, "b g", &T, &B); + + ecc_point_mul (&T, &A_priv, &T); + check_point (name, "a (b g)", &T, &S); + + ecc_scalar_clear (&A_priv); + ecc_scalar_clear (&B_priv); + + ecc_point_clear (&A); + ecc_point_clear (&B); + ecc_point_clear (&S); + ecc_point_clear (&T); +} + +void +test_main(void) +{ + test_dh ("secp-192r1", &nettle_secp_192r1, + "3406157206141798348095184987208239421004566462391397236532", + "1050363442265225480786760666329560655512990381040021438562", + "5298249600854377235107392014200406283816103564916230704184", + "738368960171459956677260317271477822683777845013274506165", + "2585840779771604687467445319428618542927556223024046979917", + "293088185788565313717816218507714888251468410990708684573", + "149293809021051532782730990145509724807636529827149481690", + "2891131861147398318714693938158856874319184314120776776192"); + + test_dh ("secp-224r1", &nettle_secp_224r1, + "1321072106881784386340709783538698930880431939595776773514895067682", + "6768311794185371282972144247871764855860666277647541840973645586477", + "2880077809069104378181313860274147139049600284805670362929579614547", + "13934723037778859565852601874354272638301919827851286722006496784914", + "373124771833407982305885866158843810218322878380632071540538232035", + "24223309755162432227459925493224336241652868856405241018762887667883", + "8330362698029245839097779050425944245826040430538860338085968752913", + "24167244512472228715617822000878192535267113543393576038737592837010"); + + test_dh ("secp-256r1", &nettle_secp_256r1, + "94731533361265297353914491124013058635674217345912524033267198103710636378786", + "22441589863306126152768848344973918725077248391248404659242620344938484650846", + "8673475622926171928656873398933611700804732317466515884933832073457396747355", + "97657865959185011849283028361556797595752581630732610898393589042714626616209", + "18453500628354973083413728373777272885280811435138222441593126858566687017580", + "14365748655141740924607822284126054269177292284541187981786689038777833170313", + "102958799567030688009123101477538973715497039396202015119148334812951370853564", + "29188877854984806245046208182450375893010623119030341548941791125497546766367"); + + test_dh ("secp-384r1", &nettle_secp_384r1, + "39086550219018474560700767788227987514008150214902287969462741484831311917159729009715909108606822193356890811565070", + "15536343869384820642787280162462493474000839389760580357050317691132784247078954166759523572989472049798969369413707", + "23268351460749985365652822073294615614961429585671989812206213135127969284347174876010177880230302801199500921999966", + "36869963309577906178833120963925446333578086292605692048464445726274368063284094788012795873582576522541658781990645", + "6571571183519639697971973492227725184968062063941037806786906539419849188357322949908539215960508669158121817812397", + "36555212611228586427448926841660565534959679681904941933188284044726925984417589749068550977832780023128545833460008", + "27780263733159299625371532605243698753833039933618994121416145881861678645978369807598146716869504289033472077532789", + "12327518461490664021199432424728005314646140038116972426756705356672414772151215711157356913456651047992140493843405"); + + test_dh ("secp-521r1", &nettle_secp_521r1, + "1177787298234877762125077260641419691552146813662613924864132680693789861345339466386194840381422980702458955378518702648732728796955434922249345867267377826", + "3168153642368000846168628288850857848098131369578410603904155841373678828215434925507474033105518841999665785152501356092020415699294327720257651796364374116", + "278603899104240796379373331240296114411332466119196525390128418935585486485808560319073463912513286987331907013829243645911963547435764718505394265715321106", + "4632844957395758597246278843156350179301194123641664447791935593091018103746003967476919616681982477804041933745387575872964923485212972039478646226080044590", + "3278857364905061449863537070675297207767865967146919975942590789168732752489407699106980407552332044280575891715425195464227794423128203118286002006478070253", + "4488572162727491199625798812850846214916160870437505769058530973184916706326908828109446998319674522651965593412129100088877891410841200092694907512496020182", + "2126311732129869456512627735193938710331935978955001830871465201548004444073866677974896970734635601049909886616595755762740651165670628002084824920216966370", + "4803556648772727869384704240411011976585308117802975396033423138930126997561438092192867119930177133880625991019440171972612468402200399449807843995563872782"); + + /* NOTE: This isn't quite the standard way to do curve25519 + diffie-hellman, but it tests that the ecc_point interface works + also with curve25519. FIXME: Which it doesn't yet do. */ + test_dh ("curve25519", &nettle_curve25519, + "238301186166219052901200372289459967515481170332211409964804596991365959539", + "16689431791973914300519294566135927090340942991104989847654071982531922134636", + "20308418066388251043787233144732111482161260158474210903552303016733832642783", + "3795950278952272509684177709511717492358770264218705926196469999516028451559", + "33748673775975978547568270043630771161978032265709185964960751948965332685487", + "45040108202870901856797106334440548809561721639881101469282515918034252408802", + "12684624775789228333626692483521764247362476074160626230698999100180553618972", + "22635121008463339848034566659860493350277619617839914078958064757823336329514"); +} diff --git a/testsuite/testutils.c b/testsuite/testutils.c index a5f67f9d885f64c180478d2394e704d18b94f9a6..9739c9ed8d7bbd7ce2edc25613d1068f47eaaf00 100644 --- a/testsuite/testutils.c +++ b/testsuite/testutils.c @@ -1276,12 +1276,6 @@ test_mpn (const char *ref, const mp_limb_t *xp, mp_size_t n) return res; } -struct ecc_ref_point -{ - const char *x; - const char *y; -}; - void write_mpn (FILE *f, int base, const mp_limb_t *xp, mp_size_t n) { @@ -1289,7 +1283,7 @@ write_mpn (FILE *f, int base, const mp_limb_t *xp, mp_size_t n) mpz_out_str (f, base, mpz_roinit_n (t,xp, n)); } -static void +void test_ecc_point (const struct ecc_curve *ecc, const struct ecc_ref_point *ref, const mp_limb_t *p) diff --git a/testsuite/testutils.h b/testsuite/testutils.h index 4768f9964240389e6ad998aca235bffbdef34e3d..b2b77b165f6532518d96021f489bb2f1c0199bee 100644 --- a/testsuite/testutils.h +++ b/testsuite/testutils.h @@ -224,6 +224,17 @@ test_dsa_key(const struct dsa_params *params, extern const struct ecc_curve * const ecc_curves[]; +struct ecc_ref_point +{ + const char *x; + const char *y; +}; + +void +test_ecc_point (const struct ecc_curve *ecc, + const struct ecc_ref_point *ref, + const mp_limb_t *p); + void test_ecc_mul_a (unsigned curve, unsigned n, const mp_limb_t *p); diff --git a/x86_64/ecc-25519-modp.asm b/x86_64/ecc-25519-modp.asm new file mode 100644 index 0000000000000000000000000000000000000000..b1622d5f1a72e3b0da5af60db6f265b4fc206d79 --- /dev/null +++ b/x86_64/ecc-25519-modp.asm @@ -0,0 +1,94 @@ +C x86_64/ecc-25519-modp.asm + +ifelse(< + Copyright (C) 2014 Niels Möller + + 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/. +>) + + .file "ecc-25519-modp.asm" + +define(<RP>, <%rsi>) +define(<U0>, <%rdi>) C Overlaps unused ecc input +define(<U1>, <%rcx>) +define(<U2>, <%r8>) +define(<U3>, <%r9>) +define(<T0>, <%r10>) +define(<T1>, <%r11>) +define(<M>, <%rbx>) + +PROLOGUE(nettle_ecc_25519_modp) + W64_ENTRY(2, 0) + push %rbx + + C First fold the limbs affecting bit 255 + mov 56(RP), %rax + mov $38, M + mul M + mov 24(RP), U3 + xor T0, T0 + add %rax, U3 + adc %rdx, T0 + + mov 40(RP), %rax C Do this early as possible + mul M + + add U3, U3 + adc T0, T0 + shr U3 C Undo shift, clear high bit + + C Fold the high limb again, together with RP[5] + imul $19, T0 + + mov (RP), U0 + mov 8(RP), U1 + mov 16(RP), U2 + add T0, U0 + adc %rax, U1 + mov 32(RP), %rax + adc %rdx, U2 + adc $0, U3 + + C Fold final two limbs, RP[4] and RP[6] + mul M + mov %rax, T0 + mov 48(RP), %rax + mov %rdx, T1 + mul M + add T0, U0 + mov U0, (RP) + adc T1, U1 + mov U1, 8(RP) + adc %rax, U2 + mov U2, 16(RP) + adc %rdx, U3 + mov U3, 24(RP) + + pop %rbx + W64_EXIT(2, 0) + ret +EPILOGUE(nettle_ecc_25519_modp)