diff --git a/.gitignore b/.gitignore
index 98ae06f46c17c04c92afc3a3e7805de84145bb5a..70ac5754a4d1dab35374444afa0b6f4e16a008ee 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,34 +1,15 @@
-RCS
-SCCS
-CVS
-CVS.adm
-RCSLOG
-cvslog.*
 tags
 TAGS
-.make.state
-.nse_depinfo
 *~
-#*
 .#*
-,*
-_$*
-*$
 *.old
-*.bak
-*.BAK
 *.orig
 *.rej
-.del-*
 *.a
-*.olb
 *.o
 *.obj
 *.so
 *.exe
-*.Z
-*.elc
-*.ln
 core
 /*.d
 /*.po
@@ -37,9 +18,7 @@ core
 /*.tar.gz.asc
 /.lib
 /*.asm
-/autom4te.cache
 /Makefile
-/aesdata
 /config.cache
 /config.h
 /config.h.in
@@ -48,12 +27,27 @@ core
 /config.make
 /config.status
 /configure
+/autom4te.cache
+/stamp-h
+/stamp-h.in
+/nettle-stdint.h
 /*.pc
 /machine.m4
+/aesdata
 /desdata
+/eccdata
+/eccdata.stamp
 /gcmdata
+/shadata
+/twofishdata
 /keymap.h
-/nettle-stdint.h
+/parity.h
+/rotors.h
+/ecc-192.h
+/ecc-224.h
+/ecc-256.h
+/ecc-384.h
+/ecc-521.h
 /nettle.aux
 /nettle.cp
 /nettle.cps
@@ -71,8 +65,3 @@ core
 /nettle.tps
 /nettle.vr
 /nettle.vrs
-/parity.h
-/rotors.h
-/shadata
-/stamp-h
-/stamp-h.in
diff --git a/ChangeLog b/ChangeLog
index 95f12da41a0ee4e9260b28555f1e9f7dd2b96626..febaa884cce1c37ba26118719a0dabfbd4a2244e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,245 @@
+2013-03-07  Niels Möller  <nisse@lysator.liu.se>
+
+	* gmp-glue.c (mpz_limbs_cmp): Don't use PTR and SIZ macros.
+
+	* Makefile.in (aesdata, desdata, twofishdata, shadata, gcmdata)
+	(eccdata): Arrange for compiling these programs for running on the
+	build system, also when cross compiling everything else.
+
+	* config.make.in (CC_FOR_BUILD, EXEEXT_FOR_BUILD): New variables.
+
+	* configure.ac: Use GMP_PROG_CC_FOR_BUILD and
+	GMP_PROG_EXEEXT_FOR_BUILD.
+
+	* aclocal.m4 (GMP_PROG_CC_FOR_BUILD, GMP_PROG_CC_FOR_BUILD_WORKS)
+	(GMP_PROG_EXEEXT_FOR_BUILD): New macros, based on GMP's.
+
+	* aesdata.c: Deleted includes of config.h and nettle-types.h. Use
+	unsigned char and unsigned long instead of stdint.h types.
+
+	* desdata.c: Deleted includes of config.h and desCode.h.
+	(main): Return 1 on invalid argument. Don't use ROR macro. Use
+	unsigned long instead of uint32_t, and make it work if unsigned
+	long is larger than 32 bits.
+
+	* gcmdata.c: Deleted include of config.h and use UNUSED macro.
+	* shadata.c: Likewise.
+
+	* twofishdata.c: Deleted include of nettle-types.h. Use unsigned
+	char instead of stdint.h types.
+
+	* x86_64/ecc-521-modp.asm: New file. 2.4 time speedup.
+
+2013-03-06  Niels Möller  <nisse@lysator.liu.se>
+
+	* x86_64/ecc-384-modp.asm: New file, 3 time speedup.
+	* x86_64/ecc-256-redc.asm: New file, 2.5 time speedup.
+	* x86_64/ecc-224-modp.asm: New file, 5 time speedup over C
+	version.
+
+2013-03-05  Niels Möller  <nisse@lysator.liu.se>
+
+	* configure.ac (asm_optional_list): Added ecc-521-modp.asm.
+	* ecc-521.c: Check HAVE_NATIVE_ecc_521_modp, and use native
+	version if available.
+	* armv7/ecc-521-modp.asm: New file, 2 time speedup over C version.
+
+2013-03-04  Niels Möller  <nisse@lysator.liu.se>
+
+	* configure.ac (asm_optional_list): Added ecc-384-modp.asm. Deleted
+	bogus reference to $asm_search_list.
+	* ecc-384.c: Check HAVE_NATIVE_ecc_384_modp, and use native
+	version if available.
+	* armv7/ecc-384-modp.asm: New file, 3 time speedup over C version.
+
+2013-03-03  Niels Möller  <nisse@lysator.liu.se>
+
+	* ecc-256.c: Fixed definition of USE_REDC.
+
+2013-03-01  Niels Möller  <nisse@lysator.liu.se>
+
+	* ecc-256.c: Check HAVE_NATIVE_ecc_256_redc, and use native
+	version if available.
+	* armv7/ecc-256-redc.asm: New file, 4 time speedup over C version.
+
+	* testsuite/ecc-redc-test.c: Increased test count.
+
+	* ecc-224.c: Check HAVE_NATIVE_ecc_224_modp, and use native
+	version if available.
+	* armv7/ecc-224-modp.asm: New file, 4.5 time speedup over C
+	version.
+
+	* configure.ac (asm_optional_list): Added ecc-224-modp.asm.
+	(OPT_ASM_SOURCES): Fixed assignment.
+
+2013-02-28  Niels Möller  <nisse@lysator.liu.se>
+
+	* x86_64/ecc-192-modp.asm: Reorganized to reduce number of
+	additions. Use setc instruction.
+
+	* examples/Makefile.in: Let $(HOGWEED_TARGETS) depend on
+	../libhogweed.a.
+
+	* armv7/ecc-192-modp.asm: New file. 2.5 time speedup over C
+	version.
+
+2013-02-27  Niels Möller  <nisse@lysator.liu.se>
+
+	* ecc-192.c: Check HAVE_NATIVE_ecc_192_modp, and use native
+	version if available.
+	(ecc_192_modp): Fixed carry handling bug in 32-bit version.
+
+	* x86_64/ecc-192-modp.asm: New file. 3.8 times speedup over C
+	version.
+
+	* configure.ac (OPT_ASM_SOURCES): New substituted variable.
+	(asm_replace_list, asm_optional_list): New variables. For files in
+	asm_optional_list, also add them to OPT_ASM_SOURCES and define
+	appropriate HAVE_NATIVE_* symbols found.
+
+	* Makefile.in (OPT_ASM_SOURCES): New variable. Used for setting
+	hogweed_OBJS and hogweed_PURE_OBJS.
+
+	* testsuite/ecc-mod-test.c: Increased test count.
+
+	* ecc-384.c (ecc_384_modp): Fixed typo which broke carry handling
+	in the 64-bit version.
+
+	* examples/ecc-benchmark.c (bench_add_jjj): Typo fix, benchmark
+	the right function.
+
+	* gmp-glue.h: Check if GMP provides mpz_limbs_read (expected in
+	next release).
+	* gmp-glue.c: Use GMP's mpz_limbs_read and friends if available.
+	Renamed all functions for consistency with GMP. Updated all
+	callers.
+
+2013-02-20  Niels Möller  <nisse@lysator.liu.se>
+
+	* examples/Makefile.in (HOGWEED_TARGETS): Added
+	hogweed-benchmark$(EXEEXT).
+	(SOURCES): Added hogweed-benchmark.c.
+	(hogweed-benchmark$(EXEEXT)): New target.
+
+	* examples/hogweed-benchmark.c: New file.
+
+	* ecdsa-keygen.c (ecdsa_generate_keypair): New file and function.
+	* Makefile.in (hogweed_SOURCES): Added ecdsa-keygen.c.
+	* testsuite/ecdsa-keygen-test.c: New testcase.
+	* testsuite/Makefile.in (TS_HOGWEED_SOURCES): Added
+	ecdsa-keygen-test.c.
+
+	* nettle-internal.h (TMP_ALLOC): Added missing parentheses.
+
+2013-02-18  Niels Möller  <nisse@lysator.liu.se>
+
+	* testsuite/ecdsa-verify-test.c: New testcase.
+	* testsuite/ecdsa-sign-test.c: New testcase.
+	* testsuite/Makefile.in (TS_HOGWEED_SOURCES): Added
+	ecdsa-sign-test.c and ecdsa-verify-test.c.
+	* testsuite/testutils.h: Include ecdsa.h.
+	(SHEX): Deleted const cast.
+
+	* ecc-point.c: New file, struct ecc_point abstraction.
+	* ecc-scalar.c: New file, struct ecc_scalar abstraction.
+	* ecc-random.c (ecc_modq_random, ecc_scalar_random): New file, new
+	functions.
+	* ecc-hash.c (ecc_hash): New file and function.
+	* ecc-ecdsa-sign.c: New file, low-level signing interface.
+	* ecc-ecdsa-verify.c: New file, low-level ecdsa verify.
+	* ecdsa-sign.c: (ecdsa_sign): New file and function.
+	* ecdsa-verify.c (ecdsa_verify): New file and function.
+	* ecdsa.h: New header file.
+	* ecc.h: Declare ecc_point and ecc_scalar functions.
+	* ecc-internal.h: Added declarations.
+	* Makefile.in (hogweed_SOURCES): Added new source files.
+	(HEADERS): Added ecdsa.h.
+
+	* gmp-glue.c (_mpz_set_mpn): New convenience function.
+	(_mpn_set_base256): New function.
+	(_gmp_alloc_limbs): New function.
+	(_gmp_free_limbs): New function.
+	* gmp-glue.h: Corresponding declarations. Include nettle-stdinh.h.
+
+	* examples/Makefile.in (HOGWEED_TARGETS): Renamed, was
+	RSA_TARGETS. Added ecc-benchmark$(EXEEXT).
+	(SOURCES): Added ecc-benchmark.c.
+	(ecc-benchmark$(EXEEXT)): New target.
+
+	* examples/ecc-benchmark.c: New file, benchmarking ecc primitives.
+
+2013-02-15  Niels Möller  <nisse@lysator.liu.se>
+
+	Integrate ecc_mul_a.
+	* ecc-a-to-j.c: New file.
+	* ecc-add-jjj.c: New file.
+	* ecc-mul-a.c: New file.
+	* Makefile.in (hogweed_SOURCES): Added new files.
+	* testsuite/ecc-mul-a-test.c: New file.
+	* testsuite/Makefile.in (TS_HOGWEED_SOURCES): Added
+	ecc-mul-a-test.c.
+
+	* testsuite/testutils.c: Removed redundant includes.
+	(die): New function.
+
+	Integrate ecc_mul_g.
+	* ecc.h: New file.
+	* ecc-j-to-a.c: New file.
+	* ecc-size.c: New file.
+	* ecc-add-jja.c: New file.
+	* ecc-dup-jj.c: New file.
+	* ecc-mul-g.c: New file.
+	* sec-tabselect.c: New file.
+	* Makefile.in (hogweed_SOURCES): Added new files.
+	(HEADERS): Added ecc.h
+	* testsuite/ecc-mul-g-test.c: New file.
+	* testsuite/Makefile.in (TS_HOGWEED_SOURCES): Added
+	ecc-mul-g-test.c.
+	* testsuite/testutils.c (xalloc_limbs): New function.
+	(test_mpn): New function.
+	(test_ecc_point): New function.
+	(test_ecc_mul_a): New function.
+	(test_ecc_mul_j): New function.
+	* testsuite/testutils.h: Corresponding declarations.
+
+	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.
+
+	* eccdata.c: New program, for generating ECC-related tables.
+	* Makefile.in (ecc-192.h, ecc-224.h, ecc-256.h, ecc-384.h)
+	(ecc-512.h): New generated files.
+
 2013-02-19  Niels Möller  <nisse@lysator.liu.se>
 
 	* armv7/memxor.asm (memxor): Software pipelining for the aligned
@@ -8,6 +250,9 @@
 
 2013-02-14  Niels Möller  <nisse@lysator.liu.se>
 
+	* configure.ac: Find GMP's GMP_NUMB_BITS. Substitute in Makefile.
+	* config.make.in (GMP_NUMB_BITS): New variable.
+
 	* examples/rsa-keygen.c (uint_arg): New function.
 	(main): New options -s and -e, to specify key size and public
 	exponent. Increased default key size to 2048.
diff --git a/Makefile.in b/Makefile.in
index 1cd062d56bb6a517b409b9b5f807b1551bdd5ad2..1ec807bef77b2fa1b91d4e38c65824648571175b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -14,6 +14,8 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@
 INSTALL_STRIP_PROGRAM = $(INSTALL_PROGRAM) -s
 MKDIR_P = @MKDIR_P@
 
+OPT_ASM_SOURCES = @OPT_ASM_SOURCES@
+
 SUBDIRS = tools testsuite examples
 
 include config.make
@@ -30,7 +32,7 @@ internal_SOURCES = nettle-internal.c
 internal_TARGETS = $(internal_SOURCES:.c=.$(OBJEXT))
 
 TARGETS = aesdata$(EXEEXT) desdata$(EXEEXT) twofishdata$(EXEEXT) \
-	  shadata$(EXEEXT) gcmdata$(EXEEXT) \
+	  shadata$(EXEEXT) gcmdata$(EXEEXT) eccdata$(EXEEXT) \
 	  $(getopt_TARGETS) $(internal_TARGETS) \
 	  $(LIBTARGETS) $(SHLIBTARGETS)
 IMPLICIT_TARGETS = @IF_DLL@ $(LIBNETTLE_FILE) $(LIBHOGWEED_FILE)
@@ -122,21 +124,31 @@ hogweed_SOURCES = sexp.c sexp-format.c \
 		  dsa-sha256-sign.c dsa-sha256-verify.c  \
 		  dsa2sexp.c sexp2dsa.c \
 		  pgp-encode.c rsa2openpgp.c \
-		  der-iterator.c der2rsa.c der2dsa.c
+		  der-iterator.c der2rsa.c der2dsa.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 \
+		  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-mul-g.c ecc-mul-a.c ecc-hash.c ecc-random.c \
+		  ecc-point.c ecc-scalar.c \
+		  ecc-ecdsa-sign.c ecdsa-sign.c \
+		  ecc-ecdsa-verify.c ecdsa-verify.c ecdsa-keygen.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 ecc.h ecdsa.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 \
@@ -146,7 +158,7 @@ INSTALL_HEADERS = $(HEADERS) nettle-stdint.h
 
 SOURCES = $(nettle_SOURCES) $(hogweed_SOURCES) \
 	  $(getopt_SOURCES) $(internal_SOURCES) \
-	  aesdata.c desdata.c twofishdata.c shadata.c gcmdata.c
+	  aesdata.c desdata.c twofishdata.c shadata.c gcmdata.c eccdata.c
 
 DISTFILES = $(SOURCES) $(HEADERS) getopt.h .bootstrap run-tests \
 	aclocal.m4 configure.ac \
@@ -159,6 +171,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 ecc-internal.h \
 	asm.m4 \
 	nettle.texinfo nettle.info nettle.html nettle.pdf sha-example.c
 
@@ -166,8 +179,8 @@ DISTFILES = $(SOURCES) $(HEADERS) getopt.h .bootstrap run-tests \
 nettle_OBJS = $(nettle_SOURCES:.c=.$(OBJEXT)) $(LIBOBJS)
 nettle_PURE_OBJS = $(nettle_OBJS:.$(OBJEXT)=.p$(OBJEXT))
 
-hogweed_OBJS = $(hogweed_SOURCES:.c=.$(OBJEXT))
-hogweed_PURE_OBJS = $(hogweed_OBJS:.$(OBJEXT)=.p$(OBJEXT))
+hogweed_OBJS = $(hogweed_SOURCES:.c=.$(OBJEXT)) $(OPT_ASM_SOURCES:.asm=.$(OBJEXT))
+hogweed_PURE_OBJS = $(hogweed_OBJS:.$(OBJEXT)=.p$(OBJEXT)) $(OPT_ASM_SOURCES:.asm=.p$(OBJEXT))
 
 libnettle.a: $(nettle_OBJS)
 	-rm -f $@
@@ -208,24 +221,32 @@ $(LIBHOGWEED_FORLINK): $(hogweed_PURE_OBJS) $(LIBNETTLE_FORLINK)
 	$(COMPILE) $(SHLIBCFLAGS) -c $< -o $@ \
 	&& $(DEP_PROCESS)
 
-# For Solaris and BSD make, we have to use an explicit rule for each executable
-aesdata$(EXEEXT): aesdata.$(OBJEXT)
-	$(LINK) aesdata.$(OBJEXT) $(LIBS) -o aesdata$(EXEEXT)
+# For Solaris and BSD make, we have to use an explicit rule for each
+# executable. Avoid object file targets to make it easy to run the
+# right compiler.
+aesdata$(EXEEXT_FOR_BUILD): aesdata.c
+	$(CC_FOR_BUILD) `test -f aesdata.c || echo '$(srcdir)/'`aesdata.c \
+	-o aesdata$(EXEEXT_FOR_BUILD)
 
-desdata$(EXEEXT): desdata.$(OBJEXT)
-	$(LINK) desdata.$(OBJEXT) $(LIBS) -o desdata$(EXEEXT)
+desdata$(EXEEXT_FOR_BUILD): desdata.c
+	$(CC_FOR_BUILD) `test -f desdata.c || echo '$(srcdir)/'`desdata.c \
+	-o desdata$(EXEEXT_FOR_BUILD)
 
-twofishdata$(EXEEXT): twofishdata.$(OBJEXT)
-	$(LINK) twofishdata.$(OBJEXT) $(LIBS) -o twofishdata$(EXEEXT)
+twofishdata$(EXEEXT_FOR_BUILD): twofishdata.c
+	$(CC_FOR_BUILD) `test -f twofishdata.c || echo '$(srcdir)/'`twofishdata.c \
+	-o twofishdata$(EXEEXT_FOR_BUILD)
 
-shadata$(EXEEXT): shadata.$(OBJEXT)
-	$(LINK) shadata.$(OBJEXT) $(LIBS) -lm -o shadata$(EXEEXT)
+shadata$(EXEEXT_FOR_BUILD): shadata.c
+	$(CC_FOR_BUILD) `test -f shadata.c || echo '$(srcdir)/'`shadata.c -lm \
+	-o shadata$(EXEEXT_FOR_BUILD)
 
-gcmdata$(EXEEXT): gcmdata.$(OBJEXT)
-	$(LINK) gcmdata.$(OBJEXT) $(LIBS) -o gcmdata$(EXEEXT)
+gcmdata$(EXEEXT_FOR_BUILD): gcmdata.c
+	$(CC_FOR_BUILD) `test -f gcmdata.c || echo '$(srcdir)/'`gcmdata.c \
+	-o gcmdata$(EXEEXT_FOR_BUILD)
 
-# .$(OBJEXT)$(EXEEXT):
-# 	$(LINK) $< $(LIBS) -o $@
+eccdata$(EXEEXT_FOR_BUILD): eccdata.c
+	$(CC_FOR_BUILD) `test -f eccdata.c || echo '$(srcdir)/'`eccdata.c -lgmp \
+	-o eccdata$(EXEEXT_FOR_BUILD)
 
 # desCore rules
 # It seems using $(srcdir)/ doesn't work with GNU make 3.79.1
@@ -241,6 +262,64 @@ $(des_headers): desdata.c
 
 des.$(OBJEXT): des.c des.h $(des_headers)
 
+# Generate ECC files.
+# Some possible choices for 192:
+#	k = 15, c = 4,  64 entries,  ~3 KB
+#	k = 20, c = 6, 128 entries,  ~6 KB
+#	k = 10, c = 6, 256 entries, ~12 KB
+#	k =  7, c = 6, 320 entries, ~15 KB
+#	k =  9, c = 7, 512 entries, ~24 KB
+ecc-192.h: eccdata.stamp
+	./eccdata$(EXEEXT) 192 7 6 $(GMP_NUMB_BITS) > $@T && mv $@T $@
+# Some possible choices for 224:
+#	k = 18, c = 4,  64 entries,  ~4 KB
+#	k = 24, c = 6, 128 entries,  ~8 KB
+#	k = 12, c = 6, 256 entries, ~16 KB
+#	k =  8, c = 6, 320 entries, ~20 KB
+#	k = 10, c = 7, 512 entries, ~32 KB
+ecc-224.h: eccdata.stamp
+	./eccdata$(EXEEXT) 224 12 6 $(GMP_NUMB_BITS) > $@T && mv $@T $@
+# Some possible choices for 256:
+#	k = 20, c = 4,  64 entries,  ~4 KB
+#	k = 27, c = 6, 128 entries,  ~8 KB
+#	k = 14, c = 6, 256 entries, ~16 KB
+#	k =  9, c = 6, 320 entries, ~20 KB
+#	k = 12, c = 7, 512 entries, ~32 KB
+ecc-256.h: eccdata.stamp
+	./eccdata$(EXEEXT) 256 14 6 $(GMP_NUMB_BITS) > $@T && mv $@T $@
+# Some possible choices for 384:
+#	k = 31, c = 4,  64 entries,  ~6 KB
+#	k = 41, c = 6, 128 entries, ~12 KB
+#	k = 20, c = 6, 256 entries, ~24 KB
+#	k = 14, c = 6, 320 entries, ~30 KB
+#	k = 18, c = 7, 512 entries, ~48 KB
+ecc-384.h: eccdata.stamp
+	./eccdata$(EXEEXT) 384 41 6 $(GMP_NUMB_BITS) > $@T && mv $@T $@
+# Some possible choices for 521:
+#	k = 42, c = 4,  64 entries,  ~9 KB
+#	k = 56, c = 6, 128 entries, ~18 KB
+#	k = 28, c = 6, 256 entries, ~35 KB
+#	k = 19, c = 6, 320 entries, ~44 KB
+#	k = 24, c = 7, 512 entries, ~70 KB
+ecc-521.h: eccdata.stamp
+	./eccdata$(EXEEXT) 521 56 6 $(GMP_NUMB_BITS) > $@T && mv $@T $@
+
+eccdata.stamp: eccdata.c
+	$(MAKE) eccdata$(EXEEXT)
+	echo stamp > eccdata.stamp
+
+ecc-192.$(OBJEXT): ecc-192.h
+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-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
+
 .asm.s:
 	$(M4) $(srcdir)/asm.m4 machine.m4 config.m4 $< >$@T \
 	&& test -s $@T && mv -f $@T $@
@@ -490,7 +569,8 @@ distcheck: dist
 	$(rm_distcheck)
 
 clean-here:
-	-rm -f $(TARGETS) $(IMPLICIT_TARGETS) *.$(OBJEXT) *.p$(OBJEXT) *.s
+	-rm -f $(TARGETS) $(IMPLICIT_TARGETS) *.$(OBJEXT) *.p$(OBJEXT) *.s \
+		ecc-192.h ecc-224.h ecc-256.h ecc-384.h ecc-521.h eccdata.stamp
 	-rm -rf .lib
 
 distclean-here: clean-here
diff --git a/aclocal.m4 b/aclocal.m4
index a94c20d308384688e38d8c608c626ddfa2ee66b5..ae6b204aee52f475bc7f3e85ca3f930772eca14d 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -496,6 +496,118 @@ fi
 rm -f conftest*
 ])
 
+dnl  GMP_PROG_CC_FOR_BUILD
+dnl  ---------------------
+dnl  Establish CC_FOR_BUILD, a C compiler for the build system.
+dnl
+dnl  If CC_FOR_BUILD is set then it's expected to work, likewise the old
+dnl  style HOST_CC, otherwise some likely candidates are tried, the same as
+dnl  configfsf.guess.
+
+AC_DEFUN([GMP_PROG_CC_FOR_BUILD],
+[AC_REQUIRE([AC_PROG_CC])
+if test -n "$CC_FOR_BUILD"; then
+  GMP_PROG_CC_FOR_BUILD_WORKS($CC_FOR_BUILD,,
+    [AC_MSG_ERROR([Specified CC_FOR_BUILD doesn't seem to work])])
+elif test -n "$HOST_CC"; then
+  GMP_PROG_CC_FOR_BUILD_WORKS($HOST_CC,
+    [CC_FOR_BUILD=$HOST_CC],
+    [AC_MSG_ERROR([Specified HOST_CC doesn't seem to work])])
+elif test $cross_compiling = no ; then
+  CC_FOR_BUILD="$CC"
+else
+  for i in cc gcc c89 c99; do
+    GMP_PROG_CC_FOR_BUILD_WORKS($i,
+      [CC_FOR_BUILD=$i
+       break])
+  done
+  if test -z "$CC_FOR_BUILD"; then
+    AC_MSG_ERROR([Cannot find a build system compiler])
+  fi
+fi
+
+AC_ARG_VAR(CC_FOR_BUILD,[build system C compiler])
+AC_SUBST(CC_FOR_BUILD)
+])
+
+
+dnl  GMP_PROG_CC_FOR_BUILD_WORKS(cc/cflags[,[action-if-good][,action-if-bad]])
+dnl  -------------------------------------------------------------------------
+dnl  See if the given cc/cflags works on the build system.
+dnl
+dnl  It seems easiest to just use the default compiler output, rather than
+dnl  figuring out the .exe or whatever at this stage.
+
+AC_DEFUN([GMP_PROG_CC_FOR_BUILD_WORKS],
+[AC_MSG_CHECKING([build system compiler $1])
+# remove anything that might look like compiler output to our "||" expression
+rm -f conftest* a.out b.out a.exe a_out.exe
+cat >conftest.c <<EOF
+int
+main ()
+{
+  exit(0);
+}
+EOF
+gmp_compile="$1 conftest.c"
+cc_for_build_works=no
+if AC_TRY_EVAL(gmp_compile); then
+  if (./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest) >&AC_FD_CC 2>&1; then
+    cc_for_build_works=yes
+  fi
+fi
+rm -f conftest* a.out b.out a.exe a_out.exe
+AC_MSG_RESULT($cc_for_build_works)
+if test "$cc_for_build_works" = yes; then
+  ifelse([$2],,:,[$2])
+else
+  ifelse([$3],,:,[$3])
+fi
+])
+
+dnl  GMP_PROG_EXEEXT_FOR_BUILD
+dnl  -------------------------
+dnl  Determine EXEEXT_FOR_BUILD, the build system executable suffix.
+dnl
+dnl  The idea is to find what "-o conftest$foo" will make it possible to run
+dnl  the program with ./conftest.  On Unix-like systems this is of course
+dnl  nothing, for DOS it's ".exe", or for a strange RISC OS foreign file
+dnl  system cross compile it can be ",ff8" apparently.  Not sure if the
+dnl  latter actually applies to a build-system executable, maybe it doesn't,
+dnl  but it won't hurt to try.
+
+AC_DEFUN([GMP_PROG_EXEEXT_FOR_BUILD],
+[AC_REQUIRE([GMP_PROG_CC_FOR_BUILD])
+AC_CACHE_CHECK([for build system executable suffix],
+               gmp_cv_prog_exeext_for_build,
+[if test $cross_compiling = no ; then
+  gmp_cv_prog_exeext_for_build="$EXEEXT"
+else
+  cat >conftest.c <<EOF
+int
+main ()
+{
+  exit (0);
+}
+EOF
+  for i in .exe ,ff8 ""; do
+    gmp_compile="$CC_FOR_BUILD conftest.c -o conftest$i"
+    if AC_TRY_EVAL(gmp_compile); then
+      if (./conftest) 2>&AC_FD_CC; then
+        gmp_cv_prog_exeext_for_build=$i
+        break
+      fi
+    fi
+  done
+  rm -f conftest*
+  if test "${gmp_cv_prog_exeext_for_build+set}" != set; then
+    AC_MSG_ERROR([Cannot determine executable suffix])
+  fi
+fi
+])
+AC_SUBST(EXEEXT_FOR_BUILD,$gmp_cv_prog_exeext_for_build)
+])
+
 dnl @synopsis AX_CREATE_STDINT_H [( HEADER-TO-GENERATE [, HEADERS-TO-CHECK])]
 dnl
 dnl the "ISO C9X: 7.18 Integer types <stdint.h>" section requires the
diff --git a/aesdata.c b/aesdata.c
index a62ab5ac17c58155fb3070cfeead18cdc5d6a31a..9202d0f374d9246a89c06dee7db6e5b0085e6317 100644
--- a/aesdata.c
+++ b/aesdata.c
@@ -1,14 +1,8 @@
-#if HAVE_CONFIG_H
-# include "config.h"
-#endif
-
 #include <assert.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 
-#include "nettle-types.h"
-
 #if 1
 # define BYTE_FORMAT "0x%02x"
 # define BYTE_COLUMNS 8
@@ -17,18 +11,18 @@
 # define BYTE_COLUMNS 0x10
 #endif
 
-#define WORD_FORMAT "0x%08x"
+#define WORD_FORMAT "0x%08lx"
 #define WORD_COLUMNS 4
 
-uint8_t sbox[0x100];
-uint8_t isbox[0x100];
+unsigned char sbox[0x100];
+unsigned char isbox[0x100];
 
-uint8_t gf2_log[0x100];
-uint8_t gf2_exp[0x100];
+unsigned char gf2_log[0x100];
+unsigned char gf2_exp[0x100];
 
-uint32_t dtable[4][0x100];
-uint32_t itable[4][0x100];
-uint32_t mtable[4][0x100];
+unsigned long dtable[4][0x100];
+unsigned long itable[4][0x100];
+unsigned long mtable[4][0x100];
 
 static unsigned
 xtime(unsigned x)
@@ -109,7 +103,7 @@ compute_dtable(void)
     {
       unsigned s = sbox[i];
       unsigned j;
-      uint32_t t  =( ( (s ^ xtime(s)) << 24)
+      unsigned long t  =( ( (s ^ xtime(s)) << 24)
 		     | (s << 16) | (s << 8)
 		     | xtime(s) );
 
@@ -128,10 +122,10 @@ compute_itable(void)
     {
       unsigned s = isbox[i];
       unsigned j;
-      uint32_t t = ( (mult(s, 0xb) << 24)
-		   | (mult(s, 0xd) << 16)
-		   | (mult(s, 0x9) << 8)
-		   | (mult(s, 0xe) ));
+      unsigned long t = ( (mult(s, 0xb) << 24)
+			| (mult(s, 0xd) << 16)
+			| (mult(s, 0x9) << 8)
+			| (mult(s, 0xe) ));
       
       for (j = 0; j<4; j++, t = (t << 8) | (t >> 24))
 	itable[j][i] = t;
@@ -146,10 +140,10 @@ compute_mtable(void)
   for (i = 0; i<0x100; i++)
     {
       unsigned j;
-      uint32_t t = ( (mult(i, 0xb) << 24)
-		   | (mult(i, 0xd) << 16)
-		   | (mult(i, 0x9) << 8)
-		   | (mult(i, 0xe) ));
+      unsigned long t = ( (mult(i, 0xb) << 24)
+			| (mult(i, 0xd) << 16)
+			| (mult(i, 0x9) << 8)
+			| (mult(i, 0xe) ));
       
       for (j = 0; j<4; j++, t = (t << 8) | (t >> 24))
 	mtable[j][i] = t;
@@ -157,7 +151,7 @@ compute_mtable(void)
 }
 
 static void
-display_byte_table(const char *name, uint8_t *table)
+display_byte_table(const char *name, unsigned char *table)
 {
   unsigned i, j;
 
@@ -174,7 +168,7 @@ display_byte_table(const char *name, uint8_t *table)
 }
 
 static void
-display_table(const char *name, uint32_t table[][0x100])
+display_table(const char *name, unsigned long table[][0x100])
 {
   unsigned i, j, k;
   
diff --git a/armv7/README b/armv7/README
index 4d01f30b1eec31a193f72d236279daba6b523c35..9bacd97b030e83f6ff91eea9660b47abd2d643d4 100644
--- a/armv7/README
+++ b/armv7/README
@@ -4,6 +4,8 @@ For efficient loads and stores, use ldmia, stmia and friends. Can do
 two loads or stores per cycle with 8-byte aligned addresses, or three
 loads or stores in two cycles, regardless of alignment.
 
+12 usable registers (if we exclude r9).
+
 ABI gnueabi(hf) (not depending on the floating point conventions)
 
 Registers	May be		Argument
@@ -23,7 +25,7 @@ r10		N
 r11		N
 r12 (ip)	Y
 r13 (sp)
-r14 (lr)
+r14 (lr)        N
 r15 (pc)
 
 q0 (d0, d1)	Y		1 (for "hf" abi)
diff --git a/armv7/ecc-192-modp.asm b/armv7/ecc-192-modp.asm
new file mode 100644
index 0000000000000000000000000000000000000000..1b226e305c5185e34382f79c30d5c9e76ffbff02
--- /dev/null
+++ b/armv7/ecc-192-modp.asm
@@ -0,0 +1,93 @@
+C nettle, low-level cryptographics library
+C
+C Copyright (C) 2013, Niels Möller
+C
+C The nettle library is free software; you can redistribute it and/or modify
+C it under the terms of the GNU Lesser General Public License as published by
+C the Free Software Foundation; either version 2.1 of the License, or (at your
+C option) any later version.
+C
+C The nettle library is distributed in the hope that it will be useful, but
+C WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+C or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+C License for more details.
+C
+C You should have received a copy of the GNU Lesser General Public License
+C along with the nettle library; see the file COPYING.LIB.  If not, write to
+C the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+C MA 02111-1301, USA.
+
+	.file "ecc-192-modp.asm"
+	.arm
+
+define(<HP>, <r0>) C Overlaps unused ecc argument
+define(<RP>, <r1>)
+
+define(<T0>, <r2>)
+define(<T1>, <r3>)
+define(<T2>, <r4>)
+define(<T3>, <r5>)
+define(<T4>, <r6>)
+define(<T5>, <r7>)
+define(<T6>, <r8>)
+define(<T7>, <r10>)
+define(<H0>, <T0>) C Overlaps T0 and T1
+define(<H1>, <T1>)
+define(<C2>, <HP>)
+define(<C4>, <r12>)
+
+	C ecc_192_modp (const struct ecc_curve *ecc, mp_limb_t *rp)
+	.text
+	.align 2
+
+PROLOGUE(nettle_ecc_192_modp)
+	push	{r4,r5,r6,r7,r8,r10}
+	C Reduce two words at a time
+	add	HP, RP, #48
+	add	RP, RP, #8
+	ldmdb	HP!, {H0,H1}
+	ldm	RP, {T2,T3,T4,T5,T6,T7}
+	mov	C4, #0
+	adds	T4, T4, H0
+	adcs	T5, T5, H1
+	adcs	T6, T6, H0
+	adcs	T7, T7, H1
+	C Need to add carry to T2 and T4, do T4 later.
+	adc	C4, C4, #0
+
+	ldmdb	HP!, {H0,H1}
+	mov	C2, #0
+	adcs	T2, T2, H0
+	adcs	T3, T3, H1
+	adcs	T4, T4, H0
+	adcs	T5, T5, H1
+	C Need to add carry to T0 and T2, do T2 later
+	adc	C2, C2, #0
+
+	ldmdb	RP!, {T0, T1}
+	adcs	T0, T0, T6
+	adcs	T1, T1, T7
+	adcs	T2, T2, T6
+	adcs	T3, T3, T7
+	adc	C4, C4, #0
+
+	adds	T2, T2, C2
+	adcs	T3, T3, #0
+	adcs	T4, T4, C4
+	adcs	T5, T5, #0
+	mov	C2, #0
+	adc	C2, C2, #0
+
+	C Add in final carry
+	adcs	T0, T0, #0
+	adcs	T1, T1, #0
+	adcs	T2, T2, C2
+	adcs	T3, T3, #0
+	adcs	T4, T4, #0
+	adc	T5, T5, #0
+
+	stm	RP, {T0,T1,T2,T3,T4,T5}
+
+	pop	{r4,r5,r6,r7,r8,r10}
+	bx	lr
+EPILOGUE(nettle_ecc_192_modp)
diff --git a/armv7/ecc-224-modp.asm b/armv7/ecc-224-modp.asm
new file mode 100644
index 0000000000000000000000000000000000000000..ef7a703ad3cfee93a15e148f79c4f23d44b690ba
--- /dev/null
+++ b/armv7/ecc-224-modp.asm
@@ -0,0 +1,111 @@
+C nettle, low-level cryptographics library
+C
+C Copyright (C) 2013, Niels Möller
+C
+C The nettle library is free software; you can redistribute it and/or modify
+C it under the terms of the GNU Lesser General Public License as published by
+C the Free Software Foundation; either version 2.1 of the License, or (at your
+C option) any later version.
+C
+C The nettle library is distributed in the hope that it will be useful, but
+C WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+C or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+C License for more details.
+C
+C You should have received a copy of the GNU Lesser General Public License
+C along with the nettle library; see the file COPYING.LIB.  If not, write to
+C the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+C MA 02111-1301, USA.
+
+	.file "ecc-224-modp.asm"
+	.arm
+
+define(<RP>, <r1>)
+define(<H>, <r0>) C Overlaps unused ecc argument
+
+define(<T0>, <r2>)
+define(<T1>, <r3>)
+define(<T2>, <r4>)
+define(<T3>, <r5>)
+define(<T4>, <r6>)
+define(<T5>, <r7>)
+define(<T6>, <r8>)
+define(<N3>, <r10>)
+define(<L0>, <r11>)
+define(<L1>, <r12>)
+define(<L2>, <lr>)
+
+	C ecc_224_modp (const struct ecc_curve *ecc, mp_limb_t *rp)
+	.text
+	.align 2
+
+PROLOGUE(nettle_ecc_224_modp)
+	push	{r4,r5,r6,r7,r8,r10,r11,lr}
+
+	add	L2, RP, #28
+	ldm	L2, {T0,T1,T2,T3,T4,T5,T6}
+	mov	H, #0
+
+	adds	T0, T0, T4
+	adcs	T1, T1, T5
+	adcs	T2, T2, T6
+	adc	H, H, #0
+
+	C This switch from adcs to sbcs takes carry into account with
+	C correct sign, but it always subtracts 1 too much. We arrange
+	C to also add B^7 + 1 below, so the effect is adding p. This
+	C addition of p also ensures that the result never is
+	C negative.
+
+	sbcs	N3, T3, T0
+	sbcs	T4, T4, T1
+	sbcs	T5, T5, T2
+	sbcs	T6, T6, H
+	mov	H, #1		C This is the B^7
+	sbc	H, #0
+	subs	T6, T6, T3
+	sbc	H, #0
+
+	C Now subtract from low half
+	ldm	RP!, {L0,L1,L2}
+
+	C Clear carry, with the sbcs, this is the 1.
+	adds	RP, #0
+
+	sbcs	T0, L0, T0
+	sbcs	T1, L1, T1
+	sbcs	T2, L2, T2
+	ldm	RP!, {T3,L0,L1,L2}
+	sbcs	T3, T3, N3
+	sbcs	T4, L0, T4
+	sbcs	T5, L1, T5
+	sbcs	T6, L2, T6
+	rsc	H, H, #0
+
+	C Now -2 <= H <= 0 is the borrow, so subtract (B^3 - 1) |H|
+	C Use (B^3 - 1) H = <H, H, H> if -1 <=H <= 0, and
+	C     (B^3 - 1) H = <1,B-1, B-1, B-2> if H = -2
+	subs	T0, T0, H
+	asr	L1, H, #1
+	sbcs	T1, T1, L1
+	eor	H, H, L1
+	sbcs	T2, T2, L1
+	sbcs	T3, T3, H
+	sbcs	T4, T4, #0
+	sbcs	T5, T5, #0
+	sbcs	T6, T6, #0
+	sbcs	H, H, H
+
+	C Final borrow, subtract (B^3 - 1) |H|
+	subs	T0, T0, H
+	sbcs	T1, T1, H
+	sbcs	T2, T2, H
+	sbcs	T3, T3, #0
+	sbcs	T4, T4, #0
+	sbcs	T5, T5, #0
+	sbcs	T6, T6, #0
+
+	stmdb	RP, {T0,T1,T2,T3,T4,T5,T6}
+
+	pop	{r4,r5,r6,r7,r8,r10,r11,pc}
+EPILOGUE(nettle_ecc_224_modp)
diff --git a/armv7/ecc-256-redc.asm b/armv7/ecc-256-redc.asm
new file mode 100644
index 0000000000000000000000000000000000000000..cbf10a8900d4b95d7b41a1d01400b37b6dd6c4b6
--- /dev/null
+++ b/armv7/ecc-256-redc.asm
@@ -0,0 +1,160 @@
+C nettle, low-level cryptographics library
+C
+C Copyright (C) 2013, Niels Möller
+C
+C The nettle library is free software; you can redistribute it and/or modify
+C it under the terms of the GNU Lesser General Public License as published by
+C the Free Software Foundation; either version 2.1 of the License, or (at your
+C option) any later version.
+C
+C The nettle library is distributed in the hope that it will be useful, but
+C WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+C or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+C License for more details.
+C
+C You should have received a copy of the GNU Lesser General Public License
+C along with the nettle library; see the file COPYING.LIB.  If not, write to
+C the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+C MA 02111-1301, USA.
+
+	.file "ecc-256-redc.asm"
+	.arm
+
+define(<RP>, <r1>)
+
+define(<T0>, <r0>) C Overlaps unused ecc argument
+define(<T1>, <r2>)
+define(<T2>, <r3>)
+define(<T3>, <r4>)
+define(<T4>, <r5>)
+define(<T5>, <r6>)
+define(<T6>, <r7>)
+define(<T7>, <r8>)
+define(<F0>, <r10>)
+define(<F1>, <r11>)
+define(<F2>, <r12>)
+define(<F3>, <lr>)
+
+	C ecc_256_redc (const struct ecc_curve *ecc, mp_limb_t *rp)
+	.text
+	.align 2
+
+PROLOGUE(nettle_ecc_256_redc)
+	push	{r4,r5,r6,r7,r8,r10,r11,lr}
+
+	ldm	RP!, {T0,T1,T2,T3,T4,T5,T6,T7}
+
+	C Set <F3,F2,F1> to the high 4 limbs of (B^2-B+1)<T2,T1,T0>
+	C         T2 T1
+	C   T2 T1 T0
+	C   -  T2 T1 T0
+	C -------------
+	C   F3 F2 F1 F0
+
+
+	adds	F1, T0, T2
+	adcs	F2, T1, #0
+	adc	F3, T2, #0
+
+	subs	F0, T1, T0
+	sbcs	F1, F1, T1	C Could also be rsc ?
+	sbcs	F2, F2, T2
+	sbc	F3, F3, #0
+
+	C Add:
+	C   T10 T9 T8 T7 T6 T5 T4 T3
+	C +  F3 F2 F1 F0 T0 T2 T1 T0
+	C --------------------------
+	C    T7 T6 T5 T4 T3 T2 T1 T0
+
+	adds	T3, T3, T0
+	adcs	T1, T4, T1
+	adcs	T2, T5, T2
+	adcs	T6, T6, T0
+	mov	T0, T3		C FIXME: Be more clever?
+	mov	T3, T6
+	adcs	T4, T7, F0
+
+	ldm	RP!, {T5,T6,T7}
+	adcs	T5, T5, F1
+	adcs	T6, T6, F2
+	adcs	T7, T7, F3
+
+	C New F3, F2, F1, F0, also adding in carry
+	adcs	F1, T0, T2
+	adcs	F2, T1, #0
+	adc	F3, T2, #0
+
+	subs	F0, T1, T0
+	sbcs	F1, F1, T1	C Could also be rsc ?
+	sbcs	F2, F2, T2
+	sbc	F3, F3, #0
+
+	C Start adding
+	adds	T3, T3, T0
+	adcs	T1, T4, T1
+	adcs	T2, T5, T2
+	adcs	T6, T6, T0
+	mov	T0, T3		C FIXME: Be more clever?
+	mov	T3, T6
+	adcs	T4, T7, F0
+
+	ldm	RP!, {T5,T6,T7}
+	adcs	T5, T5, F1
+	adcs	T6, T6, F2
+	adcs	T7, T7, F3
+
+	C Final iteration, eliminate only T0, T1
+	C Set <F2, F1, F0> to the high 3 limbs of (B^2-B+1)<T1,T0>
+
+	C      T1 T0 T1
+	C      -  T1 T0
+	C -------------
+	C      F2 F1 F0
+
+	C First add in carry
+	adcs	F1, T0, #0
+	adcs	F2, T1, #0
+	subs	F0, T1, T0
+	sbcs	F1, F1, T1
+	sbc	F2, F2, #0
+
+	C Add:
+	C    T9 T8 T7 T6 T5 T4 T3 T2
+	C +  F2 F1 F0 T0  0 T1 T0  0
+	C --------------------------
+	C    F2 F1 T7 T6 T5 T4 T3 T2
+
+	adds	T3, T3, T0
+	adcs	T4, T4, T1
+	adcs	T5, T5, #0
+	adcs	T6, T6, T0
+	adcs	T7, T7, F0
+	ldm	RP!, {T0, T1}
+	mov	F3, #0
+	adcs	F1, F1, T0
+	adcs	F2, F2, T1
+
+	C Sum is < B^8 + p, so it's enough to fold carry once,
+	C If carry, add in
+	C   B^7 - B^6 - B^3 + 1  = <0, B-2, B-1, B-1, B-1, 0, 0, 1>
+
+	C Mask from carry flag, leaving carry intact
+	adc	F3, F3, #0
+	rsb	F3, F3, #0
+
+	adcs	T0, T2, #0
+	adcs	T1, T3, #0
+	adcs	T2, T4, #0
+	adcs	T3, T5, F3
+	adcs	T4, T6, F3
+	adcs	T5, T7, F3
+	and	F3, F3, #-2
+	adcs	T6, F1, F3
+	adcs	T7, F2, #0
+
+	sub	RP, RP, #64
+	stm	RP, {T0,T1,T2,T3,T4,T5,T6,T7}
+
+	pop	{r4,r5,r6,r7,r8,r10,r11,pc}
+EPILOGUE(nettle_ecc_256_redc)
diff --git a/armv7/ecc-384-modp.asm b/armv7/ecc-384-modp.asm
new file mode 100644
index 0000000000000000000000000000000000000000..fb5a6e12afec6edc526b4716278d693199e34621
--- /dev/null
+++ b/armv7/ecc-384-modp.asm
@@ -0,0 +1,257 @@
+C nettle, low-level cryptographics library
+C
+C Copyright (C) 2013, Niels Möller
+C
+C The nettle library is free software; you can redistribute it and/or modify
+C it under the terms of the GNU Lesser General Public License as published by
+C the Free Software Foundation; either version 2.1 of the License, or (at your
+C option) any later version.
+C
+C The nettle library is distributed in the hope that it will be useful, but
+C WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+C or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+C License for more details.
+C
+C You should have received a copy of the GNU Lesser General Public License
+C along with the nettle library; see the file COPYING.LIB.  If not, write to
+C the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+C MA 02111-1301, USA.
+
+	.file "ecc-384-modp.asm"
+	.arm
+
+define(<RP>, <r1>)
+define(<T0>, <r0>)
+define(<T1>, <r2>)
+define(<T2>, <r3>)
+define(<T3>, <r4>)
+define(<F0>, <r5>)
+define(<F1>, <r6>)
+define(<F2>, <r7>)
+define(<F3>, <r8>)
+define(<F4>, <r10>)
+define(<N>, <r12>)
+define(<H>, <lr>)
+	
+	C ecc_384_modp (const struct ecc_curve *ecc, mp_limb_t *rp)
+	.text
+	.align 2
+
+PROLOGUE(nettle_ecc_384_modp)
+	push	{r4,r5,r6,r7,r8,r10,lr}
+
+	add	RP, RP, #80
+	ldm	RP, {T0, T1, T2, T3}	C 20-23
+
+	C First get top 4 limbs, which need folding twice, as
+	C
+	C     T3 T2 T1 T0
+	C        T3 T2 T1
+	C             -T3
+	C ----------------
+	C  F4 F3 F2 F1 F0
+	C
+	C Start with
+	C
+	C   T3 T1 T0
+	C         T1
+	C        -T3
+	C -----------
+	C   F2 F1 F0   Always fits
+	
+	adds	F0, T0, T1
+	adcs	F1, T1, #0
+	adcs	F2, T3, #0
+	subs	F0, F0, T3
+	sbcs	F1, F1, #0
+	sbcs	F2, F2, #0
+
+	C      T3 T2 T2  0
+	C         F2 F1 F0
+	C  ----------------
+	C   F4 F3 F2 F1 F0
+
+	mov	F4, #0
+	adds	F1, F1, T2
+	adcs	F2, F2, T2
+	adcs	F3, T3, #0
+	adcs	F4, F4, #0
+
+	C Add in to high part
+	sub	RP, RP, #32
+	ldm	RP, {T0, T1, T2, T3}	C 12-15
+	mov	H, #0
+	adds	F0, T0, F0
+	adcs	F1, T1, F1
+	adcs	F2, T2, F2
+	adcs	F3, T3, F3
+	adcs	F4, F4, #0			C Do F4 later
+
+	C Add to low part, keeping carry (positive or negative) in H
+	sub	RP, RP, #48
+	ldm	RP, {T0, T1, T2, T3}	C 0-3
+	mov	H, #0
+	adds	T0, T0, F0
+	adcs	T1, T1, F1
+	adcs	T2, T2, F2
+	adcs	T3, T3, F3
+	adc	H, H, #0
+	subs	T1, T1, F0
+	sbcs	T2, T2, F1
+	sbcs	T3, T3, F2
+	sbc	H, H, #0
+	adds	T3, T3, F0
+	adc	H, H, #0
+	
+	stm	RP!, {T0,T1,T2,T3}	C 0-3
+	mov	N, #2
+.Loop:
+	ldm	RP, {T0,T1,T2,T3}	C 4-7
+
+	C First, propagate carry
+	adds	T0, T0, H
+	asr	H, #31		C Sign extend
+	adcs	T1, T1, H
+	adcs	T2, T2, H
+	adcs	T3, T3, H
+	adc	H, H, #0
+
+	C +B^4 term
+	adds	T0, T0, F0
+	adcs	T1, T1, F1
+	adcs	T2, T2, F2
+	adcs	T3, T3, F3
+	adc	H, H, #0
+
+	C +B^3 terms
+	ldr	F0, [RP, #+48]		C 16
+	adds	T0, T0, F1
+	adcs	T1, T1, F2
+	adcs	T2, T2, F3
+	adcs	T3, T3, F0
+	adc	H, H, #0
+
+	C -B
+	ldr	F1, [RP, #+52]		C 17-18
+	ldr	F2, [RP, #+56]
+	subs	T0, T0, F3
+	sbcs	T1, T1, F0
+	sbcs	T2, T2, F1
+	sbcs	T3, T3, F2
+	sbcs	H, H, #0
+
+	C +1
+	ldr	F3, [RP, #+60]		C 19
+	adds	T0, T0, F0
+	adcs	T1, T1, F1
+	adcs	T2, T2, F2
+	adcs	T3, T3, F3
+	adc	H, H, #0
+	subs	N, N, #1
+	stm	RP!, {T0,T1,T2,T3}
+	bne	.Loop
+
+	C Fold high limbs, we need to add in
+	C
+	C F4 F4 0 -F4 F4 H H 0 -H H
+	C
+	C We always have F4 >= 0, but we can have H < 0.
+	C Sign extension gets tricky when F4 = 0 and H < 0.
+	sub	RP, RP, #48
+
+	ldm	RP, {T0,T1,T2,T3}	C 0-3
+
+	C     H  H  0 -H  H
+	C  ----------------
+	C  S  H F3 F2 F1 F0
+	C
+	C Define S = H >> 31 (asr), we then have
+	C
+	C  F0 = H
+	C  F1 = S - H
+	C  F2 = - [H > 0]
+	C  F3 = H - [H > 0]
+	C   H = H + S
+	C 
+	C And we get underflow in S - H iff H > 0
+
+	C				H = 0	H > 0	H = -1
+	mov	F0, H		C	0	H	-1
+	asr	H, #31
+	subs	F1, H, F0	C	0,C=1	-H,C=0	0,C=1
+	sbc	F2, F2, F2	C	0	-1	0
+	sbc	F3, F0, #0	C	0	H-1	-1
+
+	adds	T0, T0, F0
+	adcs	T1, T1, F1
+	adcs	T2, T2, F2
+	adcs	T3, T3, F3
+	adc	H, H, F0	C	0+cy	H+cy	-2+cy
+
+	stm	RP!, {T0,T1,T2,T3}	C 0-3
+	ldm	RP, {T0,T1,T2,T3}	C 4-7
+	
+	C   F4  0 -F4
+	C ---------
+	C   F3 F2  F1
+	
+	rsbs	F1, F4, #0
+	sbc	F2, F2, F2
+	sbc	F3, F4, #0
+
+	C Sign extend H
+	adds	F0, F4, H
+	asr	H, H, #31	
+	adcs	F1, F1, H
+	adcs	F2, F2, H
+	adcs	F3, F3, H
+	adcs	F4, F4, H
+	adc	H, H, #0
+	
+	adds	T0, T0, F0
+	adcs	T1, T1, F1
+	adcs	T2, T2, F2
+	adcs	T3, T3, F3
+
+	stm	RP!, {T0,T1,T2,T3}	C 4-7
+	ldm	RP, {T0,T1,T2,T3}	C 8-11
+
+	adcs	T0, T0, F4
+	adcs	T1, T1, H
+	adcs	T2, T2, H
+	adcs	T3, T3, H
+	adc	H, H, #0
+	
+	stm	RP, {T0,T1,T2,T3}	C 8-11
+
+	C Final (unlikely) carry
+	sub	RP, RP, #32
+	ldm	RP, {T0,T1,T2,T3}	C 0-3
+	C Fold H into F0-F4
+	mov	F0, H
+	asr	H, #31
+	subs	F1, H, F0
+	sbc	F2, F2, F2
+	sbc	F3, F0, #0
+	add	F4, F0, H
+
+	adds	T0, T0, F0
+	adcs	T1, T1, F1
+	adcs	T2, T2, F2
+	adcs	T3, T3, F3
+	
+	stm	RP!, {T0,T1,T2,T3}	C 0-3
+	ldm	RP, {T0,T1,T2,T3}	C 4-7
+	adcs	T0, T0, F4
+	adcs	T1, T1, H
+	adcs	T2, T2, H
+	adcs	T3, T3, H
+	stm	RP!, {T0,T1,T2,T3}	C 4-7
+	ldm	RP, {T0,T1,T2,T3}	C 8-11
+	adcs	T0, T0, H
+	adcs	T1, T1, H
+	adcs	T2, T2, H
+	adcs	T3, T3, H
+	stm	RP!, {T0,T1,T2,T3}	C 8-11
+	pop	{r4,r5,r6,r7,r8,r10,pc}
+EPILOGUE(nettle_ecc_384_modp)
diff --git a/armv7/ecc-521-modp.asm b/armv7/ecc-521-modp.asm
new file mode 100644
index 0000000000000000000000000000000000000000..fe305805e0ee006d0c406bb9f621c96aba74bfd0
--- /dev/null
+++ b/armv7/ecc-521-modp.asm
@@ -0,0 +1,114 @@
+C nettle, low-level cryptographics library
+C
+C Copyright (C) 2013, Niels Möller
+C
+C The nettle library is free software; you can redistribute it and/or modify
+C it under the terms of the GNU Lesser General Public License as published by
+C the Free Software Foundation; either version 2.1 of the License, or (at your
+C option) any later version.
+C
+C The nettle library is distributed in the hope that it will be useful, but
+C WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+C or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+C License for more details.
+C
+C You should have received a copy of the GNU Lesser General Public License
+C along with the nettle library; see the file COPYING.LIB.  If not, write to
+C the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+C MA 02111-1301, USA.
+
+	.file "ecc-521-modp.asm"
+	.arm
+
+define(<HP>, <r0>)
+define(<RP>, <r1>)
+define(<T0>, <r2>)
+define(<T1>, <r3>)
+define(<T2>, <r4>)
+define(<F0>, <r5>)
+define(<F1>, <r6>)
+define(<F2>, <r7>)
+define(<F3>, <r8>)
+define(<H>, <r12>)
+define(<N>, <lr>)
+
+	C ecc_521_modp (const struct ecc_curve *ecc, mp_limb_t *rp)
+	.text
+.Lc511:
+	.int 511
+
+	.align 2
+
+PROLOGUE(nettle_ecc_521_modp)
+	push	{r4,r5,r6,r7,r8,lr}
+
+	C Use that B^17 = 2^23 (mod p)
+	ldr	F3, [RP, #+68]		C 17
+	add	HP, RP, #72		C 18
+	ldr	T0, [RP]		C 0
+	adds	T0, T0, F3, lsl	#23
+	str	T0, [RP], #+4
+	mov	N, #5
+
+	C 5 iterations, reading limbs 18-20, 21-23, 24-26, 27-29, 30-32
+	C and adding to limbs          1-3,    4-6,   7-9, 19-12, 13-15
+.Loop:
+	ldm	RP, {T0,T1,T2}		C  1+3*k --  3+3*k
+	lsr	F0, F3, #9
+	ldm	HP!, {F1,F2,F3}		C 18+3*k -- 20+3*k
+	orr	F0, F0, F1, lsl #23
+	lsr	F1, F1, #9
+	orr	F1, F1, F2, lsl #23
+	lsr	F2, F2, #9
+	orr	F2, F2, F3, lsl #23
+	adcs	T0, T0, F0
+	adcs	T1, T1, F1
+	adcs	T2, T2, F2
+	sub	N, N, #1
+	stm	RP!,{T0,T1,T2}
+	teq	N, #0
+	bne	.Loop
+
+	ldr	F0, [RP], #-64		C 16
+	ldr	F1, [HP]		C 33
+	ldr	T0, .Lc511
+
+	C Handling of high limbs
+	C F0 = rp[16] + carry in + F3 >> 9
+	adcs	F0, F0, F3, lsr #9
+	C Copy low 9 bits to H, then shift right including carry
+	and	H, F0, T0
+	rrx	F0, F0
+	lsr	F0, F0, #8
+	C Add in F1 = rp[33], with weight 2^1056 = 2^14
+	adds	F0, F0, F1, lsl #14
+	lsr	F1, F1, #18
+	adc	F1, F1, #0
+
+	ldm	RP, {T0, T1}		C 0-1
+	adds	T0, T0, F0
+	adcs	T1, T1, F1
+	stm	RP!, {T0, T1}
+
+	ldm	RP, {T0,T1,T2,F0,F1,F2,F3}	C 2-8
+	adcs	T0, T0, #0
+	adcs	T1, T1, #0
+	adcs	T2, T2, #0
+	adcs	F0, F0, #0
+	adcs	F1, F1, #0
+	adcs	F2, F2, #0
+	adcs	F3, F3, #0
+	stm	RP!, {T0,T1,T2,F0,F1,F2,F3}	C 2-8
+	ldm	RP, {T0,T1,T2,F0,F1,F2,F3}	C 9-15
+	adcs	T0, T0, #0
+	adcs	T1, T1, #0
+	adcs	T2, T2, #0
+	adcs	F0, F0, #0
+	adcs	F1, F1, #0
+	adcs	F2, F2, #0
+	adcs	F3, F3, #0
+	adcs	H, H, #0
+	stm	RP, {T0,T1,T2,F0,F1,F2,F3,H}	C 9-16
+
+	pop	{r4,r5,r6,r7,r8,pc}
+EPILOGUE(nettle_ecc_521_modp)
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/config.make.in b/config.make.in
index c1f2e5d485e62b3774f5381780616f89f169f7cf..ac3393dee1c63cd4e405f627ec60c70ccbead937 100644
--- a/config.make.in
+++ b/config.make.in
@@ -17,6 +17,9 @@ NM = @NM@
 OBJEXT = @OBJEXT@
 EXEEXT = @EXEEXT@
 
+CC_FOR_BUILD = @CC_FOR_BUILD@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+
 DEP_FLAGS = @DEP_FLAGS@
 DEP_PROCESS = @DEP_PROCESS@
 
@@ -46,6 +49,8 @@ LIBHOGWEED_FORLINK = @LIBHOGWEED_FORLINK@
 LIBHOGWEED_LIBS = @LIBHOGWEED_LIBS@
 LIBHOGWEED_LINK = @LIBHOGWEED_LINK@
 
+GMP_NUMB_BITS = @GMP_NUMB_BITS@
+
 AR = @AR@
 ARFLAGS = cru
 AUTOCONF = autoconf
diff --git a/configure.ac b/configure.ac
index 3dda461248e08210ef15ca61c35013f72f60572e..d082d8b040c370018b8342957ffcb5c31710e820 100644
--- a/configure.ac
+++ b/configure.ac
@@ -118,6 +118,10 @@ AC_PROG_MKDIR_P
 
 AC_PROG_LN_S
 
+# Compiler tests for the build system
+GMP_PROG_CC_FOR_BUILD
+GMP_PROG_EXEEXT_FOR_BUILD
+
 LSH_DEPENDENCY_TRACKING
 
 if test x$enable_dependency_tracking = xyes ; then
@@ -237,25 +241,51 @@ if test "x$enable_assembler" = xyes ; then
       ;;
   esac
 fi
-# echo "enable_assembler: $enable_assembler, asm_path: $asm_path"
+
+# Files which replace a C source file (or otherwise don't correspond
+# to a new object file).
+asm_replace_list="aes-encrypt-internal.asm aes-decrypt-internal.asm \
+		arcfour-crypt.asm camellia-crypt-internal.asm \
+		md5-compress.asm memxor.asm \
+		salsa20-crypt.asm salsa20-core-internal.asm \
+		serpent-encrypt.asm serpent-decrypt.asm \
+		sha1-compress.asm machine.m4"
+# Assembler files which generate additional object files if they are used.
+asm_optional_list=""
+
+if test "x$enable_public_key" = "xyes" ; then
+  asm_optional_list="ecc-192-modp.asm ecc-224-modp.asm ecc-256-redc.asm \
+      ecc-384-modp.asm ecc-521-modp.asm"
+fi
+
+OPT_ASM_SOURCES=""
+
 asm_file_list=""
 
 if test "x$enable_assembler" = xyes ; then
   if test -n "$asm_path"; then
     AC_MSG_NOTICE([Looking for assembler files in $asm_path/.])
-    for tmp_f in aes-encrypt-internal.asm aes-decrypt-internal.asm \
-		 arcfour-crypt.asm camellia-crypt-internal.asm \
-		 md5-compress.asm memxor.asm \
-		 salsa20-crypt.asm salsa20-core-internal.asm \
-		 serpent-encrypt.asm serpent-decrypt.asm \
-		 sha1-compress.asm machine.m4; do
-#       echo "Looking for $srcdir/$asm_path/$tmp_f"
+    for tmp_f in $asm_replace_list ; do
       if test -f "$srcdir/$asm_path/$tmp_f"; then
-#        echo found
 	asm_file_list="$asm_file_list $tmp_f"
         AC_CONFIG_LINKS($tmp_f:$asm_path/$tmp_f)
       fi
     done
+    dnl Workaround for AC_CONFIG_LINKS, which complains if we use the
+    dnl same destination argument $tmp_f multiple times.
+    for tmp_o in $asm_optional_list ; do
+      if test -f "$srcdir/$asm_path/$tmp_o"; then
+	asm_file_list="$asm_file_list $tmp_o"
+        AC_CONFIG_LINKS($tmp_o:$asm_path/$tmp_o)
+	while read tmp_func ; do
+	  AC_DEFINE_UNQUOTED(HAVE_NATIVE_$tmp_func)
+	  eval HAVE_NATIVE_$tmp_func=yes
+	done <<EOF
+[`sed -n 's/[^ 	]*PROLOGUE(_*\(nettle_\)*\([^)]*\)).*$/\2/p' < "$srcdir/$asm_path/$tmp_o"`]
+EOF
+	OPT_ASM_SOURCES="$OPT_ASM_SOURCES $tmp_o"
+      fi
+    done	
     if test -z "$asm_file_list"; then
       enable_assembler=no
       AC_MSG_WARN([No assembler files found.])
@@ -263,6 +293,22 @@ if test "x$enable_assembler" = xyes ; then
   fi
 fi
 
+AC_SUBST([OPT_ASM_SOURCES])
+
+AH_VERBATIM([HAVE_NATIVE],
+[/* Define to 1 each of the following for which a native (ie. CPU specific)
+    implementation of the corresponding routine exists.  */
+#undef HAVE_NATIVE_ecc_192_modp
+#undef HAVE_NATIVE_ecc_192_redc
+#undef HAVE_NATIVE_ecc_224_modp
+#undef HAVE_NATIVE_ecc_224_redc
+#undef HAVE_NATIVE_ecc_256_modp
+#undef HAVE_NATIVE_ecc_256_redc
+#undef HAVE_NATIVE_ecc_384_modp
+#undef HAVE_NATIVE_ecc_384_redc
+#undef HAVE_NATIVE_ecc_521_modp
+#undef HAVE_NATIVE_ecc_521_redc])
+
 # Besides getting correct dependencies, the explicit rules also tell
 # make that the .s files "ought to exist", so they are preferred over
 # .c files.
