diff --git a/ChangeLog b/ChangeLog
index 592080810503c9c1a84960940d6d9dcdad69bcaa..fc0a9395ccd1527de0a0d3f640370f4788d95531 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,35 @@
 2013-02-15  Niels Möller  <nisse@lysator.liu.se>
 
+	Integrate ECC internals.
+	* ecc-curve.h: New file.
+	* ecc-internal.h: New file.
+	* cnd-copy.c: New file.
+	* ecc-192.c: New file.
+	* ecc-224.c: New file.
+	* ecc-256.c: New file.
+	* ecc-384.c: New file.
+	* ecc-521.c: New file.
+	* ecc-generic-modp.c: New file.
+	* ecc-generic-modq.c: New file.
+	* ecc-generic-redc.c: New file.
+	* ecc-mod.c: New file.
+	* ecc-modp.c: New file.
+	* ecc-modq.c: New file.
+	* sec-add-1.c: New file.
+	* sec-modinv.c: New file.
+	* sec-sub-1.c: New file.
+	* Makefile.in (hogweed_SOURCES): Added new files.
+	(HEADERS): Added ecc-curve.h.
+	(DISTFILES): Added ecc-internal.h.
+	* testsuite/ecc-mod-test.c: New file.
+	* testsuite/ecc-modinv-test.c: New file.
+	* testsuite/ecc-redc-test.c: New file.
+	* testsuite/testutils.c (ecc_curves): New constant array.
+	* testsuite/testutils.h: Include ecc-related headers. Declare
+	ecc_curves array.
+	* testsuite/Makefile.in (TS_HOGWEED_SOURCES): Added ecc-mod-test.c
+	ecc-modinv-test.c ecc-redc-test.c.
+
 	* gmp-glue.c: New file, mpn <-> mpz conversions.
 	* gmp-glue.h: New file.
 	* Makefile.in: Added to hogweed_SOURCES and DISTFILES, respectively.
diff --git a/Makefile.in b/Makefile.in
index 7d219d50afab7b3302739c79aba16118546b3d5f..b6c469209bd25004ee381af2320c1c6c387c8735 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -123,21 +123,24 @@ hogweed_SOURCES = sexp.c sexp-format.c \
 		  dsa2sexp.c sexp2dsa.c \
 		  pgp-encode.c rsa2openpgp.c \
 		  der-iterator.c der2rsa.c der2dsa.c \
-		  gmp-glue.c
+		  sec-add-1.c sec-sub-1.c sec-modinv.c sec-tabselect.c \
+		  gmp-glue.c cnd-copy.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
 
 HEADERS = aes.h arcfour.h arctwo.h asn1.h bignum.h blowfish.h \
 	  base16.h base64.h buffer.h camellia.h cast128.h \
-	  cbc.h ctr.h gcm.h \
-	  des.h des-compat.h dsa.h \
-	  hmac.h \
-	  pbkdf2.h \
+	  cbc.h ctr.h \
+	  des.h des-compat.h dsa.h ecc-curve.h \
+	  gcm.h gosthash94.h hmac.h \
 	  knuth-lfib.h \
 	  macros.h \
 	  md2.h md4.h \
-	  gosthash94.h \
 	  md5.h md5-compat.h \
 	  memxor.h \
 	  nettle-meta.h nettle-types.h \
+	  pbkdf2.h \
 	  pgp.h pkcs1.h realloc.h ripemd160.h rsa.h rsa-compat.h \
 	  salsa20.h sexp.h \
 	  serpent.h sha.h sha1.h sha2.h sha3.h twofish.h \
@@ -160,7 +163,7 @@ DISTFILES = $(SOURCES) $(HEADERS) getopt.h .bootstrap run-tests \
 	aes-internal.h camellia-internal.h serpent-internal.h \
 	cast128_sboxes.h desinfo.h desCode.h \
 	nettle-internal.h nettle-write.h prime-list.h \
-	gmp-glue.h \
+	gmp-glue.h ecc-internal.h \
 	asm.m4 \
 	nettle.texinfo nettle.info nettle.html nettle.pdf sha-example.c
 
