Remove kex_lwe_frodo and add kem_frodokem to master-new-api (#302)

* Remove kex_lwe_frodo

* Add FrodoKEM

* Prettyprint

* Missing liboqs.a

* Fix errors because of disabling frodokem

* Fix sike OQS_KEM_ prefix related inconsistencies

* Fix naming inconsistensies
This commit is contained in:
Douglas Stebila 2018-07-24 22:42:49 -04:00 committed by GitHub
parent 7f3d1b9e53
commit f5df1c159f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 1377 additions and 1050 deletions

1
.gitignore vendored
View File

@ -32,6 +32,7 @@ include
*.i*86
*.x86_64
*.hex
/example_kem
/speed_kem
/test_kem
/test_kex

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -46,8 +46,6 @@
<ClInclude Include="..\..\src\kex\kex.h" />
<ClInclude Include="..\..\src\kex_code_mcbits\kex_code_mcbits.h" />
<ClInclude Include="..\..\src\kex_code_mcbits\mcbits.h" />
<ClInclude Include="..\..\src\kex_lwe_frodo\kex_lwe_frodo.h" />
<ClInclude Include="..\..\src\kex_lwe_frodo\local.h" />
<ClInclude Include="..\..\src\kex_ntru\kex_ntru.h" />
<ClInclude Include="..\..\src\kex_rlwe_newhope\kex_rlwe_newhope.h" />
<ClInclude Include="..\..\src\kex_rlwe_newhope\params.h" />
@ -93,9 +91,6 @@
<ClCompile Include="..\..\src\kex\kex.c" />
<ClCompile Include="..\..\src\kex_code_mcbits\external\operations.c" />
<ClCompile Include="..\..\src\kex_code_mcbits\kex_code_mcbits.c" />
<ClCompile Include="..\..\src\kex_lwe_frodo\kex_lwe_frodo.c" />
<ClCompile Include="..\..\src\kex_lwe_frodo\lwe.c" />
<ClCompile Include="..\..\src\kex_lwe_frodo\lwe_noise.c" />
<ClCompile Include="..\..\src\kex_ntru\kex_ntru.c" />
<ClCompile Include="..\..\src\kex_rlwe_newhope\kex_rlwe_newhope.c" />
<ClCompile Include="..\..\src\kex_sidh_msr\kex_sidh_msr.c" />
@ -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\"

View File

@ -1,18 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="..\..\src\kex_lwe_frodo\kex_lwe_frodo.c">
<Filter>KEX_Frodo</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kex_rlwe_newhope\kex_rlwe_newhope.c">
<Filter>KEX_NewHope</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kex_lwe_frodo\lwe.c">
<Filter>KEX_Frodo</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kex_lwe_frodo\lwe_noise.c">
<Filter>KEX_Frodo</Filter>
</ClCompile>
<ClCompile Include="..\..\src\common\common.c">
<Filter>Common</Filter>
</ClCompile>
@ -123,15 +114,9 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\kex_lwe_frodo\kex_lwe_frodo.h">
<Filter>KEX_Frodo</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kex_rlwe_newhope\kex_rlwe_newhope.h">
<Filter>KEX_NewHope</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kex_lwe_frodo\local.h">
<Filter>KEX_Frodo</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kex_rlwe_newhope\params.h">
<Filter>KEX_NewHope</Filter>
</ClInclude>
@ -273,9 +258,6 @@
<Filter Include="KEX">
<UniqueIdentifier>{3bb6aa76-f294-47a9-bf22-76245c9cb1d1}</UniqueIdentifier>
</Filter>
<Filter Include="KEX_Frodo">
<UniqueIdentifier>{6bfff158-3e78-402f-ba16-e8d315089de8}</UniqueIdentifier>
</Filter>
<Filter Include="KEX_NewHope">
<UniqueIdentifier>{d0291785-4232-4264-b1bd-08b7e3f8df5e}</UniqueIdentifier>
</Filter>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 LindnerPeikert 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 197219. 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. 319339. 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. 8493. 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`

183
src/kem/example_kem.c Normal file
View File

@ -0,0 +1,183 @@
/*
* example_kem.c
*
* Minimal example of a Diffie-Hellman-style post-quantum key encapsulation
* implemented in liboqs.
*
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <oqs/oqs.h>
/* 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.
*
* <oqs/config.h>, which is included in <oqs/oqs.h>, 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);
}

View File

@ -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

90
src/kem/frodokem/config.h Normal file
View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -0,0 +1,34 @@
#include <stdint.h>
#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_

View File

@ -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"

View File

@ -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"

View File

@ -0,0 +1,34 @@
#include <stdint.h>
#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_

View File

@ -0,0 +1,342 @@
/********************************************************************************************
* FrodoKEM: Learning with Errors Key Encapsulation
*
* Abstract: matrix arithmetic functions used by the KEM
*********************************************************************************************/
#import <oqs/aes.h>
#if defined(USE_AVX2)
#include <immintrin.h>
#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;
}
}

View File

@ -0,0 +1,28 @@
/********************************************************************************************
* FrodoKEM: Learning with Errors Key Encapsulation
*
* Abstract: header for internal functions
*********************************************************************************************/
#ifndef _FRODO_MACRIFY_H_
#define _FRODO_MACRIFY_H_
#include <stddef.h>
#include <stdint.h>
#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

158
src/kem/frodokem/kem.c Normal file
View File

@ -0,0 +1,158 @@
/********************************************************************************************
* FrodoKEM: Learning with Errors Key Encapsulation
*
* Abstract: Key Encapsulation Mechanism (KEM) based on Frodo
*********************************************************************************************/
#include <oqs/rand.h>
#include <oqs/sha3.h>
#include <string.h>
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;
}

View File

@ -0,0 +1,111 @@
#include <stdlib.h>
#include <oqs/kem_frodokem.h>
#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

View File

@ -0,0 +1,66 @@
#ifndef __OQS_KEM_FRODOKEM_H
#define __OQS_KEM_FRODOKEM_H
#include <oqs/oqs.h>
#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

104
src/kem/frodokem/util.c Normal file
View File

@ -0,0 +1,104 @@
/********************************************************************************************
* FrodoKEM: Learning with Errors Key Encapsulation
*
* Abstract: additional functions for FrodoKEM
*********************************************************************************************/
#include <stdint.h>
#include <string.h>
#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++;
}
}
}

View File

@ -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 {

View File

@ -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 <oqs/kem_sike.h>
#include <oqs/kem_frodokem.h>
// EDIT-WHEN-ADDING-KEM
#endif // __OQS_KEM_H

View File

@ -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

View File

@ -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):
// ----------------------------------------------------------------------

View File

@ -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

View File

@ -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):
// ----------------------------------------------------------------------

View File

@ -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;
}

View File

@ -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

View File

@ -2,7 +2,6 @@
#include <oqs/kex.h>
#include <oqs/kex_lwe_frodo.h>
#include <oqs/kex_ntru.h>
#include <oqs/kex_rlwe_newhope.h>
#include <oqs/kex_sidh_msr.h>
@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -1,51 +0,0 @@
#include <stdlib.h>
#include <string.h>
#if !defined(_WIN32)
#include <strings.h>
#include <unistd.h>
#endif
#include <oqs/common.h>
#include <oqs/kex.h>
#include <oqs/rand.h>
#include "kex_lwe_frodo.h"
#include "local.h"
#define LWE_DIV_ROUNDUP(x, y) (((x) + (y) -1) / y)
#include <stdio.h>
// 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);
}

View File

@ -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 <stddef.h>
#include <stdint.h>
#include <oqs/common.h>
#include <oqs/kex.h>
#include <oqs/rand.h>
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

View File

@ -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 = <V>_{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;
}

View File

@ -1,42 +0,0 @@
#ifndef _OQS_KEX_LWE_FRODO_LOCAL_H_
#define _OQS_KEX_LWE_FRODO_LOCAL_H_
#include <stdint.h>
#include <oqs/rand.h>
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_ */

View File

@ -1,150 +0,0 @@
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "local.h"
#include <oqs/aes.h>
#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

View File

@ -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.
}
}
}

View File

@ -1,136 +0,0 @@
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <oqs/common.h>
#include <oqs/rand.h>
#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;
}
}

View File

@ -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