@@ -587,6 +633,20 @@ Support for public key algorithms will be unavailable.])]
 # Add -R flags needed to run programs linked with gmp
 LSH_RPATH_FIX
 
+# Check for gmp limb size
+nettle_cv_gmp_numb_bits=0
+if test "$enable_public_key" = yes; then
+  AC_MSG_CHECKING([for GMP limb size])
+  AC_COMPUTE_INT(nettle_cv_gmp_numb_bits, [GMP_NUMB_BITS],
+      [#include <gmp.h>],
+      [AC_MSG_FAILURE([cannot find value of GMP_NUMB_BITS])])
+
+  AC_MSG_RESULT([$nettle_cv_gmp_numb_bits bits])
+fi
+
+GMP_NUMB_BITS="$nettle_cv_gmp_numb_bits"
+AC_SUBST([GMP_NUMB_BITS])
+
 AH_TEMPLATE([HAVE_MPZ_POWM_SEC], [Define if mpz_powm_sec is available (appeared in GMP-5)])
 AC_CHECK_FUNC(__gmpz_powm_sec, [AC_DEFINE(HAVE_MPZ_POWM_SEC)])
 
diff --git a/desdata.c b/desdata.c
index 2d46b955cfc5aa670c21822a4cd6bc599effbf3e..f1c65043b073308c1e64cb5646f3d08a07cc8d78 100644
--- a/desdata.c
+++ b/desdata.c
@@ -11,16 +11,10 @@
  *
  */
 
-#if HAVE_CONFIG_H
-# include "config.h"
-#endif
-
 #include <stdio.h>
 
 #include	"desinfo.h"
 
-#include	"desCode.h"
-
 
 /* list of weak and semi-weak keys
 
@@ -65,13 +59,18 @@ int sorder[] = {
 };
 
 int
-main(int argc UNUSED, char **argv UNUSED)
+main(int argc, char **argv)
 {
-	uint32_t d, i, j, k, l, m, n, s;
+	unsigned long d, i, j, k, l, m, n, s; /* Always at least 32 bits */
 	char b[256], ksr[56];
 
+	if (argc <= 1)
+		return 1;
+
 	switch ( argv[1][0] ) {
 
+default: 
+	return 1;
 	/*
 	 * <<< make the key parity table >>>
 	 */
@@ -179,11 +178,11 @@ case 'k':
 			/* perform p permutation */
 			for ( m = j = 0; j < 32; j++ )
 				if ( n & (1 << (SP[j] - 1)) )
-					m |= (1 << j);
+					m |= (1UL << j);
 			/* rotate right (alg keeps everything rotated by 1) */
-			ROR(m, 1, 31);
+			m = (m >> 1) | ((m & 1) << 31);
 			/* print it out */
-			printf(" 0x%08lx,", (long) m);
+			printf(" 0x%08lx,", m);
 			if ( ( d & 3 ) == 3 )
 				printf("\n");
 		}
diff --git a/ecc-192.c b/ecc-192.c
new file mode 100644
index 0000000000000000000000000000000000000000..23015e4a5d30d0c29c024ebe84529d7892a40abf
--- /dev/null
+++ b/ecc-192.c
@@ -0,0 +1,130 @@
+/* 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"
+
+#if HAVE_NATIVE_ecc_192_modp
+
+#define ecc_192_modp nettle_ecc_192_modp
+void
+ecc_192_modp (const struct ecc_curve *ecc, mp_limb_t *rp);
+
+/* Use that p = 2^{192} - 2^64 - 1, to eliminate 128 bits at a time. */
+
+#elif 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, 6);
+  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_generic_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..cd3d05d617224db49ddba79bb2a35e6c8e42aa1c
--- /dev/null
+++ b/ecc-224.c
@@ -0,0 +1,75 @@
+/* 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"
+
+#if HAVE_NATIVE_ecc_224_modp
+
+#define USE_REDC 0
+#define ecc_224_modp nettle_ecc_224_modp
+void
+ecc_224_modp (const struct ecc_curve *ecc, mp_limb_t *rp);
+
+#else
+#define USE_REDC (ECC_REDC_SIZE != 0)
+#define ecc_224_modp ecc_generic_modp
+#endif
+
+#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_224_modp,
+  ecc_generic_redc,
+  USE_REDC ? ecc_generic_redc : ecc_224_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..8d787c595d0a43b6167f18948ff5049a57635591
--- /dev/null
+++ b/ecc-256.c
@@ -0,0 +1,240 @@
+/* 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"
+
+#if HAVE_NATIVE_ecc_256_redc
+# define USE_REDC 1
+#else
+# define USE_REDC (ECC_REDC_SIZE != 0)
+#endif
+
+#include "ecc-256.h"
+
+#if HAVE_NATIVE_ecc_256_redc
+# define ecc_256_redc nettle_ecc_256_redc
+void
+ecc_256_redc (const struct ecc_curve *ecc, mp_limb_t *rp);
+#else /* !HAVE_NATIVE_ecc_256_redc */
+# define ecc_256_redc ecc_generic_redc
+#endif
+
+#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_256_redc,
+  USE_REDC ? ecc_256_redc : ecc_256_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..ffa19fec229c23db71f319be1bd9f75d4b79d517
--- /dev/null
+++ b/ecc-384.c
@@ -0,0 +1,168 @@
+/* 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"
+
+#if HAVE_NATIVE_ecc_384_modp
+#define ecc_384_modp nettle_ecc_384_modp
+void
+ecc_384_modp (const struct ecc_curve *ecc, mp_limb_t *rp);
+#elif GMP_NUMB_BITS == 32
+
+/* 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. */
+
+/* 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 = sec_sub_1 (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 = sec_sub_1 (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..b925878fe35eb7958191aa28ebd8a3052272ecf7
--- /dev/null
+++ b/ecc-521.c
@@ -0,0 +1,97 @@
+/* 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"
+
+#if HAVE_NATIVE_ecc_521_modp
+#define ecc_521_modp nettle_ecc_521_modp
+void
+ecc_521_modp (const struct ecc_curve *ecc, mp_limb_t *rp);
+
+#else
+
+#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);
+}
+#endif
+
+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-a-to-j.c b/ecc-a-to-j.c
new file mode 100644
index 0000000000000000000000000000000000000000..5fbc0a88dfd12f68f539afb5a777e305a016463b
--- /dev/null
+++ b/ecc-a-to-j.c
@@ -0,0 +1,51 @@
+/* ecc-a-to-j.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.h"
+#include "ecc-internal.h"
+
+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)
+    {
+      mpn_copyd (r + ecc->size, p, 2*ecc->size);
+
+      mpn_zero (r, ecc->size);
+      ecc->modp (ecc, r);
+
+      mpn_zero (r + ecc->size, ecc->size);
+      ecc->modp (ecc, r + ecc->size);
+    }
+  else if (r != p)
+    mpn_copyi (r, p, 2*ecc->size);
+
+  mpn_copyi (r + 2*ecc->size, ecc->unit, ecc->size);
+}
diff --git a/ecc-add-jja.c b/ecc-add-jja.c
new file mode 100644
index 0000000000000000000000000000000000000000..f358e8ba823f6a5010864c1deb028f3675dfceb0
--- /dev/null
+++ b/ecc-add-jja.c
@@ -0,0 +1,122 @@
+/* ecc-dup-jj.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.h"
+#include "ecc-internal.h"
+
+/* NOTE: Behaviour for corner cases:
+
+   + p = 0   ==>  r = 0 (invalid except if also q = 0)
+
+   + q = 0   ==>  r = invalid
+
+   + p = -q  ==>  r = 0, correct!
+
+   + p = q   ==>  r = 0, invalid
+*/
+
+mp_size_t
+ecc_add_jja_itch (const struct ecc_curve *ecc)
+{
+  return ECC_ADD_JJA_ITCH (ecc->size);
+}
+
+void
+ecc_add_jja (const struct ecc_curve *ecc,
+	     mp_limb_t *r, const mp_limb_t *p, const mp_limb_t *q,
+	     mp_limb_t *scratch)
+{
+  /* Formulas, from djb,
+     http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b):
+
+     Computation		Operation	Live variables
+     
+      ZZ = Z_1^2		sqr		ZZ
+      H = X_2*ZZ - X_1		mul (djb: U_2)	ZZ, H
+      HH = H^2			sqr		ZZ, H, HH
+      ZZZ = ZZ*Z_1		mul		ZZ, H, HH, ZZZ
+      Z_3 = (Z_1+H)^2-ZZ-HH	sqr		H, HH, ZZZ
+      W = 2 (Y_2*ZZZ - Y_1)	mul (djb: S_2)	H, HH, W
+      I = 4*HH					H, W, I
+      J = H*I			mul		W, I, J
+      V = X_1*I			mul		W, J, V
+      X_3 = W^2-J-2*V		sqr		W, J, V
+      Y_3 = W*(V-X_3)-2*Y_1*J	mul, mul
+  */
+#define zz  scratch
+#define h  (scratch + ecc->size)
+#define hh (scratch + 2*ecc->size)
+#define w  (scratch + 3*ecc->size)
+#define j  (scratch + 4*ecc->size)
+#define v   scratch
+
+#define x1  p
+#define y1 (p + ecc->size)
+#define z1 (p + 2*ecc->size)
+#define x2  q
+#define y2 (q + ecc->size)
+
+  /* zz */
+  ecc_modp_sqr (ecc, zz, z1);
+  /* h*/
+  ecc_modp_mul (ecc, h, x2, zz);
+  ecc_modp_sub (ecc, h, h, x1);
+  /* hh */
+  ecc_modp_sqr (ecc, hh, h);
+  /* Do z^3 early, store at w. */
+  ecc_modp_mul (ecc, w, zz, z1);
+  /* z_3, use j area for scratch */
+  ecc_modp_add (ecc, r + 2*ecc->size, p + 2*ecc->size, h);
+  ecc_modp_sqr (ecc, j, r + 2*ecc->size);
+  ecc_modp_sub (ecc, j, j, zz);
+  ecc_modp_sub (ecc, r + 2*ecc->size, j, hh);
+  
+  /* w */
+  ecc_modp_mul (ecc, j, y2, w);
+  ecc_modp_sub (ecc, w, j, y1);
+  ecc_modp_mul_1 (ecc, w, w, 2);
+  
+  /* i replaces hh, j */
+  ecc_modp_mul_1 (ecc, hh, hh, 4);
+  ecc_modp_mul (ecc, j, hh, h);
+
+  /* v */
+  ecc_modp_mul (ecc, v, x1, hh);
+
+  /* x_3, use (h, hh) as sqratch */  
+  ecc_modp_sqr (ecc, h, w);
+  ecc_modp_sub (ecc, r, h, j);
+  ecc_modp_submul_1 (ecc, r, v, 2);
+
+  /* y_3, use (h, hh) as sqratch */
+  ecc_modp_mul (ecc, h, y1, j); /* frees j */
+  ecc_modp_sub (ecc, r + ecc->size, v, r);
+  ecc_modp_mul (ecc, j, r + ecc->size, w);
+  ecc_modp_submul_1 (ecc, j, h, 2);
+  mpn_copyi (r + ecc->size, j, ecc->size);
+}
diff --git a/ecc-add-jjj.c b/ecc-add-jjj.c
new file mode 100644
index 0000000000000000000000000000000000000000..e0506375d7b8b323e73850b171c1bc7367d55d4d
--- /dev/null
+++ b/ecc-add-jjj.c
@@ -0,0 +1,118 @@
+/* ecc-add-jjj.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.h"
+#include "ecc-internal.h"
+
+mp_size_t
+ecc_add_jjj_itch (const struct ecc_curve *ecc)
+{
+  /* Needs 8 * ecc->size */
+  return ECC_ADD_JJJ_ITCH (ecc->size);
+}
+
+void
+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)
+{
+  /* Formulas, from djb,
+     http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl:
+
+     Computation		Operation	Live variables
+
+      Z1Z1 = Z1^2		sqr		Z1Z1
+      Z2Z2 = Z2^2		sqr		Z1Z1, Z2Z2
+      U1 = X1*Z2Z2		mul		Z1Z1, Z2Z2, U1
+      U2 = X2*Z1Z1		mul		Z1Z1, Z2Z2, U1, U2
+      H = U2-U1					Z1Z1, Z2Z2, U1, H
+      Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2)*H sqr, mul	Z1Z1, Z2Z2, U1, H
+      S1 = Y1*Z2*Z2Z2		mul, mul	Z1Z1, U1, H, S1
+      S2 = Y2*Z1*Z1Z1		mul, mul	U1, H, S1, S2
+      W = 2*(S2-S1)	(djb: r)		U1, H, S1, W
+      I = (2*H)^2		sqr		U1, H, S1, W, I
+      J = H*I			mul		U1, S1, W, J, V
+      V = U1*I			mul		S1, W, J, V
+      X3 = W^2-J-2*V		sqr		S1, W, J, V
+      Y3 = W*(V-X3)-2*S1*J	mul, mul
+  */
+  mp_limb_t *z1z1 = scratch;
+  mp_limb_t *z2z2 = scratch + ecc->size;
+  mp_limb_t *u1   = scratch + 2*ecc->size;
+  mp_limb_t *u2   = scratch + 3*ecc->size;
+  mp_limb_t *s1   = scratch; /* overlap z1z1 */
+  mp_limb_t *s2   = scratch + ecc->size; /* overlap z2z2 */
+  mp_limb_t *i    = scratch + 4*ecc->size;
+  mp_limb_t *j    = scratch + 5*ecc->size;
+  mp_limb_t *v    = scratch + 6*ecc->size;
+
+  /* z1^2, z2^2, u1 = x1 x2^2, u2 = x2 z1^2 - u1 */
+  ecc_modp_sqr (ecc, z1z1, p + 2*ecc->size);
+  ecc_modp_sqr (ecc, z2z2, q + 2*ecc->size);
+  ecc_modp_mul (ecc, u1, p, z2z2);
+  ecc_modp_mul (ecc, u2, q, z1z1);
+  ecc_modp_sub (ecc, u2, u2, u1);  /* Store h in u2 */
+
+  /* z3, use i, j, v as scratch, result at i. */
+  ecc_modp_add (ecc, i, p + 2*ecc->size, q + 2*ecc->size);
+  ecc_modp_sqr (ecc, v, i);
+  ecc_modp_sub (ecc, v, v, z1z1);
+  ecc_modp_sub (ecc, v, v, z2z2);
+  ecc_modp_mul (ecc, i, v, u2);
+  /* Delayed write, to support in-place operation. */
+
+  /* s1 = y1 z2^3, s2 = y2 z1^3, scratch at j and v */
+  ecc_modp_mul (ecc, j, z1z1, p + 2*ecc->size); /* z1^3 */
+  ecc_modp_mul (ecc, v, z2z2, q + 2*ecc->size); /* z2^3 */
+  ecc_modp_mul (ecc, s1, p + ecc->size, v);
+  ecc_modp_mul (ecc, v, j, q + ecc->size);
+  ecc_modp_sub (ecc, s2, v, s1);
+  ecc_modp_mul_1 (ecc, s2, s2, 2);
+
+  /* Store z3 */
+  mpn_copyi (r + 2*ecc->size, i, ecc->size);
+
+  /* i, j, v */
+  ecc_modp_sqr (ecc, i, u2);
+  ecc_modp_mul_1 (ecc, i, i, 4);
+  ecc_modp_mul (ecc, j, u2, i);
+  ecc_modp_mul (ecc, v, u1, i);
+
+  /* now, u1, u2 and i are free for reuse .*/
+  /* x3, use u1, u2 as scratch */
+  ecc_modp_sqr (ecc, u1, s2);
+  ecc_modp_sub (ecc, r, u1, j);
+  ecc_modp_submul_1 (ecc, r, v, 2);
+
+  /* y3 */
+  ecc_modp_mul (ecc, u1, s1, j); /* Frees j */
+  ecc_modp_sub (ecc, u2, v, r);  /* Frees v */
+  ecc_modp_mul (ecc, i, s2, u2);
+  ecc_modp_submul_1 (ecc, i, u1, 2);
+  mpn_copyi (r + ecc->size, i, ecc->size);
+}
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-dup-jj.c b/ecc-dup-jj.c
new file mode 100644
index 0000000000000000000000000000000000000000..3c850d70391262e70ed013b604aaf01eb2ce5185
--- /dev/null
+++ b/ecc-dup-jj.c
@@ -0,0 +1,107 @@
+/* ecc-dup-jj.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.h"
+#include "ecc-internal.h"
+
+/* NOTE: Behaviour for corner cases:
+
+   + p = 0  ==>  r = 0, correct!
+*/
+mp_size_t
+ecc_dup_jj_itch (const struct ecc_curve *ecc)
+{
+  return ECC_DUP_JJ_ITCH (ecc->size);
+}
+
+void
+ecc_dup_jj (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-shortw-jacobian-3.html#doubling-dbl-2001-b):
+
+     Computation			Operation	Live variables
+     delta = z^2			sqr		delta
+     gamma = y^2			sqr		delta, gamma
+     z' = (y+z)^2-gamma-delta		sqr		delta, gamma
+     alpha = 3*(x-delta)*(x+delta)	mul		gamma, beta, alpha
+     beta = x*gamma			mul		gamma, beta, alpha
+     x' = alpha^2-8*beta		sqr		gamma, beta, alpha
+     y' = alpha*(4*beta-x')-8*gamma^2	mul, sqr
+  */
+
+#define delta  scratch
+#define gamma (scratch + ecc->size)
+#define beta  (scratch + 2*ecc->size)
+#define g2    (scratch + 3*ecc->size)
+#define sum   (scratch + 4*ecc->size)
+#define alpha  scratch /* Overlap delta */
+  
+#define xp p
+#define yp (p + ecc->size)
+#define zp (p + 2*ecc->size)
+  
+  /* delta */
+  ecc_modp_sqr (ecc, delta, zp);
+
+  /* gamma */
+  ecc_modp_sqr (ecc, gamma, yp);
+
+  /* z'. Can use beta area as scratch. */
+  ecc_modp_add (ecc, r + 2*ecc->size, yp, zp);
+  ecc_modp_sqr (ecc, beta, r + 2*ecc->size);
+  ecc_modp_sub (ecc, beta, beta, gamma);
+  ecc_modp_sub (ecc, r + 2*ecc->size, beta, delta);
+  
+  /* alpha. Can use beta area as scratch, and overwrite delta. */
+  ecc_modp_add (ecc, sum, xp, delta);
+  ecc_modp_sub (ecc, delta, xp, delta);
+  ecc_modp_mul (ecc, beta, sum, delta);
+  ecc_modp_mul_1 (ecc, alpha, beta, 3);
+
+  /* beta */
+  ecc_modp_mul (ecc, beta, xp, gamma);
+
+  /* Do gamma^2 and 4*beta early, to get them out of the way. We can
+     then use the old area at gamma as scratch. */
+  ecc_modp_sqr (ecc, g2, gamma);
+  ecc_modp_mul_1 (ecc, sum, beta, 4);
+  
+  /* x' */
+  ecc_modp_sqr (ecc, gamma, alpha);   /* Overwrites gamma and beta */
+  ecc_modp_submul_1 (ecc, gamma, sum, 2);
+  mpn_copyi (r, gamma, ecc->size);
+
+  /* y' */
+  ecc_modp_sub (ecc, sum, sum, r);
+  ecc_modp_mul (ecc, gamma, sum, alpha);
+  ecc_modp_submul_1 (ecc, gamma, g2, 8);
+  mpn_copyi (r + ecc->size, gamma, ecc->size);
+}
diff --git a/ecc-ecdsa-sign.c b/ecc-ecdsa-sign.c
new file mode 100644
index 0000000000000000000000000000000000000000..e85c325c9c3b786bee21420565c13d57670fbe53
--- /dev/null
+++ b/ecc-ecdsa-sign.c
@@ -0,0 +1,97 @@
+/* ecc-ecdsa-sign.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 <stdlib.h>
+
+#include "ecdsa.h"
+#include "ecc-internal.h"
+
+/* Low-level ECDSA signing */
+
+mp_size_t
+ecc_ecdsa_sign_itch (const struct ecc_curve *ecc)
+{
+  /* Needs 3*ecc->size + scratch for ecc_mul_g. */
+  return ECC_ECDSA_SIGN_ITCH (ecc->size);
+}
+
+/* NOTE: Caller should check if r or s is zero. */
+void
+ecc_ecdsa_sign (const struct ecc_curve *ecc,
+		const mp_limb_t *zp,
+		/* Random nonce, must be invertible mod ecc group
+		   order. */
+		const mp_limb_t *kp,
+		unsigned length, const uint8_t *digest,
+		mp_limb_t *rp, mp_limb_t *sp,
+		mp_limb_t *scratch)
+{
+  mp_limb_t cy;
+#define P	    scratch
+#define kinv	    scratch                /* Needs 5*ecc->size for computation */
+#define hp	    (scratch  + ecc->size) /* NOTE: ecc->size + 1 limbs! */
+#define tp	    (scratch + 2*ecc->size)
+  /* Procedure, according to RFC 6090, "KT-I". q denotes the group
+     order.
+
+     1. k <-- uniformly random, 0 < k < q
+
+     2. R <-- (r_x, r_y) = k g
+
+     3. s1 <-- r_x mod q
+
+     4. s2 <-- (h + z*s1)/k mod q.
+  */
+
+  ecc_mul_g (ecc, P, kp, P + 3*ecc->size);
+  /* x coordinate only */
+  ecc_j_to_a (ecc, 3, rp, P, P + 3*ecc->size);
+
+  /* We need to reduce x coordinate mod ecc->q. It should already
+     be < 2*ecc->q, so one subtraction should suffice. */
+  cy = mpn_sub_n (scratch, rp, ecc->q, ecc->size);
+  cnd_copy (cy == 0, rp, scratch, ecc->size);
+
+  /* Invert k, uses 5 * ecc->size including scratch */
+  mpn_copyi (hp, kp, ecc->size);
+  ecc_modq_inv (ecc, kinv, hp, tp);
+  
+  /* Process hash digest */
+  ecc_hash (ecc, hp, length, digest);
+
+  ecc_modq_mul (ecc, tp, zp, rp);
+  ecc_modq_add (ecc, hp, hp, tp);
+  ecc_modq_mul (ecc, tp, hp, kinv);
+
+  mpn_copyi (sp, tp, ecc->size);
+#undef P
+#undef hp
+#undef kinv
+#undef tp
+}
diff --git a/ecc-ecdsa-verify.c b/ecc-ecdsa-verify.c
new file mode 100644
index 0000000000000000000000000000000000000000..57bbb9b39d837d043e286fca77d99970d54bd5b5
--- /dev/null
+++ b/ecc-ecdsa-verify.c
@@ -0,0 +1,150 @@
+/* ecc-ecdsa-verify.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 <stdlib.h>
+
+#include "ecdsa.h"
+#include "ecc-internal.h"
+
+/* Low-level ECDSA verify */
+
+static int
+zero_p (const mp_limb_t *xp, mp_size_t n)
+{
+  while (n > 0)
+    if (xp[--n] > 0)
+      return 0;
+  return 1;
+}
+
+static int
+ecdsa_in_range (const struct ecc_curve *ecc, const mp_limb_t *xp)
+{
+  return !zero_p (xp, ecc->size)
+    && mpn_cmp (xp, ecc->q, ecc->size) < 0;
+}
+
+mp_size_t
+ecc_ecdsa_verify_itch (const struct ecc_curve *ecc)
+{
+  /* Largest storage need is for the ecc_mul_a call, 6 * ecc->size +
+     ECC_MUL_A_ITCH (size) */
+  return ECC_ECDSA_VERIFY_ITCH (ecc->size);
+}
+
+/* FIXME: Use faster primitives, not requiring side-channel silence. */
+int
+ecc_ecdsa_verify (const struct ecc_curve *ecc,
+		  const mp_limb_t *pp, /* Public key */
+		  unsigned length, const uint8_t *digest,
+		  const mp_limb_t *rp, const mp_limb_t *sp,
+		  mp_limb_t *scratch)
+{
+  /* Procedure, according to RFC 6090, "KT-I". q denotes the group
+     order.
+
+     1. Check 0 < r, s < q.
+
+     2. s' <-- s^{-1}  (mod q)
+
+     3. u1  <-- h * s' (mod q)
+
+     4. u2  <-- r * s' (mod q)
+
+     5. R = u1 G + u2 Y
+
+     6. Signature is valid if R_x = r (mod q).
+  */
+
+#define P2 scratch
+#define P1 (scratch + 3*ecc->size)
+#define sinv (scratch + 3*ecc->size)
+#define u2 (scratch + 4*ecc->size)
+#define hp (scratch + 4*ecc->size)
+#define u1 (scratch + 6*ecc->size)
+
+  if (! (ecdsa_in_range (ecc, rp)
+	 && ecdsa_in_range (ecc, sp)))
+    return 0;
+
+  /* FIXME: Micro optimizations: Either simultaneous multiplication.
+     Or convert to projective coordinates (can be done without
+     division, I think), and write an ecc_add_ppp. */
+  
+  /* Compute sinv, use P2 as scratch */
+  mpn_copyi (sinv + ecc->size, sp, ecc->size);
+  ecc_modq_inv (ecc, sinv, sinv + ecc->size, P2);
+
+  /* u2 = r / s, P2 = u2 * Y */
+  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);
+
+  /* u1 = h / s, P1 = u1 * G */
+  ecc_hash (ecc, hp, length, digest);
+  ecc_modq_mul (ecc, u1, hp, sinv);
+
+  /* u = 0 can happen only if h = 0 or h = q, which is extremely
+     unlikely. */
+  if (!zero_p (u1, ecc->size))
+    {
+      /* Total storage: 6*ecc->size + ECC_MUL_G_ITCH (ecc->size) */
+      ecc_mul_g (ecc, P1, u1, u1 + ecc->size);
+
+      /* NOTE: ecc_add_jjj and/or ecc_j_to_a will produce garbage in
+	 case u1 G = +/- u2 V. However, anyone who gets his or her
+	 hands on a signature where this happens during verification,
+	 can also get the private key as z = +/- u1 / u_2 (mod q). And
+	 then it doesn't matter very much if verification of
+	 signatures with that key succeeds or fails.
+
+	 u1 G = - u2 V can never happen for a correctly generated
+	 signature, since it implies k = 0.
+
+	 u1 G = u2 V is possible, if we are unlucky enough to get h /
+	 s_1 = z. Hitting that is about as unlikely as finding the
+	 private key by guessing.
+       */
+      /* Total storage: 6*ecc->size + ECC_ADD_JJJ_ITCH (ecc->size) */
+      ecc_add_jjj (ecc, P1, P1, P2, u1);
+    }
+  ecc_j_to_a (ecc, 3, P2, P1, u1);
+
+  if (mpn_cmp (P2, ecc->q, ecc->size) >= 0)
+    mpn_sub_n (P2, P2, ecc->q, ecc->size);
+
+  return (mpn_cmp (rp, P2, ecc->size) == 0);
+#undef P2
+#undef P1
+#undef sinv
+#undef u2
+#undef hp
+#undef u1
+}
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-hash.c b/ecc-hash.c
new file mode 100644
index 0000000000000000000000000000000000000000..7fd5c57856473ccf1ed61a00e7528c66724bddbd
--- /dev/null
+++ b/ecc-hash.c
@@ -0,0 +1,55 @@
+/* ecdsa-hash.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"
+#include "gmp-glue.h"
+
+/* Convert hash value to an integer. If the digest is larger than
+   the ecc bit size, then we must truncate it and use the leftmost
+   bits. */
+
+/* NOTE: We don't considered the hash value to be secret, so it's ok
+   if the running time of this conversion depends on h.
+
+   Requires ecc->size + 1 limbs, the extra limb may be needed for
+   unusual limb sizes.
+*/
+void
+ecc_hash (const struct ecc_curve *ecc,
+	  mp_limb_t *hp,
+	  unsigned length, const uint8_t *digest)
+{
+  if (length > ((unsigned) ecc->bit_size + 7) / 8)
+    length = (ecc->bit_size + 7) / 8;
+
+  mpn_set_base256 (hp, ecc->size + 1, digest, length);
+
+  if (8 * length > ecc->bit_size)
+    /* We got a few extra bits, at the low end. Discard them. */
+    mpn_rshift (hp, hp, ecc->size + 1, 8*length - ecc->bit_size);
+}
diff --git a/ecc-internal.h b/ecc-internal.h
new file mode 100644
index 0000000000000000000000000000000000000000..0df8c9e155350dff20e4caf7efe22275eaa07199
--- /dev/null
+++ b/ecc-internal.h
@@ -0,0 +1,251 @@
+/* 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 "nettle-types.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_modq_random _nettle_ecc_modq_random
+#define ecc_mod _nettle_ecc_mod
+#define ecc_hash _nettle_ecc_hash
+#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
+
+#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
+   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_modq_random (const struct ecc_curve *ecc, mp_limb_t *xp,
+		 void *ctx, nettle_random_func *random, 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);
+
+void
+ecc_hash (const struct ecc_curve *ecc,
+	  mp_limb_t *hp,
+	  unsigned length, const uint8_t *digest);
+
+#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 ECC_ECDSA_SIGN_ITCH(size) (12*(size))
+#define ECC_ECDSA_VERIFY_ITCH(size) \
+  (6*(size) + ECC_MUL_A_ITCH ((size)))
+#define ECC_MODQ_RANDOM_ITCH(size) (size)
+#define ECC_HASH_ITCH(size) (1+(size))
+
+#endif /* NETTLE_ECC_INTERNAL_H_INCLUDED */
diff --git a/ecc-j-to-a.c b/ecc-j-to-a.c
new file mode 100644
index 0000000000000000000000000000000000000000..ae56bbaf6df33bcb484b74d68580a942e45199e1
--- /dev/null
+++ b/ecc-j-to-a.c
@@ -0,0 +1,115 @@
+/* ecc-j-to-a.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.h"
+#include "ecc-internal.h"
+
+mp_size_t
+ecc_j_to_a_itch (const struct ecc_curve *ecc)
+{
+  /* Needs 2*ecc->size + scratch for ecc_modq_inv */
+  return ECC_J_TO_A_ITCH (ecc->size);
+}
+
+void
+ecc_j_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 up   (scratch + ecc->size)
+#define iz2p (scratch + ecc->size)
+#define iz3p (scratch + 2*ecc->size)
+#define tp    scratch
+
+  mp_limb_t cy;
+
+  if (ecc->use_redc)
+    {
+      /* Set v = (r_z / B^2)^-1,
+
+	 r_x = p_x v^2 / B^3 =  ((v/B * v)/B * p_x)/B
+	 r_y = p_y v^3 / B^4 = (((v/B * v)/B * v)/B * p_x)/B
+
+	 Skip the first redc, if we want to stay in Montgomery
+	 representation.
+      */
+
+      mpn_copyi (up, p + 2*ecc->size, ecc->size);
+      mpn_zero (up + ecc->size, ecc->size);
+      ecc->redc (ecc, up);
+      mpn_zero (up + ecc->size, ecc->size);
+      ecc->redc (ecc, up);
+
+      ecc_modp_inv (ecc, izp, up, up + ecc->size);
+
+      if (flags & 1)
+	{
+	  /* Divide this common factor by B */
+	  mpn_copyi (iz3p, izp, ecc->size);
+	  mpn_zero (iz3p + ecc->size, ecc->size);
+	  ecc->redc (ecc, iz3p);
+      
+	  ecc_modp_mul (ecc, iz2p, izp, iz3p);
+	}
+      else
+	ecc_modp_sqr (ecc, iz2p, izp);	
+    }
+  else
+    {
+      /* Set s = p_z^{-1}, r_x = p_x s^2, r_y = p_y s^3 */
+
+      mpn_copyi (up, p+2*ecc->size, ecc->size); /* p_z */
+      ecc_modp_inv (ecc, izp, up, up + ecc->size);
+
+      ecc_modp_sqr (ecc, iz2p, izp);
+    }
+
+  ecc_modp_mul (ecc, iz3p, iz2p, p);
+  /* ecc_modp (and ecc_modp_mul) may return a value up to 2p - 1, so
+     do a conditional subtraction. */
+  cy = mpn_sub_n (r, iz3p, ecc->p, ecc->size);
+  cnd_copy (cy, r, iz3p, ecc->size);
+
+  if (flags & 2)
+    /* Skip y coordinate */
+    return;
+
+  ecc_modp_mul (ecc, iz3p, iz2p, izp);
+  ecc_modp_mul (ecc, tp, iz3p, p + ecc->size);
+  /* And a similar subtraction. */
+  cy = mpn_sub_n (r + ecc->size, tp, ecc->p, ecc->size);
+  cnd_copy (cy, r + ecc->size, tp, ecc->size);
+
+#undef izp
+#undef up
+#undef iz2p
+#undef iz3p
+#undef tp
+}
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/ecc-mul-a.c b/ecc-mul-a.c
new file mode 100644
index 0000000000000000000000000000000000000000..0b347162d6dbccf46923f29ec8ae6152ce78013e
--- /dev/null
+++ b/ecc-mul-a.c
@@ -0,0 +1,181 @@
+/* ecc-mul-a.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.h"
+#include "ecc-internal.h"
+
+mp_size_t
+ecc_mul_a_itch (const struct ecc_curve *ecc)
+{
+  /* Binary algorithm needs 6*ecc->size + scratch for ecc_add_jja.
+     Current total is 12 ecc->size, at most 864 bytes.
+
+     Window algorithm needs (3<<w) * ecc->size for the table,
+     3*ecc->size for a temporary point, and scratch for
+     ecc_add_jjj. */
+  return ECC_MUL_A_ITCH (ecc->size);
+}
+
+#if ECC_MUL_A_WBITS == 0
+void
+ecc_mul_a (const struct ecc_curve *ecc,
+	   int initial, mp_limb_t *r,
+	   const mp_limb_t *np, const mp_limb_t *p,
+	   mp_limb_t *scratch)
+{
+#define tp scratch
+#define pj (scratch + 3*ecc->size)
+#define scratch_out (scratch + 6*ecc->size)
+
+  int is_zero;
+
+  unsigned i;
+
+  ecc_a_to_j (ecc, initial, pj, p);
+  mpn_zero (r, 3*ecc->size);
+  
+  for (i = ecc->size, is_zero = 1; 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_jj (ecc, r, r, scratch_out);
+	  ecc_add_jja (ecc, tp, r, pj, scratch_out);
+
+	  digit = (w & bit) > 0;
+	  /* If is_zero is set, r is the zero point,
+	     and ecc_add_jja produced garbage. */
+	  cnd_copy (is_zero, tp, pj, 3*ecc->size);
+	  is_zero &= ~digit;
+	  /* If we had a one-bit, use the sum. */
+	  cnd_copy (digit, r, tp, 3*ecc->size);
+	}
+    }
+}
+#else /* ECC_MUL_A_WBITS > 1 */
+
+#define TABLE_SIZE (1U << ECC_MUL_A_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,
+	    int initial, 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);
+
+  for (j = 2; j < size; j += 2)
+    {
+      ecc_dup_jj (ecc, TABLE(j), TABLE(j/2), scratch);
+      ecc_add_jja (ecc, TABLE(j+1), TABLE(j), TABLE(1), scratch);
+    }  
+}
+
+void
+ecc_mul_a (const struct ecc_curve *ecc,
+	   int initial, 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_WBITS);
+  int is_zero = 0;
+
+  mp_bitcnt_t blocks = (ecc->bit_size + ECC_MUL_A_WBITS - 1) / ECC_MUL_A_WBITS;
+  mp_bitcnt_t bit_index = (blocks-1) * ECC_MUL_A_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_WBITS, initial, 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);
+  is_zero = (bits == 0);
+
+  for (;;)
+    {
+      unsigned j;
+      if (shift >= ECC_MUL_A_WBITS)
+	{
+	  shift -= ECC_MUL_A_WBITS;
+	  bits = w >> shift;
+	}
+      else
+	{
+	  if (limb_index == 0)
+	    {
+	      assert (shift == 0);
+	      break;
+	    }
+	  bits = w << (ECC_MUL_A_WBITS - shift);
+	  w = np[--limb_index];
+	  shift = shift + GMP_NUMB_BITS - ECC_MUL_A_WBITS;
+	  bits |= w >> shift;
+	}
+      for (j = 0; j < ECC_MUL_A_WBITS; j++)
+	ecc_dup_jj (ecc, r, r, scratch_out);
+
+      bits &= TABLE_MASK;
+      sec_tabselect (tp, 3*ecc->size, table, TABLE_SIZE, bits);
+      cnd_copy (is_zero, r, tp, 3*ecc->size);
+      ecc_add_jjj (ecc, tp, tp, r, scratch_out);
+
+      /* Use the sum when valid. ecc_add_jja produced garbage if
+	 is_zero != 0 or bits == 0, . */	  
+      cnd_copy (bits & (is_zero - 1), r, tp, 3*ecc->size);
+      is_zero &= (bits == 0);
+    }
+#undef table
+#undef tp
+}
+
+#endif /* ECC_MUL_A_WBITS > 1 */
diff --git a/ecc-mul-g.c b/ecc-mul-g.c
new file mode 100644
index 0000000000000000000000000000000000000000..e202e26b3e35f4e65eb7ee6f9a669598b17a2009
--- /dev/null
+++ b/ecc-mul-g.c
@@ -0,0 +1,103 @@
+/* ecc-mul-g.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.h"
+#include "ecc-internal.h"
+
+mp_size_t
+ecc_mul_g_itch (const struct ecc_curve *ecc)
+{
+  /* Needs 3*ecc->size + scratch for ecc_add_jja. */
+  return ECC_MUL_G_ITCH (ecc->size);
+}
+
+void
+ecc_mul_g (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_jja 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;
+
+  int is_zero;
+
+  k = ecc->pippenger_k;
+  c = ecc->pippenger_c;
+
+  bit_rows = (ecc->bit_size + k - 1) / k;
+  
+  mpn_zero (r, 3*ecc->size);
+  
+  for (i = k, is_zero = 1; i-- > 0; )
+    {
+      ecc_dup_jj (ecc, r, r, scratch);
+      for (j = 0; j * c < bit_rows; j++)
+	{
+	  unsigned bits;
+	  mp_bitcnt_t 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);
+	  cnd_copy (is_zero, r, tp, 2*ecc->size);
+	  cnd_copy (is_zero, r + 2*ecc->size, ecc->unit, ecc->size);
+	  
+	  ecc_add_jja (ecc, tp, r, tp, scratch_out);
+	  /* Use the sum when valid. ecc_add_jja produced garbage if
+	     is_zero != 0 or bits == 0, . */	  
+	  cnd_copy (bits & (is_zero - 1), r, tp, 3*ecc->size);
+	  is_zero &= (bits == 0);
+	}
+    }
+#undef tp
+#undef scratch_out
+}
diff --git a/ecc-point.c b/ecc-point.c
new file mode 100644
index 0000000000000000000000000000000000000000..9b2639adfdf96588ce178afe2af7d3ca19a0ca81
--- /dev/null
+++ b/ecc-point.c
@@ -0,0 +1,90 @@
+/* ecc-point.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.h"
+#include "ecc-internal.h"
+#include "gmp-glue.h"
+
+void
+ecc_point_init (struct ecc_point *p, const struct ecc_curve *ecc)
+{
+  p->ecc = ecc;
+  p->p = gmp_alloc_limbs (2*ecc->size);
+}
+
+void
+ecc_point_clear (struct ecc_point *p)
+{
+  gmp_free_limbs (p->p, 2*p->ecc->size);
+}
+
+int
+ecc_point_set (struct ecc_point *p, const mpz_t x, const mpz_t y)
+{
+  mp_size_t size;  
+  mpz_t lhs, rhs;
+  mpz_t t;
+  int res;
+
+  size = p->ecc->size;
+  
+  if (mpz_sgn (x) < 0 || mpz_limbs_cmp (x, p->ecc->p, size) >= 0
+      || mpz_sgn (y) < 0 || mpz_limbs_cmp (y, p->ecc->p, size) >= 0)
+    return 0;
+
+  mpz_init (lhs);
+  mpz_init (rhs);
+
+  /* Check that y^2 = x^3 - 3*x + b (mod p) */
+  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));
+
+  mpz_clear (lhs);
+  mpz_clear (rhs);
+
+  if (!res)
+    return 0;
+
+  mpz_limbs_copy (p->p, x, size);
+  mpz_limbs_copy (p->p + size, y, size);
+
+  return 1;
+}
+
+void
+ecc_point_get (const struct ecc_point *p, mpz_t x, mpz_t y)
+{
+  mp_size_t size = p->ecc->size;
+  mpz_set_n (x, p->p, size);
+  mpz_set_n (y, p->p + size, size);
+}
diff --git a/ecc-random.c b/ecc-random.c
new file mode 100644
index 0000000000000000000000000000000000000000..5a8faefd8a4f11a261ce998d261abfb1d27acf6a
--- /dev/null
+++ b/ecc-random.c
@@ -0,0 +1,90 @@
+/* ecc-random.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.h"
+#include "ecc-internal.h"
+#include "gmp-glue.h"
+#include "nettle-internal.h"
+
+static int
+zero_p (const struct ecc_curve *ecc,
+	const mp_limb_t *xp)
+{
+  mp_limb_t t;
+  mp_size_t i;
+
+  for (i = t = 0; i < ecc->size; i++)
+    t |= xp[i];
+
+  return t == 0;
+}
+
+static int
+ecdsa_in_range (const struct ecc_curve *ecc,
+		const mp_limb_t *xp, mp_limb_t *scratch)
+{
+  /* Check if 0 < x < q, with data independent timing. */
+  return !zero_p (ecc, xp)
+    & (mpn_sub_n (scratch, xp, ecc->q, ecc->size) != 0);
+}
+
+void
+ecc_modq_random (const struct ecc_curve *ecc, mp_limb_t *xp,
+		 void *ctx, nettle_random_func *random, mp_limb_t *scratch)
+{
+  uint8_t *buf = (uint8_t *) scratch;
+  unsigned nbytes = (ecc->bit_size + 7)/8;
+
+  /* The bytes ought to fit in the scratch area, unless we have very
+     unusual limb and byte sizes. */
+  assert (nbytes <= ecc->size * sizeof (mp_limb_t));
+
+  do
+    {
+      /* q and p are of the same bitsize. */
+      random (ctx, nbytes, buf);
+      buf[0] &= 0xff >> (nbytes * 8 - ecc->bit_size);
+
+      mpn_set_base256 (xp, ecc->size, buf, nbytes);
+    }
+  while (!ecdsa_in_range (ecc, xp, scratch));
+}
+
+void
+ecc_scalar_random (struct ecc_scalar *x,
+		   void *random_ctx, nettle_random_func *random)
+{
+  TMP_DECL (scratch, mp_limb_t, ECC_MODQ_RANDOM_ITCH (ECC_MAX_SIZE));
+  TMP_ALLOC (scratch, ECC_MODQ_RANDOM_ITCH (x->ecc->size));
+
+  ecc_modq_random (x->ecc, x->p, random_ctx, random, scratch);
+}
+
+
diff --git a/ecc-scalar.c b/ecc-scalar.c
new file mode 100644
index 0000000000000000000000000000000000000000..f02fc0afcd5a8a9065219e5ec90c26caba1a272a
--- /dev/null
+++ b/ecc-scalar.c
@@ -0,0 +1,62 @@
+/* ecc-scalar.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.h"
+#include "ecc-internal.h"
+#include "gmp-glue.h"
+
+void
+ecc_scalar_init (struct ecc_scalar *s, const struct ecc_curve *ecc)
+{
+  s->ecc = ecc;
+  s->p = gmp_alloc_limbs (ecc->size);
+}
+
+void
+ecc_scalar_clear (struct ecc_scalar *s)
+{
+  gmp_free_limbs (s->p, s->ecc->size);
+}
+
+int
+ecc_scalar_set (struct ecc_scalar *s, const mpz_t z)
+{
+  mp_size_t size = s->ecc->size;
+
+  if (mpz_sgn (z) <= 0 || mpz_limbs_cmp (z, s->ecc->q, size) >= 0)
+    return 0;
+
+  mpz_limbs_copy (s->p, z, size);
+  return 1;
+}
+
+void
+ecc_scalar_get (const struct ecc_scalar *s, mpz_t z)
+{
+  mpz_set_n (z, s->p, s->ecc->size);  
+}
diff --git a/ecc-size.c b/ecc-size.c
new file mode 100644
index 0000000000000000000000000000000000000000..c829d46050bccb872385690bbf4cf4eac6e6493c
--- /dev/null
+++ b/ecc-size.c
@@ -0,0 +1,48 @@
+/* ecc-size.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.h"
+#include "ecc-internal.h"
+
+mp_size_t
+ecc_size (const struct ecc_curve *ecc)
+{
+  return ecc->size;
+}
+
+mp_size_t
+ecc_size_a (const struct ecc_curve *ecc)
+{
+  return 2*ecc->size;
+}
+
+mp_size_t
+ecc_size_j (const struct ecc_curve *ecc)
+{
+  return 3*ecc->size;
+}
diff --git a/ecc.h b/ecc.h
new file mode 100644
index 0000000000000000000000000000000000000000..af6c23d6d8a7e79918a8faa1fc6a48833a819809
--- /dev/null
+++ b/ecc.h
@@ -0,0 +1,255 @@
+/* ecc.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_H_INCLUDED
+#define NETTLE_ECC_H_INCLUDED
+
+#include <gmp.h>
+
+#include "nettle-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Name mangling */
+#define ecc_point_init nettle_ecc_point_init
+#define ecc_point_clear nettle_ecc_point_clear
+#define ecc_point_set nettle_ecc_point_set
+#define ecc_point_get nettle_ecc_point_get
+#define ecc_scalar_init nettle_ecc_scalar_init
+#define ecc_scalar_clear nettle_ecc_scalar_clear
+#define ecc_scalar_set nettle_ecc_scalar_set
+#define ecc_scalar_get nettle_ecc_scalar_get
+#define ecc_scalar_random nettle_ecc_scalar_random
+#define ecc_point_mul nettle_ecc_point_mul
+#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_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_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
+
+struct ecc_curve;
+
+/* High level interface, for ECDSA, DH, etc */
+
+/* Represents a point on the ECC curve */
+struct ecc_point
+{
+  const struct ecc_curve *ecc;
+  /* Allocated using the same allocation function as GMP. */
+  mp_limb_t *p;
+};
+
+/* Represents a non-zero scalar, an element of Z_q^*, where q is the
+   group order of the curve. */
+struct ecc_scalar
+{
+  const struct ecc_curve *ecc;
+  /* Allocated using the same allocation function as GMP. */
+  mp_limb_t *p;
+};
+
+void
+ecc_point_init (struct ecc_point *p, const struct ecc_curve *ecc);
+void
+ecc_point_clear (struct ecc_point *p);
+
+/* Fails and returns zero if the point is not on the curve. */
+int
+ecc_point_set (struct ecc_point *p, const mpz_t x, const mpz_t y);
+void
+ecc_point_get (const struct ecc_point *p, mpz_t x, mpz_t y);
+
+void
+ecc_scalar_init (struct ecc_scalar *s, const struct ecc_curve *ecc);
+void
+ecc_scalar_clear (struct ecc_scalar *s);
+
+/* Fails and returns zero if the scalar is not in the proper range. */
+int
+ecc_scalar_set (struct ecc_scalar *s, const mpz_t z);
+void
+ecc_scalar_get (const struct ecc_scalar *s, mpz_t z);
+/* Generates a random scalar, suitable as an ECDSA private key or a
+   ECDH exponent. */
+void
+ecc_scalar_random (struct ecc_scalar *s,
+		   void *random_ctx, nettle_random_func *random);
+
+/* Computes r = n p */
+void
+ecc_point_mul (struct ecc_point *r, const struct ecc_scalar *n,
+	       const struct ecc_point *p);
+
+
+/* Low-level interface */
+  
+/* Points on a curve are represented as arrays of mp_limb_t. For some
+   curves, point coordinates are represented in montgomery form. We
+   use either affine coordinates x,y, or Jacobian coordinates X, Y, Z,
+   where x = X/Z^2 and y = X/Z^2.
+
+   Since we use additive notation for the groups, the infinity point
+   on the curve is denoted 0. The infinity point can be represented
+   with x = y = 0 in affine coordinates, and Z = 0 in Jacobian
+   coordinates. However, note that most of the ECC functions do *not*
+   support infinity as an input or output.
+*/
+
+/* FIXME: Also provided some compile time constants? */
+
+/* Returns the size of a single coordinate. */
+mp_size_t
+ecc_size (const struct ecc_curve *ecc);
+
+/* Size of a point, using affine coordinates x, y. */
+mp_size_t
+ecc_size_a (const struct ecc_curve *ecc);
+
+/* Size of a point, using jacobian coordinates X, Y and Z. */
+mp_size_t
+ecc_size_j (const struct ecc_curve *ecc);
+
+/* FIXME: Rename the low-level (and side-channel silent) functions to
+   _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. */
+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
+   coordinates. If FLAGS has bit 0 set, and the curve uses montgomery
+   coordinates, also undo the montgomery conversion. If flags has bit
+   1 set, produce x coordinate only. */
+mp_size_t
+ecc_j_to_a_itch (const struct ecc_curve *ecc);
+void
+ecc_j_to_a (const struct ecc_curve *ecc,
+	    int flags,
+	    mp_limb_t *r, const mp_limb_t *p,
+	    mp_limb_t *scratch);
+
+/* Group operations */
+
+
+/* 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);
+void
+ecc_dup_ja (const struct ecc_curve *ecc,
+	    mp_limb_t *r, const mp_limb_t *p,
+	    mp_limb_t *scratch);
+
+/* Point doubling, with jacobian input and output. Corner cases:
+   Correctly sets R = 0 (r_Z = 0) if p = 0 or 2p = 0. */
+mp_size_t
+ecc_dup_jj_itch (const struct ecc_curve *ecc);
+void
+ecc_dup_jj (const struct ecc_curve *ecc,
+	    mp_limb_t *r, const mp_limb_t *p,
+	    mp_limb_t *scratch);
+
+
+/* Point addition, with jacobian output, one jacobian input and one
+   affine input. Corner cases: Fails for the cases
+
+     P = Q != 0                       Duplication of non-zero point
+     P = 0, Q != 0 or P != 0, Q = 0   One input zero
+   
+     Correctly gives R = 0 if P = Q = 0 or P = -Q. */
+mp_size_t
+ecc_add_jja_itch (const struct ecc_curve *ecc);
+void
+ecc_add_jja (const struct ecc_curve *ecc,
+	     mp_limb_t *r, const mp_limb_t *p, const mp_limb_t *q,
+	     mp_limb_t *scratch);
+
+/* Point addition with Jacobian input and output. */
+mp_size_t
+ecc_add_jjj_itch (const struct ecc_curve *ecc);
+void
+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);
+
+
+/* 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,
+   and the algorithm can work without any intermediate values getting
+   to zero. */ 
+mp_size_t
+ecc_mul_g_itch (const struct ecc_curve *ecc);
+void
+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. */
+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,
+	   const mp_limb_t *np, const mp_limb_t *p,
+	   mp_limb_t *scratch);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_ECC_H_INCLUDED */
diff --git a/eccdata.c b/eccdata.c
new file mode 100644
index 0000000000000000000000000000000000000000..ea922b5d74c5be5dd371c271238c66593f7bee67
--- /dev/null
+++ b/eccdata.c
@@ -0,0 +1,878 @@
+/* eccdata.c */
+
+/* Generate 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. */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gmp.h>
+
+/* Affine coordinates, for simplicity. Infinity point represented as x
+   == y == 0. */
+struct ecc_point
+{
+  mpz_t x;
+  mpz_t y;
+};
+
+/* Represents an elliptic curve of the form
+
+     y^2 = x^3 - 3x + b (mod p)
+*/
+struct ecc_curve
+{
+  unsigned bit_size;
+  unsigned pippenger_k;
+  unsigned pippenger_c;
+
+  /* Prime */
+  mpz_t p;
+  mpz_t b;
+
+  /* Curve order */
+  mpz_t q;
+  struct ecc_point g;
+
+  /* Table for pippenger's algorithm.
+     Element
+
+       i 2^c + j_0 + j_1 2 + j_2 2^2 + ... + j_{c-1} 2^{c-1}
+
+     holds
+
+       2^{ikc} ( j_0 + j_1 2^k + j_2 2^{2k} + ... + j_{c-1} 2^{(c-1)k}) g
+   */
+  mp_size_t table_size;
+  struct ecc_point *table;
+
+  /* If non-NULL, holds 2g, 3g, 4g */
+  struct ecc_point *ref;
+};
+
+static void
+ecc_init (struct ecc_point *p)
+{
+  mpz_init (p->x);
+  mpz_init (p->y);
+}
+
+static void
+ecc_clear (struct ecc_point *p)
+{
+  mpz_clear (p->x);
+  mpz_clear (p->y);
+}
+
+static int
+ecc_zero_p (const struct ecc_point *p)
+{
+  return mpz_sgn (p->x) == 0 && mpz_sgn (p->y) == 0;
+}
+
+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;
+}
+
+static void
+ecc_set_zero (struct ecc_point *r)
+{
+  mpz_set_ui (r->x, 0);
+  mpz_set_ui (r->y, 0);
+}
+
+static void
+ecc_set (struct ecc_point *r, const struct ecc_point *p)
+{
+  mpz_set (r->x, p->x);
+  mpz_set (r->y, p->y);
+}
+
+static void
+ecc_dup (const struct ecc_curve *ecc,
+	 struct ecc_point *r, const struct ecc_point *p)
+{
+  if (ecc_zero_p (p))
+    ecc_set_zero (r);
+
+  else
+    {
+      mpz_t m, t, x, y;
+  
+      mpz_init (m);
+      mpz_init (t);
+      mpz_init (x);
+      mpz_init (y);
+
+      /* m = (2 y)^-1 */
+      mpz_mul_ui (m, p->y, 2);
+      mpz_invert (m, m, ecc->p);
+
+      /* t = 3 (x^2 - 1) * m */
+      mpz_mul (t, p->x, p->x);
+      mpz_mod (t, t, ecc->p);
+      mpz_sub_ui (t, t, 1);
+      mpz_mul_ui (t, t, 3);
+      mpz_mul (t, t, m);
+
+      /* x' = t^2 - 2 x */
+      mpz_mul (x, t, t);
+      mpz_submul_ui (x, p->x, 2);
+      mpz_mod (x, x, ecc->p);
+
+      /* y' = (x - x') * t - y */
+      mpz_sub (y, p->x, x);
+      mpz_mul (y, y, t);
+      mpz_sub (y, y, p->y);
+      mpz_mod (y, y, ecc->p);
+
+      mpz_swap (x, r->x);
+      mpz_swap (y, r->y);
+  
+      mpz_clear (m);
+      mpz_clear (t);
+      mpz_clear (x);
+      mpz_clear (y);
+    }
+}
+
+static void
+ecc_add (const struct ecc_curve *ecc,
+	 struct ecc_point *r, const struct ecc_point *p, const struct ecc_point *q)
+{
+  if (ecc_zero_p (p))
+    ecc_set (r, q);
+
+  else if (ecc_zero_p (q))
+    ecc_set (r, p);
+
+  else if (mpz_cmp (p->x, q->x) == 0)
+    {
+      if (mpz_cmp (p->y, q->y) == 0)
+	ecc_dup (ecc, r, p);
+      else
+	ecc_set_zero (r);
+    }
+  else
+    {
+      mpz_t s, t, x, y;
+      mpz_init (s);
+      mpz_init (t);
+      mpz_init (x);
+      mpz_init (y);
+
+      /* t = (q_y - p_y) / (q_x - p_x) */
+      mpz_sub (t, q->x, p->x);
+      mpz_invert (t, t, ecc->p);
+      mpz_sub (s, q->y, p->y);
+      mpz_mul (t, t, s);
+      mpz_mod (t, t, ecc->p);
+
+      /* x' = t^2 - p_x - q_x */
+      mpz_mul (x, t, t);
+      mpz_sub (x, x, p->x);
+      mpz_sub (x, x, q->x);
+      mpz_mod (x, x, ecc->p);
+
+      /* y' = (x - x') * t - y */
+      mpz_sub (y, p->x, x);
+      mpz_mul (y, y, t);
+      mpz_sub (y, y, p->y);
+      mpz_mod (y, y, ecc->p);
+
+      mpz_swap (x, r->x);
+      mpz_swap (y, r->y);
+
+      mpz_clear (s);
+      mpz_clear (t);
+      mpz_clear (x);
+      mpz_clear (y);
+    }
+}
+
+static void 
+ecc_mul_binary (const struct ecc_curve *ecc,
+		struct ecc_point *r, const mpz_t n, const struct ecc_point *p)
+{
+  mp_bitcnt_t k;
+
+  assert (r != p);
+  assert (mpz_sgn (n) > 0);
+
+  ecc_set (r, p);
+
+  /* Index of highest one bit */
+  for (k = mpz_sizeinbase (n, 2) - 1; k-- > 0; )
+    {
+      ecc_dup (ecc, r, r);
+      if (mpz_tstbit (n, k))
+	ecc_add (ecc, r, r, p);
+    }  
+}
+
+static struct ecc_point *
+ecc_alloc (size_t n)
+{
+  struct ecc_point *p = malloc (n * sizeof(*p));
+  size_t i;
+
+  if (!p)
+    {
+      fprintf (stderr, "Virtual memory exhausted.\n");
+      exit (EXIT_FAILURE);
+    }
+  for (i = 0; i < n; i++)
+    ecc_init (&p[i]);
+
+  return p;
+}
+
+static void
+ecc_set_str (struct ecc_point *p,
+	     const char *x, const char *y)
+{
+  mpz_set_str (p->x, x, 16);
+  mpz_set_str (p->y, y, 16);  
+}
+
+static void
+ecc_curve_init_str (struct ecc_curve *ecc,
+		    const char *p, const char *b, const char *q,
+		    const char *gx, const char *gy)
+{
+  mpz_init_set_str (ecc->p, p, 16);
+  mpz_init_set_str (ecc->b, b, 16);
+  mpz_init_set_str (ecc->q, q, 16);
+  ecc_init (&ecc->g);
+  ecc_set_str (&ecc->g, gx, gy);
+
+  ecc->pippenger_k = 0;
+  ecc->pippenger_c = 0;
+  ecc->table = NULL;
+
+  ecc->ref = NULL;
+}
+
+static void
+ecc_curve_init (struct ecc_curve *ecc, unsigned bit_size)
+{
+  switch (bit_size)
+    {
+    case 192:      
+      ecc_curve_init_str (ecc,
+			  /* p = 2^{192} - 2^{64} - 1 */
+			  "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE"
+			  "FFFFFFFFFFFFFFFF",
+
+			  "64210519e59c80e70fa7e9ab72243049"
+			  "feb8deecc146b9b1", 
+
+			  "ffffffffffffffffffffffff99def836"
+			  "146bc9b1b4d22831",
+
+			  "188da80eb03090f67cbf20eb43a18800"
+			  "f4ff0afd82ff1012",
+
+			  "07192b95ffc8da78631011ed6b24cdd5"
+			  "73f977a11e794811");
+      ecc->ref = ecc_alloc (3);
+      ecc_set_str (&ecc->ref[0], /* 2 g */
+		   "dafebf5828783f2ad35534631588a3f629a70fb16982a888",
+		   "dd6bda0d993da0fa46b27bbc141b868f59331afa5c7e93ab");
+      
+      ecc_set_str (&ecc->ref[1], /* 3 g */
+		   "76e32a2557599e6edcd283201fb2b9aadfd0d359cbb263da",
+		   "782c37e372ba4520aa62e0fed121d49ef3b543660cfd05fd");
+
+      ecc_set_str (&ecc->ref[2], /* 4 g */
+		   "35433907297cc378b0015703374729d7a4fe46647084e4ba",
+		   "a2649984f2135c301ea3acb0776cd4f125389b311db3be32");
+
+      break;
+    case 224:
+      ecc_curve_init_str (ecc,
+			  /* p = 2^{224} - 2^{96} + 1 */
+			  "ffffffffffffffffffffffffffffffff"
+			  "000000000000000000000001",
+
+			  "b4050a850c04b3abf54132565044b0b7"
+			  "d7bfd8ba270b39432355ffb4",
+
+			  "ffffffffffffffffffffffffffff16a2"
+			  "e0b8f03e13dd29455c5c2a3d",
+
+			  "b70e0cbd6bb4bf7f321390b94a03c1d3"
+			  "56c21122343280d6115c1d21",
+
+			  "bd376388b5f723fb4c22dfe6cd4375a0"
+			  "5a07476444d5819985007e34");
+
+      ecc->ref = ecc_alloc (3);
+      ecc_set_str (&ecc->ref[0], /* 2 g */
+		   "706a46dc76dcb76798e60e6d89474788d16dc18032d268fd1a704fa6",
+		   "1c2b76a7bc25e7702a704fa986892849fca629487acf3709d2e4e8bb");
+      
+      ecc_set_str (&ecc->ref[1], /* 3 g */
+		   "df1b1d66a551d0d31eff822558b9d2cc75c2180279fe0d08fd896d04",
+		   "a3f7f03cadd0be444c0aa56830130ddf77d317344e1af3591981a925");
+
+      ecc_set_str (&ecc->ref[2], /* 4 g */
+		   "ae99feebb5d26945b54892092a8aee02912930fa41cd114e40447301",
+		   "482580a0ec5bc47e88bc8c378632cd196cb3fa058a7114eb03054c9");
+
+      break;
+    case 256:
+      ecc_curve_init_str (ecc,
+			  /* p = 2^{256} - 2^{224} + 2^{192} + 2^{96} - 1 */
+			  "FFFFFFFF000000010000000000000000"
+			  "00000000FFFFFFFFFFFFFFFFFFFFFFFF",
+
+			  "5AC635D8AA3A93E7B3EBBD55769886BC"
+			  "651D06B0CC53B0F63BCE3C3E27D2604B",
+
+			  "FFFFFFFF00000000FFFFFFFFFFFFFFFF"
+			  "BCE6FAADA7179E84F3B9CAC2FC632551",
+
+			  "6B17D1F2E12C4247F8BCE6E563A440F2"
+			  "77037D812DEB33A0F4A13945D898C296",
+
+			  "4FE342E2FE1A7F9B8EE7EB4A7C0F9E16"
+			  "2BCE33576B315ECECBB6406837BF51F5");
+
+      ecc->ref = ecc_alloc (3);
+      ecc_set_str (&ecc->ref[0], /* 2 g */
+		   "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978",
+		   "7775510db8ed040293d9ac69f7430dbba7dade63ce982299e04b79d227873d1");
+      
+      ecc_set_str (&ecc->ref[1], /* 3 g */
+		   "5ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c",
+		   "8734640c4998ff7e374b06ce1a64a2ecd82ab036384fb83d9a79b127a27d5032");
+
+      ecc_set_str (&ecc->ref[2], /* 4 g */
+		   "e2534a3532d08fbba02dde659ee62bd0031fe2db785596ef509302446b030852",
+		   "e0f1575a4c633cc719dfee5fda862d764efc96c3f30ee0055c42c23f184ed8c6");
+
+      break;
+    case 384:
+      ecc_curve_init_str (ecc,
+			  /* p = 2^{384} - 2^{128} - 2^{96} + 2^{32} - 1 */
+			  "ffffffffffffffffffffffffffffffff"
+			  "fffffffffffffffffffffffffffffffe"
+			  "ffffffff0000000000000000ffffffff",
+			  
+			  "b3312fa7e23ee7e4988e056be3f82d19"
+			  "181d9c6efe8141120314088f5013875a"
+			  "c656398d8a2ed19d2a85c8edd3ec2aef",
+			  
+			  "ffffffffffffffffffffffffffffffff"
+			  "ffffffffffffffffc7634d81f4372ddf"
+			  "581a0db248b0a77aecec196accc52973",
+			  
+			  "aa87ca22be8b05378eb1c71ef320ad74"
+			  "6e1d3b628ba79b9859f741e082542a38"
+			  "5502f25dbf55296c3a545e3872760ab7",
+			  
+			  "3617de4a96262c6f5d9e98bf9292dc29"
+			  "f8f41dbd289a147ce9da3113b5f0b8c0"
+			  "0a60b1ce1d7e819d7a431d7c90ea0e5f");
+
+      ecc->ref = ecc_alloc (3);
+      ecc_set_str (&ecc->ref[0], /* 2 g */
+		   "8d999057ba3d2d969260045c55b97f089025959a6f434d651d207d19fb96e9e4fe0e86ebe0e64f85b96a9c75295df61",
+		   "8e80f1fa5b1b3cedb7bfe8dffd6dba74b275d875bc6cc43e904e505f256ab4255ffd43e94d39e22d61501e700a940e80");
+
+      ecc_set_str (&ecc->ref[1], /* 3 g */
+		   "77a41d4606ffa1464793c7e5fdc7d98cb9d3910202dcd06bea4f240d3566da6b408bbae5026580d02d7e5c70500c831",
+		   "c995f7ca0b0c42837d0bbe9602a9fc998520b41c85115aa5f7684c0edc111eacc24abd6be4b5d298b65f28600a2f1df1");
+
+      ecc_set_str (&ecc->ref[2], /* 4 g */
+		   "138251cd52ac9298c1c8aad977321deb97e709bd0b4ca0aca55dc8ad51dcfc9d1589a1597e3a5120e1efd631c63e1835",
+		   "cacae29869a62e1631e8a28181ab56616dc45d918abc09f3ab0e63cf792aa4dced7387be37bba569549f1c02b270ed67");
+
+      break;
+    case 521:
+      ecc_curve_init_str (ecc,			  
+			  "1ff" /* p = 2^{521} - 1 */
+			  "ffffffffffffffffffffffffffffffff"
+			  "ffffffffffffffffffffffffffffffff"
+			  "ffffffffffffffffffffffffffffffff"
+			  "ffffffffffffffffffffffffffffffff",
+
+			  "051"
+			  "953eb9618e1c9a1f929a21a0b68540ee"
+			  "a2da725b99b315f3b8b489918ef109e1"
+			  "56193951ec7e937b1652c0bd3bb1bf07"
+			  "3573df883d2c34f1ef451fd46b503f00",
+
+			  "1ff"
+			  "ffffffffffffffffffffffffffffffff"
+			  "fffffffffffffffffffffffffffffffa"
+			  "51868783bf2f966b7fcc0148f709a5d0"
+			  "3bb5c9b8899c47aebb6fb71e91386409",
+
+			  "c6"
+			  "858e06b70404e9cd9e3ecb662395b442"
+			  "9c648139053fb521f828af606b4d3dba"
+			  "a14b5e77efe75928fe1dc127a2ffa8de"
+			  "3348b3c1856a429bf97e7e31c2e5bd66",
+
+			  "118"
+			  "39296a789a3bc0045c8a5fb42c7d1bd9"
+			  "98f54449579b446817afbd17273e662c"
+			  "97ee72995ef42640c550b9013fad0761"
+			  "353c7086a272c24088be94769fd16650");
+
+      ecc->ref = ecc_alloc (3);
+      ecc_set_str (&ecc->ref[0], /* 2 g */
+		   "433c219024277e7e682fcb288148c282747403279b1ccc06352c6e5505d769be97b3b204da6ef55507aa104a3a35c5af41cf2fa364d60fd967f43e3933ba6d783d",
+		   "f4bb8cc7f86db26700a7f3eceeeed3f0b5c6b5107c4da97740ab21a29906c42dbbb3e377de9f251f6b93937fa99a3248f4eafcbe95edc0f4f71be356d661f41b02");
+      
+      ecc_set_str (&ecc->ref[1], /* 3 g */
+		   "1a73d352443de29195dd91d6a64b5959479b52a6e5b123d9ab9e5ad7a112d7a8dd1ad3f164a3a4832051da6bd16b59fe21baeb490862c32ea05a5919d2ede37ad7d",
+		   "13e9b03b97dfa62ddd9979f86c6cab814f2f1557fa82a9d0317d2f8ab1fa355ceec2e2dd4cf8dc575b02d5aced1dec3c70cf105c9bc93a590425f588ca1ee86c0e5");
+
+      ecc_set_str (&ecc->ref[2], /* 4 g */
+		   "35b5df64ae2ac204c354b483487c9070cdc61c891c5ff39afc06c5d55541d3ceac8659e24afe3d0750e8b88e9f078af066a1d5025b08e5a5e2fbc87412871902f3",
+		   "82096f84261279d2b673e0178eb0b4abb65521aef6e6e32e1b5ae63fe2f19907f279f283e54ba385405224f750a95b85eebb7faef04699d1d9e21f47fc346e4d0d");
+
+      break;
+    default:
+      fprintf (stderr, "No known curve for size %d\n", bit_size);
+      exit(EXIT_FAILURE);     
+    }
+  ecc->bit_size = bit_size;
+}
+
+static void
+ecc_pippenger_precompute (struct ecc_curve *ecc, unsigned k, unsigned c)
+{
+  unsigned p = (ecc->bit_size + k-1) / k;
+  unsigned M = (p + c-1)/c;
+  unsigned i, j;
+
+  ecc->pippenger_k = k;
+  ecc->pippenger_c = c;
+  ecc->table_size = M << c;
+  ecc->table = ecc_alloc (ecc->table_size);
+  
+  /* Compute the first 2^c entries */
+  ecc_set_zero (&ecc->table[0]);
+  ecc_set (&ecc->table[1], &ecc->g);
+
+  for (j = 2; j < (1U<<c); j <<= 1)
+    {
+      /* T[j] = 2^k T[j/2] */
+      ecc_dup (ecc, &ecc->table[j], &ecc->table[j/2]);
+      for (i = 1; i < k; i++)
+	ecc_dup (ecc, &ecc->table[j], &ecc->table[j]);
+
+      for (i = 1; i < j; i++)
+	ecc_add (ecc, &ecc->table[j + i], &ecc->table[j], &ecc->table[i]);
+    }
+  for (j = 1<<c; j < ecc->table_size; j++)
+    {
+      /* T[j] = 2^{kc} T[j-2^c] */
+      ecc_dup (ecc, &ecc->table[j], &ecc->table[j - (1<<c)]);
+      for (i = 1; i < k*c; i++)
+	ecc_dup (ecc, &ecc->table[j], &ecc->table[j]);
+    }
+}
+
+static void
+ecc_mul_pippenger (const struct ecc_curve *ecc,
+		   struct ecc_point *r, const mpz_t n_input)
+{
+  mpz_t n;
+  unsigned k, c;
+  unsigned i, j;
+  unsigned bit_rows;
+
+  mpz_init (n);
+  
+  mpz_mod (n, n_input, ecc->q);
+  ecc_set_zero (r);
+
+  k = ecc->pippenger_k;
+  c = ecc->pippenger_c;
+
+  bit_rows = (ecc->bit_size + k - 1) / k;
+
+  for (i = k; i-- > 0; )
+    {
+      ecc_dup (ecc, r, r);
+      for (j = 0; j * c < bit_rows; j++)
+	{
+	  unsigned bits;
+	  mp_size_t bit_index;
+	  
+	  /* Extract c bits of the exponent, 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; )
+	    {
+	      bit_index -= k;
+	      bits = (bits << 1) | mpz_tstbit (n, bit_index);
+	    }
+
+	  ecc_add (ecc, r, r, &ecc->table[(j << c) | bits]);
+	}
+    }
+  mpz_clear (n);
+}
+
+#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);				\
+	gmp_fprintf (stderr, "p = (%Zx,\n     %Zx)\n", (p)->x, (p)->y); \
+	gmp_fprintf (stderr, "q = (%Zx,\n     %Zx)\n", (q)->x, (q)->y); \
+	abort();							\
+      }									\
+  } while (0)
+
+#define ASSERT_ZERO(p) do {						\
+    if (!ecc_zero_p (p))						\
+      {									\
+	fprintf (stderr, "%s:%d: ASSERT_ZERO (%s) failed.\n",		\
+		 __FILE__, __LINE__, #p);				\
+	gmp_fprintf (stderr, "p = (%Zx,\n     %Zx)\n", (p)->x, (p)->y); \
+	abort();							\
+      }									\
+  } while (0)
+
+static void
+ecc_curve_check (const struct ecc_curve *ecc)
+{
+  struct ecc_point p, q;
+  mpz_t n;
+
+  ecc_init (&p);
+  ecc_init (&q);
+  mpz_init (n);
+
+  ecc_dup (ecc, &p, &ecc->g);
+  if (ecc->ref)
+    ASSERT_EQUAL (&p, &ecc->ref[0]);
+  else
+    gmp_fprintf (stderr, "g2 = %Zx\n     %Zx\n", p.x, p.y);
+
+  ecc_add (ecc, &q, &p, &ecc->g);
+  if (ecc->ref)
+    ASSERT_EQUAL (&q, &ecc->ref[1]);
+  else
+    gmp_fprintf (stderr, "g3 = %Zx\n     %Zx\n", q.x, q.y);
+
+  ecc_add (ecc, &q, &q, &ecc->g);
+  if (ecc->ref)
+    ASSERT_EQUAL (&q, &ecc->ref[2]);
+  else
+    gmp_fprintf (stderr, "g4 = %Zx\n     %Zx\n", q.x, q.y);
+
+  ecc_dup (ecc, &q, &p);
+  if (ecc->ref)
+    ASSERT_EQUAL (&q, &ecc->ref[2]);
+  else
+    gmp_fprintf (stderr, "g4 = %Zx\n     %Zx\n", q.x, q.y);
+
+  ecc_mul_binary (ecc, &p, ecc->q, &ecc->g);
+  ASSERT_ZERO (&p);
+
+  ecc_mul_pippenger (ecc, &q, ecc->q);
+  ASSERT_ZERO (&q);
+
+  ecc_clear (&p);
+  ecc_clear (&q);
+  mpz_clear (n);
+}
+
+static void
+output_digits (const mpz_t x,
+	       unsigned size, unsigned bits_per_limb)
+{  
+  mpz_t t;
+  mpz_t mask;
+  mpz_t limb;
+  unsigned i;
+  const char *suffix;
+
+  mpz_init (t);
+  mpz_init (mask);
+  mpz_init (limb);
+
+  mpz_setbit (mask, bits_per_limb);
+  mpz_sub_ui (mask, mask, 1);
+
+  suffix = bits_per_limb > 32 ? "ULL" : "UL";
+
+  mpz_init_set (t, x);
+
+  for (i = 0; i < size; i++)
+    {
+      if ( (i % 8) == 0)
+	printf("\n ");
+      
+      mpz_and (limb, mask, t);
+      gmp_printf (" 0x%Zx%s,", limb, suffix);
+      mpz_tdiv_q_2exp (t, t, bits_per_limb);
+    }
+
+  mpz_clear (t);
+  mpz_clear (mask);
+  mpz_clear (limb);
+}
+
+static void
+output_bignum (const char *name, const mpz_t x,
+	       unsigned size, unsigned bits_per_limb)
+{  
+  printf ("static const mp_limb_t %s[%d] = {", name, size);
+  output_digits (x, size, bits_per_limb);
+  printf("\n};\n");
+}
+
+static void
+output_point (const char *name, const struct ecc_point *p,
+	      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);
+
+  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 (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);
+      
+  output_digits (t, size, bits_per_limb);
+
+  if (name)
+    printf("\n};\n");
+
+  mpz_clear (t);
+}
+
+static unsigned
+output_modulo (const char *name, const mpz_t x,
+	       unsigned size, unsigned bits_per_limb)
+{
+  mpz_t mod;
+  unsigned bits;
+
+  mpz_init (mod);
+
+  mpz_setbit (mod, bits_per_limb * size);
+  mpz_mod (mod, mod, x);
+
+  bits = mpz_sizeinbase (mod, 2);
+  assert (bits <= size * bits_per_limb - 32);
+
+  output_bignum (name, mod, size, bits_per_limb);
+  
+  mpz_clear (mod);
+  return bits;
+}
+
+static void
+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;
+  int redc_limbs;
+  mpz_t t;
+
+  mpz_init (t);
+
+  printf ("/* For NULL. */\n#include <stddef.h>\n");
+
+  printf ("#define ECC_LIMB_SIZE %u\n", limb_size);
+  printf ("#define ECC_PIPPENGER_K %u\n", ecc->pippenger_k);
+  printf ("#define ECC_PIPPENGER_C %u\n", ecc->pippenger_c);
+
+  output_bignum ("ecc_p", ecc->p, limb_size, bits_per_limb);
+  output_bignum ("ecc_b", ecc->b, 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);
+  
+  bits = output_modulo ("ecc_Bmodp", ecc->p, limb_size, bits_per_limb);
+  printf ("#define ECC_BMODP_SIZE %u\n",
+	  (bits + bits_per_limb - 1) / 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);
+
+  if (ecc->bit_size < limb_size * bits_per_limb)
+    {
+      int shift;
+
+      mpz_set_ui (t, 0);
+      mpz_setbit (t, ecc->bit_size);
+      mpz_sub (t, t, ecc->p);      
+      output_bignum ("ecc_Bmodp_shifted", t, limb_size, bits_per_limb);
+
+      shift = limb_size * bits_per_limb - ecc->bit_size;
+      if (shift > 0)
+	{
+	  /* Check condition for reducing hi limbs. If s is the
+	     normalization shift and n is the bit size (so that s + n
+	     = limb_size * bite_per_limb), then we need
+
+	       (2^n - 1) + (2^s - 1) (2^n - p) < 2p
+
+	     or equivalently,
+
+	       2^s (2^n - p) <= p
+
+	     To a allow a carry limb to be added in at the same time,
+	     substitute s+1 for s.
+	  */
+	  /* FIXME: For ecdsa verify, we actually need the stricter
+	     inequality < 2 q. */
+	  mpz_mul_2exp (t, t, shift + 1);
+	  if (mpz_cmp (t, ecc->p) > 0)
+	    {
+	      fprintf (stderr, "Reduction condition failed for %u-bit curve.\n",
+		       ecc->bit_size);
+	      exit (EXIT_FAILURE);
+	    }
+	}
+      mpz_set_ui (t, 0);
+      mpz_setbit (t, ecc->bit_size);
+      mpz_sub (t, t, ecc->q);      
+      output_bignum ("ecc_Bmodq_shifted", t, limb_size, bits_per_limb);      
+    }
+  else
+    {
+      printf ("#define ecc_Bmodp_shifted ecc_Bmodp\n");
+      printf ("#define ecc_Bmodq_shifted ecc_Bmodq\n");
+    }
+
+  mpz_add_ui (t, ecc->p, 1);
+  mpz_fdiv_q_2exp (t, t, 1);
+  output_bignum ("ecc_pp1h", t, limb_size, 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);  
+  
+  /* 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)
+    {
+      mpz_add_ui (t, ecc->p, 1);
+      mpz_fdiv_q_2exp (t, t, redc_limbs * bits_per_limb);
+      output_bignum ("ecc_redc_ppm1", t, limb_size - redc_limbs, bits_per_limb);
+    }
+  else
+    {    
+      /* Trailing zeros in p-1 correspond to zeros just above the low
+	 bit of p */
+      redc_limbs = mpz_scan1 (ecc->p, 1) / bits_per_limb;
+      if (redc_limbs > 0)
+	{
+	  printf ("#define ecc_redc_ppm1 (ecc_p + %d)\n",
+		  redc_limbs);
+	  redc_limbs = -redc_limbs;
+	}
+      else
+	printf ("#define ecc_redc_ppm1 NULL\n");
+    }
+  printf ("#define ECC_REDC_SIZE %d\n", redc_limbs);
+
+  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);
+
+  printf("\n};\n");
+
+  printf ("#else\n");
+
+  mpz_init_set_ui (t, 1);
+  output_bignum ("ecc_unit", t, limb_size, 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);
+
+  printf("\n};\n");
+  printf ("#endif\n");
+  
+  mpz_clear (t);
+}
+
+int
+main (int argc, char **argv)
+{
+  struct ecc_curve ecc;
+
+  if (argc < 4)
+    {
+      fprintf (stderr, "Usage: %s CURVE-BITS K C [BITS-PER-LIMB]\n", argv[0]);
+      return EXIT_FAILURE;
+    }
+
+  ecc_curve_init (&ecc, atoi(argv[1]));
+
+  ecc_pippenger_precompute (&ecc, atoi(argv[2]), atoi(argv[3]));
+
+  fprintf (stderr, "Table size: %lu entries\n",
+	   (unsigned long) ecc.table_size);
+
+  ecc_curve_check (&ecc);
+
+  if (argc > 4)
+    output_curve (&ecc, atoi(argv[4]));
+
+  return EXIT_SUCCESS;
+}
diff --git a/ecdsa-keygen.c b/ecdsa-keygen.c
new file mode 100644
index 0000000000000000000000000000000000000000..7f8a37f1eaafee1ab992259ed5eaa9a41808fa63
--- /dev/null
+++ b/ecdsa-keygen.c
@@ -0,0 +1,51 @@
+/* ecdsa-keygen.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 <stdlib.h>
+
+#include "ecdsa.h"
+#include "ecc-internal.h"
+#include "nettle-internal.h"
+
+void
+ecdsa_generate_keypair (struct ecc_point *pub,
+			struct ecc_scalar *key,
+			void *random_ctx, nettle_random_func *random)
+{
+  TMP_DECL(p, mp_limb_t, 3*ECC_MAX_SIZE + ECC_MUL_G_ITCH (ECC_MAX_SIZE));
+  mp_size_t itch = 3*pub->ecc->size + ECC_MUL_G_ITCH (pub->ecc->size);
+
+  assert (key->ecc == pub->ecc);
+
+  TMP_ALLOC (p, itch);
+
+  ecc_modq_random (key->ecc, key->p, random_ctx, random, p);
+  ecc_mul_g (pub->ecc, p, key->p, p + 3*pub->ecc->size);
+  ecc_j_to_a (pub->ecc, 1, pub->p, p, p + 3*pub->ecc->size);
+}
diff --git a/ecdsa-sign.c b/ecdsa-sign.c
new file mode 100644
index 0000000000000000000000000000000000000000..c0827bfd18c98cd3e034fb47c6d7a95eed98f546
--- /dev/null
+++ b/ecdsa-sign.c
@@ -0,0 +1,63 @@
+/* ecdsa-sign.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 <stdlib.h>
+
+#include "ecdsa.h"
+#include "ecc-internal.h"
+#include "gmp-glue.h"
+#include "nettle-internal.h"
+
+void
+ecdsa_sign (const struct ecc_scalar *key,
+	    void *random_ctx, nettle_random_func *random,
+	    unsigned digest_length,
+	    const uint8_t *digest,
+	    struct dsa_signature *signature)
+{
+  /* At most 936 bytes. */
+  TMP_DECL(k, mp_limb_t, ECC_MAX_SIZE + ECC_ECDSA_SIGN_ITCH (ECC_MAX_SIZE));
+  mp_limb_t size = key->ecc->size;
+  mp_limb_t *rp = mpz_limbs_write (signature->r, size);
+  mp_limb_t *sp = mpz_limbs_write (signature->s, size);
+
+  TMP_ALLOC (k, size + ECC_ECDSA_SIGN_ITCH (size));
+
+  /* Timing reveals the number of rounds through this loop, but the
+     timing is still independent of the secret k finally used. */
+  do
+    {
+      ecc_modq_random (key->ecc, k, random_ctx, random, k + size);
+      ecc_ecdsa_sign (key->ecc, key->p, k, digest_length, digest,
+		   rp, sp, k + size);
+      mpz_limbs_finish (signature->r, size);
+      mpz_limbs_finish (signature->s, size);
+    }
+  while (mpz_sgn (signature->r) == 0 || mpz_sgn (signature->s) == 0);
+}
diff --git a/ecdsa-verify.c b/ecdsa-verify.c
new file mode 100644
index 0000000000000000000000000000000000000000..37ed86867cbe178f6aa3dc14f587437ee5689ca6
--- /dev/null
+++ b/ecdsa-verify.c
@@ -0,0 +1,68 @@
+/* ecc-ecdsa-verify.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 <stdlib.h>
+
+#include "ecdsa.h"
+#include "ecc-internal.h"
+#include "gmp-glue.h"
+
+int
+ecdsa_verify (const struct ecc_point *pub,
+	      unsigned length, const uint8_t *digest,
+	      const struct dsa_signature *signature)
+{
+  mp_limb_t size = pub->ecc->size;
+  mp_size_t itch = 2*size + ECC_ECDSA_VERIFY_ITCH (size);
+  /* For ECC_MUL_A_WBITS == 0, at most 1512 bytes. With
+     ECC_MUL_A_WBITS == 4, currently needs 67 * ecc->size, at most
+     4824 bytes. Don't use stack allocation for this. */
+  mp_limb_t *scratch = gmp_alloc_limbs (itch);
+  int res;
+
+#define rp scratch
+#define sp (scratch + size)
+#define scratch_out (scratch + 2*size)
+
+  if (mpz_sgn (signature->r) <= 0 || mpz_size (signature->r) > size
+      || mpz_sgn (signature->s) <= 0 || mpz_size (signature->s) > size)
+    return 0;
+  
+  mpz_limbs_copy (rp, signature->r, size);
+  mpz_limbs_copy (sp, signature->s, size);
+
+  res = ecc_ecdsa_verify (pub->ecc, pub->p, length, digest, rp, sp, scratch_out);
+
+  gmp_free_limbs (scratch, itch);
+
+  return res;
+#undef rp
+#undef sp
+#undef scratch_out
+}
diff --git a/ecdsa.h b/ecdsa.h
new file mode 100644
index 0000000000000000000000000000000000000000..961102e58a4e1cb405839057b594d38507b48d5f
--- /dev/null
+++ b/ecdsa.h
@@ -0,0 +1,94 @@
+/* ecdsa.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_ECDSA_H_INCLUDED
+#define NETTLE_ECDSA_H_INCLUDED
+
+#include "ecc.h"
+#include "dsa.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Name mangling */
+#define ecdsa_sign nettle_ecdsa_sign
+#define ecdsa_verify nettle_ecdsa_verify
+#define ecdsa_generate_keypair nettle_ecdsa_generate_keypair
+#define ecc_ecdsa_sign nettle_ecc_ecdsa_sign
+#define ecc_ecdsa_sign_itch nettle_ecc_ecdsa_sign_itch
+#define ecc_ecdsa_verify nettle_ecc_ecdsa_verify
+#define ecc_ecdsa_verify_itch nettle_ecc_ecdsa_verify_itch
+
+/* High level ECDSA functions.
+ *
+ * A public key is represented as a struct ecc_point, and a private
+ * key as a struct ecc_scalar. FIXME: Introduce some aliases? */
+void
+ecdsa_sign (const struct ecc_scalar *key,
+	    void *random_ctx, nettle_random_func *random,
+	    unsigned digest_length,
+	    const uint8_t *digest,
+	    struct dsa_signature *signature);
+
+int
+ecdsa_verify (const struct ecc_point *pub,
+	      unsigned length, const uint8_t *digest,
+	      const struct dsa_signature *signature);
+
+void
+ecdsa_generate_keypair (struct ecc_point *pub,
+			struct ecc_scalar *key,
+			void *random_ctx, nettle_random_func *random);
+
+/* Low-level ECDSA functions. */
+mp_size_t
+ecc_ecdsa_sign_itch (const struct ecc_curve *ecc);
+
+void
+ecc_ecdsa_sign (const struct ecc_curve *ecc,
+		const mp_limb_t *zp,
+		/* Random nonce, must be invertible mod ecc group
+		   order. */
+		const mp_limb_t *kp,
+		unsigned length, const uint8_t *digest,
+		mp_limb_t *rp, mp_limb_t *sp,
+		mp_limb_t *scratch);
+
+mp_size_t
+ecc_ecdsa_verify_itch (const struct ecc_curve *ecc);
+
+int
+ecc_ecdsa_verify (const struct ecc_curve *ecc,
+		  const mp_limb_t *pp, /* Public key */
+		  unsigned length, const uint8_t *digest,
+		  const mp_limb_t *rp, const mp_limb_t *sp,
+		  mp_limb_t *scratch);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_ECDSA_H_INCLUDED */
diff --git a/examples/.gitignore b/examples/.gitignore
index 85a46ae31fc905eb0e05c41df7208247b2d3de0a..b550fefe8ef974effde397021137ae7c79f8e26f 100644
--- a/examples/.gitignore
+++ b/examples/.gitignore
@@ -1,6 +1,12 @@
 /*.d
 /Makefile
+/base16dec
+/base16enc
+/base64dec
+/base64enc
+/ecc-benchmark
 /eratosthenes
+/hogweed-benchmark
 /nettle-benchmark
 /next-prime
 /random-prime
diff --git a/examples/Makefile.in b/examples/Makefile.in
index 71af8d439a5cf1fb54a8f97bb557068ef8bd6247..3455a5826069d427d73ba3002737f1557be5b0bf 100644
--- a/examples/Makefile.in
+++ b/examples/Makefile.in
@@ -13,14 +13,18 @@ PRE_LDFLAGS = -L..
 OPENSSL_LIBFLAGS = @OPENSSL_LIBFLAGS@
 BENCH_LIBS = @BENCH_LIBS@ -lm
 
-RSA_TARGETS = rsa-keygen$(EXEEXT) rsa-sign$(EXEEXT) \
-	      rsa-verify$(EXEEXT) rsa-encrypt$(EXEEXT) rsa-decrypt$(EXEEXT)
+HOGWEED_TARGETS = rsa-keygen$(EXEEXT) rsa-sign$(EXEEXT) \
+	      rsa-verify$(EXEEXT) rsa-encrypt$(EXEEXT) rsa-decrypt$(EXEEXT) \
+	      next-prime$(EXEEXT) random-prime$(EXEEXT) \
+	      hogweed-benchmark$(EXEEXT) ecc-benchmark$(EXEEXT)
 
 ENC_TARGETS = base16enc$(EXEEXT) base16dec$(EXEEXT) \
 	      base64enc$(EXEEXT) base64dec$(EXEEXT)
 TARGETS = nettle-benchmark$(EXEEXT) eratosthenes$(EXEEXT) \
-	  $(ENC_TARGETS) @IF_HOGWEED@ $(RSA_TARGETS) next-prime$(EXEEXT) random-prime$(EXEEXT)
-SOURCES = nettle-benchmark.c eratosthenes.c next-prime.c random-prime.c \
+	  $(ENC_TARGETS) @IF_HOGWEED@ $(HOGWEED_TARGETS)
+
+SOURCES = nettle-benchmark.c hogweed-benchmark.c ecc-benchmark.c \
+	eratosthenes.c next-prime.c random-prime.c \
 	nettle-openssl.c \
 	io.c read_rsa_key.c \
 	rsa-encrypt.c rsa-decrypt.c rsa-keygen.c rsa-sign.c rsa-verify.c \
@@ -49,11 +53,11 @@ all: $(TARGETS)
 	( cd .. && $(MAKE) nettle-internal.$(OBJEXT))
 
 # For Solaris and BSD make, we have to use an explicit rule for each executable
-next-prime$(EXEEXT): next-prime.$(OBJEXT) $(GETOPT_OBJS) ../libhogweed.a
+next-prime$(EXEEXT): next-prime.$(OBJEXT) $(GETOPT_OBJS)
 	$(LINK) next-prime.$(OBJEXT) $(GETOPT_OBJS) \
 	-lhogweed -lnettle $(LIBS) -o next-prime$(EXEEXT)
 
-random-prime$(EXEEXT): random-prime.$(OBJEXT) io.$(OBJEXT) $(GETOPT_OBJS) ../libhogweed.a
+random-prime$(EXEEXT): random-prime.$(OBJEXT) io.$(OBJEXT) $(GETOPT_OBJS)
 	$(LINK) random-prime.$(OBJEXT) io.$(OBJEXT) $(GETOPT_OBJS) \
 	-lhogweed -lnettle $(LIBS) -o random-prime$(EXEEXT)
 
@@ -102,8 +106,17 @@ BENCH_OBJS = nettle-benchmark.$(OBJEXT) nettle-openssl.$(OBJEXT) \
 nettle-benchmark$(EXEEXT): $(BENCH_OBJS)
 	$(LINK) $(BENCH_OBJS) -lnettle $(BENCH_LIBS) $(OPENSSL_LIBFLAGS) -o nettle-benchmark$(EXEEXT)
 
-$(TARGETS) : io.$(OBJEXT) ../libnettle.a
+ecc-benchmark$(EXEEXT): ecc-benchmark.$(OBJEXT)
+	$(LINK) ecc-benchmark.$(OBJEXT) -lhogweed -lnettle $(BENCH_LIBS) $(LIBS) \
+	-o ecc-benchmark$(EXEEXT)
 
+hogweed-benchmark$(EXEEXT): hogweed-benchmark.$(OBJEXT)
+	$(LINK) hogweed-benchmark.$(OBJEXT) \
+	-lhogweed -lnettle $(BENCH_LIBS) $(LIBS) $(OPENSSL_LIBFLAGS) \
+	-o hogweed-benchmark$(EXEEXT)
+
+$(TARGETS) : io.$(OBJEXT) ../libnettle.a
+$(HOGWEED_TARGETS): ../libhogweed.a
 
 check: $(TS_ALL)
 	LD_LIBRARY_PATH=../.lib PATH="../.lib:$$PATH" srcdir="$(srcdir)" \
diff --git a/examples/ecc-benchmark.c b/examples/ecc-benchmark.c
new file mode 100644
index 0000000000000000000000000000000000000000..596b2ff791feba556b8343c0fd53442f71fa0a41
--- /dev/null
+++ b/examples/ecc-benchmark.c
@@ -0,0 +1,304 @@
+/* ecc-benchmark.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 <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <errno.h>
+
+#include <time.h>
+
+#include "../ecc.h"
+#include "../ecc-internal.h"
+#include "../gmp-glue.h"
+
+#define BENCH_INTERVAL 0.1
+
+static void NORETURN PRINTF_STYLE(1,2)
+die(const char *format, ...)
+{
+  va_list args;
+  va_start(args, format);
+  vfprintf(stderr, format, args);
+  va_end(args);
+
+  exit(EXIT_FAILURE);
+}
+
+static void *
+xalloc (size_t size)
+{
+  void *p = malloc (size);
+  if (!p)
+    {
+      fprintf (stderr, "Virtual memory exhausted\n");
+      abort ();
+    }
+  return p;
+}
+
+static mp_limb_t *
+xalloc_limbs (mp_size_t size)
+{
+  return xalloc (size * sizeof(mp_limb_t));
+}
+
+inline static void
+time_start(struct timespec *start)
+{
+  if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, start) < 0)
+    die("clock_gettime failed: %s\n", strerror(errno));
+}
+
+static inline double
+time_end(struct timespec *start)
+{
+  struct timespec end;
+  if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end) < 0)
+    die("clock_gettime failed: %s\n", strerror(errno));
+
+  return end.tv_sec - start->tv_sec
+    + 1e-9 * (end.tv_nsec - start->tv_nsec);
+}
+
+/* Returns second per function call */
+static double
+time_function(void (*f)(void *arg), void *arg)
+{
+  unsigned ncalls;
+  double elapsed;
+
+  /* Warm up */
+  f(arg);
+  for (ncalls = 10 ;;)
+    {
+      unsigned i;
+      struct timespec t;
+
+      time_start(&t);
+      for (i = 0; i < ncalls; i++)
+	f(arg);
+      elapsed = time_end(&t);
+      if (elapsed > BENCH_INTERVAL)
+	break;
+      else if (elapsed < BENCH_INTERVAL / 10)
+	ncalls *= 10;
+      else
+	ncalls *= 2;
+    }
+  return elapsed / ncalls;
+}
+
+static int
+modinv_gcd (const struct ecc_curve *ecc,
+	    mp_limb_t *rp, mp_limb_t *ap, mp_limb_t *tp)
+{
+  mp_size_t size = ecc->size;
+  mp_limb_t *up = tp;
+  mp_limb_t *vp = tp + size+1;
+  mp_limb_t *gp = tp + 2*(size+1);
+  mp_limb_t *sp = tp + 3*(size+1);
+  mp_size_t gn, sn;
+
+  mpn_copyi (up, ap, size);
+  mpn_copyi (vp, ecc->p, size);
+  gn = mpn_gcdext (gp, sp, &sn, up, size, vp, size);
+  if (gn != 1 || gp[0] != 1)
+    return 0;
+  
+  if (sn < 0)
+    mpn_sub (sp, ecc->p, size, sp, -sn);
+  else if (sn < size)
+    /* Zero-pad. */
+    mpn_zero (sp + sn, size - sn);
+
+  mpn_copyi (rp, sp, size);
+  return 1;
+}
+
+struct ecc_ctx {
+  const struct ecc_curve *ecc;
+  mp_limb_t *rp;
+  mp_limb_t *ap;
+  mp_limb_t *bp;
+  mp_limb_t *tp;
+};
+
+static void
+bench_modp (void *p)
+{
+  struct ecc_ctx *ctx = (struct ecc_ctx *) p;
+  mpn_copyi (ctx->rp, ctx->ap, 2*ctx->ecc->size);
+  ctx->ecc->modp (ctx->ecc, ctx->rp);
+}
+
+static void
+bench_redc (void *p)
+{
+  struct ecc_ctx *ctx = (struct ecc_ctx *) p;
+  mpn_copyi (ctx->rp, ctx->ap, 2*ctx->ecc->size);
+  ctx->ecc->redc (ctx->ecc, ctx->rp);
+}
+
+static void
+bench_modq (void *p)
+{
+  struct ecc_ctx *ctx = (struct ecc_ctx *) p;
+  mpn_copyi (ctx->rp, ctx->ap, 2*ctx->ecc->size);
+  ctx->ecc->modq (ctx->ecc, ctx->rp);
+}
+
+static void
+bench_modinv (void *p)
+{
+  struct ecc_ctx *ctx = (struct ecc_ctx *) p;
+  mpn_copyi (ctx->rp + ctx->ecc->size, ctx->ap, ctx->ecc->size);
+  ecc_modp_inv (ctx->ecc, ctx->rp, ctx->rp + ctx->ecc->size, ctx->tp);
+}
+
+static void
+bench_modinv_gcd (void *p)
+{
+  struct ecc_ctx *ctx = (struct ecc_ctx *) p;
+  mpn_copyi (ctx->rp + ctx->ecc->size, ctx->ap, ctx->ecc->size);
+  modinv_gcd (ctx->ecc, ctx->rp, ctx->rp + ctx->ecc->size, ctx->tp);  
+}
+
+static void
+bench_dup_jj (void *p)
+{
+  struct ecc_ctx *ctx = (struct ecc_ctx *) p;
+  ecc_dup_jj (ctx->ecc, ctx->rp, ctx->ap, ctx->tp);
+}
+
+static void
+bench_add_jja (void *p)
+{
+  struct ecc_ctx *ctx = (struct ecc_ctx *) p;
+  ecc_add_jja (ctx->ecc, ctx->rp, ctx->ap, ctx->bp, ctx->tp);
+}
+
+static void
+bench_add_jjj (void *p)
+{
+  struct ecc_ctx *ctx = (struct ecc_ctx *) p;
+  ecc_add_jjj (ctx->ecc, ctx->rp, ctx->ap, ctx->bp, ctx->tp);
+}
+
+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);
+}
+
+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);
+}
+
+static void
+bench_curve (const struct ecc_curve *ecc)
+{
+  struct ecc_ctx ctx;  
+  double modp, redc, modq, modinv, modinv_gcd,
+    dup_jj, add_jja, add_jjj,
+    mul_g, mul_a;
+
+  mp_limb_t mask;
+
+  ctx.ecc = ecc;
+  ctx.rp = xalloc_limbs (3*ecc->size);
+  ctx.ap = xalloc_limbs (3*ecc->size);
+  ctx.bp = xalloc_limbs (3*ecc->size);
+  ctx.tp = xalloc_limbs (ECC_MUL_A_ITCH (ecc->size));
+
+  mpn_random (ctx.ap, 3*ecc->size);
+  mpn_random (ctx.bp, 3*ecc->size);
+
+  mask = (~(mp_limb_t) 0) >> (ecc->size * GMP_NUMB_BITS - ecc->bit_size);
+  ctx.ap[ecc->size - 1] &= mask;
+  ctx.ap[2*ecc->size - 1] &= mask;
+  ctx.ap[3*ecc->size - 1] &= mask;
+  ctx.bp[ecc->size - 1] &= mask;
+  ctx.bp[2*ecc->size - 1] &= mask;
+  ctx.bp[3*ecc->size - 1] &= mask;
+
+  modp = time_function (bench_modp, &ctx);
+  redc = ecc->redc ? time_function (bench_redc, &ctx) : 0;
+
+  modq = time_function (bench_modq, &ctx);
+
+  modinv = time_function (bench_modinv, &ctx);
+  modinv_gcd = time_function (bench_modinv_gcd, &ctx);
+  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);
+
+  free (ctx.rp);
+  free (ctx.ap);
+  free (ctx.bp);
+  free (ctx.tp);
+
+  printf ("%4d %6.4f %6.4f %6.4f %6.2f %6.3f %6.3f %6.3f %6.3f %6.1f %6.1f\n",
+	  ecc->bit_size, 1e6 * modp, 1e6 * redc, 1e6 * modq,
+	  1e6 * modinv, 1e6 * modinv_gcd,
+	  1e6 * dup_jj, 1e6 * add_jja, 1e6 * add_jjj,
+	  1e6 * mul_g, 1e6 * mul_a);
+}
+
+const struct ecc_curve * const curves[] = {
+  &nettle_secp_192r1,
+  &nettle_secp_224r1,
+  &nettle_secp_256r1,
+  &nettle_secp_384r1,
+  &nettle_secp_521r1,
+};
+
+#define numberof(x)  (sizeof (x) / sizeof ((x)[0]))
+
+int
+main (int argc UNUSED, char **argv UNUSED)
+{
+  unsigned i;
+
+  printf ("%4s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s (us)\n",
+	  "size", "modp", "redc", "modq", "modinv", "mi_gcd",
+	  "dup_jj", "ad_jja", "ad_jjj",
+	  "mul_g", "mul_a");
+  for (i = 0; i < numberof (curves); i++)
+    bench_curve (curves[i]);
+
+  return EXIT_SUCCESS;
+}
diff --git a/examples/hogweed-benchmark.c b/examples/hogweed-benchmark.c
new file mode 100644
index 0000000000000000000000000000000000000000..6a7da9648ea25ecf1a7706ca12c26e2a8a7602d1
--- /dev/null
+++ b/examples/hogweed-benchmark.c
@@ -0,0 +1,636 @@
+/* hogweed-benchmark.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.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <errno.h>
+
+#include <time.h>
+
+#include <nettle/dsa.h>
+#include <nettle/rsa.h>
+
+#include <nettle/nettle-meta.h>
+#include <nettle/sexp.h>
+#include <nettle/knuth-lfib.h>
+
+#include "../ecdsa.h"
+#include "../ecc-internal.h"
+#include "../gmp-glue.h"
+
+#if WITH_OPENSSL
+#include <openssl/ec.h>
+#include <openssl/ecdsa.h>
+#include <openssl/objects.h>
+#endif
+
+#define BENCH_INTERVAL 0.1
+
+static void NORETURN PRINTF_STYLE(1,2)
+die(const char *format, ...)
+{
+  va_list args;
+  va_start(args, format);
+  vfprintf(stderr, format, args);
+  va_end(args);
+
+  exit(EXIT_FAILURE);
+}
+
+static void *
+xalloc (size_t size)
+{
+  void *p = malloc (size);
+  if (!p)
+    {
+      fprintf (stderr, "Virtual memory exhausted\n");
+      abort ();
+    }
+  return p;
+}
+
+static uint8_t *
+hash_string (const struct nettle_hash *hash,
+	     unsigned length, const char *s)
+{
+  void *ctx = xalloc (hash->context_size);
+  uint8_t *digest = xalloc (hash->digest_size);
+  hash->init (ctx);
+  hash->update (ctx, length, s);
+  hash->digest (ctx, hash->digest_size, digest);
+  free (ctx);
+
+  return digest;
+}
+
+inline static void
+time_start(struct timespec *start)
+{
+  if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, start) < 0)
+    die("clock_gettime failed: %s\n", strerror(errno));
+}
+
+static inline double
+time_end(struct timespec *start)
+{
+  struct timespec end;
+  if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end) < 0)
+    die("clock_gettime failed: %s\n", strerror(errno));
+
+  return end.tv_sec - start->tv_sec
+    + 1e-9 * (end.tv_nsec - start->tv_nsec);
+}
+
+struct alg {
+  const char *name;
+  unsigned size;
+  void *(*init) (unsigned size);
+  void (*sign)  (void *);
+  void (*verify)(void *);
+  void (*clear) (void *);
+};
+
+/* Returns second per function call */
+static double
+time_function(void (*f)(void *arg), void *arg)
+{
+  unsigned ncalls;
+  double elapsed;
+
+  /* Warm up */
+  f(arg);
+  for (ncalls = 10 ;;)
+    {
+      unsigned i;
+      struct timespec t;
+
+      time_start(&t);
+      for (i = 0; i < ncalls; i++)
+	f(arg);
+      elapsed = time_end(&t);
+      if (elapsed > BENCH_INTERVAL)
+	break;
+      else if (elapsed < BENCH_INTERVAL / 10)
+	ncalls *= 10;
+      else
+	ncalls *= 2;
+    }
+  return elapsed / ncalls;
+}
+
+static void 
+bench_alg (const struct alg *alg)
+{
+  double sign;
+  double verify;
+  void *ctx;
+
+  ctx = alg->init(alg->size);
+
+  sign = time_function (alg->sign, ctx);
+  verify = time_function (alg->verify, ctx);
+
+  alg->clear (ctx);
+
+  printf("%15s %4d %9.4f %9.4f\n",
+	 alg->name, alg->size, 1e-3/sign, 1e-3/verify);
+}
+
+struct rsa_ctx
+{
+  struct rsa_public_key pub;
+  struct rsa_private_key key;
+  uint8_t *digest;
+  mpz_t s;
+};
+
+static void *
+bench_rsa_init (unsigned size)
+{
+  char rsa1024[] = 
+    "{KDExOnByaXZhdGUta2V5KDE0OnJzYS1wa2NzMS1zaGExKDE6bjEyOToA90+K5EmjbFJBeJD"
+    " xP2KD2Df+0Twc9425uB+vhqTrVijtd2PnwEQDfR2VoducgkKcXJzYYyCNILQJbFAi2Km/sD"
+    " jImERBqDtaI217Ze+tOKEmImexYTAgFuqEptp2F3M4DqgRQ7s/3nJQ/bPE5Hfi1OZhJSShu"
+    " I80ATTU4fUgrPspKDE6ZTM6AQABKSgxOmQxMjk6APAhKckzvxxkWfHJOpXDACWnaSKcbbvo"
+    " vtWK3pGr/F2ya7CrLtE+uOx5F1sLs9G+/7flCy5k4uNILIYg4VTirZ1zQ8fNKPrjK1VMRls"
+    " JiRRU/0VAs9d7HdncJfs6rbvRQbCRSRYURo4hWir3Lq8V3UUQVBprc4dO+uWmplvwQ5qxKS"
+    " gxOnA2NToA+8aIVkdbk8Jg8dJOuzc7m/hZnwkKSs6eVDw4N/2T0CJKGJYT+B3Ct+fPkxhUR"
+    " ggd2DQ9OpkTra7SXHTNkzdPVSkoMTpxNjU6APt11P8vXNnGYF0OC/cPsR8zhSYuFmtRuX6G"
+    " ES+DdG0VCU07UeNQkok1UoW5sXqY0IGr1jkJq8AMSgKoNbLQ6w8pKDE6YTY0Ohzkxsan/8F"
+    " wQDHgQbrIduXKVXaj0fONzKu8EXOTfUAYf0pdBsOlnq/+QVsPIrS6v7oNHK253YFEG84SdX"
+    " kcktUpKDE6YjY1OgCR+cRtY3RWY+f6/TWK9gwPndv03xpasLWrMm71ky1aSbT9pasS9+opR"
+    " tAiGzthfSbFsBiLQgb3VOr+AeIybT+XKSgxOmM2NDojigqARWN5u1CVDVuD2L2ManpoGiM6"
+    " kQ6FaJjqRjxeRRKFrQxGJa9tM1hqStxokC1oJidgaOLGnn60iwzToug9KSkp}";
+    
+  char rsa2048[] =
+    "{KDExOnByaXZhdGUta2V5KDE0OnJzYS1wa2NzMS1zaGExKDE6bjI1NzoAtxWXiglIdunDK48"
+    " 8I0vW0wTqnh/riW9pLk8n1F8MUPBFdhvkkl0bDQqSJPUvSHy+w4fLVwcEzeI4qFyo3b2Avz"
+    " JK20MFbt/WfHD1TbxuK8rNqXyqmqjJ9vgjtV9nPzAz7CM9ogs3/RJHpcfZPQF15ifizleUZ"
+    " aQT0GAXHZL7cePj10yGI2u3hgTkokVzdNC/1T34guKYpErg0pt0B/KejWpsFTb84z3tkR+B"
+    " YVx07p/OoByZwoABgncS/uALl31fRS8jyJ2JqUiZOqe7XoO9hkDHYNCWUGUfNGQ7ZgVp9+e"
+    " NQpracSjrp6Jnrj7r/oxJUx5ZDVNi18AzQadE/oKOrSkoMTplMzoBAAEpKDE6ZDI1NjogBT"
+    " C5vaHk2kF+LtDvw2XRBj0aZq7FHK0ioklvBSicR0l+vKYfSxVeFIk22YLphJfAjtFraRjYA"
+    " Uaze3E1Rt1rkxoweupKV++lWAQvElOaaR/LErirz/Vysjdck1D1ZjLOi+NNofSq2DWbsvY1"
+    " iznZhQRP3lVf6XBls0iXrYs4gb0pBZqXLQW+j9Ihx6eantf1/6ZMKPgCkzcAZ0ABsCfaFSg"
+    " ouNCzilblsgFEspEbb8QqrNQoStS3F/gMwWgDsr3+vQzBqt+7ykWoCJ9wctbYy9kEPq+hX3"
+    " GP0hG6HdS81r9E8pgdf3wloNNMzYUHwn7poXGpOi8tG0pmR56TqD/BKSgxOnAxMjk6AN4AJ"
+    " TiGPm9We2ga3Y0jpTfA3mWpUbhYgaXYLWA1/riniwq16fqxRIkWQT/O2KKpBVe6WSvNYq9u"
+    " lM8N6bdPtDytJs6AOXy0X5vtJ953ZYVMhHbhmUxhIL9I+s0O1+LxMF8b9U4CrFyaTxd8Un/"
+    " FXP1BvYJRrkoup6HYvOlGx36lKSgxOnExMjk6ANMfrfH6z/3o7K56aW6kSiloDDbKZQ0+W5"
+    " 8LzP2ZOBLf6LX6jLhN3olU1Z0KGTM0S/1AxvwGjuRqhu+LcOJ7oUCUH3uusR5c5nSnArYPq"
+    " +0wbco4BQngot/HmGN7U0EDsIWqPt/qoa/b8bCk+TOwJlknNq/PnZU26SPj48XS05lpKSgx"
+    " OmExMjk6AJM2n3gLNW3ZeH5BindkktQU9qWNkV5geqDCaNyrEZ3bpI1WsrEGSj9p3Zz1ipz"
+    " a3msdbLJqQS26c72WKUzg8tFltR0s1HJInjolGtIgdNbfNdwrn9+RbQjL2VyPokOg0wXO4W"
+    " 14wlmqDhax33dRJmfe50964MvaglkGA8fhorrtKSgxOmIxMjk6AKMe+vrX2xRHf3dfxU5jS"
+    " ZmsdqNuxZzx7UB5kazvUU/kCJ1yNH/CSoq5LULkpovVgFDwV84qEwWQ+SjkCBg1hWWsDJc3"
+    " ZkobZUQENigM+72LiYiQt/PlyHI2eRuEEdNN0nm0DFhdpQeHXLoq/RBerYJ8tdgpBYxgnMn"
+    " KLhaOykbhKSgxOmMxMjg6MVlKj2bjb7qFQVkLO1OPg28jSrtRpnQCR+qegN4ZmNam/qbest"
+    " 8yn0JQ6gxX7PvP382+jx7uHHWHYYqPq/Flf8gqtOOcjqS5TJgVHz3F3xHWquo1ZofGtCMro"
+    " Dd2c0xjRjIVGvLV6Ngs+HRdljRav40vRpTyEoEdlzHBQiILesopKSk=}";
+
+  struct rsa_ctx *ctx;
+  struct sexp_iterator i;
+
+  int res;
+
+  ctx = xalloc(sizeof(*ctx));
+
+  rsa_public_key_init (&ctx->pub);
+  rsa_private_key_init (&ctx->key);
+  mpz_init (ctx->s);
+
+  /* NOTE: Base64-decodes the strings in-place */
+  if (size == 1024)
+    res = sexp_transport_iterator_first (&i, sizeof(rsa1024) - 1, rsa1024);
+  else if (size == 2048)
+    res = sexp_transport_iterator_first (&i, sizeof(rsa2048) - 1, rsa2048);
+  else
+    die ("Internal error.\n");
+
+  if (! (res
+	 && sexp_iterator_check_type (&i, "private-key")
+	 && sexp_iterator_check_type (&i, "rsa-pkcs1-sha1")
+	 && rsa_keypair_from_sexp_alist (&ctx->pub, &ctx->key, 0, &i)))
+    die ("Internal error.\n");
+
+  ctx->digest = hash_string (&nettle_sha256, 3, "foo");
+
+  rsa_sha256_sign_digest (&ctx->key, ctx->digest, ctx->s);
+  
+  return ctx;
+}
+
+static void
+bench_rsa_sign (void *p)
+{
+  struct rsa_ctx *ctx = (struct rsa_ctx *) p;
+
+  mpz_t s;
+  mpz_init (s);
+  rsa_sha256_sign_digest (&ctx->key, ctx->digest, s);
+  mpz_clear (s);
+}
+
+static void
+bench_rsa_verify (void *p)
+{
+  struct rsa_ctx *ctx = (struct rsa_ctx *) p;
+  int res = rsa_sha256_verify_digest (&ctx->pub, ctx->digest, ctx->s);
+  if (!res)
+    die ("Internal error, rsa_sha256_verify_digest failed.\n");
+}
+
+static void
+bench_rsa_clear (void *p)
+{
+  struct rsa_ctx *ctx = (struct rsa_ctx *) p;
+
+  rsa_public_key_clear (&ctx->pub);
+  rsa_private_key_clear (&ctx->key);
+  mpz_clear (ctx->s);
+  
+  free (ctx->digest);
+  free (ctx);
+}
+
+struct dsa_ctx
+{  
+  struct dsa_public_key pub;
+  struct dsa_private_key key;
+  struct knuth_lfib_ctx lfib;
+  struct dsa_signature s;
+  uint8_t *digest;
+};
+
+static void *
+bench_dsa_init (unsigned size)
+{
+  struct dsa_ctx *ctx;
+  struct sexp_iterator i;  
+
+  char dsa1024[] =
+    "{KDExOnByaXZhdGUta2V5KDM6ZHNhKDE6cDEyOToA2q4hOXEClLMXXMOl9xaPcGC/GeGmCMv"
+    " VCaaW0uWc50DvvmJDPQPdCehyfZr/1dv2UDbx06TC7ls/IFd+BsDzGBRxqIQ44J20cn+0gt"
+    " NMIXAocE1QhCCFaT5gXrk8zMlqBEGaP3RdpgxNanEXkTj2Wma8r1GtrLX3HPafio62jicpK"
+    " DE6cTIxOgDN9pcW3exdVAesC9WsxwCGoJK24ykoMTpnMTI5OgCJr9DmKdiE0WJZB7HACESv"
+    " Tpg1qZgc8E15byQ+OsHUyOTRrJRTcrgKZJW7dFRJ9cXmyi7XYCd3bJtu/2HRHLY1vd4qMvU"
+    " 7Y8x08ooCoABGV7nGqcmdQfEho1OY6TZh2NikmPKZLeur3PZFpcZ8Dl+KVWtwC55plNC7Om"
+    " iAQy8MaCkoMTp5MTI5OgDakk0LOUQwzOKt9FHOBmBKrWsvTm7549eScTUqH4OMm3btjUsXz"
+    " MmlqEe+imwQCOW/AE3Xw9pXZeETWK0jlLe8k5vnKcNskerFwZ1eQKtOPPQty8IqQ9PEfF6B"
+    " 0oVQiJg2maHUDWFnDkIBd7ZR1z8FnZMUxH9mH4kEUo6YQgtCdykoMTp4MjA6cOl3ijiiMjI"
+    " pesFD8jxESWb2mn8pKSk=}";
+
+  ctx = xalloc(sizeof(*ctx));
+
+  dsa_public_key_init (&ctx->pub);
+  dsa_private_key_init (&ctx->key);
+  dsa_signature_init (&ctx->s);
+  knuth_lfib_init (&ctx->lfib, 1);
+
+  if (size != 1024)
+    die ("Internal error.\n");
+  
+  if (! (sexp_transport_iterator_first (&i, sizeof(dsa1024) - 1, dsa1024)
+	 && sexp_iterator_check_type (&i, "private-key")
+	 && sexp_iterator_check_type (&i, "dsa")
+	 && dsa_keypair_from_sexp_alist (&ctx->pub, &ctx->key, 0, DSA_SHA1_Q_BITS, &i)) )
+    die ("Internal error.\n");
+
+  ctx->digest = hash_string (&nettle_sha1, 3, "foo");
+
+  dsa_sha1_sign_digest (&ctx->pub, &ctx->key,
+			&ctx->lfib, (nettle_random_func *)knuth_lfib_random,
+			ctx->digest, &ctx->s);
+
+  return ctx;
+}
+
+static void
+bench_dsa_sign (void *p)
+{
+  struct dsa_ctx *ctx = (struct dsa_ctx *) p;
+  struct dsa_signature s;
+
+  dsa_signature_init (&s);
+  dsa_sha1_sign_digest (&ctx->pub, &ctx->key,
+			&ctx->lfib, (nettle_random_func *)knuth_lfib_random,
+			ctx->digest, &s);
+  dsa_signature_clear (&s);
+}
+
+static void
+bench_dsa_verify (void *p)
+{
+  struct dsa_ctx *ctx = (struct dsa_ctx *) p;
+  int res = dsa_sha1_verify_digest (&ctx->pub, ctx->digest, &ctx->s);
+  if (!res)
+    die ("Internal error, dsa_sha1_verify_digest failed.\n");
+}
+
+static void
+bench_dsa_clear (void *p)
+{
+  struct dsa_ctx *ctx = (struct dsa_ctx *) p;
+  dsa_public_key_clear (&ctx->pub);
+  dsa_private_key_clear (&ctx->key);
+  dsa_signature_clear (&ctx->s);
+  free (ctx->digest);
+  free (ctx);
+}
+
+struct ecdsa_ctx
+{
+  struct ecc_point pub;
+  struct ecc_scalar key;
+  struct knuth_lfib_ctx rctx;
+  unsigned digest_size;
+  uint8_t *digest;
+  struct dsa_signature s;
+};
+  
+static void *
+bench_ecdsa_init (unsigned size)
+{
+  struct ecdsa_ctx *ctx;
+  const struct ecc_curve *ecc;
+
+  const char *xs;
+  const char *ys;
+  const char *zs;
+  mpz_t x, y, z;
+  
+  ctx = xalloc (sizeof(*ctx));
+
+  dsa_signature_init (&ctx->s);  
+  knuth_lfib_init (&ctx->rctx, 17);
+
+  switch (size)
+    {
+    case 192:
+      ecc = &nettle_secp_192r1;
+      xs = "8e8e07360350fb6b7ad8370cfd32fa8c6bba785e6e200599";
+      ys = "7f82ddb58a43d59ff8dc66053002b918b99bd01bd68d6736";
+      zs = "f2e620e086d658b4b507996988480917640e4dc107808bdd";
+      ctx->digest = hash_string (&nettle_sha1, 3, "abc");
+      ctx->digest_size = 20;
+      break;
+    case 224:
+      ecc = &nettle_secp_224r1;
+      xs = "993bf363f4f2bc0f255f22563980449164e9c894d9efd088d7b77334";
+      ys = "b75fff9849997d02d135140e4d0030944589586e22df1fc4b629082a";
+      zs = "cdfd01838247f5de3cc70b688418046f10a2bfaca6de9ec836d48c27";
+      ctx->digest = hash_string (&nettle_sha224, 3, "abc");
+      ctx->digest_size = 28;
+      break;
+
+      /* From RFC 4754 */
+    case 256:
+      ecc = &nettle_secp_256r1;
+      xs = "2442A5CC 0ECD015F A3CA31DC 8E2BBC70 BF42D60C BCA20085 E0822CB0 4235E970";
+      ys = "6FC98BD7 E50211A4 A27102FA 3549DF79 EBCB4BF2 46B80945 CDDFE7D5 09BBFD7D";
+      zs = "DC51D386 6A15BACD E33D96F9 92FCA99D A7E6EF09 34E70975 59C27F16 14C88A7F";
+      ctx->digest = hash_string (&nettle_sha256, 3, "abc");
+      ctx->digest_size = 32;
+      break;
+    case 384:
+      ecc = &nettle_secp_384r1;
+      xs = "96281BF8 DD5E0525 CA049C04 8D345D30 82968D10 FEDF5C5A CA0C64E6 465A97EA"
+	"5CE10C9D FEC21797 41571072 1F437922";
+      ys = "447688BA 94708EB6 E2E4D59F 6AB6D7ED FF9301D2 49FE49C3 3096655F 5D502FAD"
+	"3D383B91 C5E7EDAA 2B714CC9 9D5743CA";
+      zs = "0BEB6466 34BA8773 5D77AE48 09A0EBEA 865535DE 4C1E1DCB 692E8470 8E81A5AF"
+	"62E528C3 8B2A81B3 5309668D 73524D9F";
+      ctx->digest = hash_string (&nettle_sha384, 3, "abc");
+      ctx->digest_size = 48;
+      break;
+    case 521:
+      ecc = &nettle_secp_521r1;
+      xs = "0151518F 1AF0F563 517EDD54 85190DF9 5A4BF57B 5CBA4CF2 A9A3F647 4725A35F"
+	"7AFE0A6D DEB8BEDB CD6A197E 592D4018 8901CECD 650699C9 B5E456AE A5ADD190"
+	"52A8";
+      ys = "006F3B14 2EA1BFFF 7E2837AD 44C9E4FF 6D2D34C7 3184BBAD 90026DD5 E6E85317"
+	"D9DF45CA D7803C6C 20035B2F 3FF63AFF 4E1BA64D 1C077577 DA3F4286 C58F0AEA"
+	"E643";
+      zs = "0065FDA3 409451DC AB0A0EAD 45495112 A3D813C1 7BFD34BD F8C1209D 7DF58491"
+	"20597779 060A7FF9 D704ADF7 8B570FFA D6F062E9 5C7E0C5D 5481C5B1 53B48B37"
+	"5FA1";
+
+      ctx->digest = hash_string (&nettle_sha512, 3, "abc");
+      ctx->digest_size = 64;
+      break;
+    default:
+      die ("Internal error.\n");
+    }
+  ecc_point_init (&ctx->pub, ecc);
+  ecc_scalar_init (&ctx->key, ecc);
+
+  mpz_init_set_str (x, xs, 16);
+  mpz_init_set_str (y, ys, 16);
+  mpz_init_set_str (z, zs, 16);
+
+  ecc_point_set (&ctx->pub, x, y);
+  ecc_scalar_set (&ctx->key, z);
+
+  mpz_clear (x);
+  mpz_clear (y);
+  mpz_clear (z);
+
+  ecdsa_sign (&ctx->key,
+	      &ctx->rctx, (nettle_random_func *) knuth_lfib_random,
+	      ctx->digest_size, ctx->digest,
+	      &ctx->s);
+
+  return ctx;
+}
+
+static void
+bench_ecdsa_sign (void *p)
+{
+  struct ecdsa_ctx *ctx = (struct ecdsa_ctx *) p;
+  struct dsa_signature s;
+
+  dsa_signature_init (&s);
+  ecdsa_sign (&ctx->key,
+	      &ctx->rctx, (nettle_random_func *) knuth_lfib_random,
+	      ctx->digest_size, ctx->digest,
+	      &s);
+  dsa_signature_clear (&s);
+}
+
+static void
+bench_ecdsa_verify (void *p)
+{
+  struct ecdsa_ctx *ctx = (struct ecdsa_ctx *) p;
+  int res = ecdsa_verify (&ctx->pub, 
+			  ctx->digest_size, ctx->digest,
+			  &ctx->s);
+  if (!res)
+    die ("Internal error, _ecdsa_verify failed.\n");    
+}
+
+static void
+bench_ecdsa_clear (void *p)
+{
+  struct ecdsa_ctx *ctx = (struct ecdsa_ctx *) p;
+
+  ecc_point_clear (&ctx->pub);
+  ecc_scalar_clear (&ctx->key);
+  dsa_signature_clear (&ctx->s);
+  free (ctx->digest);
+
+  free (ctx);
+}
+
+#if WITH_OPENSSL
+struct openssl_ctx
+{
+  EC_KEY *key;
+  ECDSA_SIG *signature;
+  unsigned digest_length;
+  uint8_t *digest;
+};
+
+static void *
+bench_openssl_init (unsigned size)
+{
+  struct openssl_ctx *ctx = xalloc (sizeof (*ctx));
+
+  /* Apparently, secp192r1 and secp256r1 are missing */
+  switch (size)
+    {
+#if 0
+    case 192:
+      ctx->key = EC_KEY_new_by_curve_name (NID_secp192r1);
+      ctx->digest_length = 24; /* truncated */
+      ctx->digest = hash_string (&nettle_sha224, 3, "abc");
+      break;
+#endif
+    case 224:
+      ctx->key = EC_KEY_new_by_curve_name (NID_secp224r1);
+      ctx->digest_length = SHA224_DIGEST_SIZE;
+      ctx->digest = hash_string (&nettle_sha224, 3, "abc");
+      break;
+#if 0
+    case 256:
+      ctx->key = EC_KEY_new_by_curve_name (NID_secp256r1);
+      ctx->digest_length = SHA256_DIGEST_SIZE;
+      ctx->digest = hash_string (&nettle_sha256, 3, "abc");
+      break;
+#endif
+    case 384:
+      ctx->key = EC_KEY_new_by_curve_name (NID_secp384r1);
+      ctx->digest_length = SHA384_DIGEST_SIZE;
+      ctx->digest = hash_string (&nettle_sha384, 3, "abc");
+      break;
+    case 521:
+      ctx->key = EC_KEY_new_by_curve_name (NID_secp521r1);
+      ctx->digest_length = SHA512_DIGEST_SIZE;
+      ctx->digest = hash_string (&nettle_sha512, 3, "abc");
+      break;
+    default:
+      die ("Internal error.\n");
+    }
+  assert (ctx->key);
+
+  if (!EC_KEY_generate_key( ctx->key))
+    die ("Openssl EC_KEY_generate_key failed.\n");
+  
+  ctx->signature = ECDSA_do_sign (ctx->digest, ctx->digest_length, ctx->key);
+  
+  return ctx;
+}
+
+static void
+bench_openssl_sign (void *p)
+{
+  const struct openssl_ctx *ctx = (const struct openssl_ctx *) p;
+  ECDSA_SIG *sig = ECDSA_do_sign (ctx->digest, ctx->digest_length, ctx->key);
+  ECDSA_SIG_free (sig);
+}
+
+static void
+bench_openssl_verify (void *p)
+{
+  const struct openssl_ctx *ctx = (const struct openssl_ctx *) p;
+  int res = ECDSA_do_verify (ctx->digest, ctx->digest_length,
+			     ctx->signature, ctx->key);
+  if (res != 1)
+    die ("Openssl ECDSA_do_verify failed.\n");      
+}
+static void
+bench_openssl_clear (void *p)
+{
+  struct openssl_ctx *ctx = (struct openssl_ctx *) p;
+  ECDSA_SIG_free (ctx->signature);
+  EC_KEY_free (ctx->key);
+  free (ctx->digest);
+  free (ctx);
+}
+#endif
+
+struct alg alg_list[] = {
+  { "rsa",   1024, bench_rsa_init,   bench_rsa_sign,   bench_rsa_verify,   bench_rsa_clear },
+  { "rsa",   2048, bench_rsa_init,   bench_rsa_sign,   bench_rsa_verify,   bench_rsa_clear },
+  { "dsa",   1024, bench_dsa_init,   bench_dsa_sign,   bench_dsa_verify,   bench_dsa_clear },
+#if 0
+  { "dsa",2048, bench_dsa_init, bench_dsa_sign,   bench_dsa_verify, bench_dsa_clear },
+#endif
+  { "ecdsa",  192, bench_ecdsa_init, bench_ecdsa_sign, bench_ecdsa_verify, bench_ecdsa_clear },
+  { "ecdsa",  224, bench_ecdsa_init, bench_ecdsa_sign, bench_ecdsa_verify, bench_ecdsa_clear },
+  { "ecdsa",  256, bench_ecdsa_init, bench_ecdsa_sign, bench_ecdsa_verify, bench_ecdsa_clear },
+  { "ecdsa",  384, bench_ecdsa_init, bench_ecdsa_sign, bench_ecdsa_verify, bench_ecdsa_clear },
+  { "ecdsa",  521, bench_ecdsa_init, bench_ecdsa_sign, bench_ecdsa_verify, bench_ecdsa_clear },
+#if WITH_OPENSSL
+  { "ecdsa (openssl)",  224, bench_openssl_init, bench_openssl_sign, bench_openssl_verify, bench_openssl_clear },
+  { "ecdsa (openssl)",  384, bench_openssl_init, bench_openssl_sign, bench_openssl_verify, bench_openssl_clear },
+  { "ecdsa (openssl)",  521, bench_openssl_init, bench_openssl_sign, bench_openssl_verify, bench_openssl_clear },
+#endif
+};
+
+#define numberof(x)  (sizeof (x) / sizeof ((x)[0]))
+
+int
+main (int argc, char **argv)
+{
+  const char *filter = NULL;
+  unsigned i;
+
+  if (argc > 1)
+    filter = argv[1];
+
+  printf ("%15s %4s %9s %9s\n",
+	  "name", "size", "sign/ms", "verify/ms");
+
+  for (i = 0; i < numberof(alg_list); i++)
+    if (!filter || strstr (alg_list[i].name, filter))
+      bench_alg (&alg_list[i]);
+
+  return EXIT_SUCCESS;
+}
diff --git a/gcmdata.c b/gcmdata.c
index 60b41d946ac6b6515f7313b41543312e354e1280..d431e03a15ef1d9ed65cbccdcaea7a5627570647 100644
--- a/gcmdata.c
+++ b/gcmdata.c
@@ -26,9 +26,6 @@
  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  * MA 02111-1301, USA.
  */