diff --git a/cnd-copy.c b/cnd-copy.c
new file mode 100644
index 0000000000000000000000000000000000000000..002e44eab332d6bd0c1f0017c7e8b76310502432
--- /dev/null
+++ b/cnd-copy.c
@@ -0,0 +1,42 @@
+/* cnd-copy.c */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2013 Niels Möller
+ *
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+/* Development of Nettle's ECC support was funded by Internetfonden. */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "ecc-internal.h"
+
+void
+cnd_copy (int cnd, mp_limb_t *rp, const mp_limb_t *ap, mp_size_t n)
+{
+  mp_limb_t mask, keep;
+  mp_size_t i;
+
+  mask = -(mp_limb_t) (cnd !=0);
+  keep = ~mask;
+
+  for (i = 0; i < n; i++)
+    rp[i] = (rp[i] & keep) + (ap[i] & mask);
+}
diff --git a/ecc-192.c b/ecc-192.c
new file mode 100644
index 0000000000000000000000000000000000000000..e379a99b271a800f9ed66a11a7d396a8ec9018cf
--- /dev/null
+++ b/ecc-192.c
@@ -0,0 +1,124 @@
+/* ecc-192.c */
+
+/* Compile time constant (but machine dependent) tables. */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2013 Niels Möller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+/* Development of Nettle's ECC support was funded by Internetfonden. */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include "ecc-internal.h"
+
+#define USE_REDC 0
+
+#include "ecc-192.h"
+
+/* Use that p = 2^{192} - 2^64 - 1, to eliminate 128 bits at a time. */
+
+#if GMP_NUMB_BITS == 32
+/* p is 6 limbs, p = B^6 - B^2 - 1 */
+static void
+ecc_192_modp (const struct ecc_curve *ecc UNUSED, mp_limb_t *rp)
+{
+  mp_limb_t cy;
+
+  /* Reduce from 12 to 9 limbs (top limb small)*/
+  cy = mpn_add_n (rp + 2, rp + 2, rp + 8, 4);
+  cy = sec_add_1 (rp + 6, rp + 6, 2, cy);
+  cy += mpn_add_n (rp + 4, rp + 4, rp + 8, 4);
+  assert (cy <= 2);
+
+  rp[8] = cy;
+
+  /* Reduce from 9 to 6 limbs */
+  cy = mpn_add_n (rp, rp, rp + 6, 3);
+  cy = sec_add_1 (rp + 3, rp + 3, 2, cy);
+  cy += mpn_add_n (rp + 2, rp + 2, rp + 6, 3);
+  cy = sec_add_1 (rp + 5, rp + 5, 1, cy);
+  
+  assert (cy <= 1);
+  cy = cnd_add_n (cy, rp, ecc_Bmodp, 3);
+  assert (cy == 0);  
+}
+#elif GMP_NUMB_BITS == 64
+/* p is 3 limbs, p = B^3 - B - 1 */
+static void
+ecc_192_modp (const struct ecc_curve *ecc UNUSED, mp_limb_t *rp)
+{
+  mp_limb_t cy;
+
+  /* Reduce from 6 to 5 limbs (top limb small)*/
+  cy = mpn_add_n (rp + 1, rp + 1, rp + 4, 2);
+  cy = sec_add_1 (rp + 3, rp + 3, 1, cy);
+  cy += mpn_add_n (rp + 2, rp + 2, rp + 4, 2);
+  assert (cy <= 2);
+
+  rp[4] = cy;
+
+  /* Reduce from 5 to 4 limbs (high limb small) */
+  cy = mpn_add_n (rp, rp, rp + 3, 2);
+  cy = sec_add_1 (rp + 2, rp + 2, 1, cy);
+  cy += mpn_add_n (rp + 1, rp + 1, rp + 3, 2);
+
+  assert (cy <= 1);
+  cy = cnd_add_n (cy, rp, ecc_Bmodp, 3);
+  assert (cy == 0);  
+}
+  
+#else
+#define ecc_192_modp ecc_generoc_modp
+#endif
+
+const struct ecc_curve nettle_secp_192r1 =
+{
+  192,
+  ECC_LIMB_SIZE,
+  ECC_BMODP_SIZE,
+  ECC_BMODQ_SIZE,
+  USE_REDC,
+  ECC_REDC_SIZE,
+  ECC_PIPPENGER_K,
+  ECC_PIPPENGER_C,
+  ecc_p,
+  ecc_b,
+  ecc_q,
+  ecc_g,
+  ecc_redc_g,
+  ecc_192_modp,
+  ecc_generic_redc,
+  ecc_192_modp,
+  ecc_generic_modq,
+  ecc_Bmodp,
+  ecc_Bmodp_shifted,
+  ecc_pp1h,
+  ecc_redc_ppm1,
+  ecc_unit,
+  ecc_Bmodq,
+  ecc_Bmodq_shifted,
+  ecc_qp1h,
+  ecc_table
+};
+
diff --git a/ecc-224.c b/ecc-224.c
new file mode 100644
index 0000000000000000000000000000000000000000..07e30893a581b034158c01ed817cda4e110bf5a2
--- /dev/null
+++ b/ecc-224.c
@@ -0,0 +1,65 @@
+/* ecc-224.c.c */
+
+/* Compile time constant (but machine dependent) tables. */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2013 Niels Möller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+/* Development of Nettle's ECC support was funded by Internetfonden. */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "ecc-internal.h"
+
+#define USE_REDC (ECC_REDC_SIZE != 0)
+
+#include "ecc-224.h"
+
+const struct ecc_curve nettle_secp_224r1 =
+{
+  224,
+  ECC_LIMB_SIZE,    
+  ECC_BMODP_SIZE,
+  ECC_BMODQ_SIZE,
+  USE_REDC,
+  ECC_REDC_SIZE,
+  ECC_PIPPENGER_K,
+  ECC_PIPPENGER_C,
+  ecc_p,
+  ecc_b,
+  ecc_q,
+  ecc_g,
+  ecc_redc_g,
+  ecc_generic_modp,
+  ecc_generic_redc,
+  USE_REDC ? ecc_generic_redc : ecc_generic_modp,
+  ecc_generic_modq,
+  ecc_Bmodp,
+  ecc_Bmodp_shifted,
+  ecc_pp1h,
+  ecc_redc_ppm1,
+  ecc_unit,
+  ecc_Bmodq,
+  ecc_Bmodq_shifted,
+  ecc_qp1h,
+  ecc_table
+};
diff --git a/ecc-256.c b/ecc-256.c
new file mode 100644
index 0000000000000000000000000000000000000000..56e356e4442386703471ccf47368c5fd5d5dd48a
--- /dev/null
+++ b/ecc-256.c
@@ -0,0 +1,228 @@
+/* ecc-256.c.c */
+
+/* Compile time constant (but machine dependent) tables. */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2013 Niels Möller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+/* Development of Nettle's ECC support was funded by Internetfonden. */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include "ecc-internal.h"
+
+#define USE_REDC (ECC_REDC_SIZE != 0)
+
+#include "ecc-256.h"
+
+#if ECC_BMODP_SIZE < ECC_LIMB_SIZE
+#define ecc_256_modp ecc_generic_modp
+#define ecc_256_modq ecc_generic_modq
+#elif GMP_NUMB_BITS == 64
+
+static void
+ecc_256_modp (const struct ecc_curve *ecc, mp_limb_t *rp)
+{
+  mp_limb_t u1, u0;
+  mp_size_t n;
+
+  n = 2*ecc->size;
+  u1 = rp[--n];
+  u0 = rp[n-1];
+
+  /* This is not particularly fast, but should work well with assembly implementation. */
+  for (; n >= ecc->size; n--)
+    {
+      mp_limb_t q2, q1, q0, t, cy;
+
+      /* <q2, q1, q0> = v * u1 + <u1,u0>, with v = 2^32 - 1:
+
+	   +---+---+
+	   | u1| u0|
+	   +---+---+
+	       |-u1|
+	     +-+-+-+
+	     | u1|
+       +---+-+-+-+-+
+       | q2| q1| q0|
+       +---+---+---+
+      */
+      q1 = u1 - (u1 > u0);
+      q0 = u0 - u1;
+      t = u1 << 32;
+      q0 += t;
+      t = (u1 >> 32) + (q0 < t) + 1;
+      q1 += t;
+      q2 = q1 < t;
+
+      /* Compute candidate remainder */
+      u1 = u0 + (q1 << 32) - q1;
+      t = -(mp_limb_t) (u1 > q0);
+      u1 -= t & 0xffffffff;
+      q1 += t;
+      q2 += t + (q1 < t);
+
+      assert (q2 < 2);
+
+      /* We multiply by two low limbs of p, 2^96 - 1, so we could use
+	 shifts rather than mul. */
+      t = mpn_submul_1 (rp + n - 4, ecc->p, 2, q1);
+      t += cnd_sub_n (q2, rp + n - 3, ecc->p, 1);
+      t += (-q2) & 0xffffffff;
+
+      u0 = rp[n-2];
+      cy = (u0 < t);
+      u0 -= t;
+      t = (u1 < cy);
+      u1 -= cy;
+      u1 += cnd_add_n (t, rp + n - 4, ecc->p, 3);
+      u1 -= (-t) & 0xffffffff;
+    }
+  rp[2] = u0;
+  rp[3] = u1;
+}
+
+static void
+ecc_256_modq (const struct ecc_curve *ecc, mp_limb_t *rp)
+{
+  mp_limb_t u2, u1, u0;
+  mp_size_t n;
+
+  n = 2*ecc->size;
+  u2 = rp[--n];
+  u1 = rp[n-1];
+
+  /* This is not particularly fast, but should work well with assembly implementation. */
+  for (; n >= ecc->size; n--)
+    {
+      mp_limb_t q2, q1, q0, t, c1, c0;
+
+      u0 = rp[n-2];
+      
+      /* <q2, q1, q0> = v * u2 + <u2,u1>, same method as above.
+
+	   +---+---+
+	   | u2| u1|
+	   +---+---+
+	       |-u2|
+	     +-+-+-+
+	     | u2|
+       +---+-+-+-+-+
+       | q2| q1| q0|
+       +---+---+---+
+      */
+      q1 = u2 - (u2 > u1);
+      q0 = u1 - u2;
+      t = u2 << 32;
+      q0 += t;
+      t = (u2 >> 32) + (q0 < t) + 1;
+      q1 += t;
+      q2 = q1 < t;
+
+      /* Compute candidate remainder, <u1, u0> - <q2, q1> * (2^128 - 2^96 + 2^64 - 1)
+         <u1, u0> + 2^64 q2 + (2^96 - 2^64 + 1) q1 (mod 2^128)
+
+	   +---+---+
+	   | u1| u0|
+	   +---+---+
+	   | q2| q1|
+	   +---+---+
+	   |-q1|
+	 +-+-+-+
+	 | q1|
+       --+-+-+-+---+
+           | u2| u1|
+	   +---+---+
+      */	 
+      u2 = u1 + q2 - q1;
+      u1 = u0 + q1;
+      u2 += (u1 < q1);
+      u2 += (q1 << 32);
+
+      t = -(mp_limb_t) (u2 >= q0);
+      q1 += t;
+      q2 += t + (q1 < t);
+      u1 += t;
+      u2 += (t << 32) + (u1 < t);
+
+      assert (q2 < 2);
+
+      c0 = cnd_sub_n (q2, rp + n - 3, ecc->q, 1);
+      c0 += (-q2) & ecc->q[1];
+      t = mpn_submul_1 (rp + n - 4, ecc->q, 2, q1);
+      c0 += t;
+      c1 = c0 < t;
+      
+      /* Construct underflow condition. */
+      c1 += (u1 < c0);
+      t = - (mp_limb_t) (u2 < c1);
+
+      u1 -= c0;
+      u2 -= c1;
+
+      /* Conditional add of p */
+      u1 += t;
+      u2 += (t<<32) + (u0 < t);
+
+      t = cnd_add_n (t, rp + n - 4, ecc->q, 2);
+      u1 += t;
+      u2 += (u1 < t);
+    }
+  rp[2] = u1;
+  rp[3] = u2;
+}
+      
+#else
+#error Unsupported parameters
+#endif
+
+const struct ecc_curve nettle_secp_256r1 =
+{
+  256,
+  ECC_LIMB_SIZE,    
+  ECC_BMODP_SIZE,
+  ECC_BMODQ_SIZE,
+  USE_REDC,
+  ECC_REDC_SIZE,
+  ECC_PIPPENGER_K,
+  ECC_PIPPENGER_C,
+  ecc_p,
+  ecc_b,
+  ecc_q,
+  ecc_g,
+  ecc_redc_g,
+  ecc_256_modp,
+  ecc_generic_redc,
+  USE_REDC ? ecc_generic_redc : ecc_generic_modp,
+  ecc_256_modq,
+  ecc_Bmodp,
+  ecc_Bmodp_shifted,
+  ecc_pp1h,
+  ecc_redc_ppm1,
+  ecc_unit,
+  ecc_Bmodq,
+  ecc_Bmodq_shifted,
+  ecc_qp1h,
+  ecc_table
+};
diff --git a/ecc-384.c b/ecc-384.c
new file mode 100644
index 0000000000000000000000000000000000000000..3c49e0ec1404e4a8f00c6f2fcb469f5a21b542fe
--- /dev/null
+++ b/ecc-384.c
@@ -0,0 +1,163 @@
+/* ecc-384.c.c */
+
+/* Compile time constant (but machine dependent) tables. */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2013 Niels Möller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+/* Development of Nettle's ECC support was funded by Internetfonden. */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include "ecc-internal.h"
+
+#define USE_REDC 0
+
+#include "ecc-384.h"
+
+/* Use that 2^{384} = 2^{128} + 2^{96} - 2^{32} + 1, and eliminate 256
+   bits at a time.
+
+   We can get carry == 2 in the first iteration, and I think *only* in
+   the first iteration. */
+
+#if GMP_NUMB_BITS == 32
+/* p is 12 limbs, and B^12 - p = B^4 + B^3 - B + 1. We can eliminate
+   almost 8 at a time. Do only 7, to avoid additional carry
+   propagation, followed by 5. */
+static void
+ecc_384_modp (const struct ecc_curve *ecc, mp_limb_t *rp)
+{
+  mp_limb_t cy, bw;
+
+  /* Reduce from 24 to 17 limbs. */
+  cy = mpn_add_n (rp + 4, rp + 4, rp + 16, 8);
+  cy = sec_add_1 (rp + 12, rp + 12, 3, cy);
+
+  bw = mpn_sub_n (rp + 5, rp + 5, rp + 16, 8);
+  bw = sub_1_sec (rp + 13, rp + 13, 3, bw);
+
+  cy += mpn_add_n (rp + 7, rp + 7, rp + 16, 8);
+  cy = sec_add_1 (rp + 15, rp + 15, 1, cy);
+
+  cy += mpn_add_n (rp + 8, rp + 8, rp + 16, 8);
+  assert (bw <= cy);
+  cy -= bw;
+
+  assert (cy <= 2);  
+  rp[16] = cy;
+
+  /* Reduce from 17 to 12 limbs */
+  cy = mpn_add_n (rp, rp, rp + 12, 5);
+  cy = sec_add_1 (rp + 5, rp + 5, 3, cy);
+  
+  bw = mpn_sub_n (rp + 1, rp + 1, rp + 12, 5);
+  bw = sub_1_sec (rp + 6, rp + 6, 6, bw);
+  
+  cy += mpn_add_n (rp + 3, rp + 3, rp + 12, 5);
+  cy = sec_add_1 (rp + 8, rp + 8, 1, cy);
+
+  cy += mpn_add_n (rp + 4, rp + 4, rp + 12, 5);
+  cy = sec_add_1 (rp + 9, rp + 9, 3, cy);
+
+  assert (cy >= bw);
+  cy -= bw;
+  assert (cy <= 1);
+  cy = cnd_add_n (cy, rp, ecc->Bmodp, ECC_LIMB_SIZE);
+  assert (cy == 0);
+}
+#elif GMP_NUMB_BITS == 64
+/* p is 6 limbs, and B^6 - p = B^2 + 2^32 (B - 1) + 1. Eliminate 3
+   (almost 4) limbs at a time. */
+static void
+ecc_384_modp (const struct ecc_curve *ecc, mp_limb_t *rp)
+{
+  mp_limb_t tp[6];
+  mp_limb_t cy;
+
+  /* Reduce from 12 to 9 limbs */
+  tp[0] = 0; /* FIXME: Could use mpn_sub_nc */
+  mpn_copyi (tp + 1, rp + 8, 3);
+  tp[4] = rp[11] - mpn_sub_n (tp, tp, rp + 8, 4);
+  tp[5] = mpn_lshift (tp, tp, 5, 32);
+
+  cy = mpn_add_n (rp + 2, rp + 2, rp + 8, 4);
+  cy = sec_add_1 (rp + 6, rp + 6, 2, cy);
+
+  cy += mpn_add_n (rp + 2, rp + 2, tp, 6);
+  cy += mpn_add_n (rp + 4, rp + 4, rp + 8, 4);
+
+  assert (cy <= 2);
+  rp[8] = cy;
+
+  /* Reduce from 9 to 6 limbs */
+  tp[0] = 0;
+  mpn_copyi (tp + 1, rp + 6, 2);
+  tp[3] = rp[8] -= mpn_sub_n (tp, tp, rp + 6, 3);
+  tp[4] = mpn_lshift (tp, tp, 4, 32);
+
+  cy = mpn_add_n (rp, rp, rp + 6, 3);
+  cy = sec_add_1 (rp + 3, rp + 3, 2, cy);
+  cy += mpn_add_n (rp, rp, tp, 5);
+  cy += mpn_add_n (rp + 2, rp + 2, rp + 6, 3);
+
+  cy = sec_add_1 (rp + 5, rp + 5, 1, cy);
+  assert (cy <= 1);
+
+  cy = cnd_add_n (cy, rp, ecc->Bmodp, ECC_LIMB_SIZE);
+  assert (cy == 0);  
+}
+#else
+#define ecc_384_modp ecc_generic_modp
+#endif
+  
+const struct ecc_curve nettle_secp_384r1 =
+{
+  384,
+  ECC_LIMB_SIZE,    
+  ECC_BMODP_SIZE,
+  ECC_BMODQ_SIZE,
+  USE_REDC,
+  ECC_REDC_SIZE,
+  ECC_PIPPENGER_K,
+  ECC_PIPPENGER_C,
+  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,
+  ecc_Bmodp,
+  ecc_Bmodp_shifted,
+  ecc_pp1h,
+  ecc_redc_ppm1,
+  ecc_unit,
+  ecc_Bmodq,
+  ecc_Bmodq_shifted,
+  ecc_qp1h,
+  ecc_table
+};
diff --git a/ecc-521.c b/ecc-521.c
new file mode 100644
index 0000000000000000000000000000000000000000..ec3f7ceb14bd2d4b954bc19e63dec504e0c3e93e
--- /dev/null
+++ b/ecc-521.c
@@ -0,0 +1,89 @@
+/* ecc-521.c.c */
+
+/* Compile time constant (but machine dependent) tables. */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2013 Niels Möller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+/* Development of Nettle's ECC support was funded by Internetfonden. */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "ecc-internal.h"
+
+#define USE_REDC 0
+
+#include "ecc-521.h"
+
+#define B_SHIFT (521 % GMP_NUMB_BITS)
+#define BMODP_SHIFT (GMP_NUMB_BITS - B_SHIFT)
+#define BMODP ((mp_limb_t) 1 << BMODP_SHIFT)
+
+/* Result may be *slightly* larger than 2^521 */
+static void
+ecc_521_modp (const struct ecc_curve *ecc UNUSED, mp_limb_t *rp)
+{
+  /* FIXME: Should use mpn_addlsh_n_ip1 */
+  mp_limb_t hi;
+  /* Reduce from 2*ECC_LIMB_SIZE to ECC_LIMB_SIZE + 1 */
+  rp[ECC_LIMB_SIZE]
+    = mpn_addmul_1 (rp, rp + ECC_LIMB_SIZE, ECC_LIMB_SIZE, BMODP);
+  hi = mpn_addmul_1 (rp, rp + ECC_LIMB_SIZE, 1, BMODP);
+  hi = sec_add_1 (rp + 1, rp + 1, ECC_LIMB_SIZE - 1, hi);
+
+  /* Combine hi with top bits, and add in. */
+  hi = (hi << BMODP_SHIFT) | (rp[ECC_LIMB_SIZE-1] >> B_SHIFT);
+  rp[ECC_LIMB_SIZE-1] = (rp[ECC_LIMB_SIZE-1]
+			 & (((mp_limb_t) 1 << B_SHIFT)-1))
+    + sec_add_1 (rp, rp, ECC_LIMB_SIZE - 1, hi);
+}
+
+const struct ecc_curve nettle_secp_521r1 =
+{
+  521,
+  ECC_LIMB_SIZE,    
+  ECC_BMODP_SIZE,
+  ECC_BMODQ_SIZE,
+  USE_REDC,
+  ECC_REDC_SIZE,
+  ECC_PIPPENGER_K,
+  ECC_PIPPENGER_C,
+  ecc_p,
+  ecc_b,
+  ecc_q,
+  ecc_g,
+  ecc_redc_g,
+  ecc_521_modp,
+  ecc_generic_redc,
+  ecc_521_modp,
+  ecc_generic_modq,
+  ecc_Bmodp,
+  ecc_Bmodp_shifted,
+  ecc_pp1h,
+  ecc_redc_ppm1,
+  ecc_unit,
+  ecc_Bmodq,
+  ecc_Bmodq_shifted,
+  ecc_qp1h,
+  ecc_table
+};
+
diff --git a/ecc-curve.h b/ecc-curve.h
new file mode 100644
index 0000000000000000000000000000000000000000..e6f8aa6762f5d8b1301997889faf1e475e397445
--- /dev/null
+++ b/ecc-curve.h
@@ -0,0 +1,45 @@
+/* ecc-curve.h */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2013 Niels Möller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+/* Development of Nettle's ECC support was funded by Internetfonden. */
+
+#ifndef NETTLE_ECC_CURVE_H_INCLUDED
+#define NETTLE_ECC_CURVE_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The contets of this struct is internal. */
+struct ecc_curve;
+
+extern const struct ecc_curve nettle_secp_192r1;
+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;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_ECC_CURVE_H_INCLUDED */
diff --git a/ecc-generic-modp.c b/ecc-generic-modp.c
new file mode 100644
index 0000000000000000000000000000000000000000..dd557553b077bb7a06a18277dcf9152c015e1110
--- /dev/null
+++ b/ecc-generic-modp.c
@@ -0,0 +1,41 @@
+/* ecc-generic-modp.c */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2013 Niels Möller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+/* Development of Nettle's ECC support was funded by Internetfonden. */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include "ecc-internal.h"
+
+void
+ecc_generic_modp (const struct ecc_curve *ecc, mp_limb_t *rp)
+{
+  assert (ecc->Bmodp_size < ecc->size);
+  
+  ecc_mod (rp, 2*ecc->size, ecc->size, ecc->Bmodp, ecc->Bmodp_size,
+	   ecc->Bmodp_shifted,
+	   ecc->size * GMP_NUMB_BITS - ecc->bit_size);
+}
diff --git a/ecc-generic-modq.c b/ecc-generic-modq.c
new file mode 100644
index 0000000000000000000000000000000000000000..3fd3879f56e63822a78d47c9c8fec7c7f4d24dae
--- /dev/null
+++ b/ecc-generic-modq.c
@@ -0,0 +1,41 @@
+/* ecc-generic-modq.c */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2013 Niels Möller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+/* Development of Nettle's ECC support was funded by Internetfonden. */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include "ecc-internal.h"
+
+void
+ecc_generic_modq (const struct ecc_curve *ecc, mp_limb_t *rp)
+{
+  assert (ecc->Bmodq_size < ecc->size);
+
+  ecc_mod (rp, 2*ecc->size, ecc->size, ecc->Bmodq, ecc->Bmodq_size,
+	   ecc->Bmodq_shifted,
+	   ecc->size * GMP_NUMB_BITS - ecc->bit_size);
+}
diff --git a/ecc-generic-redc.c b/ecc-generic-redc.c
new file mode 100644
index 0000000000000000000000000000000000000000..1b120b5ebfc95055f70b746033985be3a0e26f53
--- /dev/null
+++ b/ecc-generic-redc.c
@@ -0,0 +1,85 @@
+/* ecc-generic-redc.c */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2013 Niels Möller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+/* Development of Nettle's ECC support was funded by Internetfonden. */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include "ecc-internal.h"
+
+void
+ecc_generic_redc (const struct ecc_curve *ecc, mp_limb_t *rp)
+{
+  unsigned i;
+  mp_limb_t hi, cy;
+  unsigned shift = ecc->size * GMP_NUMB_BITS - ecc->bit_size;
+  mp_size_t k = ecc->redc_size;
+  
+  assert (k != 0);
+  if (k > 0)    
+    {
+      /* Use that 1 = p + 1, and that at least one low limb of p + 1 is zero. */
+      for (i = 0; i < ecc->size; i++)
+	rp[i] = mpn_addmul_1 (rp + i + k,
+			      ecc->redc_ppm1, ecc->size - k, rp[i]);
+      hi = mpn_add_n (rp, rp, rp + ecc->size, ecc->size);
+      if (shift > 0)
+	{
+	  hi = (hi << shift) | (rp[ecc->size - 1] >> (GMP_NUMB_BITS - shift));
+	  rp[ecc->size - 1] = (rp[ecc->size - 1]
+			       & (((mp_limb_t) 1 << (GMP_NUMB_BITS - shift)) - 1))
+	    + mpn_addmul_1 (rp, ecc->Bmodp_shifted, ecc->size-1, hi);
+	  
+	}
+      else
+	{
+	  cy = cnd_sub_n (hi, rp, ecc->p, ecc->size);
+	  assert (cy == hi);      
+	}
+    }
+  else
+    {
+      /* Use that 1 = - (p - 1), and that at least one low limb of p -
+	 1 is zero. */
+      k = -k;
+      for (i = 0; i < ecc->size; i++)
+	rp[i] = mpn_submul_1 (rp + i + k,
+			      ecc->redc_ppm1, ecc->size - k, rp[i]);
+      hi = mpn_sub_n (rp, rp + ecc->size, rp, ecc->size);
+      cy = cnd_add_n (hi, rp, ecc->p, ecc->size);
+      assert (cy == hi);
+
+      if (shift > 0)
+	{
+	  /* Result is always < 2p, provided that
+	     2^shift * Bmodp_shifted <= p */
+	  hi = (rp[ecc->size - 1] >> (GMP_NUMB_BITS - shift));
+	  rp[ecc->size - 1] = (rp[ecc->size - 1]
+			       & (((mp_limb_t) 1 << (GMP_NUMB_BITS - shift)) - 1))
+	    + mpn_addmul_1 (rp, ecc->Bmodp_shifted, ecc->size-1, hi);
+	}
+    }
+}
diff --git a/ecc-internal.h b/ecc-internal.h
new file mode 100644
index 0000000000000000000000000000000000000000..a6b3fae41245b0bbc7f61e8e9dd044571c18a9ea
--- /dev/null
+++ b/ecc-internal.h
@@ -0,0 +1,235 @@
+/* ecc-internal.h */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2013 Niels Möller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+/* Development of Nettle's ECC support was funded by Internetfonden. */
+
+#ifndef NETTLE_ECC_INTERNAL_H_INCLUDED
+#define NETTLE_ECC_INTERNAL_H_INCLUDED
+
+#include <gmp.h>
+
+#include "ecc-curve.h"
+
+/* Name mangling */
+#define ecc_generic_modp _nettle_ecc_generic_modp
+#define ecc_generic_redc _nettle_ecc_generic_redc
+#define ecc_generic_modq _nettle_ecc_generic_modq
+#define ecc_modp_add _nettle_ecc_modp_add
+#define ecc_modp_sub _nettle_ecc_modp_sub
+#define ecc_modp_sub_1 _nettle_ecc_modp_sub_1
+#define ecc_modp_mul_1 _nettle_ecc_modp_mul_1
+#define ecc_modp_addmul_1 _nettle_ecc_modp_addmul_1
+#define ecc_modp_submul_1 _nettle_ecc_modp_submul_1
+#define ecc_modp_mul _nettle_ecc_modp_mul
+#define ecc_modp_sqr _nettle_ecc_modp_sqr
+#define ecc_modp_inv _nettle_ecc_modp_inv
+#define ecc_modq_mul _nettle_ecc_modq_mul
+#define ecc_modq_add _nettle_ecc_modq_add
+#define ecc_modq_inv _nettle_ecc_modq_inv
+#define ecc_mod _nettle_ecc_mod 
+#define cnd_copy _nettle_cnd_copy
+#define sec_add_1 _nettle_sec_add_1
+#define sec_sub_1 _nettle_sec_sub_1
+#define sec_tabselect _nettle_sec_tabselect
+#define sec_modinv _nettle_sec_modinv
+
+/* 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
+   up to 5 bits, but I don't think that's worth doubling the
+   storage. */
+#define ECC_MUL_A_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);
+
+/* Represents an elliptic curve of the form
+
+     y^2 = x^3 - 3x + b (mod p)
+*/
+struct ecc_curve
+{
+  unsigned short bit_size;
+  /* Limb size of elements in the base field, size of a point is
+     2*size in affine coordinates and 3*size in jacobian
+     coordinates. */
+  unsigned short size;
+  unsigned short Bmodp_size;
+  unsigned short Bmodq_size;
+  unsigned short use_redc;
+  /* +k if p+1 has k low zero limbs, -k if p-1 has k low zero
+     limbs. */
+  short redc_size;
+  unsigned short pippenger_k;
+  unsigned short pippenger_c;
+
+  /* The prime p. */
+  const mp_limb_t *p;
+  const mp_limb_t *b;
+  /* Group order. */
+  const mp_limb_t *q;
+  /* Generator, x coordinate followed by y (affine coordinates). */
+  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;
+
+  /* B^size mod p. Expected to have at least 32 leading zeros
+     (equality for secp_256r1). */
+  const mp_limb_t *Bmodp;
+  /* 2^{bit_size} - p, same value as above, but shifted. */
+  const mp_limb_t *Bmodp_shifted;
+  /* (p+1)/2 */
+  const mp_limb_t *pp1h;
+  /* p +/- 1, for redc, excluding |redc_size| low limbs. */
+  const mp_limb_t *redc_ppm1;
+  /* For redc, same as Bmodp, otherwise 1. */
+  const mp_limb_t *unit;
+
+  /* Similarly, B^size mod q */
+  const mp_limb_t *Bmodq;
+  /* 2^{bit_size} - q, same value as above, but shifted. */
+  const mp_limb_t *Bmodq_shifted;
+  /* (q+1)/2 */
+  const mp_limb_t *qp1h;
+  
+  /* Tables for multiplying by the generator, size determined by k and
+     c. The first 2^c entries are defined by
+
+       T[  j_0 +   j_1 2 +     ... + j_{c-1} 2^{c-1} ]
+         = j_0 g + j_1 2^k g + ... + j_{c-1} 2^{k(c-1)} g
+
+     The following entries differ by powers of 2^{kc},
+
+       T[i] = 2^{kc} T[i-2^c]
+  */  
+  const mp_limb_t *pippenger_table;
+};
+
+/* In-place reduction. */
+ecc_mod_func ecc_generic_modp;
+ecc_mod_func ecc_generic_redc;
+ecc_mod_func ecc_generic_modq;
+
+
+void
+ecc_modp_add (const struct ecc_curve *ecc, mp_limb_t *rp,
+	      const mp_limb_t *ap, const mp_limb_t *bp);
+void
+ecc_modp_sub (const struct ecc_curve *ecc, mp_limb_t *rp,
+	      const mp_limb_t *ap, const mp_limb_t *bp);
+
+void
+ecc_modp_sub_1 (const struct ecc_curve *ecc, mp_limb_t *rp,
+		const mp_limb_t *ap, mp_limb_t b);
+
+void
+ecc_modp_mul_1 (const struct ecc_curve *ecc, mp_limb_t *rp,
+		const mp_limb_t *ap, const mp_limb_t b);
+
+void
+ecc_modp_addmul_1 (const struct ecc_curve *ecc, mp_limb_t *rp,
+		   const mp_limb_t *ap, mp_limb_t b);
+void
+ecc_modp_submul_1 (const struct ecc_curve *ecc, mp_limb_t *rp,
+		   const mp_limb_t *ap, mp_limb_t b);
+
+/* NOTE: mul and sqr needs 2*ecc->size limbs at rp */
+void
+ecc_modp_mul (const struct ecc_curve *ecc, mp_limb_t *rp,
+	      const mp_limb_t *ap, const mp_limb_t *bp);
+
+void
+ecc_modp_sqr (const struct ecc_curve *ecc, mp_limb_t *rp,
+	      const mp_limb_t *ap);
+
+void
+ecc_modp_inv (const struct ecc_curve *ecc, mp_limb_t *rp, mp_limb_t *ap,
+	      mp_limb_t *scratch);
+
+/* mod q operations. */
+void
+ecc_modq_mul (const struct ecc_curve *ecc, mp_limb_t *rp,
+	      const mp_limb_t *ap, const mp_limb_t *bp);
+void
+ecc_modq_add (const struct ecc_curve *ecc, mp_limb_t *rp,
+	      const mp_limb_t *ap, const mp_limb_t *bp);
+
+void
+ecc_modq_inv (const struct ecc_curve *ecc, mp_limb_t *rp, mp_limb_t *ap,
+	      mp_limb_t *scratch);
+
+void
+ecc_mod (mp_limb_t *rp, mp_size_t rn, mp_size_t mn,
+	 const mp_limb_t *bp, mp_size_t bn,
+	 const mp_limb_t *b_shifted, unsigned shift);
+
+#define cnd_add_n(cnd, rp, ap, n)		\
+  mpn_addmul_1 ((rp), (ap), (n), (cnd) != 0)
+
+#define cnd_sub_n(cnd, rp, ap, n)		\
+  mpn_submul_1 ((rp), (ap), (n), (cnd) != 0)
+
+void
+cnd_copy (int cnd, mp_limb_t *rp, const mp_limb_t *ap, mp_size_t n);
+
+mp_limb_t
+sec_add_1 (mp_limb_t *rp, mp_limb_t *ap, mp_size_t n, mp_limb_t b);
+
+mp_limb_t
+sec_sub_1 (mp_limb_t *rp, mp_limb_t *ap, mp_size_t n, mp_limb_t b);
+
+void
+sec_tabselect (mp_limb_t *rp, mp_size_t rn,
+	       const mp_limb_t *table, unsigned tn,
+	       unsigned k);
+
+void
+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);
+
+/* 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_DUP_JJ_ITCH(size) (5*(size))
+#define ECC_ADD_JJA_ITCH(size) (6*(size))
+#define ECC_ADD_JJJ_ITCH(size) (8*(size))
+#define ECC_MUL_G_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
+#define _ECDSA_SIGN_ITCH(size) (12*(size))
+#define _ECDSA_VERIFY_ITCH(size) \
+  (6*(size) + ECC_MUL_A_ITCH ((size)))
+
+#endif /* NETTLE_ECC_INTERNAL_H_INCLUDED */
diff --git a/ecc-mod.c b/ecc-mod.c
new file mode 100644
index 0000000000000000000000000000000000000000..1d2f4232b6ab35cbe35d0e1cd774736b8b2852e1
--- /dev/null
+++ b/ecc-mod.c
@@ -0,0 +1,102 @@
+/* ecc-mod.c */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2013 Niels Möller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+/* Development of Nettle's ECC support was funded by Internetfonden. */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include "ecc-internal.h"
+
+/* Computes r mod m, where m is of size mn. bp holds B^mn mod m, as mn
+   limbs, but the upper mn - bn libms are zero. */
+void
+ecc_mod (mp_limb_t *rp, mp_size_t rn, mp_size_t mn,
+	 const mp_limb_t *bp, mp_size_t bn,
+	 const mp_limb_t *b_shifted, unsigned shift)
+{
+  mp_limb_t hi;
+  mp_size_t sn = mn - bn;
+  mp_size_t i;
+
+  assert (sn > 0);
+
+  /* FIXME: Could use mpn_addmul_2. */
+  /* Eliminate sn = mn - bn limbs at a time */
+  if (bp[bn-1] < ((mp_limb_t) 1 << (GMP_NUMB_BITS - 1)))
+    {
+      /* Multiply sn + 1 limbs at a time, so we get a mn+1 limb
+	 product. Then we can absorb the carry in the high limb */
+      while (rn > 2 * mn - bn)
+	{
+	  rn -= sn;
+
+	  for (i = 0; i <= sn; i++)
+	    rp[rn+i-1] = mpn_addmul_1 (rp + rn - mn - 1 + i, bp, bn, rp[rn+i-1]);
+	  rp[rn-1] = rp[rn+sn-1]
+	    + mpn_add_n (rp + rn - sn - 1, rp + rn - sn - 1, rp + rn - 1, sn);
+	}
+      goto final_limbs;
+    }
+  else
+    {
+      while (rn >= 2 * mn - bn)
+	{
+	  rn -= sn;
+
+	  for (i = 0; i < sn; i++)
+	    rp[rn+i] = mpn_addmul_1 (rp + rn - mn + i, bp, bn, rp[rn+i]);
+				     
+	  hi = mpn_add_n (rp + rn - sn, rp + rn - sn, rp + rn, sn);
+	  hi = cnd_add_n (hi, rp + rn - mn, bp, mn);
+	  assert (hi == 0);
+	}
+    }
+
+  if (rn > mn)
+    {
+    final_limbs:
+      sn = rn - mn;
+      
+      for (i = 0; i < sn; i++)
+	rp[mn+i] = mpn_addmul_1 (rp + i, bp, bn, rp[mn+i]);
+
+      hi = mpn_add_n (rp + bn, rp + bn, rp + mn, sn);
+      hi = sec_add_1 (rp + bn + sn, rp + bn + sn, mn - bn - sn, hi);
+    }
+
+  if (shift > 0)
+    {
+      /* Combine hi with top bits, add in */
+      hi = (hi << shift) | (rp[mn-1] >> (GMP_NUMB_BITS - shift));
+      rp[mn-1] = (rp[mn-1] & (((mp_limb_t) 1 << (GMP_NUMB_BITS - shift)) - 1))
+	+ mpn_addmul_1 (rp, b_shifted, mn-1, hi);
+    }
+  else
+    {
+      hi = cnd_add_n (hi, rp, bp, mn);
+      assert (hi == 0);
+    }
+}
diff --git a/ecc-modp.c b/ecc-modp.c
new file mode 100644
index 0000000000000000000000000000000000000000..ce7de7c8242b922b8935e5b4bf08073b926ac108
--- /dev/null
+++ b/ecc-modp.c
@@ -0,0 +1,142 @@
+/* ecc-modp.c */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2013 Niels Möller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+/* Development of Nettle's ECC support was funded by Internetfonden. */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include "ecc-internal.h"
+
+/* Routines for modp arithmetic. All values are ecc->size limbs, but
+   not necessarily < p. */
+
+void
+ecc_modp_add (const struct ecc_curve *ecc, mp_limb_t *rp,
+	      const mp_limb_t *ap, const mp_limb_t *bp)
+{
+  mp_limb_t cy;
+  cy = mpn_add_n (rp, ap, bp, ecc->size);
+  cy = cnd_add_n (cy, rp, ecc->Bmodp, ecc->size);
+  cy = cnd_add_n (cy, rp, ecc->Bmodp, ecc->size);
+  assert (cy == 0);  
+}
+
+void
+ecc_modp_sub (const struct ecc_curve *ecc, mp_limb_t *rp,
+	      const mp_limb_t *ap, const mp_limb_t *bp)
+{
+  mp_limb_t cy;
+  cy = mpn_sub_n (rp, ap, bp, ecc->size);
+  cy = cnd_sub_n (cy, rp, ecc->Bmodp, ecc->size);
+  cy = cnd_sub_n (cy, rp, ecc->Bmodp, ecc->size);
+  assert (cy == 0);  
+}
+
+void
+ecc_modp_sub_1 (const struct ecc_curve *ecc, mp_limb_t *rp,
+		const mp_limb_t *ap, mp_limb_t b)
+{
+  mp_size_t i;
+
+  for (i = 0; i < ecc->size; i++)
+    {
+      mp_limb_t cy = ap[i] < b;
+      rp[i] = ap[i] - b;
+      b = cy;
+    }
+  b = cnd_sub_n (b, rp, ecc->Bmodp, ecc->size);
+  assert (b == 0);    
+}
+
+void
+ecc_modp_mul_1 (const struct ecc_curve *ecc, mp_limb_t *rp,
+		const mp_limb_t *ap, mp_limb_t b)
+{
+  mp_limb_t hi;
+
+  assert (b <= 0xffffffff);
+  hi = mpn_mul_1 (rp, ap, ecc->size, b);
+  hi = mpn_addmul_1 (rp, ecc->Bmodp, ecc->size, hi);
+  assert (hi <= 1);
+  hi = cnd_add_n (hi, rp, ecc->Bmodp, ecc->size);
+  /* Sufficient if b < B^size / p */
+  assert (hi == 0);
+}
+
+void
+ecc_modp_addmul_1 (const struct ecc_curve *ecc, mp_limb_t *rp,
+		   const mp_limb_t *ap, mp_limb_t b)
+{
+  mp_limb_t hi;
+
+  assert (b <= 0xffffffff);
+  hi = mpn_addmul_1 (rp, ap, ecc->size, b);
+  hi = mpn_addmul_1 (rp, ecc->Bmodp, ecc->size, hi);
+  assert (hi <= 1);
+  hi = cnd_add_n (hi, rp, ecc->Bmodp, ecc->size);
+  /* Sufficient roughly if b < B^size / p */
+  assert (hi == 0);
+}
+  
+void
+ecc_modp_submul_1 (const struct ecc_curve *ecc, mp_limb_t *rp,
+		   const mp_limb_t *ap, mp_limb_t b)
+{
+  mp_limb_t hi;
+
+  assert (b <= 0xffffffff);
+  hi = mpn_submul_1 (rp, ap, ecc->size, b);
+  hi = mpn_submul_1 (rp, ecc->Bmodp, ecc->size, hi);
+  assert (hi <= 1);
+  hi = cnd_sub_n (hi, rp, ecc->Bmodp, ecc->size);
+  /* Sufficient roughly if b < B^size / p */
+  assert (hi == 0);
+}
+
+/* NOTE: mul and sqr needs 2*ecc->size limbs at rp */
+void
+ecc_modp_mul (const struct ecc_curve *ecc, mp_limb_t *rp,
+	      const mp_limb_t *ap, const mp_limb_t *bp)
+{
+  mpn_mul_n (rp, ap, bp, ecc->size);
+  ecc->reduce (ecc, rp);
+}
+
+void
+ecc_modp_sqr (const struct ecc_curve *ecc, mp_limb_t *rp,
+	      const mp_limb_t *ap)
+{
+  mpn_sqr (rp, ap, ecc->size);
+  ecc->reduce (ecc, rp);
+}
+
+void
+ecc_modp_inv (const struct ecc_curve *ecc, mp_limb_t *rp, mp_limb_t *ap,
+	      mp_limb_t *scratch)
+{
+  sec_modinv (rp, ap, ecc->size, ecc->p, ecc->pp1h, ecc->bit_size, scratch);
+}
+
diff --git a/ecc-modq.c b/ecc-modq.c
new file mode 100644
index 0000000000000000000000000000000000000000..80a719a55a29962ecbf72a86c2bef53472a6f9ef
--- /dev/null
+++ b/ecc-modq.c
@@ -0,0 +1,59 @@
+/* ecc-modq.c */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2013 Niels Möller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+/* Development of Nettle's ECC support was funded by Internetfonden. */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include "ecc-internal.h"
+
+/* Arithmetic mod q, the group order. */
+
+void
+ecc_modq_add (const struct ecc_curve *ecc, mp_limb_t *rp,
+	      const mp_limb_t *ap, const mp_limb_t *bp)
+{
+  mp_limb_t cy;
+  cy = mpn_add_n (rp, ap, bp, ecc->size);
+  cy = cnd_add_n (cy, rp, ecc->Bmodq, ecc->size);
+  cy = cnd_add_n (cy, rp, ecc->Bmodq, ecc->size);
+  assert (cy == 0);  
+}
+
+void
+ecc_modq_mul (const struct ecc_curve *ecc, mp_limb_t *rp,
+	      const mp_limb_t *ap, const mp_limb_t *bp)
+{
+  mpn_mul_n (rp, ap, bp, ecc->size);
+  ecc->modq (ecc, rp);
+}
+
+void
+ecc_modq_inv (const struct ecc_curve *ecc, mp_limb_t *rp, mp_limb_t *ap,
+	      mp_limb_t *scratch)
+{
+  sec_modinv (rp, ap, ecc->size, ecc->q, ecc->qp1h, ecc->bit_size, scratch);
+}
diff --git a/sec-add-1.c b/sec-add-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..7e7b44338ea72c7f1e3eda6930e6a3fca6615a64
--- /dev/null
+++ b/sec-add-1.c
@@ -0,0 +1,42 @@
+/* sec-add-1.c */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2013 Niels Möller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+/* Development of Nettle's ECC support was funded by Internetfonden. */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "ecc-internal.h"
+
+mp_limb_t
+sec_add_1 (mp_limb_t *rp, mp_limb_t *ap, mp_size_t n, mp_limb_t b)
+{
+  mp_size_t i;
+  for (i = 0; i < n; i++)
+    {
+      mp_limb_t r = ap[i] + b;
+      b = (r < b);
+      rp[i] = r;
+    }
+  return b;
+}
diff --git a/sec-modinv.c b/sec-modinv.c
new file mode 100644
index 0000000000000000000000000000000000000000..f674a8fb8d285ea94b4302e3e53623d0df6e3fff
--- /dev/null
+++ b/sec-modinv.c
@@ -0,0 +1,170 @@
+/* sec-modinv.c */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2013 Niels Möller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+/* Development of Nettle's ECC support was funded by Internetfonden. */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include "ecc-internal.h"
+
+static void
+cnd_neg (int cnd, mp_limb_t *rp, const mp_limb_t *ap, mp_size_t n)
+{
+  mp_limb_t cy = (cnd != 0);
+  mp_limb_t mask = -cy;
+  mp_size_t i;
+
+  for (i = 0; i < n; i++)
+    {
+      mp_limb_t r = (ap[i] ^ mask) + cy;
+      cy = r < cy;
+      rp[i] = r;
+    }
+}
+
+static void
+cnd_swap (int cnd, mp_limb_t *ap, mp_limb_t *bp, mp_size_t n)
+{
+  mp_limb_t mask = - (mp_limb_t) (cnd != 0);
+  mp_size_t i;
+  for (i = 0; i < n; i++)
+    {
+      mp_limb_t a, b, t;
+      a = ap[i];
+      b = bp[i];
+      t = (a ^ b) & mask;
+      ap[i] = a ^ t;
+      bp[i] = b ^ t;
+    }
+}
+
+/* Compute a^{-1} mod m, with running time depending only on the size.
+   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,
+	    const mp_limb_t *mp, const mp_limb_t *mp1h, mp_size_t bit_size,
+	    mp_limb_t *scratch)
+{
+#define bp scratch
+#define dp (scratch + n)
+#define up (scratch + 2*n)
+
+  mp_bitcnt_t i;
+
+  /* Maintain
+
+       a = u * orig_a (mod m)
+       b = v * orig_a (mod m)
+
+     and b odd at all times. Initially,
+
+       a = a_orig, u = 1
+       b = m,      v = 0
+     */
+
+  assert (ap != vp);
+
+  up[0] = 1;
+  mpn_zero (up+1, n - 1);
+  mpn_copyi (bp, mp, n);
+  mpn_zero (vp, n);
+
+  for (i = bit_size + GMP_NUMB_BITS * n; i-- > 0; )
+    {
+      mp_limb_t odd, swap, cy;
+      
+      /* Always maintain b odd. The logic of the iteration is as
+	 follows. For a, b:
+
+	   odd = a & 1
+	   a -= odd * b
+	   if (underflow from a-b)
+	     {
+	       b += a, assigns old a
+	       a = B^n-a
+	     }
+	   
+	   a /= 2
+
+	 For u, v:
+
+	   if (underflow from a - b)
+	     swap u, v
+	   u -= odd * v
+	   if (underflow from u - v)
+	     u += m
+
+	   u /= 2
+	   if (a one bit was shifted out)
+	     u += (m+1)/2
+
+	 As long as a > 0, the quantity
+
+	   (bitsize of a) + (bitsize of b)
+
+	 is reduced by at least one bit per iteration, hence after
+         (bit_size of orig_a) + (bit_size of m) - 1 iterations we
+         surely have a = 0. Then b = gcd(orig_a, m) and if b = 1 then
+         also v = orig_a^{-1} (mod m)
+      */
+
+      assert (bp[0] & 1);
+      odd = ap[0] & 1;
+
+      /* Which variant is fastest depends on the speed of the various
+	 cnd_* functions. Assembly implementation would help. */
+#if 1
+      swap = cnd_sub_n (odd, ap, bp, n);
+      cnd_add_n (swap, bp, ap, n);
+      cnd_neg (swap, ap, ap, n);
+#else
+      swap = odd & mpn_sub_n (dp, ap, bp, n);
+      cnd_copy (swap, bp, ap, n);
+      cnd_neg (swap, dp, dp, n);
+      cnd_copy (odd, ap, dp, n);
+#endif
+
+#if 1
+      cnd_swap (swap, up, vp, n);
+      cy = cnd_sub_n (odd, up, vp, n);
+      cy -= cnd_add_n (cy, up, mp, n);
+#else
+      cy = cnd_sub_n (odd, up, vp, n);
+      cnd_add_n (swap, vp, up, n);
+      cnd_neg (swap, up, up, n);
+      cnd_add_n (cy ^ swap, up, mp, n);
+#endif
+      cy = mpn_rshift (ap, ap, n, 1);
+      assert (cy == 0);
+      cy = mpn_rshift (up, up, n, 1);
+      cy = cnd_add_n (cy, up, mp1h, n);
+      assert (cy == 0);
+    }
+  assert ( (ap[0] | ap[n-1]) == 0);
+#undef bp
+#undef dp
+#undef up
+}
diff --git a/sec-sub-1.c b/sec-sub-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..1aa04d04731e982254a021cde35f11658213d36c
--- /dev/null
+++ b/sec-sub-1.c
@@ -0,0 +1,43 @@
+/* sec-add-1.c */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2013 Niels Möller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+/* Development of Nettle's ECC support was funded by Internetfonden. */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "ecc-internal.h"
+
+mp_limb_t
+sec_sub_1 (mp_limb_t *rp, mp_limb_t *ap, mp_size_t n, mp_limb_t b)
+{
+  mp_size_t i;
+  for (i = 0; i < n; i++)
+    {
+      mp_limb_t a;
+      a = ap[i];
+      rp[i] = a - b;
+      b = a < b;
+    }
+  return b;
+}
diff --git a/testsuite/.test-rules.make b/testsuite/.test-rules.make
index 93f1f94362023e28f8e1101be7e6ddea9137aadf..0f5cb568a12a62600f3b6c6d667798ae46e89692 100644
--- a/testsuite/.test-rules.make
+++ b/testsuite/.test-rules.make
@@ -160,6 +160,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)
 
