diff --git a/.gitignore b/.gitignore index d54eed12f..780e8222e 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ include *.i*86 *.x86_64 *.hex +/example_kem /speed_kem /test_kem /test_kex diff --git a/.travis.yml b/.travis.yml index 771100f46..57236f6bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,6 @@ matrix: compiler: gcc env: - CC_OVERRIDE=gcc - - ENABLE_KEX_LWE_FRODO=0 - ENABLE_KEX_SIDH_MSR=0 - ENABLE_SIG_PICNIC=0 - USE_OPENSSL=1 diff --git a/.travis/all-tests.sh b/.travis/all-tests.sh index b4ecf8a29..b21ba5780 100755 --- a/.travis/all-tests.sh +++ b/.travis/all-tests.sh @@ -53,10 +53,6 @@ if [[ ${ENABLE_CODE_MCBITS} == 1 ]];then fi fi -if [[ ${ENABLE_KEX_LWE_FRODO} == 0 ]];then - enable_disable_str+=" --disable-kex-lwe-frodo" -fi - if [[ ${ENABLE_KEX_NTRU} == 0 ]];then enable_disable_str+=" --disable-kex-ntru" fi diff --git a/Makefile.am b/Makefile.am index dd0688581..0d53994f5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,9 +24,6 @@ liboqs_la_LIBADD += src/kex/libkex.la if USE_KEX_RLWE_NEWHOPE_AVX2 liboqs_la_LIBADD += src/kex_rlwe_newhope/avx2/libnewhope_avx2.la endif -if USE_KEX_LWE_FRODO -liboqs_la_LIBADD += src/kex_lwe_frodo/libfrodo.la -endif if USE_KEX_NTRU liboqs_la_LIBADD += src/kex_ntru/libntru.la endif @@ -47,9 +44,12 @@ if USE_SIG_PICNIC liboqs_la_LIBADD += src/sig_picnic/libpicnic_i.la endif -if USE_KEM_SIKE +if ENABLE_KEM_SIKE liboqs_la_LIBADD += src/kem/sike/libkemsike.la endif +if ENABLE_KEM_FRODOKEM +liboqs_la_LIBADD += src/kem/frodokem/libkemfrodokem.la +endif installheaderdir=$(includedir)/oqs installheader_HEADERS=config.h \ @@ -62,11 +62,11 @@ installheader_HEADERS=config.h \ src/crypto/sha3/sha3.h \ src/kem/kem.h \ src/kex/kex.h \ - src/kex_lwe_frodo/kex_lwe_frodo.h \ src/kex_ntru/kex_ntru.h \ src/kex_rlwe_newhope/kex_rlwe_newhope.h \ src/kex_sidh_msr/kex_sidh_msr.h \ src/kem/sike/kem_sike.h \ + src/kem/frodokem/kem_frodokem.h \ src/sig/sig.h install-exec-local: @@ -87,10 +87,7 @@ if USE_MCBITS cp src/kex_code_mcbits/kex_code_mcbits.h $(includedir)/oqs endif -noinst_bin_PROGRAMS = speed_kem test_kem test_kex test_aes test_rand test_sha3 -if USE_KEX_LWE_FRODO -noinst_bin_PROGRAMS += minimal_kex_oqs -endif +noinst_bin_PROGRAMS = example_kem speed_kem test_kem test_kex test_aes test_rand test_sha3 if USE_SIG_PICNIC noinst_bin_PROGRAMS += test_sig minimal_sig_oqs endif @@ -113,6 +110,14 @@ if USE_OPENSSL test_kem_LDADD += -L$(OPENSSL_DIR)/lib -lcrypto endif +example_kem_LDADD = liboqs.la -lm +example_kem_SOURCES = src/kem/example_kem.c +example_kem_CPPFLAGS = -I./include +example_kem_CPPFLAGS += $(AM_CPPFLAGS) +if USE_OPENSSL +example_kem_LDADD += -L$(OPENSSL_DIR)/lib -lcrypto +endif + test_kex_LDADD = liboqs.la -lm test_kex_SOURCES = src/kex/test_kex.c test_kex_CPPFLAGS = -I./include @@ -143,20 +148,6 @@ endif endif # USE_SIG_PICNIC -if USE_KEX_LWE_FRODO -minimal_kex_oqs_LDADD = liboqs.la -lm -minimal_kex_oqs_SOURCES = src/kex/minimal_kex_oqs.c -minimal_kex_oqs_CPPFLAGS = -I./include -minimal_kex_oqs_CPPFLAGS += $(AM_CPPFLAGS) -if USE_MCBITS -minimal_kex_oqs_LDADD += -L${SODIUM_DIR}/lib -lsodium -endif -if USE_OPENSSL -minimal_kex_oqs_LDADD += -L$(OPENSSL_DIR)/lib -lcrypto -endif - -endif # USE_KEX_LWE_FRODO - test_aes_LDADD = liboqs.la -lm test_aes_SOURCES = src/crypto/aes/test_aes.c test_aes_CPPFLAGS = -I./include @@ -186,6 +177,7 @@ test_sha3_CPPFLAGS += $(AM_CPPFLAGS) test: clean-tests make + ./example_kem ./test_kem ./test_kex --quiet ./test_rand --quiet @@ -195,9 +187,6 @@ if USE_SIG_PICNIC ./test_sig ./minimal_sig_oqs endif -if USE_KEX_LWE_FRODO - ./minimal_kex_oqs -endif links: $(MKDIR_P) include/oqs @@ -211,8 +200,8 @@ links: cp -f src/crypto/sha3/sha3.h include/oqs cp -f src/kem/kem.h include/oqs cp -f src/kem/sike/kem_sike.h include/oqs + cp -f src/kem/frodokem/kem_frodokem.h include/oqs cp -f src/kex/kex.h include/oqs - cp -f src/kex_lwe_frodo/kex_lwe_frodo.h include/oqs cp -f src/kex_ntru/kex_ntru.h include/oqs cp -f src/kex_rlwe_newhope/kex_rlwe_newhope.h include/oqs if USE_KEX_RLWE_NEWHOPE_AVX2 @@ -230,16 +219,13 @@ endif clean-local: rm -f liboqs.a rm -rf include -if USE_KEX_LWE_FRODO - rm -f minimal_kex_oqs -endif if USE_SIG_PICNIC rm -f test_sig rm -f minimal_sig_oqs endif clean-tests: - rm -f speed_kem test_kem test_kex test_rand test_aes test_sha3 + rm -f example_kem speed_kem test_kem test_kex test_rand test_aes test_sha3 prettyprint: find src -name '*.c' -o -name '*.h' | grep -v sig_picnic/external* | grep -v "kex_rlwe_newhope/avx2" | grep -v "kex_sidh_msr" | xargs $(CLANGFORMAT) -style=file -i diff --git a/NEW_API.md b/NEW_API.md index b5737f01a..c01d7e687 100644 --- a/NEW_API.md +++ b/NEW_API.md @@ -4,3 +4,4 @@ - Create a new `test_common` program that combines `test_rand`, `test_aes`, `test_sha`, etc. - `speed_kem` needs autoconf to generate compilation information variables +- Frodo ahsn't been configured to use AVX2 where available diff --git a/README.md b/README.md index e721a2f90..ed6166536 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,6 @@ Contents liboqs currently contains: - `kex_rlwe_newhope`: "NewHope": key exchange from the ring learning with errors problem (Alkim, Ducas, Pöppelmann, Schwabe, *USENIX Security 2016*, [https://eprint.iacr.org/2015/1092](https://eprint.iacr.org/2015/1092)) (using the reference C implementation of NewHope from [https://github.com/tpoeppelmann/newhope](https://github.com/tpoeppelmann/newhope)) -- `kex_lwe_frodo`: "Frodo": key exchange from the learning with errors problem (Bos, Costello, Ducas, Mironov, Naehrig, Nikolaenko, Raghunathan, Stebila, *ACM Conference on Computer and Communications Security 2016*, [https://eprint.iacr.org/2016/659](https://eprint.iacr.org/2016/659)) - `kex_sidh_msr`: key exchange from the supersingular isogeny Diffie-Hellman problem (Costello, Naehrig, Longa, *CRYPTO 2016*, [https://eprint.iacr.org/2016/413](https://eprint.iacr.org/2016/413)), using the implementation of Microsoft Research [https://www.microsoft.com/en-us/research/project/sidh-library/](https://www.microsoft.com/en-us/research/project/sidh-library/) - `kex_code_mcbits`: "McBits": key exchange from the error correcting codes, specifically Niederreiter's form of McEliece public key encryption using hidden Goppa codes (Bernstein, Chou, Schwabe, *CHES 2013*, [https://eprint.iacr.org/2015/610](https://eprint.iacr.org/2015/610)), using the implementation of McBits from [https://www.win.tue.nl/~tchou/mcbits/](https://www.win.tue.nl/~tchou/mcbits/)) - `kex_ntru`: NTRU: key transport using NTRU public key encryption (Hoffstein, Pipher, Silverman, *ANTS 1998*) with the EES743EP1 parameter set, wrapper around the implementation from the NTRU Open Source project [https://github.com/NTRUOpenSourceProject/NTRUEncrypt](https://github.com/NTRUOpenSourceProject/NTRUEncrypt)) @@ -137,7 +136,7 @@ To build with `kex_code_mcbits ` enabled: ### Building with the following KEX algorithms disabled - ./configure --disable-kex-ntru --disable-kex-lwe-frodo --disable-kex-rlwe-newhope --disable-kex-sidh-msr + ./configure --disable-kex-ntru --disable-kex-rlwe-newhope --disable-kex-sidh-msr make clean make diff --git a/VisualStudio/oqs/oqs.vcxproj b/VisualStudio/oqs/oqs.vcxproj index 19e938e0f..2c779fba1 100644 --- a/VisualStudio/oqs/oqs.vcxproj +++ b/VisualStudio/oqs/oqs.vcxproj @@ -46,8 +46,6 @@ - - @@ -93,9 +91,6 @@ - - - @@ -269,7 +264,6 @@ copy "$(SolutionDir)..\src\crypto\rand_urandom_aesctr\rand_urandom_aesctr.h" "$( copy "$(SolutionDir)..\src\crypto\sha3\sha3.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex\kex.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_rlwe_newhope\kex_rlwe_newhope.h" "$(SolutionDir)include\oqs\" -copy "$(SolutionDir)..\src\kex_lwe_frodo\kex_lwe_frodo.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_code_mcbits\kex_code_mcbits.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_ntru\kex_ntru.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_sidh_msr\kex_sidh_msr.h" "$(SolutionDir)include\oqs\" @@ -306,7 +300,6 @@ copy "$(SolutionDir)..\src\crypto\rand_urandom_aesctr\rand_urandom_aesctr.h" "$( copy "$(SolutionDir)..\src\crypto\sha3\sha3.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex\kex.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_rlwe_newhope\kex_rlwe_newhope.h" "$(SolutionDir)include\oqs\" -copy "$(SolutionDir)..\src\kex_lwe_frodo\kex_lwe_frodo.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_code_mcbits\kex_code_mcbits.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_ntru\kex_ntru.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_sidh_msr\kex_sidh_msr.h" "$(SolutionDir)include\oqs\" @@ -343,7 +336,6 @@ copy "$(SolutionDir)..\src\crypto\rand_urandom_aesctr\rand_urandom_aesctr.h" "$( copy "$(SolutionDir)..\src\crypto\sha3\sha3.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex\kex.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_rlwe_newhope\kex_rlwe_newhope.h" "$(SolutionDir)include\oqs\" -copy "$(SolutionDir)..\src\kex_lwe_frodo\kex_lwe_frodo.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_code_mcbits\kex_code_mcbits.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_ntru\kex_ntru.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_sidh_msr\kex_sidh_msr.h" "$(SolutionDir)include\oqs\" @@ -387,7 +379,6 @@ copy "$(SolutionDir)..\src\crypto\rand_urandom_aesctr\rand_urandom_aesctr.h" "$( copy "$(SolutionDir)..\src\crypto\sha3\sha3.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex\kex.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_rlwe_newhope\kex_rlwe_newhope.h" "$(SolutionDir)include\oqs\" -copy "$(SolutionDir)..\src\kex_lwe_frodo\kex_lwe_frodo.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_code_mcbits\kex_code_mcbits.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_ntru\kex_ntru.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_sidh_msr\kex_sidh_msr.h" "$(SolutionDir)include\oqs\" @@ -430,7 +421,6 @@ copy "$(SolutionDir)..\src\crypto\rand_urandom_aesctr\rand_urandom_aesctr.h" "$( copy "$(SolutionDir)..\src\crypto\sha3\sha3.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex\kex.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_rlwe_newhope\kex_rlwe_newhope.h" "$(SolutionDir)include\oqs\" -copy "$(SolutionDir)..\src\kex_lwe_frodo\kex_lwe_frodo.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_code_mcbits\kex_code_mcbits.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_ntru\kex_ntru.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_sidh_msr\kex_sidh_msr.h" "$(SolutionDir)include\oqs\" @@ -471,7 +461,6 @@ copy "$(SolutionDir)..\src\crypto\rand_urandom_aesctr\rand_urandom_aesctr.h" "$( copy "$(SolutionDir)..\src\crypto\sha3\sha3.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex\kex.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_rlwe_newhope\kex_rlwe_newhope.h" "$(SolutionDir)include\oqs\" -copy "$(SolutionDir)..\src\kex_lwe_frodo\kex_lwe_frodo.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_code_mcbits\kex_code_mcbits.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_ntru\kex_ntru.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_sidh_msr\kex_sidh_msr.h" "$(SolutionDir)include\oqs\" @@ -512,7 +501,6 @@ copy "$(SolutionDir)..\src\crypto\rand_urandom_aesctr\rand_urandom_aesctr.h" "$( copy "$(SolutionDir)..\src\crypto\sha3\sha3.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex\kex.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_rlwe_newhope\kex_rlwe_newhope.h" "$(SolutionDir)include\oqs\" -copy "$(SolutionDir)..\src\kex_lwe_frodo\kex_lwe_frodo.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_code_mcbits\kex_code_mcbits.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_ntru\kex_ntru.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_sidh_msr\kex_sidh_msr.h" "$(SolutionDir)include\oqs\" @@ -560,7 +548,6 @@ copy "$(SolutionDir)..\src\crypto\rand_urandom_aesctr\rand_urandom_aesctr.h" "$( copy "$(SolutionDir)..\src\crypto\sha3\sha3.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex\kex.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_rlwe_newhope\kex_rlwe_newhope.h" "$(SolutionDir)include\oqs\" -copy "$(SolutionDir)..\src\kex_lwe_frodo\kex_lwe_frodo.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_code_mcbits\kex_code_mcbits.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_ntru\kex_ntru.h" "$(SolutionDir)include\oqs\" copy "$(SolutionDir)..\src\kex_sidh_msr\kex_sidh_msr.h" "$(SolutionDir)include\oqs\" diff --git a/VisualStudio/oqs/oqs.vcxproj.filters b/VisualStudio/oqs/oqs.vcxproj.filters index 90bf97d04..e0d22acd4 100644 --- a/VisualStudio/oqs/oqs.vcxproj.filters +++ b/VisualStudio/oqs/oqs.vcxproj.filters @@ -1,18 +1,9 @@  - - KEX_Frodo - KEX_NewHope - - KEX_Frodo - - - KEX_Frodo - Common @@ -123,15 +114,9 @@ - - KEX_Frodo - KEX_NewHope - - KEX_Frodo - KEX_NewHope @@ -273,9 +258,6 @@ {3bb6aa76-f294-47a9-bf22-76245c9cb1d1} - - {6bfff158-3e78-402f-ba16-e8d315089de8} - {d0291785-4232-4264-b1bd-08b7e3f8df5e} diff --git a/VisualStudio/winconfig.h b/VisualStudio/winconfig.h index 5bcdfe5af..100437f47 100644 --- a/VisualStudio/winconfig.h +++ b/VisualStudio/winconfig.h @@ -2,7 +2,6 @@ #define __WINCONFIG_H /* Enable schemes supported on Windows */ -#define ENABLE_KEX_LWE_FRODO #define ENABLE_KEX_NTRU #define ENABLE_KEX_RLWE_NEWHOPE #define ENABLE_KEX_SIDH_MSR diff --git a/configure.ac b/configure.ac index 47c28d8bb..848cfdad6 100644 --- a/configure.ac +++ b/configure.ac @@ -92,10 +92,6 @@ ARG_ENABL_SET([kex-code-mcbits], [enable KEX-CODE-MCBITS.]) AM_CONDITIONAL([kex_code_mcbits], [test "x$kex_code_mcbits" = xtrue]) AM_CONDITIONAL([USE_MCBITS], [test "x$kex_code_mcbits" = xtrue]) -ARG_DISBL_SET([kex-lwe-frodo], [disable KEX-LWE-FRODO.]) -AM_CONDITIONAL([kex_lwe_frodo], [test "x$kex_lwe_frodo" = xtrue]) -AM_CONDITIONAL([USE_KEX_LWE_FRODO], [test "x$kex_lwe_frodo" = xtrue]) - ARG_DISBL_SET([kex-ntru], [disable KEX-NTRU.]) AM_CONDITIONAL([kex_ntru], [test "x$kex_ntru" = xtrue]) AM_CONDITIONAL([USE_KEX_NTRU], [test "x$kex_ntru" = xtrue]) @@ -116,10 +112,6 @@ ARG_ENABL_SET([kex-rlwe-newhope-avx2], [enable KEX-RLWE-NEWHOPE-AVX2.]) AM_CONDITIONAL([kex_rlwe_newhope_avx2], [test "x$kex_rlwe_newhope_avx2" = xtrue]) AM_CONDITIONAL([USE_KEX_RLWE_NEWHOPE_AVX2], [test "x$kex_rlwe_newhope_avx2" = xtrue]) -ARG_DISBL_SET([kem-sike], [disable KEM-SIKE.]) -AM_CONDITIONAL([kem_sike], [test "x$kem_sike" = xtrue]) -AM_CONDITIONAL([USE_KEM_SIKE], [test "x$kem_sike" = xtrue]) - AC_CANONICAL_HOST # Check for which host we are on and setup a few things @@ -177,12 +169,6 @@ SRCDIR=${SRCDIR}" src/crypto/aes src/crypto/sha3 src/crypto/rand_urandom_aesctr # KEX SRCDIR=${SRCDIR}" src/kex" -if test x"$kex_lwe_frodo" = x"true"; then - SRCDIR=${SRCDIR}" src/kex_lwe_frodo" - AM_CPPFLAGS=${AM_CPPFLAGS}" -DENABLE_KEX_LWE_FRODO" - AC_DEFINE(ENABLE_KEX_LWE_FRODO, 1, "Define to 1 when FRODO enabled") -fi - if test x"$kex_ntru" = x"true"; then SRCDIR=${SRCDIR}" src/kex_ntru" AM_CPPFLAGS=${AM_CPPFLAGS}" -DENABLE_KEX_NTRU" @@ -218,12 +204,20 @@ fi # KEM SRCDIR=${SRCDIR}" src/kem" -if test x"$kem_sike" = x"true"; then - SRCDIR=${SRCDIR}" src/kem/sike" - AM_CPPFLAGS=${AM_CPPFLAGS}" -DOQS_ENABLE_KEM_sike_p503 -DOQS_ENABLE_KEM_sike_p751" - AC_DEFINE(OQS_ENABLE_KEM_sike_p503, 1, "Define to 1 when Sike-p503 enabled") - AC_DEFINE(OQS_ENABLE_KEM_sike_p751, 1, "Define to 1 when Sike-p751 enabled") -fi +ARG_DISBL_SET([kem-sike], [disable KEM-SIKE.]) +AM_CONDITIONAL([ENABLE_KEM_SIKE], [test "x$kem_sike" = xtrue]) +AM_COND_IF([ENABLE_KEM_SIKE], [SRCDIR="${SRCDIR} src/kem/sike"]) +AM_COND_IF([ENABLE_KEM_SIKE], [AC_DEFINE(OQS_ENABLE_KEM_sike_p503, 1, "Define to 1 when Sike-p503 enabled")]) +AM_COND_IF([ENABLE_KEM_SIKE], [AC_DEFINE(OQS_ENABLE_KEM_sike_p751, 1, "Define to 1 when Sike-p751 enabled")]) + +ARG_DISBL_SET([kem-frodokem], [disable KEM-FrodoKEM.]) +AM_CONDITIONAL([ENABLE_KEM_FRODOKEM], [test "x$kem_frodokem" = xtrue]) +AM_COND_IF([ENABLE_KEM_FRODOKEM], [SRCDIR="${SRCDIR} src/kem/frodokem"]) +AM_COND_IF([ENABLE_KEM_FRODOKEM], [AC_DEFINE(OQS_ENABLE_KEM_frodokem_640_aes, 1, "Define to 1 when FrodoKEM-640-AES enabled")]) +AM_COND_IF([ENABLE_KEM_FRODOKEM], [AC_DEFINE(OQS_ENABLE_KEM_frodokem_640_cshake, 1, "Define to 1 when FrodoKEM-640-cSHAKE enabled")]) +AM_COND_IF([ENABLE_KEM_FRODOKEM], [AC_DEFINE(OQS_ENABLE_KEM_frodokem_976_aes, 1, "Define to 1 when FrodoKEM-976-AES enabled")]) +AM_COND_IF([ENABLE_KEM_FRODOKEM], [AC_DEFINE(OQS_ENABLE_KEM_frodokem_976_cshake, 1, "Define to 1 when FrodoKEM-976-cSHAKE enabled")]) + # Flags @@ -252,14 +246,12 @@ AC_SUBST(USE_OPENSSL) AC_SUBST(USE_AES_NI) AC_SUBST(USE_KEX_NTRU) AC_SUBST(USE_MCBITS) -AC_SUBST(USE_KEX_LWE_FRODO) AC_SUBST(USE_KEX_RLWE_NEWHOPE) AC_SUBST(USE_KEX_SIDH_MSR) AC_SUBST(USE_SIG_PICNIC) AC_SUBST(ON_DARWIN) AC_SUBST(X86_64) AC_SUBST(USE_KEX_RLWE_NEWHOPE_AVX2) -AC_SUBST(USE_KEM_SIKE) AC_CONFIG_FILES([Makefile @@ -274,11 +266,11 @@ AC_CONFIG_FILES([Makefile src/kex_sidh_msr/Makefile src/kex_code_mcbits/Makefile src/kex_ntru/Makefile - src/kex_lwe_frodo/Makefile src/sig/Makefile src/sig_picnic/Makefile src/kex_rlwe_newhope/avx2/Makefile src/kem/sike/Makefile + src/kem/frodokem/Makefile ]) AC_OUTPUT diff --git a/docs/algorithms/kem_frodokem.md b/docs/algorithms/kem_frodokem.md new file mode 100644 index 000000000..367ccc30f --- /dev/null +++ b/docs/algorithms/kem_frodokem.md @@ -0,0 +1,40 @@ +liboqs master branch algorithm datasheet: `kem_frodokem` +======================================================== + +Summary +------- + +- **Name**: FrodoKEM +- **Algorithm type**: key encapsulation mechanism +- **Main cryptographic assumption**: learning with errors (LWE) +- **Scheme authors**: Michael Naehrig, Erdem Alkim, Joppe Bos, Léo Ducas, Karen Easterbrook, Brian LaMacchia, Patrick Longa, Ilya Mironov, Valeria Nikolaenko, Christopher Peikert, Ananth Raghunathan, Douglas Stebila +- **Authors' website**: https://frodokem.org/ +- **Added to liboqs by**: Douglas Stebila + +Parameter sets +-------------- + +| Parameter set | Security model | Claimed NIST security level | Public key size (bytes) | Secret key size (bytes) | Ciphertext size (bytes) | Shared secret size (bytes) | +|---------------------|:--------------:|:---------------------------:|:-----------------------:|:-----------------------:|:-----------------------:|:--------------------------:| +| FrodoKEM-640-AES | IND-CCA | 1 | 9616 | 19872 | 9736 | 16 | +| FrodoKEM-640-cSHAKE | IND-CCA | 1 | 9616 | 19872 | 9736 | 16 | +| FrodoKEM-976-AES | IND-CCA | 3 | 15632 | 31272 | 15768 | 24 | +| FrodoKEM-976-cSHAKE | IND-CCA | 3 | 15632 | 31272 | 15768 | 24 | + +Implementation +-------------- + +- **Source of implementation:** https://github.com/Microsoft/PQCrypto-LWEKE +- **License:** MIT License +- **Language:** C +- **Constant-time:** Yes +- **Architectures supported in liboqs master branch**: x86, x64 + +Additional comments +------------------- + +The original FrodoKEM implementation includes optimizations that are not currently being built in liboqs: + +- ARM +- AVX2 +- cSHAKE 4-way hashing diff --git a/docs/algorithms/kex_lwe_frodo.md b/docs/algorithms/kex_lwe_frodo.md deleted file mode 100644 index cc6dc0a1c..000000000 --- a/docs/algorithms/kex_lwe_frodo.md +++ /dev/null @@ -1,60 +0,0 @@ -Algorithm data sheet: `kex_lwe_frodo` -======================================= - -Algorithm ---------- - -**Name:** Frodo - -**Description:** Key exchange protocol proposed by Bos et al. [BCDMNNRS16] based on the ring learning with errors problem. Instantiation of the Lindner–Peikert approximate LWE key agreement scheme [LP10], which was an adaptation of the LWE public key encryption scheme of in public key encryption scheme of Regev [Reg05], using reconciliation mechanism of Peikert [Pei14]. - -**Supporting research:** - -- [BCDMNNRS16] Joppe Bos, Craig Costello, Léo Ducas, Ilya Mironov, Michael Naehrig, Valeria Nikolaenko, Ananth Raghunathan, Douglas Stebila. Frodo: Take off the ring! Practical, quantum-secure key exchange from LWE. In *Proc. 23rd ACM Conference on Computer and Communications Security (CCS) 2016*, pp. 1006-1018. ACM, October 2016. [https://eprint.iacr.org/2016/659](https://eprint.iacr.org/2016/659) -- [Pei14] Chris Peikert. Lattice cryptography for the Internet. In *PQCrypto 2014*, volume 8772 of LNCS, pages 197–219. Springer, 2014. [https://eprint.iacr.org/2014/070](https://eprint.iacr.org/2014/070) -- [LP10] Richard Lindner and Chris Peikert. Better key sizes (and attacks) for LWE-based encryption. In *Proc. CT-RSA 2011*, *LNCS*, vol. 6558, pp. 319–339. Springer, February 2011. [https://eprint.iacr.org/2010/613](https://eprint.iacr.org/2010/613) -- [Reg05] Oded Regev. On lattices, learning with errors, random linear codes, and cryptography. In *Proc. 37th ACM STOC*, pp. 84–93. ACM Press, May 2005. - -Security --------- - -**Security model:** Unauthenticated key exchange / passive (IND-CPA) key encapsulation mechanism - -**Underlying hard problem(s):** Decision learning with errors problem - -Parameter set 1 ---------------- - -"Recommended" parameter set from [BCDMNNRS16] - -**Claimed classical security:** - -- 2^144 (original paper) - -**Claimed quantum security:** - -- 2^130 (original paper) - -**Communication size:** - -- Alice → Bob: 11,377 bytes -- Bob → Alice: 11,296 bytes -- total: 22,673 bytes - -Implementation --------------- - -**Source of implementation:** Original research paper ([https://github.com/lwe-frodo/lwe-frodo](https://github.com/lwe-frodo/lwe-frodo)) - -**License:** MIT License - -**Language:** C - -**Constant-time:** Yes - -**Testing:** - -- Correctness: covered by test harness `test_kex` -- Statistics of shared secrets: covered by test harness `test_kex` -- Static analysis: - - `scan_build` diff --git a/src/kem/example_kem.c b/src/kem/example_kem.c new file mode 100644 index 000000000..c26609a98 --- /dev/null +++ b/src/kem/example_kem.c @@ -0,0 +1,183 @@ +/* + * example_kem.c + * + * Minimal example of a Diffie-Hellman-style post-quantum key encapsulation + * implemented in liboqs. + * +*/ + +#include +#include +#include +#include + +#include + +/* Cleaning up memory etc */ +void cleanup_stack(uint8_t *secret_key, size_t secret_key_len, + uint8_t *shared_secret_e, uint8_t *shared_secret_d, + size_t shared_secret_len); + +void cleanup_heap(uint8_t *secret_key, uint8_t *shared_secret_e, + uint8_t *shared_secret_d, uint8_t *public_key, + uint8_t *ciphertext, OQS_KEM *kem); + +/* This function gives an example of the operations performed by both + * the decapsulator and the encapsulator in a single KEM session, + * using only compile-time macros and allocating variables + * statically on the stack, calling a specific algorithm's functions + * directly. + * + * The macros OQS_KEM_frodokem_640_aes_length_* and the functions + * OQS_KEM_frodokem_640_aes_* are only defined if the algorithm + * FrodoKEM-640-AES was enabled at compile-time which must be + * checked using the OQS_ENABLE_KEM_frodokem_640_aes macro. + * + * , which is included in , contains macros + * indicating which algorithms were enabled when this instance of liboqs + * was compiled. + */ +OQS_STATUS example_stack() { +#ifndef OQS_ENABLE_KEM_frodokem_640_aes // if FrodoKEM-640-AES was not enabled at compile-time + printf("[example_stack] OQS_KEM_frodokem_640_aes was not enabled at " + "compile-time.\n"); + return OQS_ERROR; +#endif +#ifdef OQS_ENABLE_KEM_frodokem_640_aes + uint8_t public_key[OQS_KEM_frodokem_640_aes_length_public_key]; + uint8_t secret_key[OQS_KEM_frodokem_640_aes_length_secret_key]; + uint8_t ciphertext[OQS_KEM_frodokem_640_aes_length_ciphertext]; + uint8_t shared_secret_e[OQS_KEM_frodokem_640_aes_length_shared_secret]; + uint8_t shared_secret_d[OQS_KEM_frodokem_640_aes_length_shared_secret]; + + OQS_STATUS rc = OQS_KEM_frodokem_640_aes_keypair(public_key, secret_key); + if (rc != OQS_SUCCESS) { + fprintf(stderr, "ERROR: OQS_KEM_frodokem_640_aes_keypair failed!\n"); + cleanup_stack(secret_key, OQS_KEM_frodokem_640_aes_length_secret_key, + shared_secret_e, shared_secret_d, + OQS_KEM_frodokem_640_aes_length_shared_secret); + + return OQS_ERROR; + } + rc = OQS_KEM_frodokem_640_aes_encaps(ciphertext, shared_secret_e, public_key); + if (rc != OQS_SUCCESS) { + fprintf(stderr, "ERROR: OQS_KEM_frodokem_640_aes_encaps failed!\n"); + cleanup_stack(secret_key, OQS_KEM_frodokem_640_aes_length_secret_key, + shared_secret_e, shared_secret_d, + OQS_KEM_frodokem_640_aes_length_shared_secret); + + return OQS_ERROR; + } + rc = OQS_KEM_frodokem_640_aes_decaps(shared_secret_d, ciphertext, secret_key); + if (rc != OQS_SUCCESS) { + fprintf(stderr, "ERROR: OQS_KEM_frodokem_640_aes_decaps failed!\n"); + cleanup_stack(secret_key, OQS_KEM_frodokem_640_aes_length_secret_key, + shared_secret_e, shared_secret_d, + OQS_KEM_frodokem_640_aes_length_shared_secret); + + return OQS_ERROR; + } + printf("[example_stack] OQS_KEM_frodokem_640_aes operations completed.\n"); + + return OQS_SUCCESS; // success! +#endif +} + +/* This function gives an example of the operations performed by both + * the decapsulator and the encapsulator in a single KEM session, + * allocating variables dynamically on the heap and calling the generic + * OQS_KEM object. + * + * This does not require the use of compile-time macros to check if the + * algorithm in question was enabled at compile-time; instead, the caller + * must check that the OQS_KEM object returned is not NULL. + */ +OQS_STATUS example_heap() { + OQS_KEM *kem = NULL; + uint8_t *public_key = NULL; + uint8_t *secret_key = NULL; + uint8_t *ciphertext = NULL; + uint8_t *shared_secret_e = NULL; + uint8_t *shared_secret_d = NULL; + + kem = OQS_KEM_new(OQS_KEM_alg_frodokem_640_aes); + if (kem == NULL) { + printf("[example_heap] OQS_KEM_frodokem_640_aes was not enabled at " + "compile-time.\n"); + return OQS_ERROR; + } + + public_key = malloc(kem->length_public_key); + secret_key = malloc(kem->length_secret_key); + ciphertext = malloc(kem->length_ciphertext); + shared_secret_e = malloc(kem->length_shared_secret); + shared_secret_d = malloc(kem->length_shared_secret); + if ((public_key == NULL) || (secret_key == NULL) || (ciphertext == NULL) || + (shared_secret_e == NULL) || (shared_secret_d == NULL)) { + fprintf(stderr, "ERROR: malloc failed!\n"); + cleanup_heap(secret_key, shared_secret_e, shared_secret_d, public_key, + ciphertext, kem); + + return OQS_ERROR; + } + + OQS_STATUS rc = OQS_KEM_keypair(kem, public_key, secret_key); + if (rc != OQS_SUCCESS) { + fprintf(stderr, "ERROR: OQS_KEM_keypair failed!\n"); + cleanup_heap(secret_key, shared_secret_e, shared_secret_d, public_key, + ciphertext, kem); + + return OQS_ERROR; + } + rc = OQS_KEM_encaps(kem, ciphertext, shared_secret_e, public_key); + if (rc != OQS_SUCCESS) { + fprintf(stderr, "ERROR: OQS_KEM_encaps failed!\n"); + cleanup_heap(secret_key, shared_secret_e, shared_secret_d, public_key, + ciphertext, kem); + + return OQS_ERROR; + } + rc = OQS_KEM_decaps(kem, shared_secret_d, ciphertext, secret_key); + if (rc != OQS_SUCCESS) { + fprintf(stderr, "ERROR: OQS_KEM_decaps failed!\n"); + cleanup_heap(secret_key, shared_secret_e, shared_secret_d, public_key, + ciphertext, kem); + + return OQS_ERROR; + } + + printf("[example_heap] OQS_KEM_frodokem_640_aes operations completed.\n"); + cleanup_heap(secret_key, shared_secret_e, shared_secret_d, public_key, + ciphertext, kem); + + return OQS_SUCCESS; // success +} + +int main(void) { + if (example_stack() == OQS_SUCCESS && example_heap() == OQS_SUCCESS) { + return EXIT_SUCCESS; + } else { + return EXIT_FAILURE; + } +} + +void cleanup_stack(uint8_t *secret_key, size_t secret_key_len, + uint8_t *shared_secret_e, uint8_t *shared_secret_d, + size_t shared_secret_len) { + OQS_MEM_cleanse(secret_key, secret_key_len); + OQS_MEM_cleanse(shared_secret_e, shared_secret_len); + OQS_MEM_cleanse(shared_secret_d, shared_secret_len); +} + +void cleanup_heap(uint8_t *secret_key, uint8_t *shared_secret_e, + uint8_t *shared_secret_d, uint8_t *public_key, + uint8_t *ciphertext, OQS_KEM *kem) { + if (kem != NULL) { + OQS_MEM_secure_free(secret_key, kem->length_secret_key); + OQS_MEM_secure_free(shared_secret_e, kem->length_shared_secret); + OQS_MEM_secure_free(shared_secret_d, kem->length_shared_secret); + } + OQS_MEM_insecure_free(public_key); + OQS_MEM_insecure_free(ciphertext); + OQS_KEM_free(kem); +} diff --git a/src/kem/frodokem/Makefile.am b/src/kem/frodokem/Makefile.am new file mode 100644 index 000000000..fd2e6a679 --- /dev/null +++ b/src/kem/frodokem/Makefile.am @@ -0,0 +1,12 @@ +AUTOMAKE_OPTIONS = foreign +noinst_LTLIBRARIES = libkemfrodokem.la + +libkemfrodokem_la_SOURCES = kem_frodokem.c frodo640_aes.c frodo640_cshake.c frodo976_aes.c frodo976_cshake.c util.c + +libkemfrodokem_la_CPPFLAGS = -I../../../include -I. -fPIC -w +libkemfrodokem_la_CPPFLAGS += $(AM_CPPFLAGS) + +frodo640_aes.c: frodo_macrify.h frodo_macrify.c frodo640_params.h kem.c +frodo640_cshake.c: frodo_macrify.h frodo_macrify.c frodo640_params.h kem.c +frodo976_aes.c: frodo_macrify.h frodo_macrify.c frodo976_params.h kem.c +frodo976_cshake.c: frodo_macrify.h frodo_macrify.c frodo976_params.h kem.c diff --git a/src/kem/frodokem/config.h b/src/kem/frodokem/config.h new file mode 100644 index 000000000..946d9cd95 --- /dev/null +++ b/src/kem/frodokem/config.h @@ -0,0 +1,90 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: configuration file +*********************************************************************************************/ + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +// Definition of operating system + +#define OS_WIN 1 +#define OS_NIX 2 + +#if defined(WINDOWS) // Microsoft Windows +#define OS_TARGET OS_WIN +#elif defined(NIX) // Unix-like operative systems +#define OS_TARGET OS_NIX +#else +#error-- "Unsupported OS" +#endif + +// Definition of compiler + +#define COMPILER_VC 1 +#define COMPILER_GCC 2 +#define COMPILER_CLANG 3 + +#if defined(_MSC_VER) // Microsoft Visual C compiler +#define COMPILER COMPILER_VC +#elif defined(__GNUC__) // GNU GCC compiler +#define COMPILER COMPILER_GCC +#elif defined(__clang__) // Clang compiler +#define COMPILER COMPILER_CLANG +#else +#error-- "Unsupported COMPILER" +#endif + +// Definition of the targeted architecture and basic data types + +#define TARGET_AMD64 1 +#define TARGET_x86 2 +#define TARGET_ARM 3 + +#if defined(_AMD64_) +#define TARGET TARGET_AMD64 +#elif defined(_X86_) +#define TARGET TARGET_x86 +#elif defined(_ARM_) +#define TARGET TARGET_ARM +#else +#error-- "Unsupported ARCHITECTURE" +#endif + +#if defined(WINDOWS) +#define ALIGN_HEADER(N) __declspec(align(N)) +#define ALIGN_FOOTER(N) +#else +#define ALIGN_HEADER(N) +#define ALIGN_FOOTER(N) __attribute__((aligned(N))) +#endif + +// Selecting implementation: fast, generic or reference +#if defined(_FAST_) // The "fast" implementation requires support for AVX2 and AES_NI instructions +#define USE_AVX2 +#define AES_ENABLE_NI +#define USE_FAST +#elif defined(_FAST_GENERIC_) +#define USE_FAST_GENERIC +#elif defined(_REFERENCE_) +#define USE_REFERENCE +#else +#error-- unsupported implementation +#endif + +// Defining method for generating matrix A +#if defined(_AES128_FOR_A_) +#define USE_AES128_FOR_A +#elif defined(_CSHAKE128_FOR_A_) +#define USE_CSHAKE128_FOR_A +#else + ##error -- missing method for generating matrix A +#endif + +// Selecting use of OpenSSL's AES functions +#if defined(_USE_OPENSSL_) +#define USE_OPENSSL +#endif + +#endif diff --git a/src/kem/frodokem/frodo640_aes.c b/src/kem/frodokem/frodo640_aes.c new file mode 100644 index 000000000..e9bded64a --- /dev/null +++ b/src/kem/frodokem/frodo640_aes.c @@ -0,0 +1,20 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: functions for FrodoKEM-640 +* Instantiates "frodo_macrify.c" with the necessary matrix arithmetic functions +*********************************************************************************************/ + +#include "frodo640_params.h" +#define _AES128_FOR_A_ + +// Selecting cSHAKE XOF function for the KEM and noise sampling +#define cshake OQS_SHA3_cshake128_simple + +#define crypto_kem_keypair OQS_KEM_frodokem_640_aes_keypair +#define crypto_kem_enc OQS_KEM_frodokem_640_aes_encaps +#define crypto_kem_dec OQS_KEM_frodokem_640_aes_decaps + +#include "frodo_macrify.h" +#include "kem.c" +#include "frodo_macrify.c" diff --git a/src/kem/frodokem/frodo640_cshake.c b/src/kem/frodokem/frodo640_cshake.c new file mode 100644 index 000000000..7956088cd --- /dev/null +++ b/src/kem/frodokem/frodo640_cshake.c @@ -0,0 +1,20 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: functions for FrodoKEM-640 +* Instantiates "frodo_macrify.c" with the necessary matrix arithmetic functions +*********************************************************************************************/ + +#include "frodo640_params.h" +#define _CSHAKE128_FOR_A_ + +// Selecting cSHAKE XOF function for the KEM and noise sampling +#define cshake OQS_SHA3_cshake128_simple + +#define crypto_kem_keypair OQS_KEM_frodokem_640_cshake_keypair +#define crypto_kem_enc OQS_KEM_frodokem_640_cshake_encaps +#define crypto_kem_dec OQS_KEM_frodokem_640_cshake_decaps + +#include "frodo_macrify.h" +#include "kem.c" +#include "frodo_macrify.c" diff --git a/src/kem/frodokem/frodo640_params.h b/src/kem/frodokem/frodo640_params.h new file mode 100644 index 000000000..1499b1981 --- /dev/null +++ b/src/kem/frodokem/frodo640_params.h @@ -0,0 +1,34 @@ +#include + +#define CRYPTO_SECRETKEYBYTES 19872 // sizeof(s) + CRYPTO_PUBLICKEYBYTES + 2*PARAMS_N*PARAMS_NBAR +#define CRYPTO_PUBLICKEYBYTES 9616 // sizeof(seed_A) + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 +#define CRYPTO_BYTES 16 +#define CRYPTO_CIPHERTEXTBYTES 9736 // (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + (PARAMS_LOGQ*PARAMS_NBAR*PARAMS_NBAR)/8 + CRYPTO_BYTES + +#define PARAMS_N 640 +#define PARAMS_NBAR 8 +#define PARAMS_LOGQ 15 +#define PARAMS_Q (1 << PARAMS_LOGQ) +#define PARAMS_EXTRACTED_BITS 2 +#define PARAMS_STRIPE_STEP 8 +#define PARAMS_PARALLEL 4 +#define BYTES_SEED_A 16 +#define BYTES_MU (PARAMS_EXTRACTED_BITS * PARAMS_NBAR * PARAMS_NBAR) / 8 + +// CDF table +static uint16_t CDF_TABLE[12] = {4727, 13584, 20864, 26113, 29434, 31278, 32176, 32560, 32704, 32751, 32764, 32767}; +static uint16_t CDF_TABLE_LEN = 12; + +#if defined(_WIN32) +#define WINDOWS +#else +#define NIX +#endif + +#if defined(__amd64) || defined(__x86_64) +#define _AMD64_ +#elif defined(__i386) +#define _X86_ +#endif + +#define _FAST_GENERIC_ diff --git a/src/kem/frodokem/frodo976_aes.c b/src/kem/frodokem/frodo976_aes.c new file mode 100644 index 000000000..280eba239 --- /dev/null +++ b/src/kem/frodokem/frodo976_aes.c @@ -0,0 +1,20 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: functions for FrodoKEM-976 +* Instantiates "frodo_macrify.c" with the necessary matrix arithmetic functions +*********************************************************************************************/ + +#include "frodo976_params.h" +#define _AES128_FOR_A_ + +// Selecting cSHAKE XOF function for the KEM and noise sampling +#define cshake OQS_SHA3_cshake256_simple + +#define crypto_kem_keypair OQS_KEM_frodokem_976_aes_keypair +#define crypto_kem_enc OQS_KEM_frodokem_976_aes_encaps +#define crypto_kem_dec OQS_KEM_frodokem_976_aes_decaps + +#include "frodo_macrify.h" +#include "kem.c" +#include "frodo_macrify.c" diff --git a/src/kem/frodokem/frodo976_cshake.c b/src/kem/frodokem/frodo976_cshake.c new file mode 100644 index 000000000..5176359bc --- /dev/null +++ b/src/kem/frodokem/frodo976_cshake.c @@ -0,0 +1,20 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: functions for FrodoKEM-976 +* Instantiates "frodo_macrify.c" with the necessary matrix arithmetic functions +*********************************************************************************************/ + +#include "frodo976_params.h" +#define _CSHAKE128_FOR_A_ + +// Selecting cSHAKE XOF function for the KEM and noise sampling +#define cshake OQS_SHA3_cshake256_simple + +#define crypto_kem_keypair OQS_KEM_frodokem_976_cshake_keypair +#define crypto_kem_enc OQS_KEM_frodokem_976_cshake_encaps +#define crypto_kem_dec OQS_KEM_frodokem_976_cshake_decaps + +#include "frodo_macrify.h" +#include "kem.c" +#include "frodo_macrify.c" diff --git a/src/kem/frodokem/frodo976_params.h b/src/kem/frodokem/frodo976_params.h new file mode 100644 index 000000000..2f8f911e3 --- /dev/null +++ b/src/kem/frodokem/frodo976_params.h @@ -0,0 +1,34 @@ +#include + +#define CRYPTO_SECRETKEYBYTES 31272 // sizeof(s) + CRYPTO_PUBLICKEYBYTES + 2*PARAMS_N*PARAMS_NBAR +#define CRYPTO_PUBLICKEYBYTES 15632 // sizeof(seed_A) + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 +#define CRYPTO_BYTES 24 +#define CRYPTO_CIPHERTEXTBYTES 15768 // (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + (PARAMS_LOGQ*PARAMS_NBAR*PARAMS_NBAR)/8 + CRYPTO_BYTES + +#define PARAMS_N 976 +#define PARAMS_NBAR 8 +#define PARAMS_LOGQ 16 +#define PARAMS_Q (1 << PARAMS_LOGQ) +#define PARAMS_EXTRACTED_BITS 3 +#define PARAMS_STRIPE_STEP 8 +#define PARAMS_PARALLEL 4 +#define BYTES_SEED_A 16 +#define BYTES_MU (PARAMS_EXTRACTED_BITS * PARAMS_NBAR * PARAMS_NBAR) / 8 + +// CDF table +static uint16_t CDF_TABLE[11] = {5638, 15915, 23689, 28571, 31116, 32217, 32613, 32731, 32760, 32766, 32767}; +static uint16_t CDF_TABLE_LEN = 11; + +#if defined(_WIN32) +#define WINDOWS +#else +#define NIX +#endif + +#if defined(__amd64) || defined(__x86_64) +#define _AMD64_ +#elif defined(__i386) +#define _X86_ +#endif + +#define _FAST_GENERIC_ diff --git a/src/kem/frodokem/frodo_macrify.c b/src/kem/frodokem/frodo_macrify.c new file mode 100644 index 000000000..705672131 --- /dev/null +++ b/src/kem/frodokem/frodo_macrify.c @@ -0,0 +1,342 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: matrix arithmetic functions used by the KEM +*********************************************************************************************/ + +#import + +#if defined(USE_AVX2) +#include +#endif + +static int frodo_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) { // Generate-and-multiply: generate matrix A (N x N) row-wise, multiply by s on the right. + // Inputs: s, e (N x N_BAR) + // Output: out = A*s + e (N x N_BAR) + int i, j, k; + ALIGN_HEADER(32) + int16_t a_row[4 * PARAMS_N] ALIGN_FOOTER(32) = {0}; + + for (i = 0; i < (PARAMS_N * PARAMS_NBAR); i += 2) { + *((uint32_t *) &out[i]) = *((uint32_t *) &e[i]); + } + +#if defined(USE_AES128_FOR_A) + int16_t a_row_temp[4 * PARAMS_N] = {0}; // Take four lines of A at once + void *aes_key_schedule = NULL; + OQS_AES128_load_schedule(seed_A, &aes_key_schedule, 1); + + for (j = 0; j < PARAMS_N; j += PARAMS_STRIPE_STEP) { + a_row_temp[j + 1 + 0 * PARAMS_N] = j; // Loading values in the little-endian order + a_row_temp[j + 1 + 1 * PARAMS_N] = j; + a_row_temp[j + 1 + 2 * PARAMS_N] = j; + a_row_temp[j + 1 + 3 * PARAMS_N] = j; + } + + for (i = 0; i < PARAMS_N; i += 4) { + for (j = 0; j < PARAMS_N; j += PARAMS_STRIPE_STEP) { // Go through A, four rows at a time + a_row_temp[j + 0 * PARAMS_N] = i + 0; // Loading values in the little-endian order + a_row_temp[j + 1 * PARAMS_N] = i + 1; + a_row_temp[j + 2 * PARAMS_N] = i + 2; + a_row_temp[j + 3 * PARAMS_N] = i + 3; + } + + OQS_AES128_ECB_enc_sch((uint8_t *) a_row_temp, 4 * PARAMS_N * sizeof(int16_t), aes_key_schedule, (uint8_t *) a_row); +#elif defined(USE_CSHAKE128_FOR_A) +#if defined(WINDOWS) | !defined(USE_AVX2) + for (i = 0; i < PARAMS_N; i += 4) { + OQS_SHA3_cshake128_simple((unsigned char *) (a_row + 0 * PARAMS_N), (unsigned long long) (2 * PARAMS_N), (uint16_t)(256 + i + 0), seed_A, (unsigned long long) BYTES_SEED_A); + OQS_SHA3_cshake128_simple((unsigned char *) (a_row + 1 * PARAMS_N), (unsigned long long) (2 * PARAMS_N), (uint16_t)(256 + i + 1), seed_A, (unsigned long long) BYTES_SEED_A); + OQS_SHA3_cshake128_simple((unsigned char *) (a_row + 2 * PARAMS_N), (unsigned long long) (2 * PARAMS_N), (uint16_t)(256 + i + 2), seed_A, (unsigned long long) BYTES_SEED_A); + OQS_SHA3_cshake128_simple((unsigned char *) (a_row + 3 * PARAMS_N), (unsigned long long) (2 * PARAMS_N), (uint16_t)(256 + i + 3), seed_A, (unsigned long long) BYTES_SEED_A); +#else + for (i = 0; i < PARAMS_N; i += 4) { + cshake128_simple4x((unsigned char *) (a_row), (unsigned char *) (a_row + PARAMS_N), (unsigned char *) (a_row + 2 * PARAMS_N), (unsigned char *) (a_row + 3 * PARAMS_N), + (unsigned long long) (2 * PARAMS_N), (uint16_t)(256 + i), (uint16_t)(256 + i + 1), (uint16_t)(256 + i + 2), (uint16_t)(256 + i + 3), seed_A, (unsigned long long) BYTES_SEED_A); +#endif +#endif + + for (k = 0; k < PARAMS_NBAR; k++) { + uint16_t sum[4] = {0}; + for (j = 0; j < PARAMS_N; j++) { // Matrix-vector multiplication + uint16_t sp = s[k * PARAMS_N + j]; + sum[0] += a_row[0 * PARAMS_N + j] * sp; // Go through four lines with same s + sum[1] += a_row[1 * PARAMS_N + j] * sp; + sum[2] += a_row[2 * PARAMS_N + j] * sp; + sum[3] += a_row[3 * PARAMS_N + j] * sp; + } + out[(i + 0) * PARAMS_NBAR + k] += sum[0]; + out[(i + 2) * PARAMS_NBAR + k] += sum[2]; + out[(i + 1) * PARAMS_NBAR + k] += sum[1]; + out[(i + 3) * PARAMS_NBAR + k] += sum[3]; + } + } + +#if defined(USE_AES128_FOR_A) + OQS_AES128_free_schedule(aes_key_schedule); +#endif + return 1; +} + +static int frodo_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) { // Generate-and-multiply: generate matrix A (N x N) column-wise, multiply by s' on the left. + // Inputs: s', e' (N_BAR x N) + // Output: out = s'*A + e' (N_BAR x N) + int i, j, kk; + + for (i = 0; i < (PARAMS_N * PARAMS_NBAR); i += 2) { + *((uint32_t *) &out[i]) = *((uint32_t *) &e[i]); + } + +#if defined(USE_AES128_FOR_A) + int k; + uint16_t a_cols[PARAMS_N * PARAMS_STRIPE_STEP] = {0}; + ALIGN_HEADER(32) + uint16_t a_cols_t[PARAMS_N * PARAMS_STRIPE_STEP] ALIGN_FOOTER(32) = {0}; + uint16_t a_cols_temp[PARAMS_N * PARAMS_STRIPE_STEP] = {0}; + void *aes_key_schedule = NULL; + OQS_AES128_load_schedule(seed_A, &aes_key_schedule, 1); + + for (i = 0, j = 0; i < PARAMS_N; i++, j += PARAMS_STRIPE_STEP) { + a_cols_temp[j] = i; // Loading values in the little-endian order + } + + for (kk = 0; kk < PARAMS_N; kk += PARAMS_STRIPE_STEP) { // Go through A's columns, 8 (== PARAMS_STRIPE_STEP) columns at a time. + for (i = 0; i < (PARAMS_N * PARAMS_STRIPE_STEP); i += PARAMS_STRIPE_STEP) { + a_cols_temp[i + 1] = kk; // Loading values in the little-endian order + } + + OQS_AES128_ECB_enc_sch((uint8_t *) a_cols_temp, PARAMS_N * PARAMS_STRIPE_STEP * sizeof(int16_t), aes_key_schedule, (uint8_t *) a_cols); + + for (i = 0; i < PARAMS_N; i++) { // Transpose a_cols to have access to it in the column-major order. + for (k = 0; k < PARAMS_STRIPE_STEP; k++) { + a_cols_t[k * PARAMS_N + i] = a_cols[i * PARAMS_STRIPE_STEP + k]; + } + } + +#if !defined(USE_AVX2) + for (i = 0; i < PARAMS_NBAR; i++) { + for (k = 0; k < PARAMS_STRIPE_STEP; k += PARAMS_PARALLEL) { + uint16_t sum[PARAMS_PARALLEL] = {0}; + for (j = 0; j < PARAMS_N; j++) { // Matrix-vector multiplication + uint16_t sp = s[i * PARAMS_N + j]; + sum[0] += sp * a_cols_t[(k + 0) * PARAMS_N + j]; + sum[1] += sp * a_cols_t[(k + 1) * PARAMS_N + j]; + sum[2] += sp * a_cols_t[(k + 2) * PARAMS_N + j]; + sum[3] += sp * a_cols_t[(k + 3) * PARAMS_N + j]; + } + out[i * PARAMS_N + kk + k + 0] += sum[0]; + out[i * PARAMS_N + kk + k + 2] += sum[2]; + out[i * PARAMS_N + kk + k + 1] += sum[1]; + out[i * PARAMS_N + kk + k + 3] += sum[3]; + } + } + } +#else // Using vector intrinsics + for (i = 0; i < PARAMS_NBAR; i++) { + for (k = 0; k < PARAMS_STRIPE_STEP; k += PARAMS_PARALLEL) { + ALIGN_HEADER(32) + uint32_t sum[8 * PARAMS_PARALLEL] ALIGN_FOOTER(32); + __m256i a[PARAMS_PARALLEL], b, acc[PARAMS_PARALLEL]; + acc[0] = _mm256_setzero_si256(); + acc[1] = _mm256_setzero_si256(); + acc[2] = _mm256_setzero_si256(); + acc[3] = _mm256_setzero_si256(); + for (j = 0; j < PARAMS_N; j += 16) { // Matrix-vector multiplication + b = _mm256_load_si256((__m256i *) &s[i * PARAMS_N + j]); + a[0] = _mm256_load_si256((__m256i *) &a_cols_t[(k + 0) * PARAMS_N + j]); + a[0] = _mm256_madd_epi16(a[0], b); + acc[0] = _mm256_add_epi16(a[0], acc[0]); + a[1] = _mm256_load_si256((__m256i *) &a_cols_t[(k + 1) * PARAMS_N + j]); + a[1] = _mm256_madd_epi16(a[1], b); + acc[1] = _mm256_add_epi16(a[1], acc[1]); + a[2] = _mm256_load_si256((__m256i *) &a_cols_t[(k + 2) * PARAMS_N + j]); + a[2] = _mm256_madd_epi16(a[2], b); + acc[2] = _mm256_add_epi16(a[2], acc[2]); + a[3] = _mm256_load_si256((__m256i *) &a_cols_t[(k + 3) * PARAMS_N + j]); + a[3] = _mm256_madd_epi16(a[3], b); + acc[3] = _mm256_add_epi16(a[3], acc[3]); + } + _mm256_store_si256((__m256i *) (sum + (8 * 0)), acc[0]); + out[i * PARAMS_N + kk + k + 0] += sum[8 * 0 + 0] + sum[8 * 0 + 1] + sum[8 * 0 + 2] + sum[8 * 0 + 3] + sum[8 * 0 + 4] + sum[8 * 0 + 5] + sum[8 * 0 + 6] + sum[8 * 0 + 7]; + _mm256_store_si256((__m256i *) (sum + (8 * 1)), acc[1]); + out[i * PARAMS_N + kk + k + 1] += sum[8 * 1 + 0] + sum[8 * 1 + 1] + sum[8 * 1 + 2] + sum[8 * 1 + 3] + sum[8 * 1 + 4] + sum[8 * 1 + 5] + sum[8 * 1 + 6] + sum[8 * 1 + 7]; + _mm256_store_si256((__m256i *) (sum + (8 * 2)), acc[2]); + out[i * PARAMS_N + kk + k + 2] += sum[8 * 2 + 0] + sum[8 * 2 + 1] + sum[8 * 2 + 2] + sum[8 * 2 + 3] + sum[8 * 2 + 4] + sum[8 * 2 + 5] + sum[8 * 2 + 6] + sum[8 * 2 + 7]; + _mm256_store_si256((__m256i *) (sum + (8 * 3)), acc[3]); + out[i * PARAMS_N + kk + k + 3] += sum[8 * 3 + 0] + sum[8 * 3 + 1] + sum[8 * 3 + 2] + sum[8 * 3 + 3] + sum[8 * 3 + 4] + sum[8 * 3 + 5] + sum[8 * 3 + 6] + sum[8 * 3 + 7]; + } + } + } +#endif + OQS_AES128_free_schedule(aes_key_schedule); + +#elif defined(USE_CSHAKE128_FOR_A) // cSHAKE128 + int t = 0; + ALIGN_HEADER(32) + uint16_t a_cols[4 * PARAMS_N] ALIGN_FOOTER(32) = {0}; + +#if defined(WINDOWS) | !defined(USE_AVX2) + int k; + for (kk = 0; kk < PARAMS_N; kk += 4) { + OQS_SHA3_cshake128_simple((unsigned char *) (a_cols + 0 * PARAMS_N), (unsigned long long) (2 * PARAMS_N), (uint16_t)(256 + kk + 0), seed_A, (unsigned long long) BYTES_SEED_A); + OQS_SHA3_cshake128_simple((unsigned char *) (a_cols + 1 * PARAMS_N), (unsigned long long) (2 * PARAMS_N), (uint16_t)(256 + kk + 1), seed_A, (unsigned long long) BYTES_SEED_A); + OQS_SHA3_cshake128_simple((unsigned char *) (a_cols + 2 * PARAMS_N), (unsigned long long) (2 * PARAMS_N), (uint16_t)(256 + kk + 2), seed_A, (unsigned long long) BYTES_SEED_A); + OQS_SHA3_cshake128_simple((unsigned char *) (a_cols + 3 * PARAMS_N), (unsigned long long) (2 * PARAMS_N), (uint16_t)(256 + kk + 3), seed_A, (unsigned long long) BYTES_SEED_A); + + for (i = 0; i < PARAMS_NBAR; i++) { + uint16_t sum[PARAMS_N] = {0}; + for (j = 0; j < 4; j++) { + uint16_t sp = s[i * PARAMS_N + kk + j]; + for (k = 0; k < PARAMS_N; k++) { // Matrix-vector multiplication + sum[k] += sp * a_cols[(t + j) * PARAMS_N + k]; + } + } + for (k = 0; k < PARAMS_N; k++) { + out[i * PARAMS_N + k] += sum[k]; + } + } + } +#else // Using vector intrinsics + for (kk = 0; kk < PARAMS_N; kk += 4) { + cshake128_simple4x((unsigned char *) (a_cols), (unsigned char *) (a_cols + PARAMS_N), (unsigned char *) (a_cols + 2 * PARAMS_N), (unsigned char *) (a_cols + 3 * PARAMS_N), + (unsigned long long) (2 * PARAMS_N), (uint16_t)(256 + kk), (uint16_t)(256 + kk + 1), (uint16_t)(256 + kk + 2), (uint16_t)(256 + kk + 3), seed_A, (unsigned long long) BYTES_SEED_A); + + for (i = 0; i < PARAMS_NBAR; i++) { + __m256i a, b0, b1, b2, b3, acc[PARAMS_N / 16]; + b0 = _mm256_set1_epi16(s[i * PARAMS_N + kk + 0]); + b1 = _mm256_set1_epi16(s[i * PARAMS_N + kk + 1]); + b2 = _mm256_set1_epi16(s[i * PARAMS_N + kk + 2]); + b3 = _mm256_set1_epi16(s[i * PARAMS_N + kk + 3]); + for (j = 0; j < PARAMS_N; j += 16) { // Matrix-vector multiplication + acc[j / 16] = _mm256_load_si256((__m256i *) &out[i * PARAMS_N + j]); + a = _mm256_load_si256((__m256i *) &a_cols[(t + 0) * PARAMS_N + j]); + a = _mm256_mullo_epi16(a, b0); + acc[j / 16] = _mm256_add_epi16(a, acc[j / 16]); + a = _mm256_load_si256((__m256i *) &a_cols[(t + 1) * PARAMS_N + j]); + a = _mm256_mullo_epi16(a, b1); + acc[j / 16] = _mm256_add_epi16(a, acc[j / 16]); + a = _mm256_load_si256((__m256i *) &a_cols[(t + 2) * PARAMS_N + j]); + a = _mm256_mullo_epi16(a, b2); + acc[j / 16] = _mm256_add_epi16(a, acc[j / 16]); + a = _mm256_load_si256((__m256i *) &a_cols[(t + 3) * PARAMS_N + j]); + a = _mm256_mullo_epi16(a, b3); + acc[j / 16] = _mm256_add_epi16(a, acc[j / 16]); + } + + for (j = 0; j < PARAMS_N / 16; j++) { + _mm256_store_si256((__m256i *) &out[i * PARAMS_N + 16 * j], acc[j]); + } + } + } +#endif +#endif + + return 1; +} + +static void frodo_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s) { // Multiply by s on the right + // Inputs: b (N_BAR x N), s (N x N_BAR) + // Output: out = b*s (N_BAR x N_BAR) + int i, j, k; + + for (i = 0; i < PARAMS_NBAR; i++) { + for (j = 0; j < PARAMS_NBAR; j++) { + out[i * PARAMS_NBAR + j] = 0; + for (k = 0; k < PARAMS_N; k++) { + out[i * PARAMS_NBAR + j] += b[i * PARAMS_N + k] * s[j * PARAMS_N + k]; + } + out[i * PARAMS_NBAR + j] = (uint32_t)(out[i * PARAMS_NBAR + j]) & ((1 << PARAMS_LOGQ) - 1); + } + } +} + +static void frodo_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e) { // Multiply by s on the left + // Inputs: b (N x N_BAR), s (N_BAR x N), e (N_BAR x N_BAR) + // Output: out = s*b + e (N_BAR x N_BAR) + int i, j, k; + + for (k = 0; k < PARAMS_NBAR; k++) { + for (i = 0; i < PARAMS_NBAR; i++) { + out[k * PARAMS_NBAR + i] = e[k * PARAMS_NBAR + i]; + for (j = 0; j < PARAMS_N; j++) { + out[k * PARAMS_NBAR + i] += s[k * PARAMS_N + j] * b[j * PARAMS_NBAR + i]; + } + out[k * PARAMS_NBAR + i] = (uint32_t)(out[k * PARAMS_NBAR + i]) & ((1 << PARAMS_LOGQ) - 1); + } + } +} + +static void frodo_add(uint16_t *out, const uint16_t *a, const uint16_t *b) { // Add a and b + // Inputs: a, b (N_BAR x N_BAR) + // Output: c = a + b + + for (int i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) { + out[i] = (a[i] + b[i]) & ((1 << PARAMS_LOGQ) - 1); + } +} + +static void frodo_sub(uint16_t *out, const uint16_t *a, const uint16_t *b) { // Subtract a and b + // Inputs: a, b (N_BAR x N_BAR) + // Output: c = a - b + + for (int i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) { + out[i] = (a[i] - b[i]) & ((1 << PARAMS_LOGQ) - 1); + } +} + +static void frodo_key_encode(uint16_t *out, const uint16_t *in) { // Encoding + unsigned int i, j, npieces_word = 8; + unsigned int nwords = (PARAMS_NBAR * PARAMS_NBAR) / 8; + uint64_t temp, mask = ((uint64_t) 1 << PARAMS_EXTRACTED_BITS) - 1; + uint16_t *pos = out; + + for (i = 0; i < nwords; i++) { + temp = 0; + for (j = 0; j < PARAMS_EXTRACTED_BITS; j++) + temp |= ((uint64_t)((uint8_t *) in)[i * PARAMS_EXTRACTED_BITS + j]) << (8 * j); + for (j = 0; j < npieces_word; j++) { + *pos = (uint16_t)((temp & mask) << (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS)); + temp >>= PARAMS_EXTRACTED_BITS; + pos++; + } + } +} + +static void frodo_key_decode(uint16_t *out, const uint16_t *in) { // Decoding + unsigned int i, j, index = 0, npieces_word = 8; + unsigned int nwords = (PARAMS_NBAR * PARAMS_NBAR) / 8; + uint16_t temp, maskex = ((uint16_t) 1 << PARAMS_EXTRACTED_BITS) - 1, maskq = ((uint16_t) 1 << PARAMS_LOGQ) - 1; + uint8_t *pos = (uint8_t *) out; + uint64_t templong; + + for (i = 0; i < nwords; i++) { + templong = 0; + for (j = 0; j < npieces_word; j++) { // temp = floor(in*2^{-11}+0.5) + temp = ((in[index] & maskq) + (1 << (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS - 1))) >> (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS); + templong |= ((uint64_t)(temp & maskex)) << (PARAMS_EXTRACTED_BITS * j); + index++; + } + for (j = 0; j < PARAMS_EXTRACTED_BITS; j++) + pos[i * PARAMS_EXTRACTED_BITS + j] = (templong >> (8 * j)) & 0xFF; + } +} + +static void frodo_sample_n(uint16_t *s, const size_t n) { // Fills vector s with n samples from the noise distribution which requires 16 bits to sample. + // The distribution is specified by its CDF. + // Input: pseudo-random values (2*n bytes) passed in s. The input is overwritten by the output. + unsigned int i, j; + + for (i = 0; i < n; ++i) { + uint8_t sample = 0; + uint16_t prnd = s[i] >> 1; // Drop the least significant bit + uint8_t sign = s[i] & 0x1; // Pick the least significant bit + + // No need to compare with the last value. + for (j = 0; j < (unsigned int) (CDF_TABLE_LEN - 1); j++) { + // Constant time comparison: 1 if CDF_TABLE[j] < s, 0 otherwise. Uses the fact that CDF_TABLE[j] and s fit in 15 bits. + sample += (uint16_t)(CDF_TABLE[j] - prnd) >> 15; + } + // Assuming that sign is either 0 or 1, flips sample iff sign = 1 + s[i] = ((-sign) ^ sample) + sign; + } +} diff --git a/src/kem/frodokem/frodo_macrify.h b/src/kem/frodokem/frodo_macrify.h new file mode 100644 index 000000000..cca3d63b5 --- /dev/null +++ b/src/kem/frodokem/frodo_macrify.h @@ -0,0 +1,28 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: header for internal functions +*********************************************************************************************/ + +#ifndef _FRODO_MACRIFY_H_ +#define _FRODO_MACRIFY_H_ + +#include +#include +#include "config.h" + +void oqs_kem_frodokem_pack(unsigned char *out, const size_t outlen, const uint16_t *in, const size_t inlen, const unsigned char lsb); +void oqs_kem_frodokem_unpack(uint16_t *out, const size_t outlen, const unsigned char *in, const size_t inlen, const unsigned char lsb); +static void frodo_sample_n(uint16_t *s, const size_t n); + +static int frodo_mul_add_as_plus_e(uint16_t *b, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A); +static int frodo_mul_add_sa_plus_e(uint16_t *b, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A); +static void frodo_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e); +static void frodo_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s); + +static void frodo_add(uint16_t *out, const uint16_t *a, const uint16_t *b); +static void frodo_sub(uint16_t *out, const uint16_t *a, const uint16_t *b); +static void frodo_key_encode(uint16_t *out, const uint16_t *in); +static void frodo_key_decode(uint16_t *out, const uint16_t *in); + +#endif diff --git a/src/kem/frodokem/kem.c b/src/kem/frodokem/kem.c new file mode 100644 index 000000000..b9afe77a4 --- /dev/null +++ b/src/kem/frodokem/kem.c @@ -0,0 +1,158 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: Key Encapsulation Mechanism (KEM) based on Frodo +*********************************************************************************************/ + +#include +#include + +#include + +int crypto_kem_keypair(unsigned char *pk, unsigned char *sk) { // Frodo-KEM's key generation + // Outputs: public key pk ( BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 bytes) + // secret key sk (CRYPTO_BYTES + BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + 2*PARAMS_N*PARAMS_NBAR bytes) + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}, S[2 * PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t *E = (uint16_t *) &S[PARAMS_N * PARAMS_NBAR]; + uint8_t *randomness = sk; + + // Generate the secret value s, the seed for S and E, and the seed for A. Add seed_A to the public key + OQS_randombytes(randomness, 2 * CRYPTO_BYTES + BYTES_SEED_A); + cshake(pk, BYTES_SEED_A, 0, randomness + 2 * CRYPTO_BYTES, (unsigned long long) (BYTES_SEED_A)); + + // Generate S and E, and compute B = A*S + E. Generate A on-the-fly + cshake((uint8_t *) S, 2 * PARAMS_N * PARAMS_NBAR * sizeof(uint16_t), 1, randomness + CRYPTO_BYTES, (unsigned long long) (CRYPTO_BYTES)); + frodo_sample_n(S, PARAMS_N * PARAMS_NBAR); + frodo_sample_n(E, PARAMS_N * PARAMS_NBAR); + frodo_mul_add_as_plus_e(B, S, E, pk); + + // Encode the second part of the public key + oqs_kem_frodokem_pack(pk + BYTES_SEED_A, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, B, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ); + + // Add pk and S to the secret key + memcpy(&sk[CRYPTO_BYTES], pk, CRYPTO_PUBLICKEYBYTES); + memcpy(&sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES], S, 2 * PARAMS_N * PARAMS_NBAR); + + // Cleanup: + OQS_MEM_cleanse((void *) S, PARAMS_N * PARAMS_NBAR / 2); + OQS_MEM_cleanse((void *) E, PARAMS_N * PARAMS_NBAR / 2); + return 0; +} + +int crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk) { // Frodo-KEM's key encapsulation + unsigned char randomness[BYTES_MU]; + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}, V[PARAMS_NBAR * PARAMS_NBAR] = {0}, C[PARAMS_NBAR * PARAMS_NBAR] = {0}; + ALIGN_HEADER(32) + uint16_t Bp[PARAMS_N * PARAMS_NBAR] ALIGN_FOOTER(32) = {0}; + ALIGN_HEADER(32) + uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR] ALIGN_FOOTER(32) = {0}; + uint16_t *Ep = (uint16_t *) &Sp[PARAMS_N * PARAMS_NBAR]; + uint16_t *Epp = (uint16_t *) &Sp[2 * PARAMS_N * PARAMS_NBAR]; + uint8_t temp[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES], G[3 * CRYPTO_BYTES]; + + // temp <- pk||mu, and generate (r||KK||d) = G(pk||mu) + OQS_randombytes(randomness, BYTES_MU); + memcpy(temp, pk, CRYPTO_PUBLICKEYBYTES); + memcpy(&temp[CRYPTO_PUBLICKEYBYTES], randomness, BYTES_MU); + cshake(G, 3 * CRYPTO_BYTES, 2, temp, (unsigned long long) (CRYPTO_PUBLICKEYBYTES + BYTES_MU)); + + // Generate Sp and Ep, and compute Bp = Sp*A + Ep. Generate A on-the-fly + cshake((uint8_t *) Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), 3, G, (unsigned long long) (CRYPTO_BYTES)); + frodo_sample_n(Sp, PARAMS_N * PARAMS_NBAR); + frodo_sample_n(Ep, PARAMS_N * PARAMS_NBAR); + frodo_mul_add_sa_plus_e(Bp, Sp, Ep, temp); + oqs_kem_frodokem_pack(ct, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, Bp, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ); + + // Generate Epp, and compute V = Sp*B + Epp + frodo_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR); + oqs_kem_frodokem_unpack(B, PARAMS_N * PARAMS_NBAR, temp + BYTES_SEED_A, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ); + frodo_mul_add_sb_plus_e(V, B, Sp, Epp); + + // Encode mu, and compute C = V + enc(mu) (mode q) + frodo_key_encode(C, (uint16_t *) (temp + CRYPTO_PUBLICKEYBYTES)); + frodo_add(C, V, C); + oqs_kem_frodokem_pack(ct + (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, C, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOGQ); + + // Compute ss = F(ct||KK||d) and the ciphertext CT = ct||d + memcpy(temp, ct, CRYPTO_CIPHERTEXTBYTES - CRYPTO_BYTES); + memcpy(&temp[CRYPTO_CIPHERTEXTBYTES - CRYPTO_BYTES], &G[CRYPTO_BYTES], 2 * CRYPTO_BYTES); + cshake(ss, CRYPTO_BYTES, 4, temp, (unsigned long long) (CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES)); + memcpy(&ct[CRYPTO_CIPHERTEXTBYTES - CRYPTO_BYTES], &G[2 * CRYPTO_BYTES], CRYPTO_BYTES); + + // Cleanup: + OQS_MEM_cleanse((void *) Sp, PARAMS_N * PARAMS_NBAR / 2); + OQS_MEM_cleanse((void *) Ep, PARAMS_N * PARAMS_NBAR / 2); + OQS_MEM_cleanse((void *) Epp, PARAMS_NBAR * PARAMS_NBAR / 2); + OQS_MEM_cleanse((void *) V, PARAMS_NBAR * PARAMS_NBAR / 2); + OQS_MEM_cleanse((void *) G, CRYPTO_BYTES / 2); + OQS_MEM_cleanse((void *) (temp + CRYPTO_CIPHERTEXTBYTES - CRYPTO_BYTES), CRYPTO_BYTES / 2); + return 0; +} + +int crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk) { // Frodo-KEM's key decapsulation + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}, Bp[PARAMS_N * PARAMS_NBAR] = {0}, W[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0}, CC[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t *S = (uint16_t *) (sk + CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES); + ALIGN_HEADER(32) + uint16_t BBp[PARAMS_N * PARAMS_NBAR] ALIGN_FOOTER(32) = {0}; + ALIGN_HEADER(32) + uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR] ALIGN_FOOTER(32) = {0}; + uint16_t *Ep = (uint16_t *) &Sp[PARAMS_N * PARAMS_NBAR]; + uint16_t *Epp = (uint16_t *) &Sp[2 * PARAMS_N * PARAMS_NBAR]; + uint8_t temp[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES], G[3 * CRYPTO_BYTES], *seed_A = temp; + + // temp <- pk + memcpy(temp, &sk[CRYPTO_BYTES], CRYPTO_PUBLICKEYBYTES); + + // Compute W = C - Bp*S (mod q), and decode the randomness mu + oqs_kem_frodokem_unpack(Bp, PARAMS_N * PARAMS_NBAR, ct, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, PARAMS_LOGQ); + oqs_kem_frodokem_unpack(C, PARAMS_NBAR * PARAMS_NBAR, ct + (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, PARAMS_LOGQ); + frodo_mul_bs(W, Bp, S); + frodo_sub(W, C, W); + frodo_key_decode((uint16_t *) (temp + CRYPTO_PUBLICKEYBYTES), W); + + // Generate (r||KK||d) = G(pk||mu) + cshake(G, 3 * CRYPTO_BYTES, 2, temp, (unsigned long long) (CRYPTO_PUBLICKEYBYTES + BYTES_MU)); + + // Generate Sp and Ep, and compute BBp = Sp*A + Ep. Generate A on-the-fly + cshake((uint8_t *) Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), 3, G, (unsigned long long) (CRYPTO_BYTES)); + frodo_sample_n(Sp, PARAMS_N * PARAMS_NBAR); + frodo_sample_n(Ep, PARAMS_N * PARAMS_NBAR); + frodo_mul_add_sa_plus_e(BBp, Sp, Ep, seed_A); + + // Generate Epp, and compute W = Sp*B + Epp + frodo_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR); + oqs_kem_frodokem_unpack(B, PARAMS_N * PARAMS_NBAR, temp + BYTES_SEED_A, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ); + frodo_mul_add_sb_plus_e(W, B, Sp, Epp); + + // Encode mu, and compute CC = W + enc(mu) (mode q) + frodo_key_encode(CC, (uint16_t *) (temp + CRYPTO_PUBLICKEYBYTES)); + frodo_add(CC, W, CC); + + // temp <- ct + memcpy(temp, ct, CRYPTO_CIPHERTEXTBYTES - CRYPTO_BYTES); + + // Reducing BBp modulo q + for (int i = 0; i < PARAMS_N * PARAMS_NBAR; i++) + BBp[i] = BBp[i] & ((1 << PARAMS_LOGQ) - 1); + + // Is (dd == d & Bp == BBp & C == CC) = true + if (memcmp(G + 2 * CRYPTO_BYTES, ct + CRYPTO_CIPHERTEXTBYTES - CRYPTO_BYTES, CRYPTO_BYTES) == 0 && + memcmp(Bp, BBp, 2 * PARAMS_N * PARAMS_NBAR) == 0 && + memcmp(C, CC, 2 * PARAMS_NBAR * PARAMS_NBAR) == 0) { // Load (KK || d) to do ss = F(ct||KK||d) + memcpy(&temp[CRYPTO_CIPHERTEXTBYTES - CRYPTO_BYTES], &G[CRYPTO_BYTES], 2 * CRYPTO_BYTES); + } else { // Load (s || d) to do ss = F(ct||s||d) + memcpy(&temp[CRYPTO_CIPHERTEXTBYTES - CRYPTO_BYTES], sk, CRYPTO_BYTES); + memcpy(&temp[CRYPTO_CIPHERTEXTBYTES], &G[2 * CRYPTO_BYTES], CRYPTO_BYTES); + } + cshake(ss, CRYPTO_BYTES, 4, temp, (unsigned long long) (CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES)); + + // Cleanup: + OQS_MEM_cleanse((void *) Sp, PARAMS_N * PARAMS_NBAR / 2); + OQS_MEM_cleanse((void *) Ep, PARAMS_N * PARAMS_NBAR / 2); + OQS_MEM_cleanse((void *) Epp, PARAMS_NBAR * PARAMS_NBAR / 2); + OQS_MEM_cleanse((void *) W, PARAMS_NBAR * PARAMS_NBAR / 2); + OQS_MEM_cleanse((void *) G, CRYPTO_BYTES / 2); + OQS_MEM_cleanse((void *) (temp + CRYPTO_CIPHERTEXTBYTES - CRYPTO_BYTES), CRYPTO_BYTES / 2); + return 0; +} diff --git a/src/kem/frodokem/kem_frodokem.c b/src/kem/frodokem/kem_frodokem.c new file mode 100644 index 000000000..34e5d5f92 --- /dev/null +++ b/src/kem/frodokem/kem_frodokem.c @@ -0,0 +1,111 @@ +#include + +#include + +#ifdef OQS_ENABLE_KEM_frodokem_640_aes + +OQS_KEM *OQS_KEM_frodokem_640_aes_new() { + + OQS_KEM *kem = malloc(sizeof(OQS_KEM)); + if (kem == NULL) { + return NULL; + } + kem->method_name = OQS_KEM_alg_frodokem_640_aes; + + kem->claimed_nist_level = 1; + kem->ind_cca = true; + + kem->length_public_key = OQS_KEM_frodokem_640_aes_length_public_key; + kem->length_secret_key = OQS_KEM_frodokem_640_aes_length_secret_key; + kem->length_ciphertext = OQS_KEM_frodokem_640_aes_length_ciphertext; + kem->length_shared_secret = OQS_KEM_frodokem_640_aes_length_shared_secret; + + kem->keypair = OQS_KEM_frodokem_640_aes_keypair; + kem->encaps = OQS_KEM_frodokem_640_aes_encaps; + kem->decaps = OQS_KEM_frodokem_640_aes_decaps; + + return kem; +} + +#endif + +#ifdef OQS_ENABLE_KEM_frodokem_976_aes + +OQS_KEM *OQS_KEM_frodokem_976_aes_new() { + + OQS_KEM *kem = malloc(sizeof(OQS_KEM)); + if (kem == NULL) { + return NULL; + } + kem->method_name = OQS_KEM_alg_frodokem_976_aes; + + kem->claimed_nist_level = 3; + kem->ind_cca = true; + + kem->length_public_key = OQS_KEM_frodokem_976_aes_length_public_key; + kem->length_secret_key = OQS_KEM_frodokem_976_aes_length_secret_key; + kem->length_ciphertext = OQS_KEM_frodokem_976_aes_length_ciphertext; + kem->length_shared_secret = OQS_KEM_frodokem_976_aes_length_shared_secret; + + kem->keypair = OQS_KEM_frodokem_976_aes_keypair; + kem->encaps = OQS_KEM_frodokem_976_aes_encaps; + kem->decaps = OQS_KEM_frodokem_976_aes_decaps; + + return kem; +} + +#endif + +#ifdef OQS_ENABLE_KEM_frodokem_640_cshake + +OQS_KEM *OQS_KEM_frodokem_640_cshake_new() { + + OQS_KEM *kem = malloc(sizeof(OQS_KEM)); + if (kem == NULL) { + return NULL; + } + kem->method_name = OQS_KEM_alg_frodokem_640_cshake; + + kem->claimed_nist_level = 1; + kem->ind_cca = true; + + kem->length_public_key = OQS_KEM_frodokem_640_cshake_length_public_key; + kem->length_secret_key = OQS_KEM_frodokem_640_cshake_length_secret_key; + kem->length_ciphertext = OQS_KEM_frodokem_640_cshake_length_ciphertext; + kem->length_shared_secret = OQS_KEM_frodokem_640_cshake_length_shared_secret; + + kem->keypair = OQS_KEM_frodokem_640_cshake_keypair; + kem->encaps = OQS_KEM_frodokem_640_cshake_encaps; + kem->decaps = OQS_KEM_frodokem_640_cshake_decaps; + + return kem; +} + +#endif + +#ifdef OQS_ENABLE_KEM_frodokem_976_cshake + +OQS_KEM *OQS_KEM_frodokem_976_cshake_new() { + + OQS_KEM *kem = malloc(sizeof(OQS_KEM)); + if (kem == NULL) { + return NULL; + } + kem->method_name = OQS_KEM_alg_frodokem_976_cshake; + + kem->claimed_nist_level = 3; + kem->ind_cca = true; + + kem->length_public_key = OQS_KEM_frodokem_976_cshake_length_public_key; + kem->length_secret_key = OQS_KEM_frodokem_976_cshake_length_secret_key; + kem->length_ciphertext = OQS_KEM_frodokem_976_cshake_length_ciphertext; + kem->length_shared_secret = OQS_KEM_frodokem_976_cshake_length_shared_secret; + + kem->keypair = OQS_KEM_frodokem_976_cshake_keypair; + kem->encaps = OQS_KEM_frodokem_976_cshake_encaps; + kem->decaps = OQS_KEM_frodokem_976_cshake_decaps; + + return kem; +} + +#endif diff --git a/src/kem/frodokem/kem_frodokem.h b/src/kem/frodokem/kem_frodokem.h new file mode 100644 index 000000000..7d18d6e1c --- /dev/null +++ b/src/kem/frodokem/kem_frodokem.h @@ -0,0 +1,66 @@ +#ifndef __OQS_KEM_FRODOKEM_H +#define __OQS_KEM_FRODOKEM_H + +#include + +#ifdef OQS_ENABLE_KEM_frodokem_640_aes + +#define OQS_KEM_frodokem_640_aes_length_public_key 9616 +#define OQS_KEM_frodokem_640_aes_length_secret_key 19872 +#define OQS_KEM_frodokem_640_aes_length_ciphertext 9736 +#define OQS_KEM_frodokem_640_aes_length_shared_secret 16 + +OQS_KEM *OQS_KEM_frodokem_640_aes_new(); + +extern OQS_STATUS OQS_KEM_frodokem_640_aes_keypair(uint8_t *public_key, uint8_t *secret_key); +extern OQS_STATUS OQS_KEM_frodokem_640_aes_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key); +extern OQS_STATUS OQS_KEM_frodokem_640_aes_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key); + +#endif + +#ifdef OQS_ENABLE_KEM_frodokem_976_aes + +#define OQS_KEM_frodokem_976_aes_length_public_key 15632 +#define OQS_KEM_frodokem_976_aes_length_secret_key 31272 +#define OQS_KEM_frodokem_976_aes_length_ciphertext 15768 +#define OQS_KEM_frodokem_976_aes_length_shared_secret 24 + +OQS_KEM *OQS_KEM_frodokem_976_aes_new(); + +extern OQS_STATUS OQS_KEM_frodokem_976_aes_keypair(uint8_t *public_key, uint8_t *secret_key); +extern OQS_STATUS OQS_KEM_frodokem_976_aes_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key); +extern OQS_STATUS OQS_KEM_frodokem_976_aes_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key); + +#endif + +#ifdef OQS_ENABLE_KEM_frodokem_640_cshake + +#define OQS_KEM_frodokem_640_cshake_length_public_key 9616 +#define OQS_KEM_frodokem_640_cshake_length_secret_key 19872 +#define OQS_KEM_frodokem_640_cshake_length_ciphertext 9736 +#define OQS_KEM_frodokem_640_cshake_length_shared_secret 16 + +OQS_KEM *OQS_KEM_frodokem_640_cshake_new(); + +extern OQS_STATUS OQS_KEM_frodokem_640_cshake_keypair(uint8_t *public_key, uint8_t *secret_key); +extern OQS_STATUS OQS_KEM_frodokem_640_cshake_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key); +extern OQS_STATUS OQS_KEM_frodokem_640_cshake_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key); + +#endif + +#ifdef OQS_ENABLE_KEM_frodokem_976_cshake + +#define OQS_KEM_frodokem_976_cshake_length_public_key 15632 +#define OQS_KEM_frodokem_976_cshake_length_secret_key 31272 +#define OQS_KEM_frodokem_976_cshake_length_ciphertext 15768 +#define OQS_KEM_frodokem_976_cshake_length_shared_secret 24 + +OQS_KEM *OQS_KEM_frodokem_976_cshake_new(); + +extern OQS_STATUS OQS_KEM_frodokem_976_cshake_keypair(uint8_t *public_key, uint8_t *secret_key); +extern OQS_STATUS OQS_KEM_frodokem_976_cshake_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key); +extern OQS_STATUS OQS_KEM_frodokem_976_cshake_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key); + +#endif + +#endif diff --git a/src/kem/frodokem/util.c b/src/kem/frodokem/util.c new file mode 100644 index 000000000..d7b3f6111 --- /dev/null +++ b/src/kem/frodokem/util.c @@ -0,0 +1,104 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: additional functions for FrodoKEM +*********************************************************************************************/ + +#include +#include + +#define min(x, y) (((x) < (y)) ? (x) : (y)) + +void oqs_kem_frodokem_pack(unsigned char *out, const size_t outlen, const uint16_t *in, const size_t inlen, const unsigned char lsb) { // Pack the input uint16 vector into a char output vector, copying lsb bits from each input element. + // If inlen * lsb / 8 > outlen, only outlen * 8 bits are copied. + memset(out, 0, outlen); + + size_t i = 0; // whole bytes already filled in + size_t j = 0; // whole uint16_t already copied + uint16_t w = 0; // the leftover, not yet copied + unsigned char bits = 0; // the number of lsb in w + + while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) { + /* + in: | | |********|********| + ^ + j + w : | ****| + ^ + bits + out:|**|**|**|**|**|**|**|**|* | + ^^ + ib + */ + unsigned char b = 0; // bits in out[i] already filled in + while (b < 8) { + int nbits = min(8 - b, bits); + uint16_t mask = (1 << nbits) - 1; + unsigned char t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out + out[i] = out[i] + (t << (8 - b - nbits)); + b += nbits; + bits -= nbits; + w &= ~(mask << bits); // not strictly necessary; mostly for debugging + + if (bits == 0) { + if (j < inlen) { + w = in[j]; + bits = lsb; + j++; + } else { + break; // the input vector is exhausted + } + } + } + if (b == 8) { // out[i] is filled in + i++; + } + } +} + +void oqs_kem_frodokem_unpack(uint16_t *out, const size_t outlen, const unsigned char *in, const size_t inlen, const unsigned char lsb) { // Unpack the input char vector into a uint16_t output vector, copying lsb bits + // for each output element from input. outlen must be at least ceil(inlen * 8 / lsb). + memset(out, 0, outlen * sizeof(uint16_t)); + + size_t i = 0; // whole uint16_t already filled in + size_t j = 0; // whole bytes already copied + unsigned char w = 0; // the leftover, not yet copied + unsigned char bits = 0; // the number of lsb bits of w + + while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) { + /* + in: | | | | | | |**|**|... + ^ + j + w : | *| + ^ + bits + out:| *****| *****| *** | |... + ^ ^ + i b + */ + unsigned char b = 0; // bits in out[i] already filled in + while (b < lsb) { + int nbits = min(lsb - b, bits); + uint16_t mask = (1 << nbits) - 1; + unsigned char t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out + out[i] = out[i] + (t << (lsb - b - nbits)); + b += nbits; + bits -= nbits; + w &= ~(mask << bits); // not strictly necessary; mostly for debugging + + if (bits == 0) { + if (j < inlen) { + w = in[j]; + bits = 8; + j++; + } else { + break; // the input vector is exhausted + } + } + } + if (b == lsb) { // out[i] is filled in + i++; + } + } +} diff --git a/src/kem/kem.c b/src/kem/kem.c index d005a9b06..e59d94828 100644 --- a/src/kem/kem.c +++ b/src/kem/kem.c @@ -8,7 +8,8 @@ char *OQS_KEM_alg_identifier(size_t i) { // EDIT-WHEN-ADDING-KEM char *a[OQS_KEM_algs_length] = { OQS_KEM_alg_default, - OQS_KEM_alg_sike_p503, OQS_KEM_alg_sike_p751}; + OQS_KEM_alg_sike_p503, OQS_KEM_alg_sike_p751, + OQS_KEM_alg_frodokem_640_aes, OQS_KEM_alg_frodokem_640_cshake, OQS_KEM_alg_frodokem_976_aes, OQS_KEM_alg_frodokem_976_cshake}; if (i >= OQS_KEM_algs_length) { return NULL; } else { @@ -30,6 +31,30 @@ OQS_KEM *OQS_KEM_new(const char *method_name) { return OQS_KEM_sike_p751_new(); #else return NULL; +#endif + } else if (0 == strcasecmp(method_name, OQS_KEM_alg_frodokem_640_aes)) { +#ifdef OQS_ENABLE_KEM_frodokem_640_aes + return OQS_KEM_frodokem_640_aes_new(); +#else + return NULL; +#endif + } else if (0 == strcasecmp(method_name, OQS_KEM_alg_frodokem_976_aes)) { +#ifdef OQS_ENABLE_KEM_frodokem_976_aes + return OQS_KEM_frodokem_976_aes_new(); +#else + return NULL; +#endif + } else if (0 == strcasecmp(method_name, OQS_KEM_alg_frodokem_640_cshake)) { +#ifdef OQS_ENABLE_KEM_frodokem_640_cshake + return OQS_KEM_frodokem_640_cshake_new(); +#else + return NULL; +#endif + } else if (0 == strcasecmp(method_name, OQS_KEM_alg_frodokem_976_cshake)) { +#ifdef OQS_ENABLE_KEM_frodokem_976_cshake + return OQS_KEM_frodokem_976_cshake_new(); +#else + return NULL; #endif // EDIT-WHEN-ADDING-KEM } else { diff --git a/src/kem/kem.h b/src/kem/kem.h index 5fa0920e8..a2be5265c 100644 --- a/src/kem/kem.h +++ b/src/kem/kem.h @@ -31,9 +31,17 @@ #define OQS_KEM_alg_sike_p503 "Sike-p503" /** Algorithm identifier for Sike p751 KEM. */ #define OQS_KEM_alg_sike_p751 "Sike-p751" +/** Algorithm identifier for FrodoKEM-640-AES KEM. */ +#define OQS_KEM_alg_frodokem_640_aes "FrodoKEM-640-AES" +/** Algorithm identifier for FrodoKEM-640-cSHAKE KEM. */ +#define OQS_KEM_alg_frodokem_640_cshake "FrodoKEM-640-cSHAKE" +/** Algorithm identifier for FrodoKEM-976-AES KEM. */ +#define OQS_KEM_alg_frodokem_976_aes "FrodoKEM-976-AES" +/** Algorithm identifier for FrodoKEM-976-cSHAKE KEM. */ +#define OQS_KEM_alg_frodokem_976_cshake "FrodoKEM-976-cSHAKE" // EDIT-WHEN-ADDING-KEM /** Number of algorithm identifiers above. */ -#define OQS_KEM_algs_length 3 +#define OQS_KEM_algs_length 7 /** The default KEM. */ #define OQS_KEM_DEFAULT OQS_KEM_alg_sike_p503 @@ -180,6 +188,7 @@ OQS_STATUS OQS_KEM_decaps(const OQS_KEM *kem, uint8_t *shared_secret, const unsi void OQS_KEM_free(OQS_KEM *kem); #include +#include // EDIT-WHEN-ADDING-KEM #endif // __OQS_KEM_H diff --git a/src/kem/sike/P503/P503.c b/src/kem/sike/P503/P503.c index 91d35ef2b..af089a509 100644 --- a/src/kem/sike/P503/P503.c +++ b/src/kem/sike/P503/P503.c @@ -108,9 +108,9 @@ static const unsigned int strat_Bob[MAX_Bob - 1] = { #define mp_add_asm mp_add503_asm #define mp_addx2_asm mp_add503x2_asm #define mp_subx2_asm mp_sub503x2_asm -#define crypto_kem_keypair oqs_kem_sike_p503_keypair -#define crypto_kem_enc oqs_kem_sike_p503_enc -#define crypto_kem_dec oqs_kem_sike_p503_dec +#define crypto_kem_keypair OQS_KEM_sike_p503_keypair +#define crypto_kem_enc OQS_KEM_sike_p503_enc +#define crypto_kem_dec OQS_KEM_sike_p503_dec #define random_mod_order_A oqs_kem_sike_p503_sidh_random_mod_order_A #define random_mod_order_B oqs_kem_sike_p503_sidh_random_mod_order_B #define EphemeralKeyGeneration_A oqs_kem_sike_p503_sidh_EphemeralKeyGeneration_A diff --git a/src/kem/sike/P503/P503_api.h b/src/kem/sike/P503/P503_api.h index 7f9733196..4c7c23387 100644 --- a/src/kem/sike/P503/P503_api.h +++ b/src/kem/sike/P503/P503_api.h @@ -27,19 +27,19 @@ // It produces a private key sk and computes the public key pk. // Outputs: secret key sk (CRYPTO_SECRETKEYBYTES = 434 bytes) // public key pk (CRYPTO_PUBLICKEYBYTES = 378 bytes) -int oqs_kem_sike_p503_keypair(unsigned char *pk, unsigned char *sk); +int OQS_KEM_sike_p503_keypair(unsigned char *pk, unsigned char *sk); // SIKE's encapsulation // Input: public key pk (CRYPTO_PUBLICKEYBYTES = 378 bytes) // Outputs: shared secret ss (CRYPTO_BYTES = 16 bytes) // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = 402 bytes) -int oqs_kem_sike_p503_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); +int OQS_KEM_sike_p503_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); // SIKE's decapsulation // Input: secret key sk (CRYPTO_SECRETKEYBYTES = 434 bytes) // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = 402 bytes) // Outputs: shared secret ss (CRYPTO_BYTES = 16 bytes) -int oqs_kem_sike_p503_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); +int OQS_KEM_sike_p503_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); // Encoding of keys for KEM-based isogeny system "SIKEp503" (wire format): // ---------------------------------------------------------------------- diff --git a/src/kem/sike/P751/P751.c b/src/kem/sike/P751/P751.c index b1902d7c6..26083fec0 100644 --- a/src/kem/sike/P751/P751.c +++ b/src/kem/sike/P751/P751.c @@ -113,9 +113,9 @@ static const unsigned int strat_Bob[MAX_Bob - 1] = { #define mp_add_asm mp_add751_asm #define mp_addx2_asm mp_add751x2_asm #define mp_subx2_asm mp_sub751x2_asm -#define crypto_kem_keypair oqs_kem_sike_p751_keypair -#define crypto_kem_enc oqs_kem_sike_p751_enc -#define crypto_kem_dec oqs_kem_sike_p751_dec +#define crypto_kem_keypair OQS_KEM_sike_p751_keypair +#define crypto_kem_enc OQS_KEM_sike_p751_enc +#define crypto_kem_dec OQS_KEM_sike_p751_dec #define random_mod_order_A oqs_kem_sike_p751_sidh_random_mod_order_A #define random_mod_order_B oqs_kem_sike_p751_sidh_random_mod_order_B #define EphemeralKeyGeneration_A oqs_kem_sike_p751_sidh_EphemeralKeyGeneration_A diff --git a/src/kem/sike/P751/P751_api.h b/src/kem/sike/P751/P751_api.h index b9963161f..62ba3d594 100644 --- a/src/kem/sike/P751/P751_api.h +++ b/src/kem/sike/P751/P751_api.h @@ -26,19 +26,19 @@ // It produces a private key sk and computes the public key pk. // Outputs: secret key sk (CRYPTO_SECRETKEYBYTES = 644 bytes) // public key pk (CRYPTO_PUBLICKEYBYTES = 564 bytes) -int oqs_kem_sike_p751_keypair(unsigned char *pk, unsigned char *sk); +int OQS_KEM_sike_p751_keypair(unsigned char *pk, unsigned char *sk); // SIKE's encapsulation // Input: public key pk (CRYPTO_PUBLICKEYBYTES = 564 bytes) // Outputs: shared secret ss (CRYPTO_BYTES = 24 bytes) // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = 596 bytes) -int oqs_kem_sike_p751_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); +int OQS_KEM_sike_p751_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); // SIKE's decapsulation // Input: secret key sk (CRYPTO_SECRETKEYBYTES = 644 bytes) // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = 596 bytes) // Outputs: shared secret ss (CRYPTO_BYTES = 24 bytes) -int oqs_kem_sike_p751_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); +int OQS_KEM_sike_p751_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); // Encoding of keys for KEM-based isogeny system "SIKEp751" (wire format): // ---------------------------------------------------------------------- diff --git a/src/kem/sike/kem_sike.c b/src/kem/sike/kem_sike.c index 91200c32c..acb9f0e18 100644 --- a/src/kem/sike/kem_sike.c +++ b/src/kem/sike/kem_sike.c @@ -22,9 +22,9 @@ OQS_KEM *OQS_KEM_sike_p503_new() { kem->length_ciphertext = OQS_KEM_sike_p503_length_ciphertext; kem->length_shared_secret = OQS_KEM_sike_p503_length_shared_secret; - kem->keypair = oqs_kem_sike_p503_keypair; - kem->encaps = oqs_kem_sike_p503_enc; - kem->decaps = oqs_kem_sike_p503_dec; + kem->keypair = OQS_KEM_sike_p503_keypair; + kem->encaps = OQS_KEM_sike_p503_enc; + kem->decaps = OQS_KEM_sike_p503_dec; return kem; } @@ -51,9 +51,9 @@ OQS_KEM *OQS_KEM_sike_p751_new() { kem->length_ciphertext = OQS_KEM_sike_p751_length_ciphertext; kem->length_shared_secret = OQS_KEM_sike_p751_length_shared_secret; - kem->keypair = oqs_kem_sike_p751_keypair; - kem->encaps = oqs_kem_sike_p751_enc; - kem->decaps = oqs_kem_sike_p751_dec; + kem->keypair = OQS_KEM_sike_p751_keypair; + kem->encaps = OQS_KEM_sike_p751_enc; + kem->decaps = OQS_KEM_sike_p751_dec; return kem; } diff --git a/src/kem/sike/kem_sike.h b/src/kem/sike/kem_sike.h index 108cb5bcc..d2e313063 100644 --- a/src/kem/sike/kem_sike.h +++ b/src/kem/sike/kem_sike.h @@ -12,9 +12,9 @@ OQS_KEM *OQS_KEM_sike_p503_new(); -extern OQS_STATUS OQS_KEM_sike_p503_keypair(uint8_t *public_key, uint8_t *secret_key); -extern OQS_STATUS OQS_KEM_sike_p503_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key); -extern OQS_STATUS OQS_KEM_sike_p503_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key); +OQS_STATUS OQS_KEM_sike_p503_keypair(uint8_t *public_key, uint8_t *secret_key); +OQS_STATUS OQS_KEM_sike_p503_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key); +OQS_STATUS OQS_KEM_sike_p503_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key); #endif @@ -27,9 +27,9 @@ extern OQS_STATUS OQS_KEM_sike_p503_decaps(uint8_t *shared_secret, const unsigne OQS_KEM *OQS_KEM_sike_p751_new(); -extern OQS_STATUS OQS_KEM_sike_p751_keypair(uint8_t *public_key, uint8_t *secret_key); -extern OQS_STATUS OQS_KEM_sike_p751_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key); -extern OQS_STATUS OQS_KEM_sike_p751_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key); +OQS_STATUS OQS_KEM_sike_p751_keypair(uint8_t *public_key, uint8_t *secret_key); +OQS_STATUS OQS_KEM_sike_p751_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key); +OQS_STATUS OQS_KEM_sike_p751_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key); #endif diff --git a/src/kex/kex.c b/src/kex/kex.c index 63ee8e0b7..f65b63868 100644 --- a/src/kex/kex.c +++ b/src/kex/kex.c @@ -2,7 +2,6 @@ #include -#include #include #include #include @@ -31,12 +30,6 @@ OQS_KEX *OQS_KEX_new(OQS_RAND *rand, enum OQS_KEX_alg_name alg_name, const uint8 switch (alg_name) { case OQS_KEX_alg_default: return OQS_KEX_rlwe_newhope_new(rand); - case OQS_KEX_alg_lwe_frodo: -#ifdef ENABLE_KEX_LWE_FRODO - return OQS_KEX_lwe_frodo_new_recommended(rand, seed, seed_len, named_parameters); -#else - assert(0); -#endif case OQS_KEX_alg_code_mcbits: #ifdef ENABLE_CODE_MCBITS return OQS_KEX_code_mcbits_new(rand); diff --git a/src/kex/kex.h b/src/kex/kex.h index a41d4263b..253da712d 100644 --- a/src/kex/kex.h +++ b/src/kex/kex.h @@ -21,7 +21,6 @@ enum OQS_KEX_alg_name { OQS_KEX_alg_default, OQS_KEX_alg_rlwe_newhope, - OQS_KEX_alg_lwe_frodo, OQS_KEX_alg_sidh_msr_503, OQS_KEX_alg_sidh_msr_751, OQS_KEX_alg_sike_msr_503, diff --git a/src/kex/test_kex.c b/src/kex/test_kex.c index 0b041c4cd..164dd82e7 100644 --- a/src/kex/test_kex.c +++ b/src/kex/test_kex.c @@ -23,9 +23,6 @@ struct kex_testcase { /* Add new testcases here */ struct kex_testcase kex_testcases[] = { -#ifdef ENABLE_KEX_LWE_FRODO - {OQS_KEX_alg_lwe_frodo, (unsigned char *) "01234567890123456", 16, "recommended", "lwe_frodo_recommended", 0, 100}, -#endif #ifdef ENABLE_CODE_MCBITS {OQS_KEX_alg_code_mcbits, NULL, 0, NULL, "code_mcbits", 0, 25}, #endif diff --git a/src/kex_lwe_frodo/Makefile.am b/src/kex_lwe_frodo/Makefile.am deleted file mode 100644 index d91def872..000000000 --- a/src/kex_lwe_frodo/Makefile.am +++ /dev/null @@ -1,7 +0,0 @@ -AUTOMAKE_OPTIONS = foreign -noinst_LTLIBRARIES = libfrodo.la - -libfrodo_la_SOURCES = kex_lwe_frodo.c lwe.c lwe_noise.c -libfrodo_la_CPPFLAGS = -I../../include -I. -libfrodo_la_CPPFLAGS += $(AM_CPPFLAGS) - diff --git a/src/kex_lwe_frodo/kex_lwe_frodo.c b/src/kex_lwe_frodo/kex_lwe_frodo.c deleted file mode 100644 index d06ea4761..000000000 --- a/src/kex_lwe_frodo/kex_lwe_frodo.c +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include -#if !defined(_WIN32) -#include -#include -#endif - -#include -#include -#include - -#include "kex_lwe_frodo.h" -#include "local.h" - -#define LWE_DIV_ROUNDUP(x, y) (((x) + (y) -1) / y) - -#include - -// pre-process code to obtain "recommended" functions -#include "recommended.h" -#define MACRIFY(NAME) NAME##_recommended -#include "kex_lwe_frodo_macrify.c" -// undefine macros to avoid any confusion later -#include "recommended.h" -#undef MACRIFY - -void OQS_KEX_lwe_frodo_alice_priv_free(UNUSED OQS_KEX *k, void *alice_priv) { - free(alice_priv); -} - -void OQS_KEX_lwe_frodo_free(OQS_KEX *k) { - if (!k) { - return; - } - if (k->params) { - struct oqs_kex_lwe_frodo_params *params = (struct oqs_kex_lwe_frodo_params *) k->params; - free(params->cdf_table); - params->cdf_table = NULL; - free(params->seed); - params->seed = NULL; - free(params->param_name); - params->param_name = NULL; - free(k->params); - k->params = NULL; - } - free(k->named_parameters); - k->named_parameters = NULL; - free(k->method_name); - k->method_name = NULL; - free(k); -} diff --git a/src/kex_lwe_frodo/kex_lwe_frodo.h b/src/kex_lwe_frodo/kex_lwe_frodo.h deleted file mode 100644 index 4667d83e3..000000000 --- a/src/kex_lwe_frodo/kex_lwe_frodo.h +++ /dev/null @@ -1,25 +0,0 @@ -/** - * \file kex_lwe_frodo.h - * \brief Header for LWE key exchange protocol Frodo. - */ - -#ifndef __OQS_KEX_LWE_FRODO_H -#define __OQS_KEX_LWE_FRODO_H - -#include -#include - -#include -#include -#include - -OQS_KEX *OQS_KEX_lwe_frodo_new_recommended(OQS_RAND *rand, const uint8_t *seed, const size_t seed_len, const char *named_parameters); - -OQS_STATUS OQS_KEX_lwe_frodo_alice_0_recommended(OQS_KEX *k, void **alice_priv, uint8_t **alice_msg, size_t *alice_msg_len); -OQS_STATUS OQS_KEX_lwe_frodo_bob_recommended(OQS_KEX *k, const uint8_t *alice_msg, const size_t alice_msg_len, uint8_t **bob_msg, size_t *bob_msg_len, uint8_t **key, size_t *key_len); -OQS_STATUS OQS_KEX_lwe_frodo_alice_1_recommended(OQS_KEX *k, const void *alice_priv, const uint8_t *bob_msg, const size_t bob_msg_len, uint8_t **key, size_t *key_len); - -void OQS_KEX_lwe_frodo_alice_priv_free(OQS_KEX *k, void *alice_priv); -void OQS_KEX_lwe_frodo_free(OQS_KEX *k); - -#endif diff --git a/src/kex_lwe_frodo/kex_lwe_frodo_macrify.c b/src/kex_lwe_frodo/kex_lwe_frodo_macrify.c deleted file mode 100644 index 3f683c107..000000000 --- a/src/kex_lwe_frodo/kex_lwe_frodo_macrify.c +++ /dev/null @@ -1,260 +0,0 @@ -#if defined(_WIN32) -#define strdup _strdup // for strdup deprecation warning -#endif - -OQS_KEX *MACRIFY(OQS_KEX_lwe_frodo_new)(OQS_RAND *rand, const uint8_t *seed, const size_t seed_len, const char *named_parameters) { - - OQS_KEX *k; - struct oqs_kex_lwe_frodo_params *params; - - if ((seed_len == 0) || (seed == NULL)) { - return NULL; - } - - k = malloc(sizeof(OQS_KEX)); - if (k == NULL) { - goto err; - } - k->named_parameters = NULL; - k->method_name = NULL; - - k->params = malloc(sizeof(struct oqs_kex_lwe_frodo_params)); - if (NULL == k->params) { - goto err; - } - params = (struct oqs_kex_lwe_frodo_params *) k->params; - params->cdf_table = NULL; - params->seed = NULL; - params->param_name = NULL; - - k->rand = rand; - k->ctx = NULL; - k->alice_priv_free = &OQS_KEX_lwe_frodo_alice_priv_free; - k->free = &OQS_KEX_lwe_frodo_free; - - if (strcmp(named_parameters, "recommended") == 0) { - - k->alice_0 = &OQS_KEX_lwe_frodo_alice_0_recommended; - k->bob = &OQS_KEX_lwe_frodo_bob_recommended; - k->alice_1 = &OQS_KEX_lwe_frodo_alice_1_recommended; - - k->method_name = strdup("LWE Frodo recommended"); - if (NULL == k->method_name) { - goto err; - } - k->estimated_classical_security = 144; - k->estimated_quantum_security = 130; - k->named_parameters = strdup(named_parameters); - if (k->named_parameters == NULL) { - goto err; - } - - params->seed = malloc(seed_len); - if (NULL == params->seed) { - goto err; - } - memcpy(params->seed, seed, seed_len); - params->seed_len = seed_len; - params->param_name = strdup("recommended"); - if (NULL == params->param_name) { - goto err; - } - params->log2_q = PARAMS_LOG2Q; - params->q = PARAMS_Q; - params->n = PARAMS_N; - params->extracted_bits = PARAMS_EXTRACTED_BITS; - params->nbar = PARAMS_NBAR; - params->key_bits = PARAMS_KEY_BITS; - params->rec_hint_len = PARAMS_REC_HINT_LENGTH; - params->pub_len = PARAMS_REC_PUB_LENGTH; - params->stripe_step = PARAMS_STRIPE_STEP; - params->sampler_num = 12; - params->cdf_table_len = 6; - params->cdf_table = malloc(params->cdf_table_len * sizeof(uint16_t)); - if (NULL == params->cdf_table) { - goto err; - } - uint16_t cdf_table_tmp[6] = {602, 1521, 1927, 2031, 2046, 2047}; - memcpy(params->cdf_table, cdf_table_tmp, sizeof(cdf_table_tmp)); - } else { - goto err; - } - return k; -err: - OQS_KEX_lwe_frodo_free(k); - return NULL; -} - -OQS_STATUS MACRIFY(OQS_KEX_lwe_frodo_alice_0)(OQS_KEX *k, void **alice_priv, uint8_t **alice_msg, size_t *alice_msg_len) { - - OQS_STATUS ret; - - struct oqs_kex_lwe_frodo_params *params = (struct oqs_kex_lwe_frodo_params *) k->params; - - *alice_priv = NULL; - *alice_msg = NULL; - - /* allocate private key, error, and outgoing message */ - *alice_priv = malloc(PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); - if (*alice_priv == NULL) { - goto err; - } - uint16_t b[PARAMS_N * PARAMS_NBAR]; - uint16_t e[PARAMS_N * PARAMS_NBAR]; - - *alice_msg = malloc(PARAMS_REC_PUB_LENGTH); - *alice_msg_len = PARAMS_REC_PUB_LENGTH; - if (*alice_msg == NULL) { - goto err; - } - - /* generate S and E */ - oqs_kex_lwe_frodo_sample_n(*alice_priv, PARAMS_N * PARAMS_NBAR, params, k->rand); - oqs_kex_lwe_frodo_sample_n(e, PARAMS_N * PARAMS_NBAR, params, k->rand); - - /* compute B = AS + E */ - MACRIFY(oqs_kex_lwe_frodo_mul_add_as_plus_e_on_the_fly) - (b, *alice_priv, e, params); - - oqs_kex_lwe_frodo_pack(*alice_msg, PARAMS_REC_PUB_LENGTH, b, PARAMS_N * PARAMS_NBAR, PARAMS_LOG2Q); - - ret = OQS_SUCCESS; - goto cleanup; - -err: - OQS_MEM_cleanse(e, sizeof(e)); - free(*alice_msg); - *alice_msg = NULL; - free(*alice_priv); - *alice_priv = NULL; - ret = OQS_ERROR; - -cleanup: - return ret; -} - -OQS_STATUS MACRIFY(OQS_KEX_lwe_frodo_bob)(OQS_KEX *k, const uint8_t *alice_msg, const size_t alice_msg_len, uint8_t **bob_msg, size_t *bob_msg_len, uint8_t **key, size_t *key_len) { - - OQS_STATUS ret; - - struct oqs_kex_lwe_frodo_params *params = (struct oqs_kex_lwe_frodo_params *) k->params; - - uint8_t *bob_rec = NULL; - *bob_msg = NULL; - *key = NULL; - - /* check length of other party's public key */ - if (alice_msg_len != PARAMS_REC_PUB_LENGTH) { - goto err; - } - - /* allocate private key, errors, outgoing message, and key */ - uint16_t bob_priv[PARAMS_N * PARAMS_NBAR]; - uint16_t bprime[PARAMS_N * PARAMS_NBAR]; - uint16_t eprime[PARAMS_N * PARAMS_NBAR]; - uint16_t eprimeprime[PARAMS_N * PARAMS_NBAR]; - uint16_t b[PARAMS_N * PARAMS_NBAR]; - uint16_t v[PARAMS_N * PARAMS_NBAR]; - *bob_msg = malloc(PARAMS_REC_PUB_LENGTH + PARAMS_REC_HINT_LENGTH); - if (*bob_msg == NULL) { - goto err; - } - bob_rec = *bob_msg + PARAMS_REC_PUB_LENGTH; - *key = malloc(PARAMS_KEY_BYTES); - if (*key == NULL) { - goto err; - } - - /* generate S' and E' */ - oqs_kex_lwe_frodo_sample_n(bob_priv, PARAMS_N * PARAMS_NBAR, params, k->rand); - oqs_kex_lwe_frodo_sample_n(eprime, PARAMS_N * PARAMS_NBAR, params, k->rand); - - /* compute B' = S'A + E' */ - MACRIFY(oqs_kex_lwe_frodo_mul_add_sa_plus_e_on_the_fly) - (bprime, bob_priv, eprime, params); - - oqs_kex_lwe_frodo_pack(*bob_msg, PARAMS_REC_PUB_LENGTH, bprime, PARAMS_N * PARAMS_NBAR, PARAMS_LOG2Q); - - /* generate E'' */ - oqs_kex_lwe_frodo_sample_n(eprimeprime, PARAMS_NBAR * PARAMS_NBAR, params, k->rand); - - /* unpack B */ - oqs_kex_lwe_frodo_unpack(b, PARAMS_N * PARAMS_NBAR, alice_msg, alice_msg_len, PARAMS_LOG2Q); - - /* compute V = S'B + E'' */ - MACRIFY(oqs_kex_lwe_frodo_mul_add_sb_plus_e) - (v, b, bob_priv, eprimeprime); - - /* compute C = _{2^B} */ - MACRIFY(oqs_kex_lwe_frodo_crossround2) - (bob_rec, v); - - /* compute K = round(V)_{2^B} */ - MACRIFY(oqs_kex_lwe_frodo_round2) - (*key, v); - - *bob_msg_len = PARAMS_REC_PUB_LENGTH + PARAMS_REC_HINT_LENGTH; - *key_len = PARAMS_KEY_BYTES; - - ret = OQS_SUCCESS; - goto cleanup; - -err: - ret = OQS_ERROR; - free(*bob_msg); - *bob_msg = NULL; - OQS_MEM_secure_free(*key, PARAMS_KEY_BYTES); - *key = NULL; - -cleanup: - OQS_MEM_cleanse(eprime, sizeof(eprime)); - OQS_MEM_cleanse(eprimeprime, sizeof(eprimeprime)); - OQS_MEM_cleanse(v, sizeof(v)); - - return ret; -} - -OQS_STATUS MACRIFY(OQS_KEX_lwe_frodo_alice_1)(UNUSED OQS_KEX *k, const void *alice_priv, const uint8_t *bob_msg, const size_t bob_msg_len, uint8_t **key, size_t *key_len) { - - OQS_STATUS ret; - *key = NULL; - - /* check length of other party's public key */ - if (bob_msg_len != PARAMS_REC_PUB_LENGTH + PARAMS_REC_HINT_LENGTH) { - goto err; - } - - /* allocate working values and session key */ - uint16_t bprime[PARAMS_N * PARAMS_NBAR]; - uint16_t w[PARAMS_N * PARAMS_NBAR]; - - *key = malloc(PARAMS_KEY_BYTES); - if (*key == NULL) { - goto err; - } - - /* unpack B' */ - oqs_kex_lwe_frodo_unpack(bprime, PARAMS_N * PARAMS_NBAR, bob_msg, PARAMS_REC_PUB_LENGTH, PARAMS_LOG2Q); - - /* compute W = B'S */ - MACRIFY(oqs_kex_lwe_frodo_mul_bs) - (w, bprime, (uint16_t *) alice_priv); - - /* compute K = rec(B'S, C) */ - const uint8_t *bob_rec = bob_msg + PARAMS_REC_PUB_LENGTH; - MACRIFY(oqs_kex_lwe_frodo_reconcile) - (*key, w, bob_rec); - - *key_len = PARAMS_KEY_BYTES; - - ret = OQS_SUCCESS; - goto cleanup; - -err: - ret = OQS_ERROR; - OQS_MEM_secure_free(*key, PARAMS_KEY_BYTES); - *key = NULL; - -cleanup: - return ret; -} diff --git a/src/kex_lwe_frodo/local.h b/src/kex_lwe_frodo/local.h deleted file mode 100644 index 84d41b4d2..000000000 --- a/src/kex_lwe_frodo/local.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef _OQS_KEX_LWE_FRODO_LOCAL_H_ -#define _OQS_KEX_LWE_FRODO_LOCAL_H_ - -#include - -#include - -struct oqs_kex_lwe_frodo_params { - uint8_t *seed; - size_t seed_len; - char *param_name; - uint16_t log2_q; - uint16_t q; - uint16_t n; - uint16_t extracted_bits; - uint16_t nbar; - uint16_t key_bits; - uint16_t rec_hint_len; - uint32_t pub_len; - uint16_t stripe_step; - int sampler_num; - uint16_t *cdf_table; - size_t cdf_table_len; -}; - -void oqs_kex_lwe_frodo_crossround2_recommended(unsigned char *out, const uint16_t *in); -void oqs_kex_lwe_frodo_round2_recommended(unsigned char *out, uint16_t *in); -void oqs_kex_lwe_frodo_reconcile_recommended(unsigned char *out, uint16_t *w, const unsigned char *hint); - -void oqs_kex_lwe_frodo_key_round(uint16_t *vec, const size_t length, const int b); -void oqs_kex_lwe_frodo_key_round_hints(uint16_t *vec, const size_t length, const int b, const unsigned char *hint); -void oqs_kex_lwe_frodo_pack(unsigned char *out, const size_t outlen, const uint16_t *in, const size_t inlen, const unsigned char lsb); -void oqs_kex_lwe_frodo_unpack(uint16_t *out, const size_t outlen, const unsigned char *in, const size_t inlen, const unsigned char lsb); - -void oqs_kex_lwe_frodo_sample_n(uint16_t *s, const size_t n, struct oqs_kex_lwe_frodo_params *params, OQS_RAND *rand); - -void oqs_kex_lwe_frodo_mul_add_as_plus_e_on_the_fly_recommended(uint16_t *b, const uint16_t *s, const uint16_t *e, struct oqs_kex_lwe_frodo_params *params); -void oqs_kex_lwe_frodo_mul_add_sa_plus_e_on_the_fly_recommended(uint16_t *b, const uint16_t *s, const uint16_t *e, struct oqs_kex_lwe_frodo_params *params); -void oqs_kex_lwe_frodo_mul_add_sb_plus_e_recommended(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e); -void oqs_kex_lwe_frodo_mul_bs_recommended(uint16_t *out, const uint16_t *b, const uint16_t *s); - -#endif /* _OQS_KEX_LWE_FRODO_LOCAL_H_ */ diff --git a/src/kex_lwe_frodo/lwe.c b/src/kex_lwe_frodo/lwe.c deleted file mode 100644 index ec64b57e8..000000000 --- a/src/kex_lwe_frodo/lwe.c +++ /dev/null @@ -1,150 +0,0 @@ -#include -#include -#include -#include -#include - -#include "local.h" - -#include - -#define min(x, y) (((x) < (y)) ? (x) : (y)) - -// round all elements of a vector to the nearest multiple of 2^b -void oqs_kex_lwe_frodo_key_round(uint16_t *vec, const size_t length, const int b) { - size_t i; - uint16_t negmask = ~((1 << b) - 1); - uint16_t half = b > 0 ? 1 << (b - 1) : 0; - for (i = 0; i < length; i++) { - vec[i] = (vec[i] + half) & negmask; - } -} - -// Round all elements of a vector to the multiple of 2^b, with a hint for the -// direction of rounding when close to the boundary. -void oqs_kex_lwe_frodo_key_round_hints(uint16_t *vec, const size_t length, const int b, const unsigned char *hint) { - size_t i; - uint16_t whole = 1 << b; - uint16_t mask = whole - 1; - uint16_t negmask = ~mask; - uint16_t half = 1 << (b - 1); - uint16_t quarter = 1 << (b - 2); - - for (i = 0; i < length; i++) { - uint16_t remainder = vec[i] & mask; - uint16_t use_hint = ((remainder + quarter) >> (b - 1)) & 0x1; - - unsigned char h = (hint[i / 8] >> (i % 8)) % 2; // the hint - uint16_t shift = use_hint * (2 * h - 1) * quarter; - - // if use_hint = 1 and h = 0, adding -quarter forces rounding down - // h = 1, adding quarter forces rounding up - - vec[i] = (vec[i] + half + shift) & negmask; - } -} - -// Pack the input uint16 vector into a char output vector, copying lsb bits -// from each input element. If inlen * lsb / 8 > outlen, only outlen * 8 bits -// are copied. -void oqs_kex_lwe_frodo_pack(unsigned char *out, const size_t outlen, const uint16_t *in, const size_t inlen, const unsigned char lsb) { - memset(out, 0, outlen); - - size_t i = 0; // whole bytes already filled in - size_t j = 0; // whole uint16_t already copied - uint16_t w = 0; // the leftover, not yet copied - unsigned char bits = 0; // the number of lsb in w - while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) { - /* - in: | | |********|********| - ^ - j - w : | ****| - ^ - bits - out:|**|**|**|**|**|**|**|**|* | - ^^ - ib - */ - unsigned char b = 0; // bits in out[i] already filled in - while (b < 8) { - int nbits = min(8 - b, bits); - uint16_t mask = (1 << nbits) - 1; - unsigned char t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out - out[i] += t << (8 - b - nbits); - b += nbits; - bits -= nbits; - w &= ~(mask << bits); // not strictly necessary; mostly for debugging - - if (bits == 0) { - if (j < inlen) { - w = in[j]; - bits = lsb; - j++; - } else { - break; // the input vector is exhausted - } - } - } - if (b == 8) { // out[i] is filled in - i++; - } - } -} - -// Unpack the input char vector into a uint16_t output vector, copying lsb bits -// for each output element from input. outlen must be at least ceil(inlen * 8 / -// lsb). -void oqs_kex_lwe_frodo_unpack(uint16_t *out, const size_t outlen, const unsigned char *in, const size_t inlen, const unsigned char lsb) { - memset(out, 0, outlen * sizeof(uint16_t)); - - size_t i = 0; // whole uint16_t already filled in - size_t j = 0; // whole bytes already copied - unsigned char w = 0; // the leftover, not yet copied - unsigned char bits = 0; // the number of lsb bits of w - while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) { - /* - in: | | | | | | |**|**|... - ^ - j - w : | *| - ^ - bits - out:| *****| *****| *** | |... - ^ ^ - i b - */ - unsigned char b = 0; // bits in out[i] already filled in - while (b < lsb) { - int nbits = min(lsb - b, bits); - uint16_t mask = (1 << nbits) - 1; - unsigned char t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out - out[i] += t << (lsb - b - nbits); - b += nbits; - bits -= nbits; - w &= ~(mask << bits); // not strictly necessary; mostly for debugging - - if (bits == 0) { - if (j < inlen) { - w = in[j]; - bits = 8; - j++; - } else { - break; // the input vector is exhausted - } - } - } - if (b == lsb) { // out[i] is filled in - i++; - } - } -} - -// define parameters for "recommended" parameter set -#include "recommended.h" -// pre-process code to obtain "recommended" functions -#define MACRIFY(NAME) NAME##_recommended -#include "lwe_macrify.c" -// undefine macros to avoid any confusion later -#include "recommended.h" -#undef MACRIFY diff --git a/src/kex_lwe_frodo/lwe_macrify.c b/src/kex_lwe_frodo/lwe_macrify.c deleted file mode 100644 index f39b59ba4..000000000 --- a/src/kex_lwe_frodo/lwe_macrify.c +++ /dev/null @@ -1,160 +0,0 @@ -// [.]_2 -void MACRIFY(oqs_kex_lwe_frodo_round2)(unsigned char *out, uint16_t *in) { - oqs_kex_lwe_frodo_key_round(in, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOG2Q - PARAMS_EXTRACTED_BITS); - for (int i = 0; i < PARAMS_NBAR * PARAMS_NBAR; i++) { - in[i] >>= PARAMS_LOG2Q - PARAMS_EXTRACTED_BITS; // drop bits that were zeroed out - } - - // out should have enough space for the key - oqs_kex_lwe_frodo_pack(out, PARAMS_KEY_BITS / 8, in, PARAMS_NBAR * PARAMS_NBAR, PARAMS_EXTRACTED_BITS); -} - -void MACRIFY(oqs_kex_lwe_frodo_crossround2)(unsigned char *out, const uint16_t *in) { - // out should have enough space for N_BAR * N_BAR bits - memset((unsigned char *) out, 0, PARAMS_REC_HINT_LENGTH); - - uint16_t whole = 1 << (PARAMS_LOG2Q - PARAMS_EXTRACTED_BITS); - uint16_t half = whole >> 1; - uint16_t mask = whole - 1; - - for (int i = 0; i < PARAMS_NBAR * PARAMS_NBAR; i++) { - uint16_t remainder = in[i] & mask; - out[i / 8] += (remainder >= half) << (i % 8); - } -} - -void MACRIFY(oqs_kex_lwe_frodo_reconcile)(unsigned char *out, uint16_t *w, const unsigned char *hint) { - oqs_kex_lwe_frodo_key_round_hints(w, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOG2Q - PARAMS_EXTRACTED_BITS, hint); - for (int i = 0; i < PARAMS_NBAR * PARAMS_NBAR; i++) { - w[i] >>= PARAMS_LOG2Q - PARAMS_EXTRACTED_BITS; // drop bits that were zeroed out - } - oqs_kex_lwe_frodo_pack(out, PARAMS_KEY_BITS / 8, w, PARAMS_NBAR * PARAMS_NBAR, PARAMS_EXTRACTED_BITS); -} - -// Generate-and-multiply: generate A row-wise, multiply by s on the right. -void MACRIFY(oqs_kex_lwe_frodo_mul_add_as_plus_e_on_the_fly)(uint16_t *out, const uint16_t *s, const uint16_t *e, struct oqs_kex_lwe_frodo_params *params) { - // A (N x N) - // s,e (N x N_BAR) - // out = A * s + e (N x N_BAR) - - memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t)); - - // transpose s to store it in the column-major order - uint16_t s_transpose[PARAMS_NBAR * PARAMS_N]; - for (int j = 0; j < PARAMS_N; j++) { - for (int k = 0; k < PARAMS_NBAR; k++) { - s_transpose[k * PARAMS_N + j] = s[j * PARAMS_NBAR + k]; - } - } - - assert(params->seed_len == 16); - void *aes_key_schedule = NULL; - OQS_AES128_load_schedule(params->seed, &aes_key_schedule, 1); - - for (int i = 0; i < PARAMS_N; i++) { - uint16_t a_row[PARAMS_N] = {0}; - // go through A's rows - for (int j = 0; j < PARAMS_N; j += PARAMS_STRIPE_STEP) { - // Loading values in the little-endian order! - a_row[j] = i; - a_row[j + 1] = j; - } - - OQS_AES128_ECB_enc_sch((uint8_t *) a_row, sizeof(a_row), aes_key_schedule, (uint8_t *) a_row); - - for (int k = 0; k < PARAMS_NBAR; k++) { - uint16_t sum = 0; - for (int j = 0; j < PARAMS_N; j++) { - // matrix-vector multiplication happens here - sum += a_row[j] * s_transpose[k * PARAMS_N + j]; - } - out[i * PARAMS_NBAR + k] += sum; - //Equivalent to %= PARAMS_Q if PARAMS_Q is a power of 2 - out[i * PARAMS_NBAR + k] &= PARAMS_Q - 1; - } - } - - OQS_AES128_free_schedule(aes_key_schedule); -} - -// Generate-and-multiply: generate A column-wise, multiply by s' on the left. -void MACRIFY(oqs_kex_lwe_frodo_mul_add_sa_plus_e_on_the_fly)(uint16_t *out, const uint16_t *s, const uint16_t *e, struct oqs_kex_lwe_frodo_params *params) { - // a (N x N) - // s',e' (N_BAR x N) - // out = s'a + e' (N_BAR x N) - - memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t)); - - assert(params->seed_len == 16); - - void *aes_key_schedule = NULL; - OQS_AES128_load_schedule(params->seed, &aes_key_schedule, 1); - - for (int kk = 0; kk < PARAMS_N; kk += PARAMS_STRIPE_STEP) { - // Go through A's columns, 8 (== PARAMS_STRIPE_STEP) columns at a time. - // a_cols stores 8 columns of A at a time. - uint16_t a_cols[PARAMS_N * PARAMS_STRIPE_STEP] = {0}; - for (int i = 0; i < PARAMS_N; i++) { - // Loading values in the little-endian order! - a_cols[i * PARAMS_STRIPE_STEP] = i; - a_cols[i * PARAMS_STRIPE_STEP + 1] = kk; - } - - OQS_AES128_ECB_enc_sch((uint8_t *) a_cols, sizeof(a_cols), aes_key_schedule, (uint8_t *) a_cols); - - // transpose a_cols to have access to it in the column-major order. - uint16_t a_cols_t[PARAMS_N * PARAMS_STRIPE_STEP]; - for (int i = 0; i < PARAMS_N; i++) { - for (int k = 0; k < PARAMS_STRIPE_STEP; k++) { - a_cols_t[k * PARAMS_N + i] = a_cols[i * PARAMS_STRIPE_STEP + k]; - } - } - - for (int i = 0; i < PARAMS_NBAR; i++) { - for (int k = 0; k < PARAMS_STRIPE_STEP; k++) { - uint16_t sum = 0; - for (int j = 0; j < PARAMS_N; j++) { - sum += s[i * PARAMS_N + j] * a_cols_t[k * PARAMS_N + j]; - } - out[i * PARAMS_N + kk + k] += sum; - out[i * PARAMS_N + kk + k] &= PARAMS_Q - 1; //Works as long as PARAMS_Q is a power of 2 - } - } - } - OQS_AES128_free_schedule(aes_key_schedule); -} - -// multiply by s on the right -void MACRIFY(oqs_kex_lwe_frodo_mul_bs)(uint16_t *out, const uint16_t *b, const uint16_t *s) { - // b (N_BAR x N) - // s (N x N_BAR) - // out = bs - for (int i = 0; i < PARAMS_NBAR; i++) { - for (int j = 0; j < PARAMS_NBAR; j++) { - uint16_t sum = 0; - for (int k = 0; k < PARAMS_N; k++) { - sum += b[i * PARAMS_N + k] * s[k * PARAMS_NBAR + j]; - } - out[i * PARAMS_NBAR + j] = sum & (PARAMS_Q - 1); - } - } -} - -// multiply by s on the left -void MACRIFY(oqs_kex_lwe_frodo_mul_add_sb_plus_e)(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e) { - // b (N x N_BAR) - // s (N_BAR x N) - // e (N_BAR x N_BAR) - // out = sb + e - memcpy(out, e, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); - for (int k = 0; k < PARAMS_NBAR; k++) { - for (int i = 0; i < PARAMS_NBAR; i++) { - uint16_t sum = 0; - for (int j = 0; j < PARAMS_N; j++) { - sum += s[k * PARAMS_N + j] * b[j * PARAMS_NBAR + i]; - } - out[k * PARAMS_NBAR + i] += sum; - out[k * PARAMS_NBAR + i] &= PARAMS_Q - 1; // not really necessary since LWE_Q is a power of 2. - } - } -} diff --git a/src/kex_lwe_frodo/lwe_noise.c b/src/kex_lwe_frodo/lwe_noise.c deleted file mode 100644 index e2f82eb7f..000000000 --- a/src/kex_lwe_frodo/lwe_noise.c +++ /dev/null @@ -1,136 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include - -#include "local.h" - -#define RECOMMENDED_N_ARRAY_SIZE (752 * 8) -#define RECOMMENDED_CDF_TABLE_LEN 6 -#if defined(_WIN32) -// VS complains about arrays initialized with const param. On Windows, -// we use directly the recommended value passed down from calling functions. -// Currently there is only one set of params, so that works. Need to fix this -// in a more general setting (TODO). -#define IS_WINDOWS(windows, nix) (windows) -#else -#define IS_WINDOWS(windows, nix) (nix) -#endif - -static void lwe_sample_n_inverse_8(uint16_t *s, const size_t n, const uint8_t *cdf_table, const size_t cdf_table_len, OQS_RAND *rand) { - /* Fills vector s with n samples from the noise distribution which requires - * 8 bits to sample. The distribution is specified by its CDF. Super-constant - * timing: the CDF table is ingested for every sample. - */ - - uint8_t rndvec[IS_WINDOWS(RECOMMENDED_N_ARRAY_SIZE, n)]; - OQS_RAND_n(rand, rndvec, sizeof(rndvec)); - - for (size_t i = 0; i < n; ++i) { - uint8_t sample = 0; - uint8_t rnd = rndvec[i] >> 1; // drop the least significant bit - uint8_t sign = rndvec[i] & 0x1; // pick the least significant bit - - // No need to compare with the last value. - for (int64_t j = 0; j < (int64_t)(cdf_table_len - 1); j++) { - // Constant time comparison: 1 if cdf_table[j] < rnd, 0 otherwise. - // Critically uses the fact that cdf_table[j] and rnd fit in 7 bits. - sample += (uint8_t)(cdf_table[j] - rnd) >> 7; - } - // Assuming that sign is either 0 or 1, flips sample iff sign = 1 - s[i] = ((-sign) ^ sample) + sign; - } - OQS_MEM_cleanse(rndvec, sizeof(rndvec)); -} - -static void lwe_sample_n_inverse_12(uint16_t *s, const size_t n, const uint16_t *cdf_table, const size_t cdf_table_len, OQS_RAND *rand) { - /* Fills vector s with n samples from the noise distribution which requires - * 12 bits to sample. The distribution is specified by its CDF. Super-constant - * timing: the CDF table is ingested for every sample. - */ - - uint8_t rnd[3 * ((IS_WINDOWS(RECOMMENDED_N_ARRAY_SIZE, n) + 1) / 2)]; // 12 bits of unif randomness per output element - OQS_RAND_n(rand, rnd, sizeof(rnd)); - - for (size_t i = 0; i < n; i += 2) { // two output elements at a time - uint8_t *pRnd = (rnd + 3 * i / 2); - - uint16_t rnd1 = (((pRnd[0] << 8) + pRnd[1]) & 0xFFE0) >> 5; // first 11 bits (0..10) - uint16_t rnd2 = (((pRnd[1] << 8) + pRnd[2]) & 0x1FFC) >> 2; // next 11 bits (11..21) - - uint8_t sample1 = 0; - uint8_t sample2 = 0; - - // No need to compare with the last value. - for (size_t j = 0; j < cdf_table_len - 1; j++) { - // Constant time comparison: 1 if LWE_CDF_TABLE[j] < rnd1, 0 otherwise. - // Critically uses the fact that LWE_CDF_TABLE[j] and rnd1 fit in 15 bits. - sample1 += (uint16_t)(cdf_table[j] - rnd1) >> 15; - sample2 += (uint16_t)(cdf_table[j] - rnd2) >> 15; - } - - uint8_t sign1 = (pRnd[2] & 0x02) >> 1; // 22nd bit - uint8_t sign2 = pRnd[2] & 0x01; // 23rd bit - - // Assuming that sign1 is either 0 or 1, flips sample1 iff sign1 = 1 - s[i] = ((-sign1) ^ sample1) + sign1; - - if (i + 1 < n) { - s[i + 1] = ((-sign2) ^ sample2) + sign2; - } - } - OQS_MEM_cleanse(rnd, sizeof(rnd)); -} - -static void lwe_sample_n_inverse_16(uint16_t *s, const size_t n, const uint16_t *cdf_table, const size_t cdf_table_len, OQS_RAND *rand) { - /* Fills vector s with n samples from the noise distribution which requires - * 16 bits to sample. The distribution is specified by its CDF. Super-constant - * timing: the CDF table is ingested for every sample. - */ - - uint16_t rndvec[IS_WINDOWS(RECOMMENDED_N_ARRAY_SIZE, n)]; - OQS_RAND_n(rand, (uint8_t *) rndvec, sizeof(rndvec)); - - for (size_t i = 0; i < n; ++i) { - uint8_t sample = 0; - uint16_t rnd = rndvec[i] >> 1; // drop the least significant bit - uint8_t sign = rndvec[i] & 0x1; // pick the least significant bit - - // No need to compare with the last value. - for (size_t j = 0; j < cdf_table_len - 1; j++) { - // Constant time comparison: 1 if LWE_CDF_TABLE[j] < rnd, 0 otherwise. - // Critically uses the fact that LWE_CDF_TABLE[j] and rnd fit in 15 bits. - sample += (uint16_t)(cdf_table[j] - rnd) >> 15; - } - // Assuming that sign is either 0 or 1, flips sample iff sign = 1 - s[i] = ((-sign) ^ sample) + sign; - } - OQS_MEM_cleanse(rndvec, sizeof(rndvec)); -} - -void oqs_kex_lwe_frodo_sample_n(uint16_t *s, const size_t n, struct oqs_kex_lwe_frodo_params *params, OQS_RAND *rand) { - switch (params->sampler_num) { - case 8: { - // have to copy cdf_table from uint16_t to uint8_t - uint8_t cdf_table_8[IS_WINDOWS(RECOMMENDED_CDF_TABLE_LEN, params->cdf_table_len) * sizeof(uint8_t)]; - - for (size_t i = 0; i < params->cdf_table_len; i++) { - cdf_table_8[i] = (uint8_t) params->cdf_table[i]; - } - lwe_sample_n_inverse_8(s, n, cdf_table_8, params->cdf_table_len, rand); - } break; - case 12: - lwe_sample_n_inverse_12(s, n, params->cdf_table, params->cdf_table_len, rand); - break; - case 16: - lwe_sample_n_inverse_16(s, n, params->cdf_table, params->cdf_table_len, rand); - break; - default: - assert(0); //ERROR - break; - } -} diff --git a/src/kex_lwe_frodo/recommended.h b/src/kex_lwe_frodo/recommended.h deleted file mode 100644 index 725a94ac5..000000000 --- a/src/kex_lwe_frodo/recommended.h +++ /dev/null @@ -1,29 +0,0 @@ -//Recommended parameter set. Include twice to undefine - -#ifndef OQS_LWE_FRODO_RECOMMENDED_H -#define OQS_LWE_FRODO_RECOMMENDED_H -#define PARAMS_N 752 -#define PARAMS_NBAR 8 -#define PARAMS_LOG2Q 15 -#define PARAMS_Q (1 << PARAMS_LOG2Q) -#define PARAMS_EXTRACTED_BITS 4 -#define PARAMS_KEY_BITS 256 -#define PARAMS_KEY_BYTES (PARAMS_KEY_BITS >> 3) -#define PARAMS_STRIPE_STEP 8 -#define LWE_DIV_ROUNDUP(x, y) (((x) + (y) -1) / y) -#define PARAMS_REC_HINT_LENGTH LWE_DIV_ROUNDUP(PARAMS_NBAR *PARAMS_NBAR, 8) -#define PARAMS_REC_PUB_LENGTH LWE_DIV_ROUNDUP(PARAMS_N *PARAMS_NBAR *PARAMS_LOG2Q, 8) - -#else - -#undef OQS_LWE_FRODO_RECOMMENDED_H -#undef PARAMS_N -#undef PARAMS_NBAR -#undef PARAMS_LOG2Q -#undef PARAMS_Q -#undef PARAMS_EXTRACTED_BITS -#undef PARAMS_KEY_BITS -#undef PARAMS_STRIPE_STEP -#undef LWE_DIV_ROUNDUP -#undef PARAMS_REC_HINT_LENGTH -#endif