-#if HAVE_CONFIG_H
-# include "config.h"
-#endif
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -50,7 +47,7 @@ reduce(unsigned x)
 }
 
 int
-main(int argc UNUSED, char **argv UNUSED)
+main(int argc, char **argv)
 {
   unsigned i;
   printf("4-bit table:\n");
diff --git a/gmp-glue.c b/gmp-glue.c
new file mode 100644
index 0000000000000000000000000000000000000000..b468699bdcb9a64f41e4414351d0896a507a6aff
--- /dev/null
+++ b/gmp-glue.c
@@ -0,0 +1,215 @@
+/* gmp-glue.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.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "gmp-glue.h"
+
+#if !GMP_HAVE_mpz_limbs_read
+
+/* This implementation tries to make a minimal use of GMP internals.
+   We access and _mp_size and _mp_d, but not _mp_alloc. */
+
+/* Use macros compatible with gmp-impl.h. */
+#define ABS(x) ((x) >= 0 ? (x) : -(x))
+#define PTR(x) ((x)->_mp_d)
+#define SIZ(x) ((x)->_mp_size)
+#define ABSIZ(x) ABS (SIZ (x))
+
+#define MPN_NORMALIZE(xp, xn) do {		\
+    while ( (xn) > 0 && (xp)[xn-1] == 0)	\
+      (xn)--;					\
+  }  while (0)
+
+/* NOTE: Makes an unnecessary realloc if allocation is already large
+   enough, but looking at _mp_alloc may break in future GMP
+   versions. */
+#define MPZ_REALLOC(x, n) \
+  (ABSIZ(x) >= (n) ? PTR(x) : (_mpz_realloc ((x),(n)), PTR (x)))
+
+#define MPZ_NEWALLOC MPZ_REALLOC
+
+/* Read access to mpz numbers. */
+
+/* Return limb pointer, for read-only operations. Use mpz_size to get
+   the number of limbs. */
+const mp_limb_t *
+mpz_limbs_read (mpz_srcptr x)
+{
+  return PTR (x);
+}
+
+/* Write access to mpz numbers. */
+
+/* Get a limb pointer for writing, previous contents may be
+   destroyed. */
+mp_limb_t *
+mpz_limbs_write (mpz_ptr x, mp_size_t n)
+{
+  assert (n > 0);
+  return MPZ_NEWALLOC (x, n);
+}
+
+/* Get a limb pointer for writing, previous contents is intact. */
+mp_limb_t *
+mpz_limbs_modify (mpz_ptr x, mp_size_t n)
+{
+  assert (n > 0);
+  return MPZ_REALLOC (x, n);
+}
+
+void
+mpz_limbs_finish (mpz_ptr x, mp_size_t n)
+{
+  assert (n >= 0);
+  MPN_NORMALIZE (PTR(x), n);
+
+  SIZ (x) = n;
+}
+
+/* Needs some ugly casts. */
+mpz_srcptr
+mpz_roinit_n (mpz_ptr x, const mp_limb_t *xp, mp_size_t xs)
+{
+  mp_size_t xn = ABS (xs);
+  
+  MPN_NORMALIZE (xp, xn);
+
+  x->_mp_size = xs < 0 ? -xn : xn;
+  x->_mp_alloc = 0;
+  x->_mp_d = (mp_limb_t *) xp;
+  return x;
+}
+#endif /* !GMP_HAVE_mpz_limbs_read */
+
+/* Additional convenience functions. */
+
+int
+mpz_limbs_cmp (mpz_srcptr a, const mp_limb_t *bp, mp_size_t bn)
+{
+  mp_size_t an = mpz_size (a);
+  assert (mpz_sgn (a) >= 0);
+  assert (bn >= 0);
+
+  if (an < bn)
+    return -1;
+  if (an > bn)
+    return 1;
+  if (an == 0)
+    return 0;
+
+  return mpn_cmp (mpz_limbs_read(a), bp, an);
+}
+
+/* Get a pointer to an n limb area, for read-only operation. n must be
+   greater or equal to the current size, and the mpz is zero-padded if
+   needed. */
+const mp_limb_t *
+mpz_limbs_read_n (mpz_ptr x, mp_size_t n)
+{
+  mp_size_t xn = mpz_size (x);
+  mp_ptr xp;
+  
+  assert (xn <= n);
+
+  xp = mpz_limbs_modify (x, n);
+
+  if (xn < n)
+    mpn_zero (xp + xn, n - xn);
+
+  return xp;
+}
+
+void
+mpz_limbs_copy (mp_limb_t *xp, mpz_srcptr x, mp_size_t n)
+{
+  mp_size_t xn = mpz_size (x);
+
+  assert (xn <= n);
+  mpn_copyi (xp, mpz_limbs_read (x), xn);
+  if (xn < n)
+    mpn_zero (xp + xn, n - xn);
+}
+
+void
+mpz_set_n (mpz_t r, const mp_limb_t *xp, mp_size_t xn)
+{
+  mpn_copyi (mpz_limbs_write (r, xn), xp, xn);
+  mpz_limbs_finish (r, xn);
+}
+
+void
+mpn_set_base256 (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 = xn, out = bits = 0; xi > 0 && 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);
+    }
+}
+
+mp_limb_t *
+gmp_alloc_limbs (mp_size_t n)
+{
+
+  void *(*alloc_func)(size_t);
+
+  assert (n > 0);
+
+  mp_get_memory_functions (&alloc_func, NULL, NULL);
+  return (mp_limb_t *) alloc_func ( (size_t) n * sizeof(mp_limb_t));
+}
+
+void
+gmp_free_limbs (mp_limb_t *p, mp_size_t n)
+{
+  void (*free_func)(void *, size_t);
+  assert (n > 0);
+  assert (p != 0);
+  mp_get_memory_functions (NULL, NULL, &free_func);
+
+  free_func (p, (size_t) n * sizeof(mp_limb_t));
+}
diff --git a/gmp-glue.h b/gmp-glue.h
new file mode 100644
index 0000000000000000000000000000000000000000..e7645716b02fb131ef452342a4dc62a63309f9bb
--- /dev/null
+++ b/gmp-glue.h
@@ -0,0 +1,120 @@
+/* gmp-glue.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.
+ */
+
+#ifndef NETTLE_GMP_GLUE_H_INCLUDED
+#define NETTLE_GMP_GLUE_H_INCLUDED
+
+#include <gmp.h>
+
+#include "nettle-stdint.h"
+
+#ifdef mpz_limbs_read
+#define GMP_HAVE_mpz_limbs_read 1
+#else
+#define GMP_HAVE_mpz_limbs_read 0
+#endif
+
+/* Name mangling. */
+#if !GMP_HAVE_mpz_limbs_read
+#define mpz_limbs_read _nettle_mpz_limbs_read
+#define mpz_limbs_write _nettle_mpz_limbs_write
+#define mpz_limbs_modify _nettle_mpz_limbs_modify
+#define mpz_limbs_finish _nettle_mpz_limbs_finish
+#define mpz_roinit_n _nettle_mpz_roinit_n
+#endif
+
+#define mpz_limbs_cmp _nettle_mpz_limbs_cmp
+#define mpz_limbs_read_n _nettle_mpz_limbs_read_n
+#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 gmp_alloc_limbs _nettle_gmp_alloc_limbs
+#define gmp_free_limbs _nettle_gmp_free_limbs
+
+/* Some functions for interfacing between mpz and mpn code. Signs of
+   the mpz numbers are generally ignored. */
+
+#if !GMP_HAVE_mpz_limbs_read
+/* Read access to mpz numbers. */
+
+/* Return limb pointer, for read-only operations. Use mpz_size to get
+   the number of limbs. */
+const mp_limb_t *
+mpz_limbs_read (const mpz_srcptr x);
+
+/* Write access to mpz numbers. */
+
+/* Get a limb pointer for writing, previous contents may be
+   destroyed. */
+mp_limb_t *
+mpz_limbs_write (mpz_ptr x, mp_size_t n);
+
+/* Get a limb pointer for writing, previous contents is intact. */
+mp_limb_t *
+mpz_limbs_modify (mpz_ptr x, mp_size_t n);
+
+/* Update size. */
+void
+mpz_limbs_finish (mpz_ptr x, mp_size_t n);
+
+/* Using an mpn number as an mpz. Can be used for read-only access
+   only. x must not be cleared or reallocated. */
+mpz_srcptr
+mpz_roinit_n (mpz_ptr x, const mp_limb_t *xp, mp_size_t xs);
+
+#endif /* !GMP_HAVE_mpz_limbs_read */
+
+/* Convenience functions */
+int
+mpz_limbs_cmp (mpz_srcptr a, const mp_limb_t *bp, mp_size_t bn);
+
+/* Get a pointer to an n limb area, for read-only operation. n must be
+   greater or equal to the current size, and the mpz is zero-padded if
+   needed. */
+const mp_limb_t *
+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,
+   with argument order consistent with mpz_get_*. */
+void
+mpz_limbs_copy (mp_limb_t *xp, mpz_srcptr x, mp_size_t n);
+
+void
+mpz_set_n (mpz_t r, const mp_limb_t *xp, mp_size_t xn);
+
+/* Like mpn_set_str, but always writes rn limbs. If input is larger,
+   higher bits are ignored. */
+void
+mpn_set_base256 (mp_limb_t *rp, mp_size_t rn,
+		 const uint8_t *xp, size_t xn);
+
+
+mp_limb_t *
+gmp_alloc_limbs (mp_size_t n);
+
+void
+gmp_free_limbs (mp_limb_t *p, mp_size_t n);
+
+
+#endif /* NETTLE_GMP_GLUE_H_INCLUDED */
diff --git a/nettle-internal.h b/nettle-internal.h
index e85e3c5f08c02557b927d93f86de2338fd69fa3d..3b7f771d0c5b9b442fc0886dfa213f715ce95240 100644
--- a/nettle-internal.h
+++ b/nettle-internal.h
@@ -36,11 +36,11 @@
 
 #if HAVE_ALLOCA
 # define TMP_DECL(name, type, max) type *name