+ecc-mod-test$(EXEEXT): ecc-mod-test.$(OBJEXT)
+	$(LINK) ecc-mod-test.$(OBJEXT) $(TEST_OBJS) -o ecc-mod-test$(EXEEXT)
+
+ecc-modinv-test$(EXEEXT): ecc-modinv-test.$(OBJEXT)
+	$(LINK) ecc-modinv-test.$(OBJEXT) $(TEST_OBJS) -o ecc-modinv-test$(EXEEXT)
+
+ecc-redc-test$(EXEEXT): ecc-redc-test.$(OBJEXT)
+	$(LINK) ecc-redc-test.$(OBJEXT) $(TEST_OBJS) -o ecc-redc-test$(EXEEXT)
+
 sha1-huge-test$(EXEEXT): sha1-huge-test.$(OBJEXT)
 	$(LINK) sha1-huge-test.$(OBJEXT) $(TEST_OBJS) -o sha1-huge-test$(EXEEXT)
 
diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in
index 71e133f942d25d8e21e602c303850620ca571cc2..cdfa766bdb5825bef2b8f5881b187c001bc989ac 100644
--- a/testsuite/Makefile.in
+++ b/testsuite/Makefile.in
@@ -34,7 +34,8 @@ TS_HOGWEED_SOURCES = sexp-test.c sexp-format-test.c \
 		     bignum-test.c random-prime-test.c \
 		     pkcs1-test.c \
 		     rsa-test.c rsa-encrypt-test.c rsa-keygen-test.c \
