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