-# define TMP_ALLOC(name, size) (name = alloca(sizeof (*name) * size))
+# define TMP_ALLOC(name, size) (name = alloca(sizeof (*name) * (size)))
 #else /* !HAVE_ALLOCA */
 # define TMP_DECL(name, type, max) type name[max]
 # define TMP_ALLOC(name, size) \
-do { if (size > (sizeof(name) / sizeof(name[0]))) abort(); } while (0)
+  do { if ((size) > (sizeof(name) / sizeof(name[0]))) abort(); } while (0)
 #endif 
 
 /* Arbitrary limits which apply to systems that don't have alloca */
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/sec-tabselect.c b/sec-tabselect.c
new file mode 100644
index 0000000000000000000000000000000000000000..f9e3c8c524de7acd0ee116b3b1fff2e84b1e466b
--- /dev/null
+++ b/sec-tabselect.c
@@ -0,0 +1,53 @@
+/* sec-tabselect.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"
+
+/* Copy the k'th element of the table out tn elements, each of size
+   rn. Always read complete table. Similar to gmp's mpn_tabselect. */
+/* FIXME: Should we need to volatile declare anything? */
+void
+sec_tabselect (mp_limb_t *rp, mp_size_t rn,
+	       const mp_limb_t *table, unsigned tn,
+	       unsigned k)
+{
+  const mp_limb_t *end = table + tn * rn;
+  const mp_limb_t *p;
+  mp_size_t i;
+  
+  assert (k < tn);
+  mpn_zero (rp, rn);
+  for (p = table; p < end; p += rn, k--)
+    {
+      mp_limb_t mask = - (mp_limb_t) (k == 0);
+      for (i = 0; i < rn; i++)
+	rp[i] += mask & p[i];
+    }
+}
diff --git a/shadata.c b/shadata.c
index 3275f0ceabef8373d580577c6b1681305a511930..cba87269f68b9dc8ddb11805af2acd197270dd34 100644
--- a/shadata.c
+++ b/shadata.c
@@ -1,7 +1,3 @@
-#if HAVE_CONFIG_H
-# include "config.h"
-#endif
-
 #include <math.h>
 #include <stdio.h>
 