-		     dsa-test.c dsa-keygen-test.c
+		     dsa-test.c dsa-keygen-test.c \
+		     ecc-mod-test.c ecc-modinv-test.c ecc-redc-test.c
 
 TS_SOURCES = $(TS_NETTLE_SOURCES) $(TS_HOGWEED_SOURCES)
 CXX_SOURCES = cxx-test.cxx
diff --git a/testsuite/ecc-mod-test.c b/testsuite/ecc-mod-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..3ce82ed4be9fd82249a012237a2bcc00f1c3ac62
--- /dev/null
+++ b/testsuite/ecc-mod-test.c
@@ -0,0 +1,115 @@
+#include "testutils.h"
+
+static void
+ref_mod (mp_limb_t *rp, const mp_limb_t *ap, const mp_limb_t *mp, mp_size_t mn)
+{
+  mp_limb_t q[mn + 1];
+  mpn_tdiv_qr (q, rp, 0, ap, 2*mn, mp, mn);
+}
+
+#define MAX_ECC_SIZE (1 + 521 / GMP_NUMB_BITS)
+#define MAX_SIZE (2*MAX_ECC_SIZE)
+#define COUNT 500
+
+void
+test_main (void)
+{
+  gmp_randstate_t state;
+  mp_limb_t a[MAX_SIZE];
+  mp_limb_t m[MAX_SIZE];
+  mp_limb_t ref[MAX_SIZE];
+  unsigned i;
+  mpz_t r;
+
+  gmp_randinit_default (state);
+  
+  mpz_init (r);
+  
+  for (i = 0; ecc_curves[i]; i++)
+    {
+      const struct ecc_curve *ecc = ecc_curves[i];
+      unsigned j;
+      for (j = 0; j < COUNT; j++)
+	{
+	  if (j & 1)
+	    mpz_rrandomb (r, state, 2*ecc->size * GMP_NUMB_BITS);
+	  else
+	    mpz_urandomb (r, state, 2*ecc->size * GMP_NUMB_BITS);
+
+	  _mpz_copy_limbs (a, r, 2*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_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);
+
+	  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->Bmodp_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);
+  gmp_randclear (state);
+}
diff --git a/testsuite/ecc-modinv-test.c b/testsuite/ecc-modinv-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..b8414e98afadeed5b4f350504df45ef5722294b7
--- /dev/null
+++ b/testsuite/ecc-modinv-test.c
@@ -0,0 +1,107 @@
+#include "testutils.h"
+
+static int
+ref_modinv (mp_limb_t *rp, const mp_limb_t *ap, const mp_limb_t *mp, mp_size_t mn)
+{
+  mp_limb_t tp[4*(mn+1)];
+  mp_limb_t *up = tp;
+  mp_limb_t *vp = tp + mn+1;
+  mp_limb_t *gp = tp + 2*(mn+1);
+  mp_limb_t *sp = tp + 3*(mn+1);
+  mp_size_t gn, sn;
+
+  mpn_copyi (up, ap, mn);
+  mpn_copyi (vp, mp, mn);
+  gn = mpn_gcdext (gp, sp, &sn, up, mn, vp, mn);
+  if (gn != 1 || gp[0] != 1)
+    return 0;
+  
+  if (sn < 0)
+    mpn_sub (sp, mp, mn, sp, -sn);
+  else if (sn < mn)
+    /* Zero-pad. */
+    mpn_zero (sp + sn, mn - sn);
+
+  mpn_copyi (rp, sp, mn);
+  return 1;
+}
+
+#define MAX_ECC_SIZE (1 + 521 / GMP_NUMB_BITS)
+#define COUNT 500
+
+void
+test_main (void)
+{
+  gmp_randstate_t state;
+  mp_limb_t a[MAX_ECC_SIZE];
+  mp_limb_t ai[MAX_ECC_SIZE];
+  mp_limb_t ref[MAX_ECC_SIZE];
+  mp_limb_t scratch[ECC_MODINV_ITCH (MAX_ECC_SIZE)];
+  unsigned i;
+  mpz_t r;
+
+  gmp_randinit_default (state);
+  mpz_init (r);
+  
+  for (i = 0; ecc_curves[i]; i++)
+    {
+      const struct ecc_curve *ecc = ecc_curves[i];
+      unsigned j;
+      for (j = 0; j < COUNT; j++)
+	{
+	  if (j & 1)
+	    mpz_rrandomb (r, state, ecc->size * GMP_NUMB_BITS);
+	  else
+	    mpz_urandomb (r, state, ecc->size * GMP_NUMB_BITS);
+
+	  _mpz_copy_limbs (a, r, ecc->size);
+
+	  if (!ref_modinv (ref, a, ecc->p, ecc->size))
+	    {
+	      if (verbose)
+		fprintf (stderr, "Test %u (bit size %u) not invertible.\n",
+			 j, ecc->bit_size);
+	      continue;
+	    }
+	  ecc_modp_inv (ecc, ai, a, scratch);
+	  if (mpn_cmp (ref, ai, ecc->size))
+	    {
+	      fprintf (stderr, "ecc_modp_inv failed (test %u, bit size %u):\n",
+		       j, ecc->bit_size);
+	      gmp_fprintf (stderr, "a = %Zx\n"
+			   "p = %Nx\n"
+			   "t = %Nx (bad)\n"
+			   "r = %Nx\n",
+			   r, ecc->p, ecc->size,
+			   ai, ecc->size,
+			   ref, ecc->size);
+	      abort ();
+	    }
+
+	  _mpz_copy_limbs (a, r, ecc->size);
+
+	  if (!ref_modinv (ref, a, ecc->q, ecc->size))
+	    {
+	      fprintf (stderr, "Test %u (bit size %u) not invertible.\n",
+		       j, ecc->bit_size);
+	      continue;
+	    }
+	  ecc_modq_inv (ecc, ai, a, scratch);
+	  if (mpn_cmp (ref, ai, ecc->size))
+	    {
+	      fprintf (stderr, "ecc_modq_inv failed (test %u, bit size %u):\n",
+		       j, ecc->bit_size);
+	      gmp_fprintf (stderr, "a = %Zx\n"
+			   "p = %Nx\n"
+			   "t = %Nx (bad)\n"
+			   "r = %Nx\n",
+			   r, ecc->p, ecc->size,
+			   ai, ecc->size,
+			   ref, ecc->size);
+	      abort ();
+	    }
+	}
+    }
+  gmp_randclear (state);
+  mpz_clear (r);
+}
diff --git a/testsuite/ecc-redc-test.c b/testsuite/ecc-redc-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..ac7de74e31ecb5f775aca7c36b0ebe4d8a3a245d
--- /dev/null
+++ b/testsuite/ecc-redc-test.c
@@ -0,0 +1,100 @@
+#include "testutils.h"
+
+static void
+ref_redc (mp_limb_t *rp, const mp_limb_t *ap, const mp_limb_t *mp, mp_size_t mn)
+{
+  mpz_t t;
+  mpz_t m, a;
+  mp_size_t an;
+
+  mpz_init (t);
+  mpz_setbit (t, mn * GMP_NUMB_BITS);
+
+  _mpz_init_mpn (m, mp, mn);
+
+  an = 2*mn;
+  while (an > 0 && ap[an-1] == 0)
+    an--;
+
+  _mpz_init_mpn (a, ap, an);
+  
+  mpz_invert (t, t, m);
+  mpz_mul (t, t, a);
+  mpz_mod (t, t, m);
+
+  _mpz_copy_limbs (rp, t, mn);
+
+  mpz_clear (t);
+}
+
+#define MAX_ECC_SIZE (1 + 521 / GMP_NUMB_BITS)
+#define MAX_SIZE (2*MAX_ECC_SIZE)
+#define COUNT 1000
+
+void
+test_main (void)
+{
+  gmp_randstate_t state;
+  mp_limb_t a[MAX_SIZE];
+  mp_limb_t m[MAX_SIZE];
+  mp_limb_t ref[MAX_SIZE];
+  unsigned i;
+  mpz_t r;
+
+  gmp_randinit_default (state);
+  
+  mpz_init (r);
+  
+  for (i = 0; ecc_curves[i]; i++)
+    {
+      const struct ecc_curve *ecc = ecc_curves[i];
+      unsigned j;
+      if (!ecc->redc)
+	continue;
+
+      for (j = 0; j < COUNT; j++)
+	{
+	  if (j & 1)
+	    mpz_rrandomb (r, state, 2*ecc->size * GMP_NUMB_BITS);
+	  else
+	    mpz_urandomb (r, state, 2*ecc->size * GMP_NUMB_BITS);
+
+	  _mpz_copy_limbs (a, r, 2*ecc->size);
+
+	  ref_redc (ref, a, ecc->p, ecc->size);
+
+	  mpn_copyi (m, a, 2*ecc->size);
+	  ecc->redc (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->redc 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 ();
+	    }
+
+	  mpn_copyi (m, a, 2*ecc->size);
+	  ecc_generic_redc (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_redc 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);
+  gmp_randclear (state);
+}
diff --git a/testsuite/testutils.c b/testsuite/testutils.c
index c0a75f8f9d85f57234b6076c7e7ce06c5fe029e2..60614a0e450b9657bb6cfc78d85635612df5f0ea 100644
--- a/testsuite/testutils.c
+++ b/testsuite/testutils.c
@@ -1086,5 +1086,14 @@ test_dsa_key(struct dsa_public_key *pub,
   mpz_clear(t);
 }
 
+const struct ecc_curve * const ecc_curves[] = {
+  &nettle_secp_192r1,
+  &nettle_secp_224r1,
+  &nettle_secp_256r1,
+  &nettle_secp_384r1,
+  &nettle_secp_521r1,
+  NULL
+};
+
 #endif /* WITH_HOGWEED */
 
diff --git a/testsuite/testutils.h b/testsuite/testutils.h
index 7519d65bbf0a218601f2564ce5f7988c7aa03b76..ed57b33ec7cf27849ab3c6c30fac7bb3c408b35a 100644
--- a/testsuite/testutils.h
+++ b/testsuite/testutils.h
@@ -18,6 +18,9 @@
 #if WITH_HOGWEED
 # include "rsa.h"
 # include "dsa.h"
+# include "ecc-curve.h"
+# include "ecc-internal.h"
+# include "gmp-glue.h"
 #endif
 
 #include "nettle-meta.h"
@@ -190,6 +193,8 @@ test_dsa_key(struct dsa_public_key *pub,
 	     struct dsa_private_key *key,
 	     unsigned q_size);
 
+extern const struct ecc_curve * const ecc_curves[];
+
 #endif /* WITH_HOGWEED */
   
 /* LDATA needs to handle NUL characters. */