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)