@@ -16,7 +12,7 @@ static const unsigned primes[64] =
   283, 293, 307, 311
 };
 
-int main(int argc UNUSED, char **argv UNUSED)
+int main(int argc, char **argv)
 {
   int i;
   static const double third = 1.0/3;
diff --git a/testsuite/.gitignore b/testsuite/.gitignore
index 783c9f5d11d045dadc035f9cce5e6ff125e85d56..642d8c42d47f6143aad7ff1a14df4a6ba55c9e7c 100644
--- a/testsuite/.gitignore
+++ b/testsuite/.gitignore
@@ -18,7 +18,16 @@
 /des3-test
 /dsa-keygen-test
 /dsa-test
+/ecc-mod-test
+/ecc-modinv-test
+/ecc-mul-a-test
+/ecc-mul-g-test
+/ecc-redc-test
+/ecdsa-keygen-test
+/ecdsa-sign-test
+/ecdsa-verify-test
 /gcm-test
+/gosthash94-test
 /hmac-test
 /knuth-lfib-test
 /md2-test
@@ -46,6 +55,11 @@
 /sha1-test
 /sha224-test
 /sha256-test
+/sha3-224-test
+/sha3-256-test
+/sha3-384-test
+/sha3-512-test
+/sha3-permute-test
 /sha384-test
 /sha512-test
 /twofish-test
diff --git a/testsuite/.test-rules.make b/testsuite/.test-rules.make
index 93f1f94362023e28f8e1101be7e6ddea9137aadf..a935171d209c6a1be314d57cceeaa97ada305a70 100644
--- a/testsuite/.test-rules.make
+++ b/testsuite/.test-rules.make
@@ -160,6 +160,30 @@ 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)
+
+ecc-mul-g-test$(EXEEXT): ecc-mul-g-test.$(OBJEXT)
+	$(LINK) ecc-mul-g-test.$(OBJEXT) $(TEST_OBJS) -o ecc-mul-g-test$(EXEEXT)
+
+ecc-mul-a-test$(EXEEXT): ecc-mul-a-test.$(OBJEXT)
+	$(LINK) ecc-mul-a-test.$(OBJEXT) $(TEST_OBJS) -o ecc-mul-a-test$(EXEEXT)
+
+ecdsa-sign-test$(EXEEXT): ecdsa-sign-test.$(OBJEXT)
+	$(LINK) ecdsa-sign-test.$(OBJEXT) $(TEST_OBJS) -o ecdsa-sign-test$(EXEEXT)
+
+ecdsa-verify-test$(EXEEXT): ecdsa-verify-test.$(OBJEXT)
+	$(LINK) ecdsa-verify-test.$(OBJEXT) $(TEST_OBJS) -o ecdsa-verify-test$(EXEEXT)
+
+ecdsa-keygen-test$(EXEEXT): ecdsa-keygen-test.$(OBJEXT)
+	$(LINK) ecdsa-keygen-test.$(OBJEXT) $(TEST_OBJS) -o ecdsa-keygen-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..a155b447b0a41249c1aca65f7daf68d327fee32a 100644
--- a/testsuite/Makefile.in
+++ b/testsuite/Makefile.in
@@ -34,7 +34,10 @@ 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 \
+		     ecc-mul-g-test.c ecc-mul-a-test.c \
+		     ecdsa-sign-test.c ecdsa-verify-test.c ecdsa-keygen-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..658f54036c38d9903cc340d989b86b421c00b9b6
--- /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 50000
+
+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_limbs_copy (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..c20f42fc1a7a61dee4e36cf7accf4f61d08606ad
--- /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_limbs_copy (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_limbs_copy (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-mul-a-test.c b/testsuite/ecc-mul-a-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..b1c299c2c80dff4f2e812d13ed5fd3db769b4887
--- /dev/null
+++ b/testsuite/ecc-mul-a-test.c
@@ -0,0 +1,102 @@
+#include "testutils.h"
+
+void
+test_main (void)
+{
+  gmp_randstate_t state;
+  mpz_t r;
+  unsigned i;
+
+  gmp_randinit_default (state);
+  mpz_init (r);
+  
+  for (i = 0; ecc_curves[i]; i++)
+    {
+      const struct ecc_curve *ecc = ecc_curves[i];
+      mp_size_t size = ecc_size (ecc);
+      mp_limb_t *p = xalloc_limbs (ecc_size_j (ecc));
+      mp_limb_t *q = xalloc_limbs (ecc_size_j (ecc));
+      mp_limb_t *n = xalloc_limbs (size);
+      mp_limb_t *scratch = xalloc_limbs (ecc_mul_a_itch (ecc));
+      unsigned j;
+      
+      mpn_zero (n, size);
+
+      n[0] = 1;
+      ecc_mul_a (ecc, 1, 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);
+	  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_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)
+	{
+	  fprintf (stderr, "ecc_mul_a with n = order - 1 failed.\n");
+	  abort ();
+	}
+
+      mpn_zero (n, size);
+
+      for (j = 0; j < 100; j++)
+	{
+	  if (j & 1)
+	    mpz_rrandomb (r, state, size * GMP_NUMB_BITS);
+	  else
+	    mpz_urandomb (r, state, size * GMP_NUMB_BITS);
+
+	  /* Reduce so that (almost surely) n < q */
+	  mpz_limbs_copy (n, r, size);
+	  n[size - 1] %= ecc->q[size - 1];
+
+	  ecc_mul_a (ecc, 1, p, n, ecc->g, scratch);
+	  ecc_j_to_a (ecc, 1, p, p, scratch);
+
+	  ecc_mul_g (ecc, q, n, scratch);
+	  ecc_j_to_a (ecc, 1, q, q, scratch);
+
+	  if (mpn_cmp (p, q, 2*size))
+	    {
+	      gmp_fprintf (stderr,
+			   "Different results from ecc_mul_a and ecc_mul_g.\n"
+			   " bits = %u\n"
+			   " n = %Nx\n",
+			   ecc->bit_size, n, size);
+	      gmp_fprintf (stderr, "p = %Nx,\n    %Nx\n",
+			   p, size, p + size, size);
+	      gmp_fprintf (stderr, "q = %Nx,\n    %Nx\n",
+			   q, size, q + size, size);
+	      abort ();
+	    }
+	}
+      free (n);
+      free (p);
+      free (q);
+      free (scratch);
+    }
+  mpz_clear (r); 
+  gmp_randclear (state);
+}
diff --git a/testsuite/ecc-mul-g-test.c b/testsuite/ecc-mul-g-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..c5319ed0d62e830335d0a9cfe73c30b090ae1481
--- /dev/null
+++ b/testsuite/ecc-mul-g-test.c
@@ -0,0 +1,58 @@
+#include "testutils.h"
+
+void
+test_main (void)
+{
+  gmp_randstate_t state;
+  mpz_t r;
+  unsigned i;
+
+  gmp_randinit_default (state);
+  mpz_init (r);
+
+  for (i = 0; ecc_curves[i]; i++)
+    {
+      const struct ecc_curve *ecc = ecc_curves[i];
+      mp_size_t size = ecc_size (ecc);
+      mp_limb_t *p = xalloc_limbs (ecc_size_j (ecc));
+      mp_limb_t *q = xalloc_limbs (ecc_size_j (ecc));
+      mp_limb_t *n = xalloc_limbs (size);
+      mp_limb_t *scratch = xalloc_limbs (ecc_mul_g_itch (ecc));
+
+      mpn_zero (n, size);
+
+      n[0] = 1;
+      ecc_mul_g (ecc, p, n, scratch);
+      ecc_j_to_a (ecc, 1, p, p, scratch);
+
+      if (mpn_cmp (p, ecc->g, 2*size != 0))
+	{
+	  fprintf (stderr, "ecc_mul_g with n = 1 failed.\n");
+	  abort ();
+	}
+
+      for (n[0] = 2; n[0] <= 4; n[0]++)
+	{
+	  ecc_mul_g (ecc, p, n, scratch);
+	  test_ecc_mul_j (i, n[0], p);
+	}
+
+      /* (order - 1) * g = - g */
+      mpn_sub_1 (n, ecc->q, size, 1);
+      ecc_mul_g (ecc, p, n, 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)
+	{
+	  fprintf (stderr, "ecc_mul_g with n = order - 1 failed.\n");
+	  abort ();
+	}
+
+      free (n);
+      free (p);
+      free (q);
+      free (scratch);
+    }
+  mpz_clear (r);
+  gmp_randclear (state);
+}
diff --git a/testsuite/ecc-redc-test.c b/testsuite/ecc-redc-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..9987792fc1e473d9085d261b2e0f49562c2e2832
--- /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_roinit_n (m, mp, mn);
+
+  an = 2*mn;
+  while (an > 0 && ap[an-1] == 0)
+    an--;
+
+  mpz_roinit_n (a, ap, an);
+  
+  mpz_invert (t, t, m);
+  mpz_mul (t, t, a);
+  mpz_mod (t, t, m);
+
+  mpz_limbs_copy (rp, t, mn);
+
+  mpz_clear (t);
+}
+
+#define MAX_ECC_SIZE (1 + 521 / GMP_NUMB_BITS)
+#define MAX_SIZE (2*MAX_ECC_SIZE)
+#define COUNT 50000
+
+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_limbs_copy (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/ecdsa-keygen-test.c b/testsuite/ecdsa-keygen-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..4f46d0d4077b2dca409f68cd5c1764cda1b10595
--- /dev/null
+++ b/testsuite/ecdsa-keygen-test.c
@@ -0,0 +1,113 @@
+#include "testutils.h"
+#include <nettle/knuth-lfib.h>
+
+/* Check if y^2 = x^3 - 3x + b */
+static int
+ecc_valid_p (struct ecc_point *pub)
+{
+  mpz_t t, x, y;
+  mpz_t lhs, rhs;
+  int res;
+  mp_size_t size;
+
+  size = pub->ecc->size;
+
+  /* First check range */
+  if (mpn_cmp (pub->p, pub->ecc->p, size) >= 0
+      || mpn_cmp (pub->p + size, pub->ecc->p, size) >= 0)
+    return 0;
+
+  mpz_init (lhs);
+  mpz_init (rhs);
+
+  mpz_roinit_n (x, pub->p, size);
+  mpz_roinit_n (y, pub->p + size, 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, pub->ecc->b, size));
+
+  res = mpz_congruent_p (lhs, rhs, mpz_roinit_n (t, pub->ecc->p, size));
+  
+  mpz_clear (lhs);
+  mpz_clear (rhs);
+
+  return res;
+}
+
+void
+test_main (void)
+{
+  unsigned i;
+  struct knuth_lfib_ctx rctx;
+  struct dsa_signature signature;
+
+  struct tstring *digest;
+
+  knuth_lfib_init (&rctx, 4711);
+  dsa_signature_init (&signature);
+
+  digest = SHEX (/* sha256("abc") */
+		 "BA7816BF 8F01CFEA 414140DE 5DAE2223"
+		 "B00361A3 96177A9C B410FF61 F20015AD");
+
+  for (i = 0; ecc_curves[i]; i++)
+    {
+      const struct ecc_curve *ecc = ecc_curves[i];
+      struct ecc_point pub;
+      struct ecc_scalar key;
+
+      if (verbose)
+	fprintf (stderr, "Curve %d\n", ecc->bit_size);
+
+      ecc_point_init (&pub, ecc);
+      ecc_scalar_init (&key, ecc);
+
+      ecdsa_generate_keypair (&pub, &key,
+			      &rctx,
+			      (nettle_random_func *) knuth_lfib_random);
+
+      if (verbose)
+	{
+	  gmp_fprintf (stderr,
+		       "Public key:\nx = %Nx\ny = %Nx\n",
+		       pub.p, ecc->size, pub.p + ecc->size, ecc->size);
+	  gmp_fprintf (stderr,
+		       "Private key: %Nx\n", key.p, ecc->size);
+	}
+      if (!ecc_valid_p (&pub))
+	die ("ecdsa_generate_keypair produced an invalid point.\n");
+
+      ecdsa_sign (&key,
+		  &rctx, (nettle_random_func *) knuth_lfib_random,
+		  digest->length, digest->data,
+		  &signature);
+
+      if (!ecdsa_verify (&pub, digest->length, digest->data,
+			  &signature))
+	die ("ecdsa_verify failed.\n");
+
+      digest->data[3] ^= 17;
+      if (ecdsa_verify (&pub, digest->length, digest->data,
+			 &signature))
+	die ("ecdsa_verify  returned success with invalid digest.\n");
+      digest->data[3] ^= 17;
+
+      mpz_combit (signature.r, 117);
+      if (ecdsa_verify (&pub, digest->length, digest->data,
+			 &signature))
+	die ("ecdsa_verify  returned success with invalid signature.r.\n");
+
+      mpz_combit (signature.r, 117);
+      mpz_combit (signature.s, 93);
+      if (ecdsa_verify (&pub, digest->length, digest->data,
+			 &signature))
+	die ("ecdsa_verify  returned success with invalid signature.s.\n");
+
+      ecc_point_clear (&pub);
+      ecc_scalar_clear (&key);
+    }
+  dsa_signature_clear (&signature);
+}
diff --git a/testsuite/ecdsa-sign-test.c b/testsuite/ecdsa-sign-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..fc9ea2a58c744a88fc2be62ad1a34d2df8996cf8
--- /dev/null
+++ b/testsuite/ecdsa-sign-test.c
@@ -0,0 +1,155 @@
+#include "testutils.h"
+
+static void
+test_ecdsa (const struct ecc_curve *ecc,
+	    /* Private key */
+	    const char *sz,
+	    /* Random nonce */
+	    const char *sk,
+	    /* Hash */
+	    const struct tstring *h,
+	    /* Expected signature */
+	    const char *r, const char *s)
+{
+  struct dsa_signature ref;
+  mpz_t z;
+  mpz_t k;
+  mp_limb_t *rp = xalloc_limbs (ecc->size);
+  mp_limb_t *sp = xalloc_limbs (ecc->size);
+  mp_limb_t *scratch = xalloc_limbs (ecc_ecdsa_sign_itch (ecc));
+
+  dsa_signature_init (&ref);
+
+  mpz_init_set_str (z, sz, 16);
+  mpz_init_set_str (k, sk, 16);
+
+  ecc_ecdsa_sign (ecc, mpz_limbs_read_n (z, ecc->size),
+		  mpz_limbs_read_n (k, ecc->size),
+		  h->length, h->data, rp, sp, scratch);
+
+  mpz_set_str (ref.r, r, 16);
+  mpz_set_str (ref.s, s, 16);
+
+  if (mpz_limbs_cmp (ref.r, rp, ecc->size) != 0
+      || mpz_limbs_cmp (ref.s, sp, ecc->size) != 0)
+    {
+      fprintf (stderr, "_ecdsa_sign failed, bit_size = %u\n", ecc->bit_size);
+      gmp_fprintf (stderr, "r     = %Nx\n", rp, ecc->size);
+      gmp_fprintf (stderr, "s     = %Nx\n", sp, ecc->size);
+      gmp_fprintf (stderr, "ref.r = %Zx\n", ref.r);
+      gmp_fprintf (stderr, "ref.s = %Zx\n", ref.s);
+      abort();
+    }
+
+  free (rp);
+  free (sp);
+  free (scratch);
+
+  dsa_signature_clear (&ref);
+  mpz_clear (k);
+  mpz_clear (z);
+}
+
+void
+test_main (void)
+{
+  /* Test cases for the smaller groups, verified with a
+     proof-of-concept implementation done for Yubico AB. */
+  test_ecdsa (&nettle_secp_192r1,
+	      "DC51D3866A15BACDE33D96F992FCA99D"
+	      "A7E6EF0934E70975", /* z */
+
+	      "9E56F509196784D963D1C0A401510EE7"
+	      "ADA3DCC5DEE04B15", /* k */
+
+	      SHEX("BA7816BF8F01CFEA414140DE5DAE2223"
+		   "B00361A396177A9C"), /* h */
+
+	      "8c478db6a5c131540cebc739f9c0a9a8"
+	      "c720c2abdd14a891", /* r */
+
+	      "a91fb738f9f175d72f9c98527e881c36"
+	      "8de68cb55ffe589"); /* s */
+
+  test_ecdsa (&nettle_secp_224r1,
+	      "446df0a771ed58403ca9cb316e617f6b"
+	      "158420465d00a69601e22858",  /* z */
+
+	      "4c13f1905ad7eb201178bc08e0c9267b"
+	      "4751c15d5e1831ca214c33f4",  /* z */
+
+	      SHEX("1b28a611fe62ab3649350525d06703ba"
+		   "4b979a1e543566fd5caa85c6"),  /* h */
+
+	      "2cc280778f3d067df6d3adbe3a6aad63"
+	      "bc75f08f5c5f915411902a99",  /* r */ 
+
+	      "d0f069fd0f108eb07b7bbc54c8d6c88d"
+	      "f2715c38a95c31a2b486995f"); /* s */
+
+  /* From RFC 4754 */
+  test_ecdsa (&nettle_secp_256r1,
+	      "DC51D386 6A15BACD E33D96F9 92FCA99D"
+	      "A7E6EF09 34E70975 59C27F16 14C88A7F",  /* z */
+
+	      "9E56F509 196784D9 63D1C0A4 01510EE7"
+	      "ADA3DCC5 DEE04B15 4BF61AF1 D5A6DECE",  /* k */
+
+	      SHEX("BA7816BF 8F01CFEA 414140DE 5DAE2223"
+		   "B00361A3 96177A9C B410FF61 F20015AD"),  /* h */
+	      
+	      "CB28E099 9B9C7715 FD0A80D8 E47A7707"
+	      "9716CBBF 917DD72E 97566EA1 C066957C",  /* r */
+	      "86FA3BB4 E26CAD5B F90B7F81 899256CE"
+	      "7594BB1E A0C89212 748BFF3B 3D5B0315"); /* s */
+
+  test_ecdsa (&nettle_secp_384r1,
+	      "0BEB6466 34BA8773 5D77AE48 09A0EBEA"
+	      "865535DE 4C1E1DCB 692E8470 8E81A5AF"
+	      "62E528C3 8B2A81B3 5309668D 73524D9F",  /* z */
+
+	      "B4B74E44 D71A13D5 68003D74 89908D56"
+	      "4C7761E2 29C58CBF A1895009 6EB7463B"
+	      "854D7FA9 92F934D9 27376285 E63414FA",  /* k */
+
+	      SHEX("CB00753F 45A35E8B B5A03D69 9AC65007"
+		   "272C32AB 0EDED163 1A8B605A 43FF5BED"
+		   "8086072B A1E7CC23 58BAECA1 34C825A7"),  /* h */
+
+	      "FB017B91 4E291494 32D8BAC2 9A514640"
+	      "B46F53DD AB2C6994 8084E293 0F1C8F7E"
+	      "08E07C9C 63F2D21A 07DCB56A 6AF56EB3",  /* r */
+	      "B263A130 5E057F98 4D38726A 1B468741"
+	      "09F417BC A112674C 528262A4 0A629AF1"
+	      "CBB9F516 CE0FA7D2 FF630863 A00E8B9F"); /* s*/
+
+  test_ecdsa (&nettle_secp_521r1,
+	      "0065FDA3 409451DC AB0A0EAD 45495112"
+	      "A3D813C1 7BFD34BD F8C1209D 7DF58491"
+	      "20597779 060A7FF9 D704ADF7 8B570FFA"
+	      "D6F062E9 5C7E0C5D 5481C5B1 53B48B37"
+	      "5FA1", /* z */
+	      
+	      "00C1C2B3 05419F5A 41344D7E 4359933D"
+	      "734096F5 56197A9B 244342B8 B62F46F9"
+	      "373778F9 DE6B6497 B1EF825F F24F42F9"
+	      "B4A4BD73 82CFC337 8A540B1B 7F0C1B95"
+	      "6C2F", /* k */
+
+	      SHEX("DDAF35A1 93617ABA CC417349 AE204131"
+		   "12E6FA4E 89A97EA2 0A9EEEE6 4B55D39A"
+		   "2192992A 274FC1A8 36BA3C23 A3FEEBBD"
+		   "454D4423 643CE80E 2A9AC94F A54CA49F"), /* h */
+
+	      "0154FD38 36AF92D0 DCA57DD5 341D3053"
+	      "988534FD E8318FC6 AAAAB68E 2E6F4339"
+	      "B19F2F28 1A7E0B22 C269D93C F8794A92"
+	      "78880ED7 DBB8D936 2CAEACEE 54432055"
+	      "2251", /* r */
+	      "017705A7 030290D1 CEB605A9 A1BB03FF"
+	      "9CDD521E 87A696EC 926C8C10 C8362DF4"
+	      "97536710 1F67D1CF 9BCCBF2F 3D239534"
+	      "FA509E70 AAC851AE 01AAC68D 62F86647"
+	      "2660"); /* s */
+}
+
diff --git a/testsuite/ecdsa-verify-test.c b/testsuite/ecdsa-verify-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..5f880729b69d5813479e946829146fe0f16d4a93
--- /dev/null
+++ b/testsuite/ecdsa-verify-test.c
@@ -0,0 +1,143 @@
+#include "testutils.h"
+
+static void
+test_ecdsa (const struct ecc_curve *ecc,
+	    /* Public key */
+	    const char *xs, const char *ys,
+	    /* Hash */
+	    struct tstring *h,
+	    /* Valid signature */
+	    const char *r, const char *s)
+{
+  struct ecc_point pub;
+  struct dsa_signature signature;
+  mpz_t x, y;
+
+  ecc_point_init (&pub, ecc);
+  dsa_signature_init (&signature);
+
+  mpz_init_set_str (x, xs, 16);
+  mpz_init_set_str (y, ys, 16);
+
+  if (!ecc_point_set (&pub, x, y))
+    die ("ecc_point_set failed.\n");
+
+  mpz_set_str (signature.r, r, 16);
+  mpz_set_str (signature.s, s, 16);
+
+  if (!ecdsa_verify (&pub, h->length, h->data, &signature))
+    {
+      fprintf (stderr, "ecdsa_verify failed with valid signature.\n");
+    fail:
+      fprintf (stderr, "bit_size = %u\n", ecc->bit_size);
+      gmp_fprintf (stderr, "x = %Zx\n", x);
+      gmp_fprintf (stderr, "y = %Zx\ndigest ", y);
+      print_hex (h->length, h->data);
+      gmp_fprintf (stderr, "r = %Zx\n", signature.r);
+      gmp_fprintf (stderr, "s = %Zx\n", signature.s);
+      abort();
+    }
+
+  mpz_combit (signature.r, ecc->bit_size / 3);
+  if (ecdsa_verify (&pub, h->length, h->data, &signature))
+    {
+      fprintf (stderr, "ecdsa_verify unexpectedly succeeded with invalid signature.\n");
+      goto fail;
+    }
+  mpz_combit (signature.r, ecc->bit_size / 3);
+  
+  mpz_combit (signature.s, 4*ecc->bit_size / 5);
+  if (ecdsa_verify (&pub, h->length, h->data, &signature))
+    {
+      fprintf (stderr, "ecdsa_verify unexpectedly succeeded with invalid signature.\n");
+      goto fail;
+    }
+  mpz_combit (signature.s, 4*ecc->bit_size / 5);
+
+  h->data[2*h->length / 3] ^= 0x40;
+  if (ecdsa_verify (&pub, h->length, h->data, &signature))
+    {
+      fprintf (stderr, "ecdsa_verify unexpectedly succeeded with invalid signature.\n");
+      goto fail;
+    }
+  h->data[2*h->length / 3] ^= 0x40;
+  if (!ecdsa_verify (&pub, h->length, h->data, &signature))
+    {
+      fprintf (stderr, "ecdsa_verify failed, internal testsuite error.\n");
+      goto fail;
+    }
+
+  ecc_point_clear (&pub);
+  dsa_signature_clear (&signature);
+  mpz_clear (x);
+  mpz_clear (y);  
+}
+
+void
+test_main (void)
+{
+  /* From RFC 4754 */
+  test_ecdsa (&nettle_secp_256r1,
+	      "2442A5CC 0ECD015F A3CA31DC 8E2BBC70"
+	      "BF42D60C BCA20085 E0822CB0 4235E970",  /* x */
+
+	      "6FC98BD7 E50211A4 A27102FA 3549DF79"
+	      "EBCB4BF2 46B80945 CDDFE7D5 09BBFD7D",  /* y */
+
+	      SHEX("BA7816BF 8F01CFEA 414140DE 5DAE2223"
+		   "B00361A3 96177A9C B410FF61 F20015AD"),  /* h */
+	      
+	      "CB28E099 9B9C7715 FD0A80D8 E47A7707"
+	      "9716CBBF 917DD72E 97566EA1 C066957C",  /* r */
+	      "86FA3BB4 E26CAD5B F90B7F81 899256CE"
+	      "7594BB1E A0C89212 748BFF3B 3D5B0315"); /* s */
+
+  test_ecdsa (&nettle_secp_384r1,
+	      "96281BF8 DD5E0525 CA049C04 8D345D30"
+	      "82968D10 FEDF5C5A CA0C64E6 465A97EA"
+	      "5CE10C9D FEC21797 41571072 1F437922",  /* x */
+
+	      "447688BA 94708EB6 E2E4D59F 6AB6D7ED"
+	      "FF9301D2 49FE49C3 3096655F 5D502FAD"
+	      "3D383B91 C5E7EDAA 2B714CC9 9D5743CA",  /* y */
+
+	      SHEX("CB00753F 45A35E8B B5A03D69 9AC65007"
+		   "272C32AB 0EDED163 1A8B605A 43FF5BED"
+		   "8086072B A1E7CC23 58BAECA1 34C825A7"),  /* h */
+
+	      "FB017B91 4E291494 32D8BAC2 9A514640"
+	      "B46F53DD AB2C6994 8084E293 0F1C8F7E"
+	      "08E07C9C 63F2D21A 07DCB56A 6AF56EB3",  /* r */
+	      "B263A130 5E057F98 4D38726A 1B468741"
+	      "09F417BC A112674C 528262A4 0A629AF1"
+	      "CBB9F516 CE0FA7D2 FF630863 A00E8B9F"); /* s*/
+
+  test_ecdsa (&nettle_secp_521r1,
+	      "0151518F 1AF0F563 517EDD54 85190DF9"
+	      "5A4BF57B 5CBA4CF2 A9A3F647 4725A35F"
+	      "7AFE0A6D DEB8BEDB CD6A197E 592D4018"
+	      "8901CECD 650699C9 B5E456AE A5ADD190"
+	      "52A8", /* x */
+
+	      "006F3B14 2EA1BFFF 7E2837AD 44C9E4FF"
+	      "6D2D34C7 3184BBAD 90026DD5 E6E85317"
+	      "D9DF45CA D7803C6C 20035B2F 3FF63AFF"
+	      "4E1BA64D 1C077577 DA3F4286 C58F0AEA"
+	      "E643", /* y */
+
+	      SHEX("DDAF35A1 93617ABA CC417349 AE204131" 
+		   "12E6FA4E 89A97EA2 0A9EEEE6 4B55D39A"
+		   "2192992A 274FC1A8 36BA3C23 A3FEEBBD" 
+		   "454D4423 643CE80E 2A9AC94F A54CA49F"), /* h */
+
+	      "0154FD38 36AF92D0 DCA57DD5 341D3053" 
+	      "988534FD E8318FC6 AAAAB68E 2E6F4339"
+	      "B19F2F28 1A7E0B22 C269D93C F8794A92" 
+	      "78880ED7 DBB8D936 2CAEACEE 54432055"
+	      "2251", /* r */
+	      "017705A7 030290D1 CEB605A9 A1BB03FF"
+	      "9CDD521E 87A696EC 926C8C10 C8362DF4"
+	      "97536710 1F67D1CF 9BCCBF2F 3D239534" 
+	      "FA509E70 AAC851AE 01AAC68D 62F86647"
+	      "2660"); /* s */
+}
diff --git a/testsuite/testutils.c b/testsuite/testutils.c
index c0a75f8f9d85f57234b6076c7e7ce06c5fe029e2..b1eb57477e82c59e4975fde054d17ce0ffd28085 100644
--- a/testsuite/testutils.c
+++ b/testsuite/testutils.c
@@ -8,10 +8,8 @@
 #include "macros.h"
 #include "nettle-internal.h"
 
+#include <assert.h>
 #include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 
 /* -1 means invalid */
 static const signed char hex_digits[0x100] =
@@ -34,6 +32,21 @@ static const signed char hex_digits[0x100] =
     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
   };
 
