Merge branch 'curve25519'
authorNiels Möller <nisse@lysator.liu.se>
Wed, 27 Aug 2014 11:47:02 +0000 (13:47 +0200)
committerNiels Möller <nisse@lysator.liu.se>
Wed, 27 Aug 2014 11:47:02 +0000 (13:47 +0200)
49 files changed:
ChangeLog
Makefile.in
configure.ac
curve25519-mul-g.c [new file with mode: 0644]
curve25519-mul.c [new file with mode: 0644]
curve25519.h [new file with mode: 0644]
ecc-192.c
ecc-224.c
ecc-25519.c [new file with mode: 0644]
ecc-256.c
ecc-384.c
ecc-521.c
ecc-a-to-eh.c [new file with mode: 0644]
ecc-a-to-j.c
ecc-add-eh.c [new file with mode: 0644]
ecc-add-ehh.c [new file with mode: 0644]
ecc-curve.h
ecc-dup-eh.c [new file with mode: 0644]
ecc-ecdsa-verify.c
ecc-eh-to-a.c [new file with mode: 0644]
ecc-internal.h
ecc-mul-a-eh.c [new file with mode: 0644]
ecc-mul-a.c
ecc-mul-g-eh.c [new file with mode: 0644]
ecc-point-mul-g.c
ecc-point-mul.c
ecc-point.c
ecc.h
eccdata.c
examples/ecc-benchmark.c
gmp-glue.c
gmp-glue.h
mini-gmp.c
misc/.gitignore
misc/ecc-formulas.tex [new file with mode: 0644]
misc/ecc-ref.gp [new file with mode: 0644]
sec-modinv.c
testsuite/.test-rules.make
testsuite/Makefile.in
testsuite/curve25519-add-test.c [new file with mode: 0644]
testsuite/curve25519-dh-test.c [new file with mode: 0644]
testsuite/curve25519-dup-test.c [new file with mode: 0644]
testsuite/ecc-mod-test.c
testsuite/ecc-modinv-test.c
testsuite/ecc-mul-a-test.c
testsuite/ecdh-test.c [new file with mode: 0644]
testsuite/testutils.c
testsuite/testutils.h
x86_64/ecc-25519-modp.asm [new file with mode: 0644]

index aab10bb1aa776f3fb36f45b8ba650a296db78e15..3fde054b6d475f23551bfe31592475f4e689aa4c 100644 (file)
--- 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.
index b4082110a9dcdd43f4cc7eb89a7dfbfbd19696c7..d637087262676440bb349de605234efec69e39c2 100644 (file)
@@ -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
 
index 6923d3a3514fba48e359d407f018db20f1f5e4b1..ddee35c775c2314ab28ec9084212d2d6a4bf7767 100644 (file)
@@ -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 (file)
index 0000000..f98bee3
--- /dev/null
@@ -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 (file)
index 0000000..ddc50eb
--- /dev/null
@@ -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 (file)
index 0000000..bcf579d
--- /dev/null
@@ -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 */
index 2af501fa32503bc690d92c602dfbe41ad88d1196..29ff7f6a2ee00aff90ea2fae4905d052e3583790 100644 (file)
--- 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,
index 6ed2365b1e75947065272775389d1b46c8c99599..8a99f0e38ad0ca5894d024e3e7c85e733c21948f 100644 (file)
--- 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 (file)
index 0000000..3cbc60e
--- /dev/null
@@ -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
+};
index 2f2297e67c4d6d20c6958983d6e04e2d0c4e15f1..f888aafef92510ae555fad9e547ed5598ef4ec30 100644 (file)
--- 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,
index 8bfcb2145e6d2ca55db79d407cf4669798e9cf59..c20d8ab425dce7073e314b912a81e0911568b029 100644 (file)
--- 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,
index fc84dfe6501acec0c52f1d1e7252c0349a630bee..821c77c769681d7760cc0ea3bbfc9fe27187b7f1 100644 (file)
--- 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 (file)
index 0000000..7f77394
--- /dev/null
@@ -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);
+}
index 5f7cc6877c0905ab70c859ed609c4014cb1ae8d0..36e4d150383bb4be6b3ea6650f9be7ce83a71716 100644 (file)
 
 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 (file)