+void
+die(const char *format, ...)
+{
+  va_list args;
+  va_start(args, format);
+#if WITH_HOGWEED
+  gmp_vfprintf(stderr, format, args);
+#else
+  vfprintf(stderr, format, args);
+#endif
+  va_end(args);
+
+  abort ();
+}
+
 void *
 xalloc(size_t size)
 {
@@ -628,6 +641,12 @@ mpz_togglebit (mpz_t x, unsigned long int bit)
 
 #if WITH_HOGWEED
 
+mp_limb_t *
+xalloc_limbs (mp_size_t n)
+{
+  return xalloc (n * sizeof (mp_limb_t));
+}
+
 #define SIGN(key, hash, msg, signature) do {		\
   hash##_update(&hash, LDATA(msg));		\
   ASSERT(rsa_##hash##_sign(key, &hash, signature));	\
@@ -1086,5 +1105,133 @@ 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
+};
+
+static int
+test_mpn (const char *ref, const mp_limb_t *xp, mp_size_t n)
+{
+  mpz_t r;
+  int res;
+
+  mpz_init_set_str (r, ref, 16);
+  while (n > 0 && xp[n-1] == 0)
+    n--;
+  
+  res = (mpz_limbs_cmp (r, xp, n) == 0);
+  mpz_clear (r);
+  return res;
+}
+
+struct ecc_ref_point
+{
+  const char *x;
+  const char *y;
+};
+
+static void
+test_ecc_point (const struct ecc_curve *ecc,
+		const struct ecc_ref_point *ref,
+		const mp_limb_t *p)
+{
+  if (! (test_mpn (ref->x, p, ecc->size)
+	 && test_mpn (ref->y, p + ecc->size, ecc->size) ))
+    {
+      gmp_fprintf (stderr, "Incorrect point!\n"
+		   "got: x = %Nx\n"
+		   "     y = %Nx\n"
+		   "ref: x = %s\n"
+		   "     y = %s\n",
+		   p, ecc->size, p + ecc->size, ecc->size,
+		   ref->x, ref->y);
+      abort();
+    }
+}
+
+void
+test_ecc_mul_a (unsigned curve, unsigned n, const mp_limb_t *p)
+{
+  /* For each curve, the points 2 g, 3 g and 4 g */
+  static const struct ecc_ref_point ref[5][3] = {
+    { { "dafebf5828783f2ad35534631588a3f629a70fb16982a888",
+	"dd6bda0d993da0fa46b27bbc141b868f59331afa5c7e93ab" },
+      { "76e32a2557599e6edcd283201fb2b9aadfd0d359cbb263da",
+	"782c37e372ba4520aa62e0fed121d49ef3b543660cfd05fd" },
+      { "35433907297cc378b0015703374729d7a4fe46647084e4ba",
+	"a2649984f2135c301ea3acb0776cd4f125389b311db3be32" }
+    },
+    { { "706a46dc76dcb76798e60e6d89474788d16dc18032d268fd1a704fa6",
+	"1c2b76a7bc25e7702a704fa986892849fca629487acf3709d2e4e8bb" },
+      { "df1b1d66a551d0d31eff822558b9d2cc75c2180279fe0d08fd896d04",
+	"a3f7f03cadd0be444c0aa56830130ddf77d317344e1af3591981a925" },
+      { "ae99feebb5d26945b54892092a8aee02912930fa41cd114e40447301",
+	"482580a0ec5bc47e88bc8c378632cd196cb3fa058a7114eb03054c9" },
+    },
+    { { "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978",
+	"7775510db8ed040293d9ac69f7430dbba7dade63ce982299e04b79d227873d1" },
+      { "5ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c",
+	"8734640c4998ff7e374b06ce1a64a2ecd82ab036384fb83d9a79b127a27d5032" },
+      { "e2534a3532d08fbba02dde659ee62bd0031fe2db785596ef509302446b030852",
+	"e0f1575a4c633cc719dfee5fda862d764efc96c3f30ee0055c42c23f184ed8c6" },
+    },
+    { { "8d999057ba3d2d969260045c55b97f089025959a6f434d651d207d19fb96e9e"
+	"4fe0e86ebe0e64f85b96a9c75295df61",
+	"8e80f1fa5b1b3cedb7bfe8dffd6dba74b275d875bc6cc43e904e505f256ab425"
+	"5ffd43e94d39e22d61501e700a940e80" },
+      { "77a41d4606ffa1464793c7e5fdc7d98cb9d3910202dcd06bea4f240d3566da6"
+	"b408bbae5026580d02d7e5c70500c831",
+	"c995f7ca0b0c42837d0bbe9602a9fc998520b41c85115aa5f7684c0edc111eac"
+	"c24abd6be4b5d298b65f28600a2f1df1" },
+      { "138251cd52ac9298c1c8aad977321deb97e709bd0b4ca0aca55dc8ad51dcfc9d"
+	"1589a1597e3a5120e1efd631c63e1835",
+	"cacae29869a62e1631e8a28181ab56616dc45d918abc09f3ab0e63cf792aa4dc"
+	"ed7387be37bba569549f1c02b270ed67" },
+    },
+    { { "43"
+	"3c219024277e7e682fcb288148c282747403279b1ccc06352c6e5505d769be97"
+	"b3b204da6ef55507aa104a3a35c5af41cf2fa364d60fd967f43e3933ba6d783d",
+	"f4"
+	"bb8cc7f86db26700a7f3eceeeed3f0b5c6b5107c4da97740ab21a29906c42dbb"
+	"b3e377de9f251f6b93937fa99a3248f4eafcbe95edc0f4f71be356d661f41b02"
+      },
+      { "1a7"
+	"3d352443de29195dd91d6a64b5959479b52a6e5b123d9ab9e5ad7a112d7a8dd1"
+	"ad3f164a3a4832051da6bd16b59fe21baeb490862c32ea05a5919d2ede37ad7d",
+	"13e"
+	"9b03b97dfa62ddd9979f86c6cab814f2f1557fa82a9d0317d2f8ab1fa355ceec"
+	"2e2dd4cf8dc575b02d5aced1dec3c70cf105c9bc93a590425f588ca1ee86c0e5" },
+      { "35"
+	"b5df64ae2ac204c354b483487c9070cdc61c891c5ff39afc06c5d55541d3ceac"
+	"8659e24afe3d0750e8b88e9f078af066a1d5025b08e5a5e2fbc87412871902f3",
+	"82"
+	"096f84261279d2b673e0178eb0b4abb65521aef6e6e32e1b5ae63fe2f19907f2"
+	"79f283e54ba385405224f750a95b85eebb7faef04699d1d9e21f47fc346e4d0d" },
+    }
+  };
+  assert (curve < 5);
+  assert (n >= 2 && n <= 4);
+  test_ecc_point (ecc_curves[curve], &ref[curve][n-2], p);
+}
+
+void
+test_ecc_mul_j (unsigned curve, unsigned n, const mp_limb_t *p)
+{
+  const struct ecc_curve *ecc = ecc_curves[curve];
+  mp_limb_t *np = xalloc_limbs (ecc_size_a (ecc));
+  mp_limb_t *scratch = xalloc_limbs (ecc_j_to_a_itch(ecc));
+  ecc_j_to_a (ecc, 1, np, p, scratch);
+
+  test_ecc_mul_a (curve, n, np);
+
+  free (np);
+  free (scratch);
+}
+
 #endif /* WITH_HOGWEED */
 
diff --git a/testsuite/testutils.h b/testsuite/testutils.h
index 7519d65bbf0a218601f2564ce5f7988c7aa03b76..123bae2b680b9d45eefd6cc196d37abc6cb5b3d6 100644
--- a/testsuite/testutils.h
+++ b/testsuite/testutils.h
@@ -7,9 +7,10 @@
 
 #include "nettle-types.h"
 
-#include <string.h>
+#include <stdarg.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <string.h>
 
 #if HAVE_LIBGMP
 # include "bignum.h"
@@ -18,6 +19,11 @@
 #if WITH_HOGWEED
 # include "rsa.h"
 # include "dsa.h"
+# include "ecc-curve.h"
+# include "ecc.h"
+# include "ecc-internal.h"
+# include "ecdsa.h"
+# include "gmp-glue.h"
 #endif
 
 #include "nettle-meta.h"
@@ -29,6 +35,9 @@ struct nettle_aead;
 extern "C" {
 #endif
 
+void
+die(const char *format, ...) PRINTF_STYLE (1, 2) NORETURN;
+
 void *
 xalloc(size_t size);
 
@@ -147,6 +156,9 @@ test_armor(const struct nettle_armor *armor,
            const uint8_t *ascii);
 
 #if WITH_HOGWEED
+mp_limb_t *
+xalloc_limbs (mp_size_t n);
+
 void
 test_rsa_set_key_1(struct rsa_public_key *pub,
 		   struct rsa_private_key *key);
@@ -190,6 +202,14 @@ test_dsa_key(struct dsa_public_key *pub,
 	     struct dsa_private_key *key,
 	     unsigned q_size);
 
+extern const struct ecc_curve * const ecc_curves[];
+
+void
+test_ecc_mul_a (unsigned curve, unsigned n, const mp_limb_t *p);
+
+void
+test_ecc_mul_j (unsigned curve, unsigned n, const mp_limb_t *p);
+
 #endif /* WITH_HOGWEED */
   
 /* LDATA needs to handle NUL characters. */
@@ -197,7 +217,7 @@ test_dsa_key(struct dsa_public_key *pub,
 #define LDATA(x) LLENGTH(x), x
 #define LDUP(x) strlen(x), strdup(x)
 
-#define SHEX(x) ((const struct tstring *) tstring_hex(x))
+#define SHEX(x) (tstring_hex(x))
 #define SDATA(x) ((const struct tstring *)tstring_data(LLENGTH(x), x))
 #define H(x) (SHEX(x)->data)
 
diff --git a/twofishdata.c b/twofishdata.c
index 81090d50c362ecda1adb7318b76b193646a0649a..53ac17159b8d55bdd2bc1785b0e4d565f17dd329 100644
--- a/twofishdata.c
+++ b/twofishdata.c
@@ -19,84 +19,82 @@
 
 #include <stdio.h>
 
-#include "nettle-stdint.h"
-
 #define ror4(x) (((x) >> 1) | (((x) & 1) << 3))
 
-static uint8_t q0(uint8_t x)
+static unsigned char q0(unsigned char x)
 {
-    static const uint8_t t0[16] = {
+    static const unsigned char t0[16] = {
       0x8, 0x1, 0x7, 0xD, 0x6, 0xF, 0x3, 0x2,
       0x0, 0xB, 0x5, 0x9, 0xE, 0xC, 0xA, 0x4
     };
-    static const uint8_t t1[16] = {
+    static const unsigned char t1[16] = {
       0xE, 0xC, 0xB, 0x8, 0x1, 0x2, 0x3, 0x5,
       0xF, 0x4, 0xA, 0x6, 0x7, 0x0, 0x9, 0xD
     };
-    static const uint8_t t2[16] = {
+    static const unsigned char t2[16] = {
       0xB, 0xA, 0x5, 0xE, 0x6, 0xD, 0x9, 0x0,
       0xC, 0x8, 0xF, 0x3, 0x2, 0x4, 0x7, 0x1
     };
-    static const uint8_t t3[16] = {
+    static const unsigned char t3[16] = {
       0xD, 0x7, 0xF, 0x4, 0x1, 0x2, 0x6, 0xE,
       0x9, 0xB, 0x3, 0x0, 0x8, 0x5, 0xC, 0xA
     };
 
-    uint8_t a0 = x / 16;
-    uint8_t b0 = x % 16;
+    unsigned char a0 = x / 16;
+    unsigned char b0 = x % 16;
 
-    uint8_t a1 = a0 ^ b0;
-    uint8_t b1 = a0 ^ ror4(b0) ^ ((8*a0) % 16);
+    unsigned char a1 = a0 ^ b0;
+    unsigned char b1 = a0 ^ ror4(b0) ^ ((8*a0) % 16);
 
-    uint8_t a2 = t0[a1];
-    uint8_t b2 = t1[b1];
+    unsigned char a2 = t0[a1];
+    unsigned char b2 = t1[b1];
 
-    uint8_t a3 = a2 ^ b2;
-    uint8_t b3 = a2 ^ ror4(b2) ^ ((8*a2) % 16);
+    unsigned char a3 = a2 ^ b2;
+    unsigned char b3 = a2 ^ ror4(b2) ^ ((8*a2) % 16);
 
-    uint8_t a4 = t2[a3];
-    uint8_t b4 = t3[b3];
+    unsigned char a4 = t2[a3];
+    unsigned char b4 = t3[b3];
 
-    uint8_t y = 16*b4 + a4;
+    unsigned char y = 16*b4 + a4;
 
     return y;
 }
 
-static uint8_t q1(uint8_t x)
+static unsigned char q1(unsigned char x)
 {
-  static const uint8_t t0[16] = {
+  static const unsigned char t0[16] = {
     0x2, 0x8, 0xB, 0xD, 0xF, 0x7, 0x6, 0xE,
     0x3, 0x1, 0x9, 0x4, 0x0, 0xA, 0xC, 0x5
   };
-  static const uint8_t t1[16] = {
+  static const unsigned char t1[16] = {
     0x1, 0xE, 0x2, 0xB, 0x4, 0xC, 0x3, 0x7,
     0x6, 0xD, 0xA, 0x5, 0xF, 0x9, 0x0, 0x8
   };
-  static const uint8_t t2[16] = {
+  static const unsigned char t2[16] = {
     0x4, 0xC, 0x7, 0x5, 0x1, 0x6, 0x9, 0xA,
     0x0, 0xE, 0xD, 0x8, 0x2, 0xB, 0x3, 0xF
   };
-  static const uint8_t t3[16] = {
+  static const unsigned char t3[16] = {
     0xB, 0x9, 0x5, 0x1, 0xC, 0x3, 0xD, 0xE,
     0x6, 0x4, 0x7, 0xF, 0x2, 0x0, 0x8, 0xA
   };
 
-  uint8_t a0 = x / 16;
-  uint8_t b0 = x % 16;
+  unsigned char a0 = x / 16;
+  unsigned char b0 = x % 16;
 
-  uint8_t a1 = a0 ^ b0;
-  uint8_t b1 = a0 ^ ror4(b0) ^ ((8*a0) % 16);
+  unsigned char a1 = a0 ^ b0;
+  unsigned char b1 = a0 ^ ror4(b0) ^ ((8*a0) % 16);
 
-  uint8_t a2 = t0[a1];
-  uint8_t b2 = t1[b1];
+  unsigned char a2 = t0[a1];
+  unsigned char b2 = t1[b1];
 
-  uint8_t a3 = a2 ^ b2;
-  uint8_t b3 = a2 ^ ror4(b2) ^ ((8*a2) % 16);
+  unsigned char a3 = a2 ^ b2;
+  unsigned char b3 = a2 ^ ror4(b2) ^ ((8*a2) % 16);
 
-  uint8_t a4 = t2[a3];
-  uint8_t b4 = t3[b3];
+  unsigned char a4 = t2[a3];
+  unsigned char b4 = t3[b3];
 
-  uint8_t y = 16*b4 + a4;
+  unsigned char y = 16*b4 + a4;
 
   return y;
 }
diff --git a/x86_64/README b/x86_64/README
index e8cb17b64820f8ee5487afefced1e67efc30a557..ae693be55b3591be1542d2ba87b1c7fb332655e7 100644
--- a/x86_64/README
+++ b/x86_64/README
@@ -49,8 +49,7 @@ Registers	May be		Argument
 
 Additional arguments are passed on the stack. "backing store" on the
 stack for the four register arguments is also required. %xmm6 to
-%xmm15 are callee-saved. The "long" type is just 32 bits. Nettle
-currently does *NOT* support this ABI.
+%xmm15 are callee-saved. The "long" type is just 32 bits.
 
 If we have five arguments, and push the additional callee-save
 registers %rdi and %rsi on the stack, we get a stack frame like
diff --git a/x86_64/ecc-192-modp.asm b/x86_64/ecc-192-modp.asm
new file mode 100644
index 0000000000000000000000000000000000000000..5812070b88908f0a3c48513d25fa5af48a07d80b
--- /dev/null
+++ b/x86_64/ecc-192-modp.asm
@@ -0,0 +1,75 @@
+C nettle, low-level cryptographics library
+C
+C Copyright (C) 2013 Niels Möller
+C
+C The nettle library is free software; you can redistribute it and/or modify
+C it under the terms of the GNU Lesser General Public License as published by
+C the Free Software Foundation; either version 2.1 of the License, or (at your
+C option) any later version.
+C
+C The nettle library is distributed in the hope that it will be useful, but
+C WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+C or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+C License for more details.
+C
+C You should have received a copy of the GNU Lesser General Public License
+C along with the nettle library; see the file COPYING.LIB.  If not, write to
+C the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+C MA 02111-1301, USA.
+
+	.file "ecc-192-modp.asm"
+
+define(<RP>, <%rsi>)
+define(<T0>, <%rdi>) C Overlaps unused ecc input
+define(<T1>, <%rcx>)
+define(<T2>, <%rdx>)
+define(<T3>, <%r8>)
+define(<H>, <%r9>)
+define(<C1>, <%r10>)
+define(<C2>, <%r11>)
+
+	C ecc_192_modp (const struct ecc_curve *ecc, mp_limb_t *rp)
+	.text
+	ALIGN(4)
+PROLOGUE(nettle_ecc_192_modp)
+	W64_ENTRY(2, 0)
+	mov	16(RP), T2
+	mov	24(RP), T3
+	mov	40(RP), H
+	xor	C1, C1
+	xor	C2, C2
+
+	add	H, T2
+	adc	H, T3
+	C Carry to be added in at T1 and T2
+	setc	LREG(C2)
+	
+	mov	8(RP), T1
+	mov	32(RP), H
+	adc	H, T1
+	adc	H, T2
+	C Carry to be added in at T0 and T1
+	setc	LREG(C1)
+	
+	mov	(RP), T0
+	adc	T3, T0
+	adc	T3, T1
+	adc	$0, C2
+
+	C Add in C1 and C2
+	add	C1, T1
+	adc	C2, T2
+	setc	LREG(C1)
+
+	C Fold final carry.
+	adc	$0, T0
+	adc	C1, T1
+	adc	$0, T2
+
+	mov	T0, (RP)
+	mov	T1, 8(RP)
+	mov	T2, 16(RP)
+
+	W64_EXIT(2, 0)
+	ret
+EPILOGUE(nettle_ecc_192_modp)
diff --git a/x86_64/ecc-224-modp.asm b/x86_64/ecc-224-modp.asm
new file mode 100644
index 0000000000000000000000000000000000000000..b759e1f2b55225dce7379c6e989fffbcdc5bf5a2
--- /dev/null
+++ b/x86_64/ecc-224-modp.asm
@@ -0,0 +1,115 @@
+C nettle, low-level cryptographics library
+C
+C Copyright (C) 2013 Niels Möller
+C
+C The nettle library is free software; you can redistribute it and/or modify
+C it under the terms of the GNU Lesser General Public License as published by
+C the Free Software Foundation; either version 2.1 of the License, or (at your
+C option) any later version.
+C
+C The nettle library is distributed in the hope that it will be useful, but
+C WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+C or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+C License for more details.
+C
+C You should have received a copy of the GNU Lesser General Public License
+C along with the nettle library; see the file COPYING.LIB.  If not, write to
+C the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+C MA 02111-1301, USA.
+
+	.file "ecc-224-modp.asm"
+
+define(<RP>, <%rsi>)
+define(<T0>, <%rdi>) C Overlaps unused ecc input
+define(<T1>, <%rcx>)
+define(<H0>, <%rax>)
+define(<H1>, <%rdx>)
+define(<H2>, <%r8>)
+define(<F0>, <%r9>)
+define(<F1>, <%r10>)
+define(<F2>, <%r11>)
+
+PROLOGUE(nettle_ecc_224_modp)
+	W64_ENTRY(2, 0)
+	mov	48(RP), H0
+	mov	56(RP), H1
+	C Set (F2,F1,F0)  <--  (H1,H0) << 32
+	mov	H0, F0
+	mov	H0, F1
+	shl	$32, F0
+	shr	$32, F1
+	mov	H1, F2
+	mov	H1, T0
+	shl	$32, T0
+	shr	$32, F2
+	or	T0, F1
+
+	xor	H2, H2
+	mov	16(RP), T0
+	mov	24(RP), T1
+	sub	F0, T0
+	sbb	F1, T1
+	sbb	F2, H0
+	sbb	$0, H1		C No further borrow
+
+	adc	32(RP), H0
+	adc	40(RP), H1
+	adc	$0, H2
+
+	C Set (F2,F1,F0)  <--  (H2,H1,H0) << 32
+	C To free registers, add in T1, T0 as soon as H0, H1 have been copied
+	mov	H0, F0
+	mov	H0, F1
+	add	T0, H0
+	mov	H1, F2
+	mov	H1, T0
+	adc	T1, H1
+	mov	H2, T1
+	adc	$0, H2
+
+	C Shift 32 bits
+	shl	$32, F0
+	shr	$32, F1
+	shl	$32, T0
+	shr	$32, F2
+	shl	$32, T1
+	or	T0, F1
+	or	T1, F2
+
+	mov	(RP), T0
+	mov	8(RP), T1
+	sub	F0, T0
+	sbb	F1, T1
+	sbb	F2, H0
+	sbb	$0, H1
+	sbb	$0, H2
+
+	C We now have H2, H1, H0, T1, T0, with 33 bits left to reduce
+	C Set F0       <-- (H2, H1) >> 32
+	C Set (F2,F1)  <-- (H2, H1 & 0xffffffff00000000)
+	C H1  <--  H1 & 0xffffffff
+
+	mov	H1, F0
+	mov	H1, F1
+	mov	H2, F2
+	movl	XREG(H1), XREG(H1)	C Clears high 32 bits
+	sub	H1, F1			C Clears low 32 bits
+	shr	$32, F0
+	shl	$32, H2
+	or	H2, F0
+
+	sub	F0, T0
+	sbb	$0, F1
+	sbb	$0, F2
+	add	F1, T1
+	adc	F2, H0
+	adc	$0, H1
+
+	mov	T0, (RP)
+	mov	T1, 8(RP)
+	mov	H0, 16(RP)
+	mov	H1, 24(RP)
+
+	W64_EXIT(2, 0)
+	ret
+EPILOGUE(nettle_ecc_224_modp)
diff --git a/x86_64/ecc-256-redc.asm b/x86_64/ecc-256-redc.asm
new file mode 100644
index 0000000000000000000000000000000000000000..dc7ea340ab2b2d95952bd0e14984c298feb950fb
--- /dev/null
+++ b/x86_64/ecc-256-redc.asm
@@ -0,0 +1,116 @@
+C nettle, low-level cryptographics library
+C
+C Copyright (C) 2013 Niels Möller
+C
+C The nettle library is free software; you can redistribute it and/or modify
+C it under the terms of the GNU Lesser General Public License as published by
+C the Free Software Foundation; either version 2.1 of the License, or (at your
+C option) any later version.
+C
+C The nettle library is distributed in the hope that it will be useful, but
+C WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+C or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+C License for more details.
+C
+C You should have received a copy of the GNU Lesser General Public License
+C along with the nettle library; see the file COPYING.LIB.  If not, write to
+C the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+C MA 02111-1301, USA.
+
+	.file "ecc-256-redc.asm"
+
+define(<RP>, <%rsi>)
+define(<U0>, <%rdi>) C Overlaps unused ecc input
+define(<U1>, <%rcx>)
+define(<U2>, <%rax>)
+define(<U3>, <%rdx>)
+define(<U4>, <%r8>)
+define(<U5>, <%r9>)
+define(<U6>, <%r10>)
+define(<F0>, <%r11>)
+define(<F1>, <%r12>)
+define(<F2>, <%rbx>)
+define(<F3>, <%rbp>)
+
+C FOLD(x), sets (F3,F2,F1,F0)  <-- (x << 224) - (x << 128) - (x<<32)
+define(<FOLD>, <
+	mov	$1, F2
+	mov	$1, F3
+	shl	<$>32, F2
+	shr	<$>32, F3
+	xor	F0,F0
+	xor	F1,F1
+	sub	F2, F0
+	sbb	F3, F1
+	sbb	$1, F2
+	sbb	<$>0, F3
+>)
+PROLOGUE(nettle_ecc_256_redc)
+	W64_ENTRY(2, 0)
+	C save all registers that need to be saved
+	push	%rbx
+	push	%rbp
+	push	%r12
+
+	mov	(RP), U0
+	FOLD(U0)
+	mov	8(RP), U1
+	mov	16(RP), U2
+	mov	24(RP), U3
+	sub	F0, U1
+	sbb	F1, U2
+	sbb	F2, U3
+	sbb	F3, U0		C Add in later
+
+	FOLD(U1)
+	mov	32(RP), U4
+	sub	F0, U2
+	sbb	F1, U3
+	sbb	F2, U4
+	sbb	F3, U1
+
+	FOLD(U2)
+	mov	40(RP), U5
+	sub	F0, U3
+	sbb	F1, U4
+	sbb	F2, U5
+	sbb	F3, U2
+
+	FOLD(U3)
+	mov	48(RP), U6
+	sub	F0, U4
+	sbb	F1, U5
+	sbb	F2, U6
+	sbb	F3, U3
+
+	add	U4, U0
+	adc	U5, U1
+	adc	U6, U2
+	adc	56(RP), U3
+
+	C If carry, we need to add in
+	C 2^256 - p = <0xfffffffe, 0xff..ff, 0xffffffff00000000, 1>
+	sbb	F2, F2
+	mov	F2, F0
+	mov	F2, F1
+	mov	XREG(F2), XREG(F3)
+	neg	F0
+	shl	$32, F1
+	and	$-2, XREG(F3)
+
+	add	F0, U0
+	mov	U0, (RP)
+	adc	F1, U1
+	mov	U1, 8(RP)
+	adc	F2, U2
+	mov	U2, 16(RP)
+	adc	F3, U3
+
+	mov	U3, 24(RP)
+
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	W64_EXIT(2, 0)
+	ret
+EPILOGUE(nettle_ecc_256_redc)
diff --git a/x86_64/ecc-384-modp.asm b/x86_64/ecc-384-modp.asm
new file mode 100644
index 0000000000000000000000000000000000000000..698838fd781ae8276c5e0dba12da24e5b78fd219
--- /dev/null
+++ b/x86_64/ecc-384-modp.asm
@@ -0,0 +1,240 @@
+C nettle, low-level cryptographics library
+C
+C Copyright (C) 2013 Niels Möller
+C
+C The nettle library is free software; you can redistribute it and/or modify
+C it under the terms of the GNU Lesser General Public License as published by
+C the Free Software Foundation; either version 2.1 of the License, or (at your
+C option) any later version.
+C
+C The nettle library is distributed in the hope that it will be useful, but
+C WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+C or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+C License for more details.
+C
+C You should have received a copy of the GNU Lesser General Public License
+C along with the nettle library; see the file COPYING.LIB.  If not, write to
+C the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+C MA 02111-1301, USA.
+
+	.file "ecc-384-modp.asm"
+
+define(<RP>, <%rsi>)
+define(<D4>, <%rax>)
+define(<T0>, <%rbx>)
+define(<T1>, <%rcx>)
+define(<T2>, <%rdx>)
+define(<T3>, <%rbp>)
+define(<T4>, <%rdi>)
+define(<T5>, <%r8>)
+define(<H0>, <%r9>)
+define(<H1>, <%r10>)
+define(<H2>, <%r11>)
+define(<H3>, <%r12>)
+define(<H4>, <%r13>)
+define(<H5>, <%r14>)
+define(<C2>, <%r15>)
+define(<C0>, H5)	C Overlap
+define(<D0>, RP)	C Overlap
+define(<TMP>, H4)	C Overlap
+
+PROLOGUE(nettle_ecc_384_modp)
+	W64_ENTRY(2, 0)
+
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	C First get top 2 limbs, which need folding twice
+	C
+	C   H5 H4
+	C     -H5
+	C  ------
+	C   H0 D4
+	C
+	C Then shift right, (H1,H0,D4)  <--  (H0,D4) << 32
+	C and add
+	C
+	C     H5 H4
+	C     H1 H0
+	C ----------
+	C  C2 H1 H0
+
+	mov	80(RP), D4
+	mov	88(RP), H0
+	mov	D4, H4
+	mov	H0, H5
+	sub	H0, D4
+	sbb	$0, H0
+
+	mov	D4, T2
+	mov	H0, H1
+	shl	$32, H0
+	shr	$32, T2
+	shr	$32, H1
+	or	T2, H0
+
+	xor	C2, C2
+	add	H4, H0
+	adc	H5, H1
+	adc	$0, C2
+
+	C Add in to high part
+	add	48(RP), H0
+	adc	56(RP), H1
+	adc	$0, C2		C Do C2 later
+
+	C +1 term
+	mov	(RP), T0
+	add	H0, T0
+	mov	8(RP), T1
+	adc	H1, T1
+	mov	16(RP), T2
+	mov	64(RP), H2
+	adc	H2, T2
+	mov	24(RP), T3
+	mov	72(RP), H3
+	adc	H3, T3
+	mov	32(RP), T4
+	adc	H4, T4
+	mov	40(RP), T5
+	adc	H5, T5
+	sbb	C0, C0
+	neg	C0		C FIXME: Switch sign of C0?
+
+	push	RP
+
+	C +B^2 term
+	add	H0, T2
+	adc	H1, T3
+	adc	H2, T4
+	adc	H3, T5
+	adc	$0, C0
+
+	C   H3 H2 H1 H0  0
+	C - H4 H3 H2 H1 H0
+	C  ---------------
+	C   H3 H2 H1 H0 D0
+
+	mov	XREG(D4), XREG(D4)
+	mov	H0, D0
+	neg	D0
+	sbb	H1, H0
+	sbb	H2, H1
+	sbb	H3, H2
+	sbb	H4, H3
+	sbb	$0, D4
+
+	C Shift right. High bits are sign, to be added to C0.
+	mov	D4, TMP
+	sar	$32, TMP
+	shl	$32, D4
+	add	TMP, C0
+
+	mov	H3, TMP
+	shr	$32, TMP
+	shl	$32, H3
+	or	TMP, D4
+
+	mov	H2, TMP
+	shr	$32, TMP
+	shl	$32, H2
+	or	TMP, H3
+
+	mov	H1, TMP
+	shr	$32, TMP
+	shl	$32, H1
+	or	TMP, H2
+
+	mov	H0, TMP
+	shr	$32, TMP
+	shl	$32, H0
+	or	TMP, H1
+
+	mov	D0, TMP
+	shr	$32, TMP
+	shl	$32, D0
+	or	TMP, H0
+
+	add	D0, T0
+	adc	H0, T1
+	adc	H1, T2
+	adc	H2, T3
+	adc	H3, T4
+	adc	D4, T5
+	adc	$0, C0
+
+	C Remains to add in C2 and C0
+	C                         C0  C0<<32  (-2^32+1)C0
+	C    C2  C2<<32  (-2^32+1)C2
+	C where C2 is always positive, while C0 may be -1.
+	mov	C0, H0
+	mov	C0, H1
+	mov	C0, H2
+	sar	$63, C0		C Get sign
+	shl	$32, H1
+	sub	H1, H0		C Gives borrow iff C0 > 0
+	sbb	$0, H1
+	add	C0, H2
+
+	add	H0, T0
+	adc	H1, T1
+	adc	$0, H2
+	adc	$0, C0
+
+	C Set (H1 H0)  <-- C2 << 96 - C2 << 32 + 1
+	mov	C2, H0
+	mov	C2, H1
+	shl	$32, H1
+	sub	H1, H0
+	sbb	$0, H1
+
+	add	H2, H0
+	adc	C0, H1
+	adc	C2, C0
+	mov	C0, H2
+	sar	$63, C0
+	add	H0, T2
+	adc	H1, T3
+	adc	H2, T4
+	adc	C0, T5
+	sbb	C0, C0
+
+	C Final unlikely carry
+	mov	C0, H0
+	mov	C0, H1
+	mov	C0, H2
+	sar	$63, C0
+	shl	$32, H1
+	sub	H1, H0
+	sbb	$0, H1
+	add	C0, H2
+
+	pop	RP
+
+	sub	H0, T0
+	mov	T0, (RP)
+	sbb	H1, T1
+	mov	T1, 8(RP)
+	sbb	H2, T2
+	mov	T2, 16(RP)
+	sbb	C0, T3
+	mov	T3, 24(RP)
+	sbb	C0, T4
+	mov	T4, 32(RP)
+	sbb	C0, T5
+	mov	T5, 40(RP)
+
+	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+
+	W64_EXIT(2, 0)
+	ret
+EPILOGUE(nettle_ecc_384_modp)
diff --git a/x86_64/ecc-521-modp.asm b/x86_64/ecc-521-modp.asm
new file mode 100644
index 0000000000000000000000000000000000000000..afe3d2aa52cde0fc0a65fd7733c4b0792bebfd52
--- /dev/null
+++ b/x86_64/ecc-521-modp.asm
@@ -0,0 +1,143 @@
+C nettle, low-level cryptographics library
+C
+C Copyright (C) 2013 Niels Möller
+C
+C The nettle library is free software; you can redistribute it and/or modify
+C it under the terms of the GNU Lesser General Public License as published by
+C the Free Software Foundation; either version 2.1 of the License, or (at your
+C option) any later version.
+C
+C The nettle library is distributed in the hope that it will be useful, but
+C WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+C or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+C License for more details.
+C
+C You should have received a copy of the GNU Lesser General Public License
+C along with the nettle library; see the file COPYING.LIB.  If not, write to
+C the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+C MA 02111-1301, USA.
+
+	.file "ecc-521-modp.asm"
+
+define(<RP>, <%rsi>)
+define(<U0>, <%rax>)
+define(<U1>, <%rbx>)
+define(<U2>, <%rcx>)
+define(<U3>, <%rdx>)
+define(<U4>, <%rbp>)
+define(<U5>, <%rdi>)
+define(<U6>, <%r8>)
+define(<U7>, <%r9>)
+define(<U8>, <%r10>)
+define(<U9>, <%r11>)
+define(<T0>, <%r12>)
+define(<T1>, <%r13>)
+
+PROLOGUE(nettle_ecc_521_modp)
+	W64_ENTRY(2, 0)
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+
+	C Read top 17 limbs, shift left 55 bits
+	mov	72(RP), U1
+	mov	U1, U0
+	shl	$55, U0
+	shr	$9, U1
+
+	mov	80(RP), U2
+	mov	U2, T0
+	shr	$9, U2
+	shl	$55, T0
+	or	T0, U1
+
+	mov	88(RP), U3
+	mov	U3, T0
+	shr	$9, U3
+	shl	$55, T0
+	or	T0, U2
+
+	mov	96(RP), U4
+	mov	U4, T0
+	shr	$9, U4
+	shl	$55, T0
+	or	T0, U3
+
+	mov	104(RP), U5
+	mov	U5, T0
+	shr	$9, U5
+	shl	$55, T0
+	or	T0, U4
+
+	mov	112(RP), U6
+	mov	U6, T0
+	shr	$9, U6
+	shl	$55, T0
+	or	T0, U5
+
+	mov	120(RP), U7
+	mov	U7, T0
+	shr	$9, U7
+	shl	$55, T0
+	or	T0, U6
+
+	mov	128(RP), U8
+	mov	U8, T0
+	shr	$9, U8
+	shl	$55, T0
+	or	T0, U7
+
+	mov	136(RP), U9
+	mov	U9, T0
+	shr	$9, U9
+	shl	$55, T0
+	or	T0, U8
+
+	add	  (RP), U0
+	adc	 8(RP), U1
+	adc	16(RP), U2
+	adc	24(RP), U3
+	adc	32(RP), U4
+	adc	40(RP), U5
+	adc	48(RP), U6
+	adc	56(RP), U7
+	adc	64(RP), U8
+	adc	$0, U9
+
+	C Top limbs are <U9, U8>. Keep low 9 bits of 8, and fold the
+	C top bits (at most 65 bits).
+	mov	U8, T0
+	shr	$9, T0
+	and	$0x1ff, U8
+	mov	U9, T1
+	shl	$55, U9
+	shr	$9, T1
+	or	U9, T0
+
+	add	T0, U0
+	mov	U0, (RP)
+	adc	T1, U1
+	mov	U1, 8(RP)
+	adc	$0, U2
+	mov	U2, 16(RP)
+	adc	$0, U3
+	mov	U3, 24(RP)
+	adc	$0, U4
+	mov	U4, 32(RP)
+	adc	$0, U5
+	mov	U5, 40(RP)
+	adc	$0, U6
+	mov	U6, 48(RP)
+	adc	$0, U7
+	mov	U7, 56(RP)
+	adc	$0, U8
+	mov	U8, 64(RP)
+
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	W64_EXIT(2, 0)
+	ret
+EPILOGUE(nettle_ecc_521_modp)