index 0000000..a3471b2
--- /dev/null
@@ -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 (file)
index 0000000..b009d84
--- /dev/null
@@ -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);
+}
index b5f0f975dfd8f3a28f313d097b6da106582f68ea..df72569c01da39095bdf8147b4ad4b571c61c6af 100644 (file)
@@ -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 (file)
index 0000000..7065063
--- /dev/null
@@ -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);
+}
index 6337d7bad24e0cc30f250b9507788438835a412e..1310b3125c206ad1ae9ba6135b3fc0bcbd0ca2a4 100644 (file)
@@ -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 (file)
index 0000000..fd953bf
--- /dev/null
@@ -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);
+}
index aae2fba4aea6bb6e77304d36790b481cef2574a0..d9e107303d092b722bf8cf5103c43dac28c84c14 100644 (file)
 #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 (file)
index 0000000..1e9f4fc
--- /dev/null
@@ -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 */
index 17bc6d2585f8a11dcb3f7a55aff5aee16bdb3f9c..82f72e65540ad35317040a38b5aaffb36bdacfd3 100644 (file)
@@ -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 (file)
index 0000000..4242479
--- /dev/null
@@ -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
+}
index 8186bf2c9746453161f2d0460c44b7ff657ea071..bb9a2d760f48174ccb7903b2b1c967bc532773dc 100644 (file)
@@ -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);
 }
index d8329cf5112538e342dac44bed03c860b74c7923..2080b60815bcadeb1d91e615c91dd03f3e32b87a 100644 (file)
@@ -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);
 }
index 448b17b16e524e4e755a625d739c44392178dd86..60fbd080c22b3f8f37c12789d8df792c25c1393d 100644 (file)
@@ -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 (file)
--- 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
index 4e17f9ac64b9db8a9600a026d6b78f7a8fe7ddc3..9069e61082467bb099788373755bb1f9b9d71737 100644 (file)
--- 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.
 
 
 #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");
index 0153b74460c5a0b2e8bcd4d44f698725cda942b3..6fc4860d3659df8b453c5f9056170dffd29350e0 100644 (file)
@@ -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,
index 754a849b5ec3b19bddeae70c24feccc80bc009c1..013c4cfa0dd60a8af3d12604538665749570fd4e 100644 (file)
@@ -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)
 {
index 69663de695251e31004df83b69d33c3aa2ab172a..f9e149ada64b92b18ede13aeb81e39d332422aeb 100644 (file)
@@ -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);
index b9186951cbb5f8039d60a43cde33b9ab2ae06325..acbe1becd8718cc2fa4f39241b8c5efeae8f44a6 100644 (file)
@@ -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;
 }
 
index 2bd18fa44c50410f251ef0996354f6ef19fcd381..81c83739da1c867d63bc801fa28079c3c3151f1b 100644 (file)
@@ -1 +1,5 @@
 /*.pdf
+/*.dvi
+/*.log
+/*.aux
+/auto
diff --git a/misc/ecc-formulas.tex b/misc/ecc-formulas.tex
new file mode 100644 (file)
index 0000000..46740d1
--- /dev/null
@@ -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 (file)
index 0000000..7ef7325
--- /dev/null
@@ -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
index 6c7253df4ab6107af2d998c72b8387db0f771211..ea94abd3ac85810de14f264179221ecde99d5e30 100644 (file)
@@ -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,
index 8fc7ed415637f356605e453d2d700fd2d341c07c..59a9c0fa70c8d0445fb4c24c82fbbe48d7b88e03 100644 (file)
@@ -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)
 
index 34c43087352198a134da532f5162645caed9a4b2..6109a669cc0dd6c5226fb678f4c236ff7dd5d093 100644 (file)
@@ -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 (file)
index 0000000..cee6b51
--- /dev/null
@@ -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 (file)
index 0000000..cd075d9
--- /dev/null
@@ -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 (file)
index 0000000..2490900
--- /dev/null
@@ -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);
+}
index 5caee758081ee79c39e9de1e5576f116e590c7c6..c8af4a722b6a19fc4c1e04acb58a1decb9e3ade1 100644 (file)
@@ -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 */
index 31b5c27e934ecf72b0cd24e809bea55a1eaa6a76..ee4267dc811a6bbdb1bb47843f1292a7a79cb10d 100644 (file)
@@ -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)
index eef09c725f018721862ff142fb0ce9be9fb642c9..e182aacc44e45e0fe126590bf45ff1d95276d4e0 100644 (file)
@@ -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 (file)
index 0000000..14f0139
--- /dev/null
@@ -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");
+}
index a5f67f9d885f64c180478d2394e704d18b94f9a6..9739c9ed8d7bbd7ce2edc25613d1068f47eaaf00 100644 (file)
@@ -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)
index 4768f9964240389e6ad998aca235bffbdef34e3d..b2b77b165f6532518d96021f489bb2f1c0199bee 100644 (file)
@@ -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 (file)
index 0000000..b1622d5
--- /dev/null
@@ -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)