mirror of
https://github.com/open-quantum-safe/liboqs.git
synced 2025-11-27 00:04:24 -05:00
Merge pull request #475 from open-quantum-safe/ds-frodo-round2
Add FrodoKEM Round 2
This commit is contained in:
commit
d112a8a1b0
@ -10,15 +10,9 @@ EXPORTS
|
||||
OQS_KEM_frodokem_640_aes_decaps
|
||||
OQS_KEM_frodokem_640_aes_encaps
|
||||
OQS_KEM_frodokem_640_aes_keypair
|
||||
OQS_KEM_frodokem_640_cshake_decaps
|
||||
OQS_KEM_frodokem_640_cshake_encaps
|
||||
OQS_KEM_frodokem_640_cshake_keypair
|
||||
OQS_KEM_frodokem_976_aes_decaps
|
||||
OQS_KEM_frodokem_976_aes_encaps
|
||||
OQS_KEM_frodokem_976_aes_keypair
|
||||
OQS_KEM_frodokem_976_cshake_decaps
|
||||
OQS_KEM_frodokem_976_cshake_encaps
|
||||
OQS_KEM_frodokem_976_cshake_keypair
|
||||
OQS_KEM_frodokem_640_shake_decaps
|
||||
OQS_KEM_frodokem_640_shake_encaps
|
||||
OQS_KEM_frodokem_640_shake_keypair
|
||||
OQS_KEM_kyber_512_cca_kem_keypair
|
||||
OQS_KEM_kyber_512_cca_kem_encaps
|
||||
OQS_KEM_kyber_512_cca_kem_decaps
|
||||
|
||||
@ -35,7 +35,6 @@
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\kem\frodokem\kem_frodokem.h" />
|
||||
<ClInclude Include="..\..\src\kem\kyber\kem_kyber.h" />
|
||||
<ClInclude Include="..\..\src\kem\newhopenist\kem_newhopenist.h" />
|
||||
<ClInclude Include="..\..\src\kem\kem.h" />
|
||||
@ -84,12 +83,36 @@
|
||||
<ClCompile Include="..\..\src\crypto\aes\aes_c.c" />
|
||||
<ClCompile Include="..\..\src\crypto\aes\aes_ni.c" />
|
||||
<ClCompile Include="..\..\src\crypto\sha3\sha3.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\frodo640_aes.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\frodo640_cshake.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\frodo976_aes.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\frodo976_cshake.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\kem_frodokem.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\util.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\kem_frodokem640aes.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem640aes_clean\kem.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem640aes_clean\matrix_aes.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem640aes_clean\noise.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem640aes_clean\util.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\kem_frodokem640shake.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem640shake_clean\kem.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem640shake_clean\matrix_shake.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem640shake_clean\noise.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem640shake_clean\util.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\kem_frodokem976aes.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem976aes_clean\kem.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem976aes_clean\matrix_aes.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem976aes_clean\noise.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem976aes_clean\util.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\kem_frodokem976shake.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem976shake_clean\kem.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem976shake_clean\matrix_shake.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem976shake_clean\noise.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem976shake_clean\util.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\kem_frodokem1344aes.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem1344aes_clean\kem.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem1344aes_clean\matrix_aes.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem1344aes_clean\noise.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem1344aes_clean\util.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\kem_frodokem1344shake.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem1344shake_clean\kem.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem1344shake_clean\matrix_shake.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem1344shake_clean\noise.c" />
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem1344shake_clean\util.c" />
|
||||
<ClCompile Include="..\..\src\kem\kyber\kem_kyber.c" />
|
||||
<ClCompile Include="..\..\src\kem\kyber\win_kyber1024.c" />
|
||||
<ClCompile Include="..\..\src\kem\kyber\win_kyber512.c" />
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\common\common.c">
|
||||
@ -25,23 +25,95 @@
|
||||
<ClCompile Include="..\..\src\kem\kem.c">
|
||||
<Filter>kem</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\kem_frodokem.c">
|
||||
<Filter>frodo</Filter>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\kem_frodokem640aes.c">
|
||||
<Filter>frodo\640aes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\frodo640_aes.c">
|
||||
<Filter>frodo</Filter>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem640aes_clean\kem.c">
|
||||
<Filter>frodo\640aes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\frodo640_cshake.c">
|
||||
<Filter>frodo</Filter>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem640aes_clean\matrix_aes.c">
|
||||
<Filter>frodo\640aes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\frodo976_aes.c">
|
||||
<Filter>frodo</Filter>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem640aes_clean\noise.c">
|
||||
<Filter>frodo\640aes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\frodo976_cshake.c">
|
||||
<Filter>frodo</Filter>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem640aes_clean\util.c">
|
||||
<Filter>frodo\640aes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\util.c">
|
||||
<Filter>frodo</Filter>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\kem_frodokem640shake.c">
|
||||
<Filter>frodo\640shake</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem640shake_clean\kem.c">
|
||||
<Filter>frodo\640shake</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem640shake_clean\matrix_shake.c">
|
||||
<Filter>frodo\640shake</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem640shake_clean\noise.c">
|
||||
<Filter>frodo\640shake</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem640shake_clean\util.c">
|
||||
<Filter>frodo\640shake</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\kem_frodokem976aes.c">
|
||||
<Filter>frodo\976aes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem976aes_clean\kem.c">
|
||||
<Filter>frodo\976aes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem976aes_clean\matrix_aes.c">
|
||||
<Filter>frodo\976aes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem976aes_clean\noise.c">
|
||||
<Filter>frodo\976aes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem976aes_clean\util.c">
|
||||
<Filter>frodo\976aes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\kem_frodokem976shake.c">
|
||||
<Filter>frodo\976shake</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem976shake_clean\kem.c">
|
||||
<Filter>frodo\976shake</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem976shake_clean\matrix_shake.c">
|
||||
<Filter>frodo\976shake</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem976shake_clean\noise.c">
|
||||
<Filter>frodo\976shake</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem976shake_clean\util.c">
|
||||
<Filter>frodo\976shake</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\kem_frodokem1344aes.c">
|
||||
<Filter>frodo\1344aes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem1344aes_clean\kem.c">
|
||||
<Filter>frodo\1344aes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem1344aes_clean\matrix_aes.c">
|
||||
<Filter>frodo\1344aes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem1344aes_clean\noise.c">
|
||||
<Filter>frodo\1344aes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem1344aes_clean\util.c">
|
||||
<Filter>frodo\1344aes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\kem_frodokem1344shake.c">
|
||||
<Filter>frodo\1344shake</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem1344shake_clean\kem.c">
|
||||
<Filter>frodo\1344shake</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem1344shake_clean\matrix_shake.c">
|
||||
<Filter>frodo\1344shake</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem1344shake_clean\noise.c">
|
||||
<Filter>frodo\1344shake</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\frodokem\pqclean_frodokem1344shake_clean\util.c">
|
||||
<Filter>frodo\1344shake</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kem\sike\kem_sike.c">
|
||||
<Filter>sike</Filter>
|
||||
@ -161,9 +233,6 @@
|
||||
<ClInclude Include="..\..\src\kem\kem.h">
|
||||
<Filter>kem</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kem\frodokem\kem_frodokem.h">
|
||||
<Filter>frodo</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kem\sike\kem_sike.h">
|
||||
<Filter>sike</Filter>
|
||||
</ClInclude>
|
||||
@ -274,9 +343,6 @@
|
||||
<Filter Include="kem">
|
||||
<UniqueIdentifier>{ceb9c773-d92e-44b7-916a-eb1d6a2ec89b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="frodo">
|
||||
<UniqueIdentifier>{10d21755-2db3-4ce1-a5ce-fbfe1aadcc53}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="sike">
|
||||
<UniqueIdentifier>{620a9f8e-2013-4cb3-ad37-2ee4348ed893}</UniqueIdentifier>
|
||||
</Filter>
|
||||
@ -286,5 +352,23 @@
|
||||
<Filter Include="kyber">
|
||||
<UniqueIdentifier>{17171b11-2a2c-4084-a710-c555295e2484}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="frodo\640aes">
|
||||
<UniqueIdentifier>{453e77f7-95b8-4adc-adc8-033fe561c018}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="frodo\976aes">
|
||||
<UniqueIdentifier>{c94df6b4-9bff-4578-afc4-b6231012249a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="frodo\1344aes">
|
||||
<UniqueIdentifier>{3c0ce99d-3db6-4a29-8c4d-d1fd4fcda1ab}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="frodo\640shake">
|
||||
<UniqueIdentifier>{0e47e6c0-e5f5-4614-8d31-e0d3caea98eb}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="frodo\976shake">
|
||||
<UniqueIdentifier>{90a8df32-f17b-431b-b488-7a21b1c7d2d3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="frodo\1344shake">
|
||||
<UniqueIdentifier>{de0439be-1a4f-42e3-90f1-e667ccad442b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@ -3,9 +3,11 @@
|
||||
|
||||
/* Enable schemes supported on Windows */
|
||||
#define OQS_ENABLE_KEM_frodokem_640_aes
|
||||
#define OQS_ENABLE_KEM_frodokem_976_aes
|
||||
#define OQS_ENABLE_KEM_frodokem_640_cshake
|
||||
#define OQS_ENABLE_KEM_frodokem_976_cshake
|
||||
#define OQS_ENABLE_KEM_frodokem_640_shake
|
||||
/* #define OQS_ENABLE_KEM_frodokem_976_aes */
|
||||
/* #define OQS_ENABLE_KEM_frodokem_976_shake */
|
||||
/* #define OQS_ENABLE_KEM_frodokem_1344_aes */
|
||||
/* #define OQS_ENABLE_KEM_frodokem_1344_shake */
|
||||
#define OQS_ENABLE_KEM_kyber_512_cca_kem
|
||||
#define OQS_ENABLE_KEM_kyber_768_cca_kem
|
||||
#define OQS_ENABLE_KEM_kyber_1024_cca_kem
|
||||
|
||||
@ -81,9 +81,11 @@ AC_DEFUN([CONFIG_FEATURES],
|
||||
|
||||
AM_COND_IF([ENABLE_KEM_FRODOKEM], [
|
||||
AC_DEFINE(OQS_ENABLE_KEM_frodokem_640_aes, 1, "Define to 1 when FrodoKEM-640-AES enabled")
|
||||
AC_DEFINE(OQS_ENABLE_KEM_frodokem_640_cshake, 1, "Define to 1 when FrodoKEM-640-cSHAKE enabled")
|
||||
AC_DEFINE(OQS_ENABLE_KEM_frodokem_640_shake, 1, "Define to 1 when FrodoKEM-640-SHAKE enabled")
|
||||
AC_DEFINE(OQS_ENABLE_KEM_frodokem_976_aes, 1, "Define to 1 when FrodoKEM-976-AES enabled")
|
||||
AC_DEFINE(OQS_ENABLE_KEM_frodokem_976_cshake, 1, "Define to 1 when FrodoKEM-976-cSHAKE enabled")
|
||||
AC_DEFINE(OQS_ENABLE_KEM_frodokem_976_shake, 1, "Define to 1 when FrodoKEM-976-SHAKE enabled")
|
||||
AC_DEFINE(OQS_ENABLE_KEM_frodokem_1344_aes, 1, "Define to 1 when FrodoKEM-1344-AES enabled")
|
||||
AC_DEFINE(OQS_ENABLE_KEM_frodokem_1344_shake, 1, "Define to 1 when FrodoKEM-1344-SHAKE enabled")
|
||||
])
|
||||
|
||||
AM_COND_IF([ENABLE_KEM_SIKE], [
|
||||
|
||||
@ -10,22 +10,25 @@ Summary
|
||||
- **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
|
||||
- **NIST Round 2 submission**
|
||||
|
||||
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 |
|
||||
| FrodoKEM-640-AES | IND-CCA | 1 | 9616 | 19888 | 9720 | 16 |
|
||||
| FrodoKEM-640-SHAKE | IND-CCA | 1 | 9616 | 19888 | 9720 | 16 |
|
||||
| FrodoKEM-976-AES | IND-CCA | 3 | 15632 | 31296 | 15744 | 24 |
|
||||
| FrodoKEM-976-SHAKE | IND-CCA | 3 | 15632 | 31296 | 15744 | 24 |
|
||||
| FrodoKEM-1344-AES | IND-CCA | 5 | 21520 | 43088 | 21632 | 32 |
|
||||
| FrodoKEM-1344-SHAKE | IND-CCA | 5 | 15632 | 43088 | 21632 | 32 |
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
|
||||
- **Source of implementation:** https://github.com/Microsoft/PQCrypto-LWEKE
|
||||
- **Implementation version:** https://github.com/Microsoft/PQCrypto-LWEKE/commit/47da00a91270b6f103232314eef0b891b83bfd3b
|
||||
- **Source of implementation:** https://github.com/Microsoft/PQCrypto-LWEKE/
|
||||
- **Implementation version:** https://github.com/PQClean/PQClean/commit/e72fd489baaef597715aa4335ceeea4362301b55
|
||||
- **License:** MIT License
|
||||
- **Language:** C
|
||||
- **Constant-time:** Yes
|
||||
|
||||
14
scripts/copy_from_pqclean.sh
Executable file
14
scripts/copy_from_pqclean.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
if [ "x${PQCLEAN_DIR}" == "x" ]; then
|
||||
echo "Must specify PQCLEAN_DIR environment variable"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for SCHEME in frodokem640aes frodokem640shake frodokem976aes frodokem976shake frodokem1344aes frodokem1344shake; do
|
||||
rm -rf src/kem/frodokem/pqclean_${SCHEME}_clean
|
||||
cp -pr ${PQCLEAN_DIR}/crypto_kem/${SCHEME}/clean src/kem/frodokem/pqclean_${SCHEME}_clean
|
||||
rm src/kem/frodokem/pqclean_${SCHEME}_clean/Makefile*
|
||||
done
|
||||
29
src/common/pqclean_shims/aes.h
Normal file
29
src/common/pqclean_shims/aes.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef AES_H
|
||||
#define AES_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <oqs/aes.h>
|
||||
|
||||
#define AES128_KEYBYTES 16
|
||||
#define AES192_KEYBYTES 24
|
||||
#define AES256_KEYBYTES 32
|
||||
#define AESCTR_NONCEBYTES 12
|
||||
#define AES_BLOCKBYTES 16
|
||||
|
||||
typedef void * aes128ctx;
|
||||
|
||||
static void aes128_keyexp(aes128ctx *r, const unsigned char *key) {
|
||||
OQS_AES128_load_schedule(key, r, 1);
|
||||
}
|
||||
|
||||
static void aes128_ecb(unsigned char *out, const unsigned char *in, size_t nblocks, aes128ctx *ctx) {
|
||||
OQS_AES128_ECB_enc_sch(in, nblocks * AES_BLOCKBYTES, *ctx, out);
|
||||
OQS_AES128_free_schedule(*ctx);
|
||||
// FIXME: PQClean AES API expects that aes128_ecb can be called multiple
|
||||
// times with the same key schedule, but this instantiation does not, since
|
||||
// it frees the key schedule immediately
|
||||
}
|
||||
|
||||
#endif
|
||||
6
src/kem/frodokem/FrodoKEM-1344-AES.kat
Normal file
6
src/kem/frodokem/FrodoKEM-1344-AES.kat
Normal file
File diff suppressed because one or more lines are too long
6
src/kem/frodokem/FrodoKEM-1344-SHAKE.kat
Normal file
6
src/kem/frodokem/FrodoKEM-1344-SHAKE.kat
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
6
src/kem/frodokem/FrodoKEM-640-SHAKE.kat
Normal file
6
src/kem/frodokem/FrodoKEM-640-SHAKE.kat
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
6
src/kem/frodokem/FrodoKEM-976-SHAKE.kat
Normal file
6
src/kem/frodokem/FrodoKEM-976-SHAKE.kat
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,9 +1,24 @@
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
noinst_LTLIBRARIES = libkemfrodokem.la
|
||||
noinst_LTLIBRARIES = libkemfrodokem.la
|
||||
noinst_LTLIBRARIES += libkemfrodokem640aes.la libkemfrodokem640shake.la libkemfrodokem976aes.la libkemfrodokem976shake.la libkemfrodokem1344aes.la libkemfrodokem1344shake.la
|
||||
|
||||
libkemfrodokem_la_SOURCES = kem_frodokem.c frodo640_aes.c frodo640_cshake.c frodo976_aes.c frodo976_cshake.c util.c
|
||||
libkemfrodokem_la_LIBADD = libkemfrodokem640aes.la libkemfrodokem640shake.la libkemfrodokem976aes.la libkemfrodokem976shake.la libkemfrodokem1344aes.la libkemfrodokem1344shake.la
|
||||
libkemfrodokem_la_SOURCES =
|
||||
|
||||
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
|
||||
libkemfrodokem640aes_la_SOURCES = kem_frodokem640aes.c pqclean_frodokem640aes_clean/kem.c pqclean_frodokem640aes_clean/matrix_aes.c pqclean_frodokem640aes_clean/noise.c pqclean_frodokem640aes_clean/util.c
|
||||
libkemfrodokem640aes_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims
|
||||
|
||||
libkemfrodokem640shake_la_SOURCES = kem_frodokem640shake.c pqclean_frodokem640shake_clean/kem.c pqclean_frodokem640shake_clean/matrix_shake.c pqclean_frodokem640shake_clean/noise.c pqclean_frodokem640shake_clean/util.c
|
||||
libkemfrodokem640shake_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims
|
||||
|
||||
libkemfrodokem976aes_la_SOURCES = kem_frodokem976aes.c pqclean_frodokem976aes_clean/kem.c pqclean_frodokem976aes_clean/matrix_aes.c pqclean_frodokem976aes_clean/noise.c pqclean_frodokem976aes_clean/util.c
|
||||
libkemfrodokem976aes_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims
|
||||
|
||||
libkemfrodokem976shake_la_SOURCES = kem_frodokem976shake.c pqclean_frodokem976shake_clean/kem.c pqclean_frodokem976shake_clean/matrix_shake.c pqclean_frodokem976shake_clean/noise.c pqclean_frodokem976shake_clean/util.c
|
||||
libkemfrodokem976shake_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims
|
||||
|
||||
libkemfrodokem1344aes_la_SOURCES = kem_frodokem1344aes.c pqclean_frodokem1344aes_clean/kem.c pqclean_frodokem1344aes_clean/matrix_aes.c pqclean_frodokem1344aes_clean/noise.c pqclean_frodokem1344aes_clean/util.c
|
||||
libkemfrodokem1344aes_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims
|
||||
|
||||
libkemfrodokem1344shake_la_SOURCES = kem_frodokem1344shake.c pqclean_frodokem1344shake_clean/kem.c pqclean_frodokem1344shake_clean/matrix_shake.c pqclean_frodokem1344shake_clean/noise.c pqclean_frodokem1344shake_clean/util.c
|
||||
libkemfrodokem1344shake_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims
|
||||
|
||||
@ -1,90 +0,0 @@
|
||||
/********************************************************************************************
|
||||
* 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
|
||||
@ -1,20 +0,0 @@
|
||||
/********************************************************************************************
|
||||
* 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"
|
||||
@ -1,20 +0,0 @@
|
||||
/********************************************************************************************
|
||||
* 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"
|
||||
@ -1,34 +0,0 @@
|
||||
#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_
|
||||
@ -1,20 +0,0 @@
|
||||
/********************************************************************************************
|
||||
* 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"
|
||||
@ -1,20 +0,0 @@
|
||||
/********************************************************************************************
|
||||
* 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"
|
||||
@ -1,34 +0,0 @@
|
||||
#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_
|
||||
@ -1,342 +0,0 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: matrix arithmetic functions used by the KEM
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <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]) = *((const 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]) = *((const 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)((const 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;
|
||||
}
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: header for internal functions
|
||||
*********************************************************************************************/
|
||||
|
||||
#ifndef _FRODOKEM_MACRIFY_H_
|
||||
#define _FRODOKEM_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
|
||||
@ -1,158 +0,0 @@
|
||||
/********************************************************************************************
|
||||
* 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>
|
||||
|
||||
OQS_API 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 OQS_SUCCESS;
|
||||
}
|
||||
|
||||
OQS_API 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 OQS_SUCCESS;
|
||||
}
|
||||
|
||||
OQS_API 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};
|
||||
const uint16_t *S = (const 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 OQS_SUCCESS;
|
||||
}
|
||||
@ -1,115 +0,0 @@
|
||||
#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->alg_version = "https://github.com/Microsoft/PQCrypto-LWEKE/commit/47da00a91270b6f103232314eef0b891b83bfd3b";
|
||||
|
||||
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->alg_version = "https://github.com/Microsoft/PQCrypto-LWEKE/commit/47da00a91270b6f103232314eef0b891b83bfd3b";
|
||||
|
||||
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->alg_version = "https://github.com/Microsoft/PQCrypto-LWEKE/commit/47da00a91270b6f103232314eef0b891b83bfd3b";
|
||||
|
||||
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->alg_version = "https://github.com/Microsoft/PQCrypto-LWEKE/commit/47da00a91270b6f103232314eef0b891b83bfd3b";
|
||||
|
||||
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
|
||||
@ -4,63 +4,69 @@
|
||||
#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_secret_key 19888
|
||||
#define OQS_KEM_frodokem_640_aes_length_ciphertext 9720
|
||||
#define OQS_KEM_frodokem_640_aes_length_shared_secret 16
|
||||
|
||||
OQS_KEM *OQS_KEM_frodokem_640_aes_new();
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_640_aes_keypair(uint8_t *public_key, uint8_t *secret_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_640_aes_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key);
|
||||
OQS_API 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_640_shake
|
||||
#define OQS_KEM_frodokem_640_shake_length_public_key 9616
|
||||
#define OQS_KEM_frodokem_640_shake_length_secret_key 19888
|
||||
#define OQS_KEM_frodokem_640_shake_length_ciphertext 9720
|
||||
#define OQS_KEM_frodokem_640_shake_length_shared_secret 16
|
||||
OQS_KEM *OQS_KEM_frodokem_640_shake_new();
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_640_shake_keypair(uint8_t *public_key, uint8_t *secret_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_640_shake_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_640_shake_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_secret_key 31296
|
||||
#define OQS_KEM_frodokem_976_aes_length_ciphertext 15744
|
||||
#define OQS_KEM_frodokem_976_aes_length_shared_secret 24
|
||||
|
||||
OQS_KEM *OQS_KEM_frodokem_976_aes_new();
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_976_aes_keypair(uint8_t *public_key, uint8_t *secret_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_976_aes_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key);
|
||||
OQS_API 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();
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_640_cshake_keypair(uint8_t *public_key, uint8_t *secret_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_640_cshake_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_640_cshake_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key);
|
||||
|
||||
#ifdef OQS_ENABLE_KEM_frodokem_976_shake
|
||||
#define OQS_KEM_frodokem_976_shake_length_public_key 15632
|
||||
#define OQS_KEM_frodokem_976_shake_length_secret_key 31296
|
||||
#define OQS_KEM_frodokem_976_shake_length_ciphertext 15744
|
||||
#define OQS_KEM_frodokem_976_shake_length_shared_secret 24
|
||||
OQS_KEM *OQS_KEM_frodokem_976_shake_new();
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_976_shake_keypair(uint8_t *public_key, uint8_t *secret_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_976_shake_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_976_shake_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();
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_976_cshake_keypair(uint8_t *public_key, uint8_t *secret_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_976_cshake_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_976_cshake_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key);
|
||||
#ifdef OQS_ENABLE_KEM_frodokem_1344_aes
|
||||
#define OQS_KEM_frodokem_1344_aes_length_public_key 21520
|
||||
#define OQS_KEM_frodokem_1344_aes_length_secret_key 43088
|
||||
#define OQS_KEM_frodokem_1344_aes_length_ciphertext 21632
|
||||
#define OQS_KEM_frodokem_1344_aes_length_shared_secret 32
|
||||
OQS_KEM *OQS_KEM_frodokem_1344_aes_new();
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_1344_aes_keypair(uint8_t *public_key, uint8_t *secret_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_1344_aes_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_1344_aes_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key);
|
||||
#endif
|
||||
|
||||
#ifdef OQS_ENABLE_KEM_frodokem_1344_shake
|
||||
#define OQS_KEM_frodokem_1344_shake_length_public_key 21520
|
||||
#define OQS_KEM_frodokem_1344_shake_length_secret_key 43088
|
||||
#define OQS_KEM_frodokem_1344_shake_length_ciphertext 21632
|
||||
#define OQS_KEM_frodokem_1344_shake_length_shared_secret 32
|
||||
OQS_KEM *OQS_KEM_frodokem_1344_shake_new();
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_1344_shake_keypair(uint8_t *public_key, uint8_t *secret_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_1344_shake_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_1344_shake_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
50
src/kem/frodokem/kem_frodokem1344aes.c
Normal file
50
src/kem/frodokem/kem_frodokem1344aes.c
Normal file
@ -0,0 +1,50 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <oqs/kem_frodokem.h>
|
||||
|
||||
#ifdef OQS_ENABLE_KEM_frodokem_1344_aes
|
||||
|
||||
OQS_KEM *OQS_KEM_frodokem_1344_aes_new() {
|
||||
|
||||
OQS_KEM *kem = malloc(sizeof(OQS_KEM));
|
||||
if (kem == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
kem->method_name = OQS_KEM_alg_frodokem_1344_aes;
|
||||
kem->alg_version = "https://github.com/PQClean/PQClean/commit/e72fd489baaef597715aa4335ceeea4362301b55";
|
||||
|
||||
kem->claimed_nist_level = 5;
|
||||
kem->ind_cca = true;
|
||||
|
||||
kem->length_public_key = OQS_KEM_frodokem_1344_aes_length_public_key;
|
||||
kem->length_secret_key = OQS_KEM_frodokem_1344_aes_length_secret_key;
|
||||
kem->length_ciphertext = OQS_KEM_frodokem_1344_aes_length_ciphertext;
|
||||
kem->length_shared_secret = OQS_KEM_frodokem_1344_aes_length_shared_secret;
|
||||
|
||||
kem->keypair = OQS_KEM_frodokem_1344_aes_keypair;
|
||||
kem->encaps = OQS_KEM_frodokem_1344_aes_encaps;
|
||||
kem->decaps = OQS_KEM_frodokem_1344_aes_decaps;
|
||||
|
||||
return kem;
|
||||
}
|
||||
|
||||
int PQCLEAN_FRODOKEM1344AES_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk);
|
||||
int PQCLEAN_FRODOKEM1344AES_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk);
|
||||
int PQCLEAN_FRODOKEM1344AES_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk);
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_1344_aes_keypair(uint8_t *public_key,
|
||||
uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_FRODOKEM1344AES_CLEAN_crypto_kem_keypair(public_key, secret_key);
|
||||
}
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_1344_aes_encaps(uint8_t *ciphertext,
|
||||
uint8_t *shared_secret,
|
||||
const uint8_t *public_key) {
|
||||
return (OQS_STATUS) PQCLEAN_FRODOKEM1344AES_CLEAN_crypto_kem_enc(ciphertext, shared_secret, public_key);
|
||||
}
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_1344_aes_decaps(uint8_t *shared_secret,
|
||||
const unsigned char *ciphertext,
|
||||
const uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_FRODOKEM1344AES_CLEAN_crypto_kem_dec(shared_secret, ciphertext, secret_key);
|
||||
}
|
||||
|
||||
#endif
|
||||
50
src/kem/frodokem/kem_frodokem1344shake.c
Normal file
50
src/kem/frodokem/kem_frodokem1344shake.c
Normal file
@ -0,0 +1,50 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <oqs/kem_frodokem.h>
|
||||
|
||||
#ifdef OQS_ENABLE_KEM_frodokem_1344_shake
|
||||
|
||||
OQS_KEM *OQS_KEM_frodokem_1344_shake_new() {
|
||||
|
||||
OQS_KEM *kem = malloc(sizeof(OQS_KEM));
|
||||
if (kem == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
kem->method_name = OQS_KEM_alg_frodokem_1344_shake;
|
||||
kem->alg_version = "https://github.com/PQClean/PQClean/commit/e72fd489baaef597715aa4335ceeea4362301b55";
|
||||
|
||||
kem->claimed_nist_level = 5;
|
||||
kem->ind_cca = true;
|
||||
|
||||
kem->length_public_key = OQS_KEM_frodokem_1344_shake_length_public_key;
|
||||
kem->length_secret_key = OQS_KEM_frodokem_1344_shake_length_secret_key;
|
||||
kem->length_ciphertext = OQS_KEM_frodokem_1344_shake_length_ciphertext;
|
||||
kem->length_shared_secret = OQS_KEM_frodokem_1344_shake_length_shared_secret;
|
||||
|
||||
kem->keypair = OQS_KEM_frodokem_1344_shake_keypair;
|
||||
kem->encaps = OQS_KEM_frodokem_1344_shake_encaps;
|
||||
kem->decaps = OQS_KEM_frodokem_1344_shake_decaps;
|
||||
|
||||
return kem;
|
||||
}
|
||||
|
||||
int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk);
|
||||
int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk);
|
||||
int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk);
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_1344_shake_keypair(uint8_t *public_key,
|
||||
uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_FRODOKEM1344SHAKE_CLEAN_crypto_kem_keypair(public_key, secret_key);
|
||||
}
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_1344_shake_encaps(uint8_t *ciphertext,
|
||||
uint8_t *shared_secret,
|
||||
const uint8_t *public_key) {
|
||||
return (OQS_STATUS) PQCLEAN_FRODOKEM1344SHAKE_CLEAN_crypto_kem_enc(ciphertext, shared_secret, public_key);
|
||||
}
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_1344_shake_decaps(uint8_t *shared_secret,
|
||||
const unsigned char *ciphertext,
|
||||
const uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_FRODOKEM1344SHAKE_CLEAN_crypto_kem_dec(shared_secret, ciphertext, secret_key);
|
||||
}
|
||||
|
||||
#endif
|
||||
50
src/kem/frodokem/kem_frodokem640aes.c
Normal file
50
src/kem/frodokem/kem_frodokem640aes.c
Normal file
@ -0,0 +1,50 @@
|
||||
#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->alg_version = "https://github.com/PQClean/PQClean/commit/e72fd489baaef597715aa4335ceeea4362301b55";
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int PQCLEAN_FRODOKEM640AES_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk);
|
||||
int PQCLEAN_FRODOKEM640AES_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk);
|
||||
int PQCLEAN_FRODOKEM640AES_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk);
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_640_aes_keypair(uint8_t *public_key,
|
||||
uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_FRODOKEM640AES_CLEAN_crypto_kem_keypair(public_key, secret_key);
|
||||
}
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_640_aes_encaps(uint8_t *ciphertext,
|
||||
uint8_t *shared_secret,
|
||||
const uint8_t *public_key) {
|
||||
return (OQS_STATUS) PQCLEAN_FRODOKEM640AES_CLEAN_crypto_kem_enc(ciphertext, shared_secret, public_key);
|
||||
}
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_640_aes_decaps(uint8_t *shared_secret,
|
||||
const unsigned char *ciphertext,
|
||||
const uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_FRODOKEM640AES_CLEAN_crypto_kem_dec(shared_secret, ciphertext, secret_key);
|
||||
}
|
||||
|
||||
#endif
|
||||
50
src/kem/frodokem/kem_frodokem640shake.c
Normal file
50
src/kem/frodokem/kem_frodokem640shake.c
Normal file
@ -0,0 +1,50 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <oqs/kem_frodokem.h>
|
||||
|
||||
#ifdef OQS_ENABLE_KEM_frodokem_640_shake
|
||||
|
||||
OQS_KEM *OQS_KEM_frodokem_640_shake_new() {
|
||||
|
||||
OQS_KEM *kem = malloc(sizeof(OQS_KEM));
|
||||
if (kem == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
kem->method_name = OQS_KEM_alg_frodokem_640_shake;
|
||||
kem->alg_version = "https://github.com/PQClean/PQClean/commit/e72fd489baaef597715aa4335ceeea4362301b55";
|
||||
|
||||
kem->claimed_nist_level = 1;
|
||||
kem->ind_cca = true;
|
||||
|
||||
kem->length_public_key = OQS_KEM_frodokem_640_shake_length_public_key;
|
||||
kem->length_secret_key = OQS_KEM_frodokem_640_shake_length_secret_key;
|
||||
kem->length_ciphertext = OQS_KEM_frodokem_640_shake_length_ciphertext;
|
||||
kem->length_shared_secret = OQS_KEM_frodokem_640_shake_length_shared_secret;
|
||||
|
||||
kem->keypair = OQS_KEM_frodokem_640_shake_keypair;
|
||||
kem->encaps = OQS_KEM_frodokem_640_shake_encaps;
|
||||
kem->decaps = OQS_KEM_frodokem_640_shake_decaps;
|
||||
|
||||
return kem;
|
||||
}
|
||||
|
||||
int PQCLEAN_FRODOKEM640SHAKE_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk);
|
||||
int PQCLEAN_FRODOKEM640SHAKE_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk);
|
||||
int PQCLEAN_FRODOKEM640SHAKE_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk);
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_640_shake_keypair(uint8_t *public_key,
|
||||
uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_FRODOKEM640SHAKE_CLEAN_crypto_kem_keypair(public_key, secret_key);
|
||||
}
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_640_shake_encaps(uint8_t *ciphertext,
|
||||
uint8_t *shared_secret,
|
||||
const uint8_t *public_key) {
|
||||
return (OQS_STATUS) PQCLEAN_FRODOKEM640SHAKE_CLEAN_crypto_kem_enc(ciphertext, shared_secret, public_key);
|
||||
}
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_640_shake_decaps(uint8_t *shared_secret,
|
||||
const unsigned char *ciphertext,
|
||||
const uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_FRODOKEM640SHAKE_CLEAN_crypto_kem_dec(shared_secret, ciphertext, secret_key);
|
||||
}
|
||||
|
||||
#endif
|
||||
50
src/kem/frodokem/kem_frodokem976aes.c
Normal file
50
src/kem/frodokem/kem_frodokem976aes.c
Normal file
@ -0,0 +1,50 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <oqs/kem_frodokem.h>
|
||||
|
||||
#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->alg_version = "https://github.com/PQClean/PQClean/commit/e72fd489baaef597715aa4335ceeea4362301b55";
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int PQCLEAN_FRODOKEM976AES_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk);
|
||||
int PQCLEAN_FRODOKEM976AES_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk);
|
||||
int PQCLEAN_FRODOKEM976AES_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk);
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_976_aes_keypair(uint8_t *public_key,
|
||||
uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_FRODOKEM976AES_CLEAN_crypto_kem_keypair(public_key, secret_key);
|
||||
}
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_976_aes_encaps(uint8_t *ciphertext,
|
||||
uint8_t *shared_secret,
|
||||
const uint8_t *public_key) {
|
||||
return (OQS_STATUS) PQCLEAN_FRODOKEM976AES_CLEAN_crypto_kem_enc(ciphertext, shared_secret, public_key);
|
||||
}
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_976_aes_decaps(uint8_t *shared_secret,
|
||||
const unsigned char *ciphertext,
|
||||
const uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_FRODOKEM976AES_CLEAN_crypto_kem_dec(shared_secret, ciphertext, secret_key);
|
||||
}
|
||||
|
||||
#endif
|
||||
50
src/kem/frodokem/kem_frodokem976shake.c
Normal file
50
src/kem/frodokem/kem_frodokem976shake.c
Normal file
@ -0,0 +1,50 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <oqs/kem_frodokem.h>
|
||||
|
||||
#ifdef OQS_ENABLE_KEM_frodokem_976_shake
|
||||
|
||||
OQS_KEM *OQS_KEM_frodokem_976_shake_new() {
|
||||
|
||||
OQS_KEM *kem = malloc(sizeof(OQS_KEM));
|
||||
if (kem == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
kem->method_name = OQS_KEM_alg_frodokem_976_shake;
|
||||
kem->alg_version = "https://github.com/PQClean/PQClean/commit/e72fd489baaef597715aa4335ceeea4362301b55";
|
||||
|
||||
kem->claimed_nist_level = 3;
|
||||
kem->ind_cca = true;
|
||||
|
||||
kem->length_public_key = OQS_KEM_frodokem_976_shake_length_public_key;
|
||||
kem->length_secret_key = OQS_KEM_frodokem_976_shake_length_secret_key;
|
||||
kem->length_ciphertext = OQS_KEM_frodokem_976_shake_length_ciphertext;
|
||||
kem->length_shared_secret = OQS_KEM_frodokem_976_shake_length_shared_secret;
|
||||
|
||||
kem->keypair = OQS_KEM_frodokem_976_shake_keypair;
|
||||
kem->encaps = OQS_KEM_frodokem_976_shake_encaps;
|
||||
kem->decaps = OQS_KEM_frodokem_976_shake_decaps;
|
||||
|
||||
return kem;
|
||||
}
|
||||
|
||||
int PQCLEAN_FRODOKEM976SHAKE_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk);
|
||||
int PQCLEAN_FRODOKEM976SHAKE_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk);
|
||||
int PQCLEAN_FRODOKEM976SHAKE_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk);
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_976_shake_keypair(uint8_t *public_key,
|
||||
uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_FRODOKEM976SHAKE_CLEAN_crypto_kem_keypair(public_key, secret_key);
|
||||
}
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_976_shake_encaps(uint8_t *ciphertext,
|
||||
uint8_t *shared_secret,
|
||||
const uint8_t *public_key) {
|
||||
return (OQS_STATUS) PQCLEAN_FRODOKEM976SHAKE_CLEAN_crypto_kem_enc(ciphertext, shared_secret, public_key);
|
||||
}
|
||||
OQS_API OQS_STATUS OQS_KEM_frodokem_976_shake_decaps(uint8_t *shared_secret,
|
||||
const unsigned char *ciphertext,
|
||||
const uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_FRODOKEM976SHAKE_CLEAN_crypto_kem_dec(shared_secret, ciphertext, secret_key);
|
||||
}
|
||||
|
||||
#endif
|
||||
21
src/kem/frodokem/pqclean_frodokem1344aes_clean/LICENSE
Normal file
21
src/kem/frodokem/pqclean_frodokem1344aes_clean/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
20
src/kem/frodokem/pqclean_frodokem1344aes_clean/api.h
Normal file
20
src/kem/frodokem/pqclean_frodokem1344aes_clean/api.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef PQCLEAN_FRODOKEM1344AES_CLEAN_API_H
|
||||
#define PQCLEAN_FRODOKEM1344AES_CLEAN_API_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define PQCLEAN_FRODOKEM1344AES_CLEAN_CRYPTO_SECRETKEYBYTES 43088 // sizeof(s) + CRYPTO_PUBLICKEYBYTES + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH
|
||||
#define PQCLEAN_FRODOKEM1344AES_CLEAN_CRYPTO_PUBLICKEYBYTES 21520 // sizeof(seed_A) + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8
|
||||
#define PQCLEAN_FRODOKEM1344AES_CLEAN_CRYPTO_BYTES 32
|
||||
#define PQCLEAN_FRODOKEM1344AES_CLEAN_CRYPTO_CIPHERTEXTBYTES 21632 // (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + (PARAMS_LOGQ*PARAMS_NBAR*PARAMS_NBAR)/8
|
||||
|
||||
#define PQCLEAN_FRODOKEM1344AES_CLEAN_CRYPTO_ALGNAME "FrodoKEM-1344-AES"
|
||||
|
||||
int PQCLEAN_FRODOKEM1344AES_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk);
|
||||
|
||||
int PQCLEAN_FRODOKEM1344AES_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
|
||||
|
||||
int PQCLEAN_FRODOKEM1344AES_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
|
||||
|
||||
#endif
|
||||
19
src/kem/frodokem/pqclean_frodokem1344aes_clean/common.h
Normal file
19
src/kem/frodokem/pqclean_frodokem1344aes_clean/common.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
int PQCLEAN_FRODOKEM1344AES_CLEAN_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A);
|
||||
int PQCLEAN_FRODOKEM1344AES_CLEAN_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A);
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_sample_n(uint16_t *s, size_t n);
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s);
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e);
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_add(uint16_t *out, const uint16_t *a, const uint16_t *b);
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_sub(uint16_t *out, const uint16_t *a, const uint16_t *b);
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_key_encode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_key_decode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb);
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb);
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes(uint8_t *mem, size_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM1344AES_CLEAN_LE_TO_UINT16(uint16_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM1344AES_CLEAN_UINT16_TO_LE(uint16_t n);
|
||||
|
||||
#endif
|
||||
238
src/kem/frodokem/pqclean_frodokem1344aes_clean/kem.c
Normal file
238
src/kem/frodokem/pqclean_frodokem1344aes_clean/kem.c
Normal file
@ -0,0 +1,238 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: Key Encapsulation Mechanism (KEM) based on Frodo
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fips202.h"
|
||||
#include "randombytes.h"
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
int PQCLEAN_FRODOKEM1344AES_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) {
|
||||
// FrodoKEM'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_PKHASH bytes)
|
||||
uint8_t *pk_seedA = &pk[0];
|
||||
uint8_t *pk_b = &pk[BYTES_SEED_A];
|
||||
uint8_t *sk_s = &sk[0];
|
||||
uint8_t *sk_pk = &sk[CRYPTO_BYTES];
|
||||
uint8_t *sk_S = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
|
||||
uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR];
|
||||
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t S[2 * PARAMS_N * PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t *E = &S[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint8_t randomness[2 * CRYPTO_BYTES + BYTES_SEED_A]; // contains secret data via randomness_s and randomness_seedSE
|
||||
uint8_t *randomness_s = &randomness[0]; // contains secret data
|
||||
uint8_t *randomness_seedSE = &randomness[CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t *randomness_z = &randomness[2 * CRYPTO_BYTES];
|
||||
uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data
|
||||
|
||||
// Generate the secret value s, the seed for S and E, and the seed for the seed for A. Add seed_A to the public key
|
||||
randombytes(randomness, CRYPTO_BYTES + CRYPTO_BYTES + BYTES_SEED_A);
|
||||
shake(pk_seedA, BYTES_SEED_A, randomness_z, BYTES_SEED_A);
|
||||
|
||||
// Generate S and E, and compute B = A*S + E. Generate A on-the-fly
|
||||
shake_input_seedSE[0] = 0x5F;
|
||||
memcpy(&shake_input_seedSE[1], randomness_seedSE, CRYPTO_BYTES);
|
||||
shake((uint8_t *)S, 2 * PARAMS_N * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
for (size_t i = 0; i < 2 * PARAMS_N * PARAMS_NBAR; i++) {
|
||||
S[i] = PQCLEAN_FRODOKEM1344AES_CLEAN_LE_TO_UINT16(S[i]);
|
||||
}
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_sample_n(S, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_sample_n(E, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_mul_add_as_plus_e(B, S, E, pk);
|
||||
|
||||
// Encode the second part of the public key
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_pack(pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, B, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ);
|
||||
|
||||
// Add s, pk and S to the secret key
|
||||
memcpy(sk_s, randomness_s, CRYPTO_BYTES);
|
||||
memcpy(sk_pk, pk, CRYPTO_PUBLICKEYBYTES);
|
||||
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
|
||||
S[i] = PQCLEAN_FRODOKEM1344AES_CLEAN_UINT16_TO_LE(S[i]);
|
||||
}
|
||||
memcpy(sk_S, S, 2 * PARAMS_N * PARAMS_NBAR);
|
||||
|
||||
// Add H(pk) to the secret key
|
||||
shake(sk_pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);
|
||||
|
||||
// Cleanup:
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes((uint8_t *)E, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes(randomness, 2 * CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int PQCLEAN_FRODOKEM1344AES_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
|
||||
// FrodoKEM's key encapsulation
|
||||
const uint8_t *pk_seedA = &pk[0];
|
||||
const uint8_t *pk_b = &pk[BYTES_SEED_A];
|
||||
uint8_t *ct_c1 = &ct[0];
|
||||
uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8];
|
||||
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t V[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0};
|
||||
uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via mu
|
||||
uint8_t *pkh = &G2in[0];
|
||||
uint8_t *mu = &G2in[BYTES_PKHASH]; // contains secret data
|
||||
uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t *seedSE = &G2out[0]; // contains secret data
|
||||
uint8_t *k = &G2out[CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k
|
||||
uint8_t *Fin_ct = &Fin[0];
|
||||
uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data
|
||||
uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data
|
||||
|
||||
// pkh <- G_1(pk), generate random mu, compute (seedSE || k) = G_2(pkh || mu)
|
||||
shake(pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);
|
||||
randombytes(mu, BYTES_MU);
|
||||
shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);
|
||||
|
||||
// Generate Sp and Ep, and compute Bp = Sp*A + Ep. Generate A on-the-fly
|
||||
shake_input_seedSE[0] = 0x96;
|
||||
memcpy(&shake_input_seedSE[1], seedSE, CRYPTO_BYTES);
|
||||
shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) {
|
||||
Sp[i] = PQCLEAN_FRODOKEM1344AES_CLEAN_LE_TO_UINT16(Sp[i]);
|
||||
}
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_sample_n(Sp, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_sample_n(Ep, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_mul_add_sa_plus_e(Bp, Sp, Ep, pk_seedA);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_pack(ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, Bp, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ);
|
||||
|
||||
// Generate Epp, and compute V = Sp*B + Epp
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_mul_add_sb_plus_e(V, B, Sp, Epp);
|
||||
|
||||
// Encode mu, and compute C = V + enc(mu) (mod q)
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_key_encode(C, (uint16_t *)mu);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_add(C, V, C);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_pack(ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, C, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOGQ);
|
||||
|
||||
// Compute ss = F(ct||KK)
|
||||
memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);
|
||||
memcpy(Fin_k, k, CRYPTO_BYTES);
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes((uint8_t *)V, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes(mu, BYTES_MU);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes(G2out, 2 * CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes(Fin_k, CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int PQCLEAN_FRODOKEM1344AES_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
|
||||
// FrodoKEM's key decapsulation
|
||||
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t W[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0};
|
||||
uint16_t CC[PARAMS_NBAR * PARAMS_NBAR] = {0};
|
||||
uint16_t BBp[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
const uint8_t *ct_c1 = &ct[0];
|
||||
const uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8];
|
||||
const uint8_t *sk_s = &sk[0];
|
||||
const uint8_t *sk_pk = &sk[CRYPTO_BYTES];
|
||||
const uint16_t *sk_S = (uint16_t *) &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
|
||||
uint16_t S[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
const uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR];
|
||||
const uint8_t *pk_seedA = &sk_pk[0];
|
||||
const uint8_t *pk_b = &sk_pk[BYTES_SEED_A];
|
||||
uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via muprime
|
||||
uint8_t *pkh = &G2in[0];
|
||||
uint8_t *muprime = &G2in[BYTES_PKHASH]; // contains secret data
|
||||
uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t *seedSEprime = &G2out[0]; // contains secret data
|
||||
uint8_t *kprime = &G2out[CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k
|
||||
uint8_t *Fin_ct = &Fin[0];
|
||||
uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data
|
||||
uint8_t shake_input_seedSEprime[1 + CRYPTO_BYTES]; // contains secret data
|
||||
|
||||
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
|
||||
S[i] = PQCLEAN_FRODOKEM1344AES_CLEAN_LE_TO_UINT16(sk_S[i]);
|
||||
}
|
||||
|
||||
// Compute W = C - Bp*S (mod q), and decode the randomness mu
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_unpack(Bp, PARAMS_N * PARAMS_NBAR, ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_unpack(C, PARAMS_NBAR * PARAMS_NBAR, ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_mul_bs(W, Bp, S);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_sub(W, C, W);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_key_decode((uint16_t *)muprime, W);
|
||||
|
||||
// Generate (seedSE' || k') = G_2(pkh || mu')
|
||||
memcpy(pkh, sk_pkh, BYTES_PKHASH);
|
||||
shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);
|
||||
|
||||
// Generate Sp and Ep, and compute BBp = Sp*A + Ep. Generate A on-the-fly
|
||||
shake_input_seedSEprime[0] = 0x96;
|
||||
memcpy(&shake_input_seedSEprime[1], seedSEprime, CRYPTO_BYTES);
|
||||
shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSEprime, 1 + CRYPTO_BYTES);
|
||||
for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) {
|
||||
Sp[i] = PQCLEAN_FRODOKEM1344AES_CLEAN_LE_TO_UINT16(Sp[i]);
|
||||
}
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_sample_n(Sp, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_sample_n(Ep, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_mul_add_sa_plus_e(BBp, Sp, Ep, pk_seedA);
|
||||
|
||||
// Generate Epp, and compute W = Sp*B + Epp
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_mul_add_sb_plus_e(W, B, Sp, Epp);
|
||||
|
||||
// Encode mu, and compute CC = W + enc(mu') (mod q)
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_key_encode(CC, (uint16_t *)muprime);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_add(CC, W, CC);
|
||||
|
||||
// Prepare input to F
|
||||
memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);
|
||||
|
||||
// Reducing BBp modulo q
|
||||
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
|
||||
BBp[i] = BBp[i] & ((1 << PARAMS_LOGQ) - 1);
|
||||
}
|
||||
|
||||
// Is (Bp == BBp & C == CC) = true
|
||||
if (memcmp(Bp, BBp, 2 * PARAMS_N * PARAMS_NBAR) == 0 && memcmp(C, CC, 2 * PARAMS_NBAR * PARAMS_NBAR) == 0) {
|
||||
// Load k' to do ss = F(ct || k')
|
||||
memcpy(Fin_k, kprime, CRYPTO_BYTES);
|
||||
} else {
|
||||
// Load s to do ss = F(ct || s)
|
||||
memcpy(Fin_k, sk_s, CRYPTO_BYTES);
|
||||
}
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes((uint8_t *)W, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes(muprime, BYTES_MU);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes(G2out, 2 * CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes(Fin_k, CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes(shake_input_seedSEprime, 1 + CRYPTO_BYTES);
|
||||
return 0;
|
||||
}
|
||||
93
src/kem/frodokem/pqclean_frodokem1344aes_clean/matrix_aes.c
Normal file
93
src/kem/frodokem/pqclean_frodokem1344aes_clean/matrix_aes.c
Normal file
@ -0,0 +1,93 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: matrix arithmetic functions used by the KEM
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "aes.h"
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
int PQCLEAN_FRODOKEM1344AES_CLEAN_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;
|
||||
int16_t A[PARAMS_N * PARAMS_N] = {0};
|
||||
aes128ctx ctx128;
|
||||
|
||||
aes128_keyexp(&ctx128, seed_A);
|
||||
for (i = 0; i < PARAMS_N; i++) {
|
||||
for (j = 0; j < PARAMS_N; j += PARAMS_STRIPE_STEP) {
|
||||
A[i * PARAMS_N + j] = (int16_t) i; // Loading values in the little-endian order
|
||||
A[i * PARAMS_N + j + 1] = (int16_t) j;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
|
||||
A[i] = PQCLEAN_FRODOKEM1344AES_CLEAN_UINT16_TO_LE(A[i]);
|
||||
}
|
||||
|
||||
aes128_ecb((uint8_t *) A, (uint8_t *) A, PARAMS_N * PARAMS_N * sizeof(int16_t) / AES_BLOCKBYTES, &ctx128);
|
||||
|
||||
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
|
||||
A[i] = PQCLEAN_FRODOKEM1344AES_CLEAN_LE_TO_UINT16(A[i]);
|
||||
}
|
||||
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));
|
||||
|
||||
for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e
|
||||
for (k = 0; k < PARAMS_NBAR; k++) {
|
||||
uint16_t sum = 0;
|
||||
for (j = 0; j < PARAMS_N; j++) {
|
||||
sum += A[i * PARAMS_N + j] * s[k * PARAMS_N + j];
|
||||
}
|
||||
out[i * PARAMS_NBAR + k] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on.
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int PQCLEAN_FRODOKEM1344AES_CLEAN_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, k;
|
||||
int16_t A[PARAMS_N * PARAMS_N] = {0};
|
||||
aes128ctx ctx128;
|
||||
|
||||
aes128_keyexp(&ctx128, seed_A);
|
||||
for (i = 0; i < PARAMS_N; i++) {
|
||||
for (j = 0; j < PARAMS_N; j += PARAMS_STRIPE_STEP) {
|
||||
A[i * PARAMS_N + j] = (int16_t) i; // Loading values in the little-endian order
|
||||
A[i * PARAMS_N + j + 1] = (int16_t) j;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
|
||||
A[i] = PQCLEAN_FRODOKEM1344AES_CLEAN_UINT16_TO_LE(A[i]);
|
||||
}
|
||||
|
||||
aes128_ecb((uint8_t *) A, (uint8_t *) A, PARAMS_N * PARAMS_N * sizeof(int16_t) / AES_BLOCKBYTES, &ctx128);
|
||||
|
||||
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
|
||||
A[i] = PQCLEAN_FRODOKEM1344AES_CLEAN_LE_TO_UINT16(A[i]);
|
||||
}
|
||||
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));
|
||||
|
||||
for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e
|
||||
for (k = 0; k < PARAMS_NBAR; k++) {
|
||||
uint16_t sum = 0;
|
||||
for (j = 0; j < PARAMS_N; j++) {
|
||||
sum += A[j * PARAMS_N + i] * s[k * PARAMS_N + j];
|
||||
}
|
||||
out[k * PARAMS_N + i] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on.
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
35
src/kem/frodokem/pqclean_frodokem1344aes_clean/noise.c
Normal file
35
src/kem/frodokem/pqclean_frodokem1344aes_clean/noise.c
Normal file
@ -0,0 +1,35 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: noise sampling functions
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
static uint16_t CDF_TABLE[CDF_TABLE_LEN] = CDF_TABLE_DATA;
|
||||
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_sample_n(uint16_t *s, 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.
|
||||
size_t i;
|
||||
unsigned int j;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
uint16_t sample = 0;
|
||||
uint16_t prnd = s[i] >> 1; // Drop the least significant bit
|
||||
uint16_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;
|
||||
}
|
||||
}
|
||||
27
src/kem/frodokem/pqclean_frodokem1344aes_clean/params.h
Normal file
27
src/kem/frodokem/pqclean_frodokem1344aes_clean/params.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef PARAMS_H
|
||||
#define PARAMS_H
|
||||
|
||||
#define CRYPTO_SECRETKEYBYTES PQCLEAN_FRODOKEM1344AES_CLEAN_CRYPTO_SECRETKEYBYTES
|
||||
#define CRYPTO_PUBLICKEYBYTES PQCLEAN_FRODOKEM1344AES_CLEAN_CRYPTO_PUBLICKEYBYTES
|
||||
#define CRYPTO_BYTES PQCLEAN_FRODOKEM1344AES_CLEAN_CRYPTO_BYTES
|
||||
#define CRYPTO_CIPHERTEXTBYTES PQCLEAN_FRODOKEM1344AES_CLEAN_CRYPTO_CIPHERTEXTBYTES
|
||||
|
||||
#define PARAMS_N 1344
|
||||
#define PARAMS_NBAR 8
|
||||
#define PARAMS_LOGQ 16
|
||||
#define PARAMS_Q (1 << PARAMS_LOGQ)
|
||||
#define PARAMS_EXTRACTED_BITS 4
|
||||
#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)
|
||||
#define BYTES_PKHASH CRYPTO_BYTES
|
||||
|
||||
// Selecting SHAKE XOF function for the KEM and noise sampling
|
||||
#define shake shake256
|
||||
|
||||
// CDF table
|
||||
#define CDF_TABLE_DATA {9142, 23462, 30338, 32361, 32725, 32765, 32767}
|
||||
#define CDF_TABLE_LEN 7
|
||||
|
||||
#endif
|
||||
235
src/kem/frodokem/pqclean_frodokem1344aes_clean/util.c
Normal file
235
src/kem/frodokem/pqclean_frodokem1344aes_clean/util.c
Normal file
@ -0,0 +1,235 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: additional functions for FrodoKEM
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
#define min(x, y) (((x) < (y)) ? (x) : (y))
|
||||
|
||||
uint16_t PQCLEAN_FRODOKEM1344AES_CLEAN_LE_TO_UINT16(uint16_t n) {
|
||||
return (((uint8_t *) &n)[0] | (((uint8_t *) &n)[1] << 8));
|
||||
}
|
||||
|
||||
uint16_t PQCLEAN_FRODOKEM1344AES_CLEAN_UINT16_TO_LE(uint16_t n) {
|
||||
uint16_t y;
|
||||
uint8_t *z = (uint8_t *) &y;
|
||||
z[0] = n & 0xFF;
|
||||
z[1] = (n & 0xFF00) >> 8;
|
||||
return y;
|
||||
}
|
||||
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_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 (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) {
|
||||
out[i] = (a[i] + b[i]) & ((1 << PARAMS_LOGQ) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_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 (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) {
|
||||
out[i] = (a[i] - b[i]) & ((1 << PARAMS_LOGQ) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t 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
|
||||
uint8_t bits = 0; // the number of lsb in w
|
||||
|
||||
while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) {
|
||||
/*
|
||||
in: | | |********|********|
|
||||
^
|
||||
j
|
||||
w : | ****|
|
||||
^
|
||||
bits
|
||||
out:|**|**|**|**|**|**|**|**|* |
|
||||
^^
|
||||
ib
|
||||
*/
|
||||
uint8_t b = 0; // bits in out[i] already filled in
|
||||
while (b < 8) {
|
||||
int nbits = min(8 - b, bits);
|
||||
uint16_t mask = (1 << nbits) - 1;
|
||||
uint8_t t = (uint8_t) ((w >> (bits - nbits)) & mask); // the bits to copy from w to out
|
||||
out[i] = out[i] + (t << (8 - b - nbits));
|
||||
b += (uint8_t) nbits;
|
||||
bits -= (uint8_t) 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 PQCLEAN_FRODOKEM1344AES_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t 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
|
||||
uint8_t w = 0; // the leftover, not yet copied
|
||||
uint8_t 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
|
||||
*/
|
||||
uint8_t b = 0; // bits in out[i] already filled in
|
||||
while (b < lsb) {
|
||||
int nbits = min(lsb - b, bits);
|
||||
uint16_t mask = (1 << nbits) - 1;
|
||||
uint8_t t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out
|
||||
out[i] = out[i] + (t << (lsb - b - nbits));
|
||||
b += (uint8_t) nbits;
|
||||
bits -= (uint8_t) 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes(uint8_t *mem, size_t n) {
|
||||
// Clear 8-bit bytes from memory. "n" indicates the number of bytes to be zeroed.
|
||||
// This function uses the volatile type qualifier to inform the compiler not to optimize out the memory clearing.
|
||||
volatile uint8_t *v = mem;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
v[i] = 0;
|
||||
}
|
||||
}
|
||||
21
src/kem/frodokem/pqclean_frodokem1344shake_clean/LICENSE
Normal file
21
src/kem/frodokem/pqclean_frodokem1344shake_clean/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
20
src/kem/frodokem/pqclean_frodokem1344shake_clean/api.h
Normal file
20
src/kem/frodokem/pqclean_frodokem1344shake_clean/api.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef PQCLEAN_FRODOKEM1344SHAKE_CLEAN_API_H
|
||||
#define PQCLEAN_FRODOKEM1344SHAKE_CLEAN_API_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define PQCLEAN_FRODOKEM1344SHAKE_CLEAN_CRYPTO_SECRETKEYBYTES 43088 // sizeof(s) + CRYPTO_PUBLICKEYBYTES + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH
|
||||
#define PQCLEAN_FRODOKEM1344SHAKE_CLEAN_CRYPTO_PUBLICKEYBYTES 21520 // sizeof(seed_A) + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8
|
||||
#define PQCLEAN_FRODOKEM1344SHAKE_CLEAN_CRYPTO_BYTES 32
|
||||
#define PQCLEAN_FRODOKEM1344SHAKE_CLEAN_CRYPTO_CIPHERTEXTBYTES 21632 // (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + (PARAMS_LOGQ*PARAMS_NBAR*PARAMS_NBAR)/8
|
||||
|
||||
#define PQCLEAN_FRODOKEM1344SHAKE_CLEAN_CRYPTO_ALGNAME "FrodoKEM-1344-SHAKE"
|
||||
|
||||
int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk);
|
||||
|
||||
int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
|
||||
|
||||
int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
|
||||
|
||||
#endif
|
||||
19
src/kem/frodokem/pqclean_frodokem1344shake_clean/common.h
Normal file
19
src/kem/frodokem/pqclean_frodokem1344shake_clean/common.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A);
|
||||
int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A);
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(uint16_t *s, size_t n);
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s);
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e);
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_add(uint16_t *out, const uint16_t *a, const uint16_t *b);
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sub(uint16_t *out, const uint16_t *a, const uint16_t *b);
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_key_encode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_key_decode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb);
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb);
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(uint8_t *mem, size_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(uint16_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM1344SHAKE_CLEAN_UINT16_TO_LE(uint16_t n);
|
||||
|
||||
#endif
|
||||
238
src/kem/frodokem/pqclean_frodokem1344shake_clean/kem.c
Normal file
238
src/kem/frodokem/pqclean_frodokem1344shake_clean/kem.c
Normal file
@ -0,0 +1,238 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: Key Encapsulation Mechanism (KEM) based on Frodo
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fips202.h"
|
||||
#include "randombytes.h"
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) {
|
||||
// FrodoKEM'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_PKHASH bytes)
|
||||
uint8_t *pk_seedA = &pk[0];
|
||||
uint8_t *pk_b = &pk[BYTES_SEED_A];
|
||||
uint8_t *sk_s = &sk[0];
|
||||
uint8_t *sk_pk = &sk[CRYPTO_BYTES];
|
||||
uint8_t *sk_S = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
|
||||
uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR];
|
||||
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t S[2 * PARAMS_N * PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t *E = &S[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint8_t randomness[2 * CRYPTO_BYTES + BYTES_SEED_A]; // contains secret data via randomness_s and randomness_seedSE
|
||||
uint8_t *randomness_s = &randomness[0]; // contains secret data
|
||||
uint8_t *randomness_seedSE = &randomness[CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t *randomness_z = &randomness[2 * CRYPTO_BYTES];
|
||||
uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data
|
||||
|
||||
// Generate the secret value s, the seed for S and E, and the seed for the seed for A. Add seed_A to the public key
|
||||
randombytes(randomness, CRYPTO_BYTES + CRYPTO_BYTES + BYTES_SEED_A);
|
||||
shake(pk_seedA, BYTES_SEED_A, randomness_z, BYTES_SEED_A);
|
||||
|
||||
// Generate S and E, and compute B = A*S + E. Generate A on-the-fly
|
||||
shake_input_seedSE[0] = 0x5F;
|
||||
memcpy(&shake_input_seedSE[1], randomness_seedSE, CRYPTO_BYTES);
|
||||
shake((uint8_t *)S, 2 * PARAMS_N * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
for (size_t i = 0; i < 2 * PARAMS_N * PARAMS_NBAR; i++) {
|
||||
S[i] = PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(S[i]);
|
||||
}
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(S, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(E, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_add_as_plus_e(B, S, E, pk);
|
||||
|
||||
// Encode the second part of the public key
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_pack(pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, B, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ);
|
||||
|
||||
// Add s, pk and S to the secret key
|
||||
memcpy(sk_s, randomness_s, CRYPTO_BYTES);
|
||||
memcpy(sk_pk, pk, CRYPTO_PUBLICKEYBYTES);
|
||||
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
|
||||
S[i] = PQCLEAN_FRODOKEM1344SHAKE_CLEAN_UINT16_TO_LE(S[i]);
|
||||
}
|
||||
memcpy(sk_S, S, 2 * PARAMS_N * PARAMS_NBAR);
|
||||
|
||||
// Add H(pk) to the secret key
|
||||
shake(sk_pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);
|
||||
|
||||
// Cleanup:
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)E, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(randomness, 2 * CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
|
||||
// FrodoKEM's key encapsulation
|
||||
const uint8_t *pk_seedA = &pk[0];
|
||||
const uint8_t *pk_b = &pk[BYTES_SEED_A];
|
||||
uint8_t *ct_c1 = &ct[0];
|
||||
uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8];
|
||||
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t V[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0};
|
||||
uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via mu
|
||||
uint8_t *pkh = &G2in[0];
|
||||
uint8_t *mu = &G2in[BYTES_PKHASH]; // contains secret data
|
||||
uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t *seedSE = &G2out[0]; // contains secret data
|
||||
uint8_t *k = &G2out[CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k
|
||||
uint8_t *Fin_ct = &Fin[0];
|
||||
uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data
|
||||
uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data
|
||||
|
||||
// pkh <- G_1(pk), generate random mu, compute (seedSE || k) = G_2(pkh || mu)
|
||||
shake(pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);
|
||||
randombytes(mu, BYTES_MU);
|
||||
shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);
|
||||
|
||||
// Generate Sp and Ep, and compute Bp = Sp*A + Ep. Generate A on-the-fly
|
||||
shake_input_seedSE[0] = 0x96;
|
||||
memcpy(&shake_input_seedSE[1], seedSE, CRYPTO_BYTES);
|
||||
shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) {
|
||||
Sp[i] = PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(Sp[i]);
|
||||
}
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(Sp, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(Ep, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_add_sa_plus_e(Bp, Sp, Ep, pk_seedA);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_pack(ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, Bp, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ);
|
||||
|
||||
// Generate Epp, and compute V = Sp*B + Epp
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_add_sb_plus_e(V, B, Sp, Epp);
|
||||
|
||||
// Encode mu, and compute C = V + enc(mu) (mod q)
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_key_encode(C, (uint16_t *)mu);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_add(C, V, C);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_pack(ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, C, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOGQ);
|
||||
|
||||
// Compute ss = F(ct||KK)
|
||||
memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);
|
||||
memcpy(Fin_k, k, CRYPTO_BYTES);
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)V, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(mu, BYTES_MU);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(G2out, 2 * CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(Fin_k, CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
|
||||
// FrodoKEM's key decapsulation
|
||||
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t W[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0};
|
||||
uint16_t CC[PARAMS_NBAR * PARAMS_NBAR] = {0};
|
||||
uint16_t BBp[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
const uint8_t *ct_c1 = &ct[0];
|
||||
const uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8];
|
||||
const uint8_t *sk_s = &sk[0];
|
||||
const uint8_t *sk_pk = &sk[CRYPTO_BYTES];
|
||||
const uint16_t *sk_S = (uint16_t *) &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
|
||||
uint16_t S[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
const uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR];
|
||||
const uint8_t *pk_seedA = &sk_pk[0];
|
||||
const uint8_t *pk_b = &sk_pk[BYTES_SEED_A];
|
||||
uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via muprime
|
||||
uint8_t *pkh = &G2in[0];
|
||||
uint8_t *muprime = &G2in[BYTES_PKHASH]; // contains secret data
|
||||
uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t *seedSEprime = &G2out[0]; // contains secret data
|
||||
uint8_t *kprime = &G2out[CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k
|
||||
uint8_t *Fin_ct = &Fin[0];
|
||||
uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data
|
||||
uint8_t shake_input_seedSEprime[1 + CRYPTO_BYTES]; // contains secret data
|
||||
|
||||
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
|
||||
S[i] = PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(sk_S[i]);
|
||||
}
|
||||
|
||||
// Compute W = C - Bp*S (mod q), and decode the randomness mu
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_unpack(Bp, PARAMS_N * PARAMS_NBAR, ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_unpack(C, PARAMS_NBAR * PARAMS_NBAR, ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_bs(W, Bp, S);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sub(W, C, W);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_key_decode((uint16_t *)muprime, W);
|
||||
|
||||
// Generate (seedSE' || k') = G_2(pkh || mu')
|
||||
memcpy(pkh, sk_pkh, BYTES_PKHASH);
|
||||
shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);
|
||||
|
||||
// Generate Sp and Ep, and compute BBp = Sp*A + Ep. Generate A on-the-fly
|
||||
shake_input_seedSEprime[0] = 0x96;
|
||||
memcpy(&shake_input_seedSEprime[1], seedSEprime, CRYPTO_BYTES);
|
||||
shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSEprime, 1 + CRYPTO_BYTES);
|
||||
for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) {
|
||||
Sp[i] = PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(Sp[i]);
|
||||
}
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(Sp, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(Ep, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_add_sa_plus_e(BBp, Sp, Ep, pk_seedA);
|
||||
|
||||
// Generate Epp, and compute W = Sp*B + Epp
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_add_sb_plus_e(W, B, Sp, Epp);
|
||||
|
||||
// Encode mu, and compute CC = W + enc(mu') (mod q)
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_key_encode(CC, (uint16_t *)muprime);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_add(CC, W, CC);
|
||||
|
||||
// Prepare input to F
|
||||
memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);
|
||||
|
||||
// Reducing BBp modulo q
|
||||
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
|
||||
BBp[i] = BBp[i] & ((1 << PARAMS_LOGQ) - 1);
|
||||
}
|
||||
|
||||
// Is (Bp == BBp & C == CC) = true
|
||||
if (memcmp(Bp, BBp, 2 * PARAMS_N * PARAMS_NBAR) == 0 && memcmp(C, CC, 2 * PARAMS_NBAR * PARAMS_NBAR) == 0) {
|
||||
// Load k' to do ss = F(ct || k')
|
||||
memcpy(Fin_k, kprime, CRYPTO_BYTES);
|
||||
} else {
|
||||
// Load s to do ss = F(ct || s)
|
||||
memcpy(Fin_k, sk_s, CRYPTO_BYTES);
|
||||
}
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)W, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(muprime, BYTES_MU);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(G2out, 2 * CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(Fin_k, CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(shake_input_seedSEprime, 1 + CRYPTO_BYTES);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: matrix arithmetic functions used by the KEM
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fips202.h"
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_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;
|
||||
int16_t A[PARAMS_N * PARAMS_N] = {0};
|
||||
|
||||
uint8_t seed_A_separated[2 + BYTES_SEED_A];
|
||||
uint16_t *seed_A_origin = (uint16_t *)&seed_A_separated;
|
||||
memcpy(&seed_A_separated[2], seed_A, BYTES_SEED_A);
|
||||
for (i = 0; i < PARAMS_N; i++) {
|
||||
seed_A_origin[0] = PQCLEAN_FRODOKEM1344SHAKE_CLEAN_UINT16_TO_LE((uint16_t) i);
|
||||
shake128((uint8_t *)(A + i * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A);
|
||||
}
|
||||
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
|
||||
A[i] = PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(A[i]);
|
||||
}
|
||||
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));
|
||||
|
||||
for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e
|
||||
for (k = 0; k < PARAMS_NBAR; k++) {
|
||||
uint16_t sum = 0;
|
||||
for (j = 0; j < PARAMS_N; j++) {
|
||||
sum += A[i * PARAMS_N + j] * s[k * PARAMS_N + j];
|
||||
}
|
||||
out[i * PARAMS_NBAR + k] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on.
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_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, k;
|
||||
int16_t A[PARAMS_N * PARAMS_N] = {0};
|
||||
|
||||
uint8_t seed_A_separated[2 + BYTES_SEED_A];
|
||||
uint16_t *seed_A_origin = (uint16_t *)&seed_A_separated;
|
||||
memcpy(&seed_A_separated[2], seed_A, BYTES_SEED_A);
|
||||
for (i = 0; i < PARAMS_N; i++) {
|
||||
seed_A_origin[0] = PQCLEAN_FRODOKEM1344SHAKE_CLEAN_UINT16_TO_LE((uint16_t) i);
|
||||
shake128((uint8_t *)(A + i * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A);
|
||||
}
|
||||
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
|
||||
A[i] = PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(A[i]);
|
||||
}
|
||||
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));
|
||||
|
||||
for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e
|
||||
for (k = 0; k < PARAMS_NBAR; k++) {
|
||||
uint16_t sum = 0;
|
||||
for (j = 0; j < PARAMS_N; j++) {
|
||||
sum += A[j * PARAMS_N + i] * s[k * PARAMS_N + j];
|
||||
}
|
||||
out[k * PARAMS_N + i] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on.
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
35
src/kem/frodokem/pqclean_frodokem1344shake_clean/noise.c
Normal file
35
src/kem/frodokem/pqclean_frodokem1344shake_clean/noise.c
Normal file
@ -0,0 +1,35 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: noise sampling functions
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
static uint16_t CDF_TABLE[CDF_TABLE_LEN] = CDF_TABLE_DATA;
|
||||
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(uint16_t *s, 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.
|
||||
size_t i;
|
||||
unsigned int j;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
uint16_t sample = 0;
|
||||
uint16_t prnd = s[i] >> 1; // Drop the least significant bit
|
||||
uint16_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;
|
||||
}
|
||||
}
|
||||
27
src/kem/frodokem/pqclean_frodokem1344shake_clean/params.h
Normal file
27
src/kem/frodokem/pqclean_frodokem1344shake_clean/params.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef PARAMS_H
|
||||
#define PARAMS_H
|
||||
|
||||
#define CRYPTO_SECRETKEYBYTES PQCLEAN_FRODOKEM1344SHAKE_CLEAN_CRYPTO_SECRETKEYBYTES
|
||||
#define CRYPTO_PUBLICKEYBYTES PQCLEAN_FRODOKEM1344SHAKE_CLEAN_CRYPTO_PUBLICKEYBYTES
|
||||
#define CRYPTO_BYTES PQCLEAN_FRODOKEM1344SHAKE_CLEAN_CRYPTO_BYTES
|
||||
#define CRYPTO_CIPHERTEXTBYTES PQCLEAN_FRODOKEM1344SHAKE_CLEAN_CRYPTO_CIPHERTEXTBYTES
|
||||
|
||||
#define PARAMS_N 1344
|
||||
#define PARAMS_NBAR 8
|
||||
#define PARAMS_LOGQ 16
|
||||
#define PARAMS_Q (1 << PARAMS_LOGQ)
|
||||
#define PARAMS_EXTRACTED_BITS 4
|
||||
#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)
|
||||
#define BYTES_PKHASH CRYPTO_BYTES
|
||||
|
||||
// Selecting SHAKE XOF function for the KEM and noise sampling
|
||||
#define shake shake256
|
||||
|
||||
// CDF table
|
||||
#define CDF_TABLE_DATA {9142, 23462, 30338, 32361, 32725, 32765, 32767}
|
||||
#define CDF_TABLE_LEN 7
|
||||
|
||||
#endif
|
||||
235
src/kem/frodokem/pqclean_frodokem1344shake_clean/util.c
Normal file
235
src/kem/frodokem/pqclean_frodokem1344shake_clean/util.c
Normal file
@ -0,0 +1,235 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: additional functions for FrodoKEM
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
#define min(x, y) (((x) < (y)) ? (x) : (y))
|
||||
|
||||
uint16_t PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(uint16_t n) {
|
||||
return (((uint8_t *) &n)[0] | (((uint8_t *) &n)[1] << 8));
|
||||
}
|
||||
|
||||
uint16_t PQCLEAN_FRODOKEM1344SHAKE_CLEAN_UINT16_TO_LE(uint16_t n) {
|
||||
uint16_t y;
|
||||
uint8_t *z = (uint8_t *) &y;
|
||||
z[0] = n & 0xFF;
|
||||
z[1] = (n & 0xFF00) >> 8;
|
||||
return y;
|
||||
}
|
||||
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_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 (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) {
|
||||
out[i] = (a[i] + b[i]) & ((1 << PARAMS_LOGQ) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_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 (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) {
|
||||
out[i] = (a[i] - b[i]) & ((1 << PARAMS_LOGQ) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t 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
|
||||
uint8_t bits = 0; // the number of lsb in w
|
||||
|
||||
while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) {
|
||||
/*
|
||||
in: | | |********|********|
|
||||
^
|
||||
j
|
||||
w : | ****|
|
||||
^
|
||||
bits
|
||||
out:|**|**|**|**|**|**|**|**|* |
|
||||
^^
|
||||
ib
|
||||
*/
|
||||
uint8_t b = 0; // bits in out[i] already filled in
|
||||
while (b < 8) {
|
||||
int nbits = min(8 - b, bits);
|
||||
uint16_t mask = (1 << nbits) - 1;
|
||||
uint8_t t = (uint8_t) ((w >> (bits - nbits)) & mask); // the bits to copy from w to out
|
||||
out[i] = out[i] + (t << (8 - b - nbits));
|
||||
b += (uint8_t) nbits;
|
||||
bits -= (uint8_t) 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 PQCLEAN_FRODOKEM1344SHAKE_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t 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
|
||||
uint8_t w = 0; // the leftover, not yet copied
|
||||
uint8_t 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
|
||||
*/
|
||||
uint8_t b = 0; // bits in out[i] already filled in
|
||||
while (b < lsb) {
|
||||
int nbits = min(lsb - b, bits);
|
||||
uint16_t mask = (1 << nbits) - 1;
|
||||
uint8_t t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out
|
||||
out[i] = out[i] + (t << (lsb - b - nbits));
|
||||
b += (uint8_t) nbits;
|
||||
bits -= (uint8_t) 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(uint8_t *mem, size_t n) {
|
||||
// Clear 8-bit bytes from memory. "n" indicates the number of bytes to be zeroed.
|
||||
// This function uses the volatile type qualifier to inform the compiler not to optimize out the memory clearing.
|
||||
volatile uint8_t *v = mem;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
v[i] = 0;
|
||||
}
|
||||
}
|
||||
21
src/kem/frodokem/pqclean_frodokem640aes_clean/LICENSE
Normal file
21
src/kem/frodokem/pqclean_frodokem640aes_clean/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
20
src/kem/frodokem/pqclean_frodokem640aes_clean/api.h
Normal file
20
src/kem/frodokem/pqclean_frodokem640aes_clean/api.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef PQCLEAN_FRODOKEM640AES_CLEAN_API_H
|
||||
#define PQCLEAN_FRODOKEM640AES_CLEAN_API_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define PQCLEAN_FRODOKEM640AES_CLEAN_CRYPTO_SECRETKEYBYTES 19888 // sizeof(s) + CRYPTO_PUBLICKEYBYTES + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH
|
||||
#define PQCLEAN_FRODOKEM640AES_CLEAN_CRYPTO_PUBLICKEYBYTES 9616 // sizeof(seed_A) + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8
|
||||
#define PQCLEAN_FRODOKEM640AES_CLEAN_CRYPTO_BYTES 16
|
||||
#define PQCLEAN_FRODOKEM640AES_CLEAN_CRYPTO_CIPHERTEXTBYTES 9720 // (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + (PARAMS_LOGQ*PARAMS_NBAR*PARAMS_NBAR)/8
|
||||
|
||||
#define PQCLEAN_FRODOKEM640AES_CLEAN_CRYPTO_ALGNAME "FrodoKEM-640-AES"
|
||||
|
||||
int PQCLEAN_FRODOKEM640AES_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk);
|
||||
|
||||
int PQCLEAN_FRODOKEM640AES_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
|
||||
|
||||
int PQCLEAN_FRODOKEM640AES_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
|
||||
|
||||
#endif
|
||||
19
src/kem/frodokem/pqclean_frodokem640aes_clean/common.h
Normal file
19
src/kem/frodokem/pqclean_frodokem640aes_clean/common.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
int PQCLEAN_FRODOKEM640AES_CLEAN_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A);
|
||||
int PQCLEAN_FRODOKEM640AES_CLEAN_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A);
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_sample_n(uint16_t *s, size_t n);
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s);
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e);
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_add(uint16_t *out, const uint16_t *a, const uint16_t *b);
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_sub(uint16_t *out, const uint16_t *a, const uint16_t *b);
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_key_encode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_key_decode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb);
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb);
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes(uint8_t *mem, size_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM640AES_CLEAN_LE_TO_UINT16(uint16_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM640AES_CLEAN_UINT16_TO_LE(uint16_t n);
|
||||
|
||||
#endif
|
||||
238
src/kem/frodokem/pqclean_frodokem640aes_clean/kem.c
Normal file
238
src/kem/frodokem/pqclean_frodokem640aes_clean/kem.c
Normal file
@ -0,0 +1,238 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: Key Encapsulation Mechanism (KEM) based on Frodo
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fips202.h"
|
||||
#include "randombytes.h"
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
int PQCLEAN_FRODOKEM640AES_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) {
|
||||
// FrodoKEM'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_PKHASH bytes)
|
||||
uint8_t *pk_seedA = &pk[0];
|
||||
uint8_t *pk_b = &pk[BYTES_SEED_A];
|
||||
uint8_t *sk_s = &sk[0];
|
||||
uint8_t *sk_pk = &sk[CRYPTO_BYTES];
|
||||
uint8_t *sk_S = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
|
||||
uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR];
|
||||
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t S[2 * PARAMS_N * PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t *E = &S[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint8_t randomness[2 * CRYPTO_BYTES + BYTES_SEED_A]; // contains secret data via randomness_s and randomness_seedSE
|
||||
uint8_t *randomness_s = &randomness[0]; // contains secret data
|
||||
uint8_t *randomness_seedSE = &randomness[CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t *randomness_z = &randomness[2 * CRYPTO_BYTES];
|
||||
uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data
|
||||
|
||||
// Generate the secret value s, the seed for S and E, and the seed for the seed for A. Add seed_A to the public key
|
||||
randombytes(randomness, CRYPTO_BYTES + CRYPTO_BYTES + BYTES_SEED_A);
|
||||
shake(pk_seedA, BYTES_SEED_A, randomness_z, BYTES_SEED_A);
|
||||
|
||||
// Generate S and E, and compute B = A*S + E. Generate A on-the-fly
|
||||
shake_input_seedSE[0] = 0x5F;
|
||||
memcpy(&shake_input_seedSE[1], randomness_seedSE, CRYPTO_BYTES);
|
||||
shake((uint8_t *)S, 2 * PARAMS_N * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
for (size_t i = 0; i < 2 * PARAMS_N * PARAMS_NBAR; i++) {
|
||||
S[i] = PQCLEAN_FRODOKEM640AES_CLEAN_LE_TO_UINT16(S[i]);
|
||||
}
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_sample_n(S, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_sample_n(E, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_mul_add_as_plus_e(B, S, E, pk);
|
||||
|
||||
// Encode the second part of the public key
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_pack(pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, B, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ);
|
||||
|
||||
// Add s, pk and S to the secret key
|
||||
memcpy(sk_s, randomness_s, CRYPTO_BYTES);
|
||||
memcpy(sk_pk, pk, CRYPTO_PUBLICKEYBYTES);
|
||||
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
|
||||
S[i] = PQCLEAN_FRODOKEM640AES_CLEAN_UINT16_TO_LE(S[i]);
|
||||
}
|
||||
memcpy(sk_S, S, 2 * PARAMS_N * PARAMS_NBAR);
|
||||
|
||||
// Add H(pk) to the secret key
|
||||
shake(sk_pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);
|
||||
|
||||
// Cleanup:
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes((uint8_t *)E, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes(randomness, 2 * CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int PQCLEAN_FRODOKEM640AES_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
|
||||
// FrodoKEM's key encapsulation
|
||||
const uint8_t *pk_seedA = &pk[0];
|
||||
const uint8_t *pk_b = &pk[BYTES_SEED_A];
|
||||
uint8_t *ct_c1 = &ct[0];
|
||||
uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8];
|
||||
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t V[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0};
|
||||
uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via mu
|
||||
uint8_t *pkh = &G2in[0];
|
||||
uint8_t *mu = &G2in[BYTES_PKHASH]; // contains secret data
|
||||
uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t *seedSE = &G2out[0]; // contains secret data
|
||||
uint8_t *k = &G2out[CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k
|
||||
uint8_t *Fin_ct = &Fin[0];
|
||||
uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data
|
||||
uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data
|
||||
|
||||
// pkh <- G_1(pk), generate random mu, compute (seedSE || k) = G_2(pkh || mu)
|
||||
shake(pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);
|
||||
randombytes(mu, BYTES_MU);
|
||||
shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);
|
||||
|
||||
// Generate Sp and Ep, and compute Bp = Sp*A + Ep. Generate A on-the-fly
|
||||
shake_input_seedSE[0] = 0x96;
|
||||
memcpy(&shake_input_seedSE[1], seedSE, CRYPTO_BYTES);
|
||||
shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) {
|
||||
Sp[i] = PQCLEAN_FRODOKEM640AES_CLEAN_LE_TO_UINT16(Sp[i]);
|
||||
}
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_sample_n(Sp, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_sample_n(Ep, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_mul_add_sa_plus_e(Bp, Sp, Ep, pk_seedA);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_pack(ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, Bp, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ);
|
||||
|
||||
// Generate Epp, and compute V = Sp*B + Epp
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_mul_add_sb_plus_e(V, B, Sp, Epp);
|
||||
|
||||
// Encode mu, and compute C = V + enc(mu) (mod q)
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_key_encode(C, (uint16_t *)mu);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_add(C, V, C);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_pack(ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, C, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOGQ);
|
||||
|
||||
// Compute ss = F(ct||KK)
|
||||
memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);
|
||||
memcpy(Fin_k, k, CRYPTO_BYTES);
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes((uint8_t *)V, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes(mu, BYTES_MU);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes(G2out, 2 * CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes(Fin_k, CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int PQCLEAN_FRODOKEM640AES_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
|
||||
// FrodoKEM's key decapsulation
|
||||
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t W[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0};
|
||||
uint16_t CC[PARAMS_NBAR * PARAMS_NBAR] = {0};
|
||||
uint16_t BBp[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
const uint8_t *ct_c1 = &ct[0];
|
||||
const uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8];
|
||||
const uint8_t *sk_s = &sk[0];
|
||||
const uint8_t *sk_pk = &sk[CRYPTO_BYTES];
|
||||
const uint16_t *sk_S = (uint16_t *) &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
|
||||
uint16_t S[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
const uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR];
|
||||
const uint8_t *pk_seedA = &sk_pk[0];
|
||||
const uint8_t *pk_b = &sk_pk[BYTES_SEED_A];
|
||||
uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via muprime
|
||||
uint8_t *pkh = &G2in[0];
|
||||
uint8_t *muprime = &G2in[BYTES_PKHASH]; // contains secret data
|
||||
uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t *seedSEprime = &G2out[0]; // contains secret data
|
||||
uint8_t *kprime = &G2out[CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k
|
||||
uint8_t *Fin_ct = &Fin[0];
|
||||
uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data
|
||||
uint8_t shake_input_seedSEprime[1 + CRYPTO_BYTES]; // contains secret data
|
||||
|
||||
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
|
||||
S[i] = PQCLEAN_FRODOKEM640AES_CLEAN_LE_TO_UINT16(sk_S[i]);
|
||||
}
|
||||
|
||||
// Compute W = C - Bp*S (mod q), and decode the randomness mu
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_unpack(Bp, PARAMS_N * PARAMS_NBAR, ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_unpack(C, PARAMS_NBAR * PARAMS_NBAR, ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_mul_bs(W, Bp, S);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_sub(W, C, W);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_key_decode((uint16_t *)muprime, W);
|
||||
|
||||
// Generate (seedSE' || k') = G_2(pkh || mu')
|
||||
memcpy(pkh, sk_pkh, BYTES_PKHASH);
|
||||
shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);
|
||||
|
||||
// Generate Sp and Ep, and compute BBp = Sp*A + Ep. Generate A on-the-fly
|
||||
shake_input_seedSEprime[0] = 0x96;
|
||||
memcpy(&shake_input_seedSEprime[1], seedSEprime, CRYPTO_BYTES);
|
||||
shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSEprime, 1 + CRYPTO_BYTES);
|
||||
for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) {
|
||||
Sp[i] = PQCLEAN_FRODOKEM640AES_CLEAN_LE_TO_UINT16(Sp[i]);
|
||||
}
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_sample_n(Sp, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_sample_n(Ep, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_mul_add_sa_plus_e(BBp, Sp, Ep, pk_seedA);
|
||||
|
||||
// Generate Epp, and compute W = Sp*B + Epp
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_mul_add_sb_plus_e(W, B, Sp, Epp);
|
||||
|
||||
// Encode mu, and compute CC = W + enc(mu') (mod q)
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_key_encode(CC, (uint16_t *)muprime);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_add(CC, W, CC);
|
||||
|
||||
// Prepare input to F
|
||||
memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);
|
||||
|
||||
// Reducing BBp modulo q
|
||||
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
|
||||
BBp[i] = BBp[i] & ((1 << PARAMS_LOGQ) - 1);
|
||||
}
|
||||
|
||||
// Is (Bp == BBp & C == CC) = true
|
||||
if (memcmp(Bp, BBp, 2 * PARAMS_N * PARAMS_NBAR) == 0 && memcmp(C, CC, 2 * PARAMS_NBAR * PARAMS_NBAR) == 0) {
|
||||
// Load k' to do ss = F(ct || k')
|
||||
memcpy(Fin_k, kprime, CRYPTO_BYTES);
|
||||
} else {
|
||||
// Load s to do ss = F(ct || s)
|
||||
memcpy(Fin_k, sk_s, CRYPTO_BYTES);
|
||||
}
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes((uint8_t *)W, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes(muprime, BYTES_MU);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes(G2out, 2 * CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes(Fin_k, CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes(shake_input_seedSEprime, 1 + CRYPTO_BYTES);
|
||||
return 0;
|
||||
}
|
||||
93
src/kem/frodokem/pqclean_frodokem640aes_clean/matrix_aes.c
Normal file
93
src/kem/frodokem/pqclean_frodokem640aes_clean/matrix_aes.c
Normal file
@ -0,0 +1,93 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: matrix arithmetic functions used by the KEM
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "aes.h"
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
int PQCLEAN_FRODOKEM640AES_CLEAN_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;
|
||||
int16_t A[PARAMS_N * PARAMS_N] = {0};
|
||||
aes128ctx ctx128;
|
||||
|
||||
aes128_keyexp(&ctx128, seed_A);
|
||||
for (i = 0; i < PARAMS_N; i++) {
|
||||
for (j = 0; j < PARAMS_N; j += PARAMS_STRIPE_STEP) {
|
||||
A[i * PARAMS_N + j] = (int16_t) i; // Loading values in the little-endian order
|
||||
A[i * PARAMS_N + j + 1] = (int16_t) j;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
|
||||
A[i] = PQCLEAN_FRODOKEM640AES_CLEAN_UINT16_TO_LE(A[i]);
|
||||
}
|
||||
|
||||
aes128_ecb((uint8_t *) A, (uint8_t *) A, PARAMS_N * PARAMS_N * sizeof(int16_t) / AES_BLOCKBYTES, &ctx128);
|
||||
|
||||
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
|
||||
A[i] = PQCLEAN_FRODOKEM640AES_CLEAN_LE_TO_UINT16(A[i]);
|
||||
}
|
||||
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));
|
||||
|
||||
for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e
|
||||
for (k = 0; k < PARAMS_NBAR; k++) {
|
||||
uint16_t sum = 0;
|
||||
for (j = 0; j < PARAMS_N; j++) {
|
||||
sum += A[i * PARAMS_N + j] * s[k * PARAMS_N + j];
|
||||
}
|
||||
out[i * PARAMS_NBAR + k] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on.
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int PQCLEAN_FRODOKEM640AES_CLEAN_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, k;
|
||||
int16_t A[PARAMS_N * PARAMS_N] = {0};
|
||||
aes128ctx ctx128;
|
||||
|
||||
aes128_keyexp(&ctx128, seed_A);
|
||||
for (i = 0; i < PARAMS_N; i++) {
|
||||
for (j = 0; j < PARAMS_N; j += PARAMS_STRIPE_STEP) {
|
||||
A[i * PARAMS_N + j] = (int16_t) i; // Loading values in the little-endian order
|
||||
A[i * PARAMS_N + j + 1] = (int16_t) j;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
|
||||
A[i] = PQCLEAN_FRODOKEM640AES_CLEAN_UINT16_TO_LE(A[i]);
|
||||
}
|
||||
|
||||
aes128_ecb((uint8_t *) A, (uint8_t *) A, PARAMS_N * PARAMS_N * sizeof(int16_t) / AES_BLOCKBYTES, &ctx128);
|
||||
|
||||
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
|
||||
A[i] = PQCLEAN_FRODOKEM640AES_CLEAN_LE_TO_UINT16(A[i]);
|
||||
}
|
||||
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));
|
||||
|
||||
for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e
|
||||
for (k = 0; k < PARAMS_NBAR; k++) {
|
||||
uint16_t sum = 0;
|
||||
for (j = 0; j < PARAMS_N; j++) {
|
||||
sum += A[j * PARAMS_N + i] * s[k * PARAMS_N + j];
|
||||
}
|
||||
out[k * PARAMS_N + i] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on.
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
35
src/kem/frodokem/pqclean_frodokem640aes_clean/noise.c
Normal file
35
src/kem/frodokem/pqclean_frodokem640aes_clean/noise.c
Normal file
@ -0,0 +1,35 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: noise sampling functions
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
static uint16_t CDF_TABLE[CDF_TABLE_LEN] = CDF_TABLE_DATA;
|
||||
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_sample_n(uint16_t *s, 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.
|
||||
size_t i;
|
||||
unsigned int j;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
uint16_t sample = 0;
|
||||
uint16_t prnd = s[i] >> 1; // Drop the least significant bit
|
||||
uint16_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;
|
||||
}
|
||||
}
|
||||
27
src/kem/frodokem/pqclean_frodokem640aes_clean/params.h
Normal file
27
src/kem/frodokem/pqclean_frodokem640aes_clean/params.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef PARAMS_H
|
||||
#define PARAMS_H
|
||||
|
||||
#define CRYPTO_SECRETKEYBYTES PQCLEAN_FRODOKEM640AES_CLEAN_CRYPTO_SECRETKEYBYTES
|
||||
#define CRYPTO_PUBLICKEYBYTES PQCLEAN_FRODOKEM640AES_CLEAN_CRYPTO_PUBLICKEYBYTES
|
||||
#define CRYPTO_BYTES PQCLEAN_FRODOKEM640AES_CLEAN_CRYPTO_BYTES
|
||||
#define CRYPTO_CIPHERTEXTBYTES PQCLEAN_FRODOKEM640AES_CLEAN_CRYPTO_CIPHERTEXTBYTES
|
||||
|
||||
#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)
|
||||
#define BYTES_PKHASH CRYPTO_BYTES
|
||||
|
||||
// Selecting SHAKE XOF function for the KEM and noise sampling
|
||||
#define shake shake128
|
||||
|
||||
// CDF table
|
||||
#define CDF_TABLE_DATA {4643, 13363, 20579, 25843, 29227, 31145, 32103, 32525, 32689, 32745, 32762, 32766, 32767}
|
||||
#define CDF_TABLE_LEN 13
|
||||
|
||||
#endif
|
||||
235
src/kem/frodokem/pqclean_frodokem640aes_clean/util.c
Normal file
235
src/kem/frodokem/pqclean_frodokem640aes_clean/util.c
Normal file
@ -0,0 +1,235 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: additional functions for FrodoKEM
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
#define min(x, y) (((x) < (y)) ? (x) : (y))
|
||||
|
||||
uint16_t PQCLEAN_FRODOKEM640AES_CLEAN_LE_TO_UINT16(uint16_t n) {
|
||||
return (((uint8_t *) &n)[0] | (((uint8_t *) &n)[1] << 8));
|
||||
}
|
||||
|
||||
uint16_t PQCLEAN_FRODOKEM640AES_CLEAN_UINT16_TO_LE(uint16_t n) {
|
||||
uint16_t y;
|
||||
uint8_t *z = (uint8_t *) &y;
|
||||
z[0] = n & 0xFF;
|
||||
z[1] = (n & 0xFF00) >> 8;
|
||||
return y;
|
||||
}
|
||||
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_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 (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) {
|
||||
out[i] = (a[i] + b[i]) & ((1 << PARAMS_LOGQ) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_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 (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) {
|
||||
out[i] = (a[i] - b[i]) & ((1 << PARAMS_LOGQ) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t 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
|
||||
uint8_t bits = 0; // the number of lsb in w
|
||||
|
||||
while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) {
|
||||
/*
|
||||
in: | | |********|********|
|
||||
^
|
||||
j
|
||||
w : | ****|
|
||||
^
|
||||
bits
|
||||
out:|**|**|**|**|**|**|**|**|* |
|
||||
^^
|
||||
ib
|
||||
*/
|
||||
uint8_t b = 0; // bits in out[i] already filled in
|
||||
while (b < 8) {
|
||||
int nbits = min(8 - b, bits);
|
||||
uint16_t mask = (1 << nbits) - 1;
|
||||
uint8_t t = (uint8_t) ((w >> (bits - nbits)) & mask); // the bits to copy from w to out
|
||||
out[i] = out[i] + (t << (8 - b - nbits));
|
||||
b += (uint8_t) nbits;
|
||||
bits -= (uint8_t) 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 PQCLEAN_FRODOKEM640AES_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t 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
|
||||
uint8_t w = 0; // the leftover, not yet copied
|
||||
uint8_t 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
|
||||
*/
|
||||
uint8_t b = 0; // bits in out[i] already filled in
|
||||
while (b < lsb) {
|
||||
int nbits = min(lsb - b, bits);
|
||||
uint16_t mask = (1 << nbits) - 1;
|
||||
uint8_t t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out
|
||||
out[i] = out[i] + (t << (lsb - b - nbits));
|
||||
b += (uint8_t) nbits;
|
||||
bits -= (uint8_t) 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes(uint8_t *mem, size_t n) {
|
||||
// Clear 8-bit bytes from memory. "n" indicates the number of bytes to be zeroed.
|
||||
// This function uses the volatile type qualifier to inform the compiler not to optimize out the memory clearing.
|
||||
volatile uint8_t *v = mem;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
v[i] = 0;
|
||||
}
|
||||
}
|
||||
21
src/kem/frodokem/pqclean_frodokem640shake_clean/LICENSE
Normal file
21
src/kem/frodokem/pqclean_frodokem640shake_clean/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
20
src/kem/frodokem/pqclean_frodokem640shake_clean/api.h
Normal file
20
src/kem/frodokem/pqclean_frodokem640shake_clean/api.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef PQCLEAN_FRODOKEM640SHAKE_CLEAN_API_H
|
||||
#define PQCLEAN_FRODOKEM640SHAKE_CLEAN_API_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define PQCLEAN_FRODOKEM640SHAKE_CLEAN_CRYPTO_SECRETKEYBYTES 19888 // sizeof(s) + CRYPTO_PUBLICKEYBYTES + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH
|
||||
#define PQCLEAN_FRODOKEM640SHAKE_CLEAN_CRYPTO_PUBLICKEYBYTES 9616 // sizeof(seed_A) + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8
|
||||
#define PQCLEAN_FRODOKEM640SHAKE_CLEAN_CRYPTO_BYTES 16
|
||||
#define PQCLEAN_FRODOKEM640SHAKE_CLEAN_CRYPTO_CIPHERTEXTBYTES 9720 // (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + (PARAMS_LOGQ*PARAMS_NBAR*PARAMS_NBAR)/8
|
||||
|
||||
#define PQCLEAN_FRODOKEM640SHAKE_CLEAN_CRYPTO_ALGNAME "FrodoKEM-640-SHAKE"
|
||||
|
||||
int PQCLEAN_FRODOKEM640SHAKE_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk);
|
||||
|
||||
int PQCLEAN_FRODOKEM640SHAKE_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
|
||||
|
||||
int PQCLEAN_FRODOKEM640SHAKE_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
|
||||
|
||||
#endif
|
||||
19
src/kem/frodokem/pqclean_frodokem640shake_clean/common.h
Normal file
19
src/kem/frodokem/pqclean_frodokem640shake_clean/common.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
int PQCLEAN_FRODOKEM640SHAKE_CLEAN_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A);
|
||||
int PQCLEAN_FRODOKEM640SHAKE_CLEAN_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A);
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_sample_n(uint16_t *s, size_t n);
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s);
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e);
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_add(uint16_t *out, const uint16_t *a, const uint16_t *b);
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_sub(uint16_t *out, const uint16_t *a, const uint16_t *b);
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_key_encode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_key_decode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb);
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb);
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes(uint8_t *mem, size_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM640SHAKE_CLEAN_LE_TO_UINT16(uint16_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM640SHAKE_CLEAN_UINT16_TO_LE(uint16_t n);
|
||||
|
||||
#endif
|
||||
238
src/kem/frodokem/pqclean_frodokem640shake_clean/kem.c
Normal file
238
src/kem/frodokem/pqclean_frodokem640shake_clean/kem.c
Normal file
@ -0,0 +1,238 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: Key Encapsulation Mechanism (KEM) based on Frodo
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fips202.h"
|
||||
#include "randombytes.h"
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
int PQCLEAN_FRODOKEM640SHAKE_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) {
|
||||
// FrodoKEM'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_PKHASH bytes)
|
||||
uint8_t *pk_seedA = &pk[0];
|
||||
uint8_t *pk_b = &pk[BYTES_SEED_A];
|
||||
uint8_t *sk_s = &sk[0];
|
||||
uint8_t *sk_pk = &sk[CRYPTO_BYTES];
|
||||
uint8_t *sk_S = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
|
||||
uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR];
|
||||
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t S[2 * PARAMS_N * PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t *E = &S[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint8_t randomness[2 * CRYPTO_BYTES + BYTES_SEED_A]; // contains secret data via randomness_s and randomness_seedSE
|
||||
uint8_t *randomness_s = &randomness[0]; // contains secret data
|
||||
uint8_t *randomness_seedSE = &randomness[CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t *randomness_z = &randomness[2 * CRYPTO_BYTES];
|
||||
uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data
|
||||
|
||||
// Generate the secret value s, the seed for S and E, and the seed for the seed for A. Add seed_A to the public key
|
||||
randombytes(randomness, CRYPTO_BYTES + CRYPTO_BYTES + BYTES_SEED_A);
|
||||
shake(pk_seedA, BYTES_SEED_A, randomness_z, BYTES_SEED_A);
|
||||
|
||||
// Generate S and E, and compute B = A*S + E. Generate A on-the-fly
|
||||
shake_input_seedSE[0] = 0x5F;
|
||||
memcpy(&shake_input_seedSE[1], randomness_seedSE, CRYPTO_BYTES);
|
||||
shake((uint8_t *)S, 2 * PARAMS_N * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
for (size_t i = 0; i < 2 * PARAMS_N * PARAMS_NBAR; i++) {
|
||||
S[i] = PQCLEAN_FRODOKEM640SHAKE_CLEAN_LE_TO_UINT16(S[i]);
|
||||
}
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_sample_n(S, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_sample_n(E, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_mul_add_as_plus_e(B, S, E, pk);
|
||||
|
||||
// Encode the second part of the public key
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_pack(pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, B, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ);
|
||||
|
||||
// Add s, pk and S to the secret key
|
||||
memcpy(sk_s, randomness_s, CRYPTO_BYTES);
|
||||
memcpy(sk_pk, pk, CRYPTO_PUBLICKEYBYTES);
|
||||
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
|
||||
S[i] = PQCLEAN_FRODOKEM640SHAKE_CLEAN_UINT16_TO_LE(S[i]);
|
||||
}
|
||||
memcpy(sk_S, S, 2 * PARAMS_N * PARAMS_NBAR);
|
||||
|
||||
// Add H(pk) to the secret key
|
||||
shake(sk_pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);
|
||||
|
||||
// Cleanup:
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes((uint8_t *)E, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes(randomness, 2 * CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int PQCLEAN_FRODOKEM640SHAKE_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
|
||||
// FrodoKEM's key encapsulation
|
||||
const uint8_t *pk_seedA = &pk[0];
|
||||
const uint8_t *pk_b = &pk[BYTES_SEED_A];
|
||||
uint8_t *ct_c1 = &ct[0];
|
||||
uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8];
|
||||
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t V[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0};
|
||||
uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via mu
|
||||
uint8_t *pkh = &G2in[0];
|
||||
uint8_t *mu = &G2in[BYTES_PKHASH]; // contains secret data
|
||||
uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t *seedSE = &G2out[0]; // contains secret data
|
||||
uint8_t *k = &G2out[CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k
|
||||
uint8_t *Fin_ct = &Fin[0];
|
||||
uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data
|
||||
uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data
|
||||
|
||||
// pkh <- G_1(pk), generate random mu, compute (seedSE || k) = G_2(pkh || mu)
|
||||
shake(pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);
|
||||
randombytes(mu, BYTES_MU);
|
||||
shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);
|
||||
|
||||
// Generate Sp and Ep, and compute Bp = Sp*A + Ep. Generate A on-the-fly
|
||||
shake_input_seedSE[0] = 0x96;
|
||||
memcpy(&shake_input_seedSE[1], seedSE, CRYPTO_BYTES);
|
||||
shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) {
|
||||
Sp[i] = PQCLEAN_FRODOKEM640SHAKE_CLEAN_LE_TO_UINT16(Sp[i]);
|
||||
}
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_sample_n(Sp, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_sample_n(Ep, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_mul_add_sa_plus_e(Bp, Sp, Ep, pk_seedA);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_pack(ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, Bp, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ);
|
||||
|
||||
// Generate Epp, and compute V = Sp*B + Epp
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_mul_add_sb_plus_e(V, B, Sp, Epp);
|
||||
|
||||
// Encode mu, and compute C = V + enc(mu) (mod q)
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_key_encode(C, (uint16_t *)mu);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_add(C, V, C);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_pack(ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, C, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOGQ);
|
||||
|
||||
// Compute ss = F(ct||KK)
|
||||
memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);
|
||||
memcpy(Fin_k, k, CRYPTO_BYTES);
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes((uint8_t *)V, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes(mu, BYTES_MU);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes(G2out, 2 * CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes(Fin_k, CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int PQCLEAN_FRODOKEM640SHAKE_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
|
||||
// FrodoKEM's key decapsulation
|
||||
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t W[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0};
|
||||
uint16_t CC[PARAMS_NBAR * PARAMS_NBAR] = {0};
|
||||
uint16_t BBp[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
const uint8_t *ct_c1 = &ct[0];
|
||||
const uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8];
|
||||
const uint8_t *sk_s = &sk[0];
|
||||
const uint8_t *sk_pk = &sk[CRYPTO_BYTES];
|
||||
const uint16_t *sk_S = (uint16_t *) &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
|
||||
uint16_t S[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
const uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR];
|
||||
const uint8_t *pk_seedA = &sk_pk[0];
|
||||
const uint8_t *pk_b = &sk_pk[BYTES_SEED_A];
|
||||
uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via muprime
|
||||
uint8_t *pkh = &G2in[0];
|
||||
uint8_t *muprime = &G2in[BYTES_PKHASH]; // contains secret data
|
||||
uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t *seedSEprime = &G2out[0]; // contains secret data
|
||||
uint8_t *kprime = &G2out[CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k
|
||||
uint8_t *Fin_ct = &Fin[0];
|
||||
uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data
|
||||
uint8_t shake_input_seedSEprime[1 + CRYPTO_BYTES]; // contains secret data
|
||||
|
||||
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
|
||||
S[i] = PQCLEAN_FRODOKEM640SHAKE_CLEAN_LE_TO_UINT16(sk_S[i]);
|
||||
}
|
||||
|
||||
// Compute W = C - Bp*S (mod q), and decode the randomness mu
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_unpack(Bp, PARAMS_N * PARAMS_NBAR, ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_unpack(C, PARAMS_NBAR * PARAMS_NBAR, ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_mul_bs(W, Bp, S);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_sub(W, C, W);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_key_decode((uint16_t *)muprime, W);
|
||||
|
||||
// Generate (seedSE' || k') = G_2(pkh || mu')
|
||||
memcpy(pkh, sk_pkh, BYTES_PKHASH);
|
||||
shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);
|
||||
|
||||
// Generate Sp and Ep, and compute BBp = Sp*A + Ep. Generate A on-the-fly
|
||||
shake_input_seedSEprime[0] = 0x96;
|
||||
memcpy(&shake_input_seedSEprime[1], seedSEprime, CRYPTO_BYTES);
|
||||
shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSEprime, 1 + CRYPTO_BYTES);
|
||||
for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) {
|
||||
Sp[i] = PQCLEAN_FRODOKEM640SHAKE_CLEAN_LE_TO_UINT16(Sp[i]);
|
||||
}
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_sample_n(Sp, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_sample_n(Ep, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_mul_add_sa_plus_e(BBp, Sp, Ep, pk_seedA);
|
||||
|
||||
// Generate Epp, and compute W = Sp*B + Epp
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_mul_add_sb_plus_e(W, B, Sp, Epp);
|
||||
|
||||
// Encode mu, and compute CC = W + enc(mu') (mod q)
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_key_encode(CC, (uint16_t *)muprime);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_add(CC, W, CC);
|
||||
|
||||
// Prepare input to F
|
||||
memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);
|
||||
|
||||
// Reducing BBp modulo q
|
||||
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
|
||||
BBp[i] = BBp[i] & ((1 << PARAMS_LOGQ) - 1);
|
||||
}
|
||||
|
||||
// Is (Bp == BBp & C == CC) = true
|
||||
if (memcmp(Bp, BBp, 2 * PARAMS_N * PARAMS_NBAR) == 0 && memcmp(C, CC, 2 * PARAMS_NBAR * PARAMS_NBAR) == 0) {
|
||||
// Load k' to do ss = F(ct || k')
|
||||
memcpy(Fin_k, kprime, CRYPTO_BYTES);
|
||||
} else {
|
||||
// Load s to do ss = F(ct || s)
|
||||
memcpy(Fin_k, sk_s, CRYPTO_BYTES);
|
||||
}
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes((uint8_t *)W, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes(muprime, BYTES_MU);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes(G2out, 2 * CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes(Fin_k, CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes(shake_input_seedSEprime, 1 + CRYPTO_BYTES);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: matrix arithmetic functions used by the KEM
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fips202.h"
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
int PQCLEAN_FRODOKEM640SHAKE_CLEAN_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;
|
||||
int16_t A[PARAMS_N * PARAMS_N] = {0};
|
||||
|
||||
uint8_t seed_A_separated[2 + BYTES_SEED_A];
|
||||
uint16_t *seed_A_origin = (uint16_t *)&seed_A_separated;
|
||||
memcpy(&seed_A_separated[2], seed_A, BYTES_SEED_A);
|
||||
for (i = 0; i < PARAMS_N; i++) {
|
||||
seed_A_origin[0] = PQCLEAN_FRODOKEM640SHAKE_CLEAN_UINT16_TO_LE((uint16_t) i);
|
||||
shake128((uint8_t *)(A + i * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A);
|
||||
}
|
||||
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
|
||||
A[i] = PQCLEAN_FRODOKEM640SHAKE_CLEAN_LE_TO_UINT16(A[i]);
|
||||
}
|
||||
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));
|
||||
|
||||
for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e
|
||||
for (k = 0; k < PARAMS_NBAR; k++) {
|
||||
uint16_t sum = 0;
|
||||
for (j = 0; j < PARAMS_N; j++) {
|
||||
sum += A[i * PARAMS_N + j] * s[k * PARAMS_N + j];
|
||||
}
|
||||
out[i * PARAMS_NBAR + k] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on.
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int PQCLEAN_FRODOKEM640SHAKE_CLEAN_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, k;
|
||||
int16_t A[PARAMS_N * PARAMS_N] = {0};
|
||||
|
||||
uint8_t seed_A_separated[2 + BYTES_SEED_A];
|
||||
uint16_t *seed_A_origin = (uint16_t *)&seed_A_separated;
|
||||
memcpy(&seed_A_separated[2], seed_A, BYTES_SEED_A);
|
||||
for (i = 0; i < PARAMS_N; i++) {
|
||||
seed_A_origin[0] = PQCLEAN_FRODOKEM640SHAKE_CLEAN_UINT16_TO_LE((uint16_t) i);
|
||||
shake128((uint8_t *)(A + i * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A);
|
||||
}
|
||||
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
|
||||
A[i] = PQCLEAN_FRODOKEM640SHAKE_CLEAN_LE_TO_UINT16(A[i]);
|
||||
}
|
||||
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));
|
||||
|
||||
for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e
|
||||
for (k = 0; k < PARAMS_NBAR; k++) {
|
||||
uint16_t sum = 0;
|
||||
for (j = 0; j < PARAMS_N; j++) {
|
||||
sum += A[j * PARAMS_N + i] * s[k * PARAMS_N + j];
|
||||
}
|
||||
out[k * PARAMS_N + i] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on.
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
35
src/kem/frodokem/pqclean_frodokem640shake_clean/noise.c
Normal file
35
src/kem/frodokem/pqclean_frodokem640shake_clean/noise.c
Normal file
@ -0,0 +1,35 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: noise sampling functions
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
static uint16_t CDF_TABLE[CDF_TABLE_LEN] = CDF_TABLE_DATA;
|
||||
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_sample_n(uint16_t *s, 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.
|
||||
size_t i;
|
||||
unsigned int j;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
uint16_t sample = 0;
|
||||
uint16_t prnd = s[i] >> 1; // Drop the least significant bit
|
||||
uint16_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;
|
||||
}
|
||||
}
|
||||
27
src/kem/frodokem/pqclean_frodokem640shake_clean/params.h
Normal file
27
src/kem/frodokem/pqclean_frodokem640shake_clean/params.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef PARAMS_H
|
||||
#define PARAMS_H
|
||||
|
||||
#define CRYPTO_SECRETKEYBYTES PQCLEAN_FRODOKEM640SHAKE_CLEAN_CRYPTO_SECRETKEYBYTES
|
||||
#define CRYPTO_PUBLICKEYBYTES PQCLEAN_FRODOKEM640SHAKE_CLEAN_CRYPTO_PUBLICKEYBYTES
|
||||
#define CRYPTO_BYTES PQCLEAN_FRODOKEM640SHAKE_CLEAN_CRYPTO_BYTES
|
||||
#define CRYPTO_CIPHERTEXTBYTES PQCLEAN_FRODOKEM640SHAKE_CLEAN_CRYPTO_CIPHERTEXTBYTES
|
||||
|
||||
#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)
|
||||
#define BYTES_PKHASH CRYPTO_BYTES
|
||||
|
||||
// Selecting SHAKE XOF function for the KEM and noise sampling
|
||||
#define shake shake128
|
||||
|
||||
// CDF table
|
||||
#define CDF_TABLE_DATA {4643, 13363, 20579, 25843, 29227, 31145, 32103, 32525, 32689, 32745, 32762, 32766, 32767}
|
||||
#define CDF_TABLE_LEN 13
|
||||
|
||||
#endif
|
||||
235
src/kem/frodokem/pqclean_frodokem640shake_clean/util.c
Normal file
235
src/kem/frodokem/pqclean_frodokem640shake_clean/util.c
Normal file
@ -0,0 +1,235 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: additional functions for FrodoKEM
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
#define min(x, y) (((x) < (y)) ? (x) : (y))
|
||||
|
||||
uint16_t PQCLEAN_FRODOKEM640SHAKE_CLEAN_LE_TO_UINT16(uint16_t n) {
|
||||
return (((uint8_t *) &n)[0] | (((uint8_t *) &n)[1] << 8));
|
||||
}
|
||||
|
||||
uint16_t PQCLEAN_FRODOKEM640SHAKE_CLEAN_UINT16_TO_LE(uint16_t n) {
|
||||
uint16_t y;
|
||||
uint8_t *z = (uint8_t *) &y;
|
||||
z[0] = n & 0xFF;
|
||||
z[1] = (n & 0xFF00) >> 8;
|
||||
return y;
|
||||
}
|
||||
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_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 (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) {
|
||||
out[i] = (a[i] + b[i]) & ((1 << PARAMS_LOGQ) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_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 (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) {
|
||||
out[i] = (a[i] - b[i]) & ((1 << PARAMS_LOGQ) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t 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
|
||||
uint8_t bits = 0; // the number of lsb in w
|
||||
|
||||
while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) {
|
||||
/*
|
||||
in: | | |********|********|
|
||||
^
|
||||
j
|
||||
w : | ****|
|
||||
^
|
||||
bits
|
||||
out:|**|**|**|**|**|**|**|**|* |
|
||||
^^
|
||||
ib
|
||||
*/
|
||||
uint8_t b = 0; // bits in out[i] already filled in
|
||||
while (b < 8) {
|
||||
int nbits = min(8 - b, bits);
|
||||
uint16_t mask = (1 << nbits) - 1;
|
||||
uint8_t t = (uint8_t) ((w >> (bits - nbits)) & mask); // the bits to copy from w to out
|
||||
out[i] = out[i] + (t << (8 - b - nbits));
|
||||
b += (uint8_t) nbits;
|
||||
bits -= (uint8_t) 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 PQCLEAN_FRODOKEM640SHAKE_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t 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
|
||||
uint8_t w = 0; // the leftover, not yet copied
|
||||
uint8_t 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
|
||||
*/
|
||||
uint8_t b = 0; // bits in out[i] already filled in
|
||||
while (b < lsb) {
|
||||
int nbits = min(lsb - b, bits);
|
||||
uint16_t mask = (1 << nbits) - 1;
|
||||
uint8_t t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out
|
||||
out[i] = out[i] + (t << (lsb - b - nbits));
|
||||
b += (uint8_t) nbits;
|
||||
bits -= (uint8_t) 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes(uint8_t *mem, size_t n) {
|
||||
// Clear 8-bit bytes from memory. "n" indicates the number of bytes to be zeroed.
|
||||
// This function uses the volatile type qualifier to inform the compiler not to optimize out the memory clearing.
|
||||
volatile uint8_t *v = mem;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
v[i] = 0;
|
||||
}
|
||||
}
|
||||
21
src/kem/frodokem/pqclean_frodokem976aes_clean/LICENSE
Normal file
21
src/kem/frodokem/pqclean_frodokem976aes_clean/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
20
src/kem/frodokem/pqclean_frodokem976aes_clean/api.h
Normal file
20
src/kem/frodokem/pqclean_frodokem976aes_clean/api.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef PQCLEAN_FRODOKEM976AES_CLEAN_API_H
|
||||
#define PQCLEAN_FRODOKEM976AES_CLEAN_API_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define PQCLEAN_FRODOKEM976AES_CLEAN_CRYPTO_SECRETKEYBYTES 31296 // sizeof(s) + CRYPTO_PUBLICKEYBYTES + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH
|
||||
#define PQCLEAN_FRODOKEM976AES_CLEAN_CRYPTO_PUBLICKEYBYTES 15632 // sizeof(seed_A) + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8
|
||||
#define PQCLEAN_FRODOKEM976AES_CLEAN_CRYPTO_BYTES 24
|
||||
#define PQCLEAN_FRODOKEM976AES_CLEAN_CRYPTO_CIPHERTEXTBYTES 15744 // (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + (PARAMS_LOGQ*PARAMS_NBAR*PARAMS_NBAR)/8
|
||||
|
||||
#define PQCLEAN_FRODOKEM976AES_CLEAN_CRYPTO_ALGNAME "FrodoKEM-976-AES"
|
||||
|
||||
int PQCLEAN_FRODOKEM976AES_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk);
|
||||
|
||||
int PQCLEAN_FRODOKEM976AES_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
|
||||
|
||||
int PQCLEAN_FRODOKEM976AES_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
|
||||
|
||||
#endif
|
||||
19
src/kem/frodokem/pqclean_frodokem976aes_clean/common.h
Normal file
19
src/kem/frodokem/pqclean_frodokem976aes_clean/common.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
int PQCLEAN_FRODOKEM976AES_CLEAN_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A);
|
||||
int PQCLEAN_FRODOKEM976AES_CLEAN_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A);
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_sample_n(uint16_t *s, size_t n);
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s);
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e);
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_add(uint16_t *out, const uint16_t *a, const uint16_t *b);
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_sub(uint16_t *out, const uint16_t *a, const uint16_t *b);
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_key_encode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_key_decode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb);
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb);
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes(uint8_t *mem, size_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM976AES_CLEAN_LE_TO_UINT16(uint16_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM976AES_CLEAN_UINT16_TO_LE(uint16_t n);
|
||||
|
||||
#endif
|
||||
238
src/kem/frodokem/pqclean_frodokem976aes_clean/kem.c
Normal file
238
src/kem/frodokem/pqclean_frodokem976aes_clean/kem.c
Normal file
@ -0,0 +1,238 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: Key Encapsulation Mechanism (KEM) based on Frodo
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fips202.h"
|
||||
#include "randombytes.h"
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
int PQCLEAN_FRODOKEM976AES_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) {
|
||||
// FrodoKEM'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_PKHASH bytes)
|
||||
uint8_t *pk_seedA = &pk[0];
|
||||
uint8_t *pk_b = &pk[BYTES_SEED_A];
|
||||
uint8_t *sk_s = &sk[0];
|
||||
uint8_t *sk_pk = &sk[CRYPTO_BYTES];
|
||||
uint8_t *sk_S = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
|
||||
uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR];
|
||||
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t S[2 * PARAMS_N * PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t *E = &S[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint8_t randomness[2 * CRYPTO_BYTES + BYTES_SEED_A]; // contains secret data via randomness_s and randomness_seedSE
|
||||
uint8_t *randomness_s = &randomness[0]; // contains secret data
|
||||
uint8_t *randomness_seedSE = &randomness[CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t *randomness_z = &randomness[2 * CRYPTO_BYTES];
|
||||
uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data
|
||||
|
||||
// Generate the secret value s, the seed for S and E, and the seed for the seed for A. Add seed_A to the public key
|
||||
randombytes(randomness, CRYPTO_BYTES + CRYPTO_BYTES + BYTES_SEED_A);
|
||||
shake(pk_seedA, BYTES_SEED_A, randomness_z, BYTES_SEED_A);
|
||||
|
||||
// Generate S and E, and compute B = A*S + E. Generate A on-the-fly
|
||||
shake_input_seedSE[0] = 0x5F;
|
||||
memcpy(&shake_input_seedSE[1], randomness_seedSE, CRYPTO_BYTES);
|
||||
shake((uint8_t *)S, 2 * PARAMS_N * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
for (size_t i = 0; i < 2 * PARAMS_N * PARAMS_NBAR; i++) {
|
||||
S[i] = PQCLEAN_FRODOKEM976AES_CLEAN_LE_TO_UINT16(S[i]);
|
||||
}
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_sample_n(S, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_sample_n(E, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_mul_add_as_plus_e(B, S, E, pk);
|
||||
|
||||
// Encode the second part of the public key
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_pack(pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, B, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ);
|
||||
|
||||
// Add s, pk and S to the secret key
|
||||
memcpy(sk_s, randomness_s, CRYPTO_BYTES);
|
||||
memcpy(sk_pk, pk, CRYPTO_PUBLICKEYBYTES);
|
||||
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
|
||||
S[i] = PQCLEAN_FRODOKEM976AES_CLEAN_UINT16_TO_LE(S[i]);
|
||||
}
|
||||
memcpy(sk_S, S, 2 * PARAMS_N * PARAMS_NBAR);
|
||||
|
||||
// Add H(pk) to the secret key
|
||||
shake(sk_pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);
|
||||
|
||||
// Cleanup:
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes((uint8_t *)E, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes(randomness, 2 * CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int PQCLEAN_FRODOKEM976AES_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
|
||||
// FrodoKEM's key encapsulation
|
||||
const uint8_t *pk_seedA = &pk[0];
|
||||
const uint8_t *pk_b = &pk[BYTES_SEED_A];
|
||||
uint8_t *ct_c1 = &ct[0];
|
||||
uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8];
|
||||
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t V[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0};
|
||||
uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via mu
|
||||
uint8_t *pkh = &G2in[0];
|
||||
uint8_t *mu = &G2in[BYTES_PKHASH]; // contains secret data
|
||||
uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t *seedSE = &G2out[0]; // contains secret data
|
||||
uint8_t *k = &G2out[CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k
|
||||
uint8_t *Fin_ct = &Fin[0];
|
||||
uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data
|
||||
uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data
|
||||
|
||||
// pkh <- G_1(pk), generate random mu, compute (seedSE || k) = G_2(pkh || mu)
|
||||
shake(pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);
|
||||
randombytes(mu, BYTES_MU);
|
||||
shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);
|
||||
|
||||
// Generate Sp and Ep, and compute Bp = Sp*A + Ep. Generate A on-the-fly
|
||||
shake_input_seedSE[0] = 0x96;
|
||||
memcpy(&shake_input_seedSE[1], seedSE, CRYPTO_BYTES);
|
||||
shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) {
|
||||
Sp[i] = PQCLEAN_FRODOKEM976AES_CLEAN_LE_TO_UINT16(Sp[i]);
|
||||
}
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_sample_n(Sp, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_sample_n(Ep, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_mul_add_sa_plus_e(Bp, Sp, Ep, pk_seedA);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_pack(ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, Bp, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ);
|
||||
|
||||
// Generate Epp, and compute V = Sp*B + Epp
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_mul_add_sb_plus_e(V, B, Sp, Epp);
|
||||
|
||||
// Encode mu, and compute C = V + enc(mu) (mod q)
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_key_encode(C, (uint16_t *)mu);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_add(C, V, C);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_pack(ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, C, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOGQ);
|
||||
|
||||
// Compute ss = F(ct||KK)
|
||||
memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);
|
||||
memcpy(Fin_k, k, CRYPTO_BYTES);
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes((uint8_t *)V, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes(mu, BYTES_MU);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes(G2out, 2 * CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes(Fin_k, CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int PQCLEAN_FRODOKEM976AES_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
|
||||
// FrodoKEM's key decapsulation
|
||||
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t W[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0};
|
||||
uint16_t CC[PARAMS_NBAR * PARAMS_NBAR] = {0};
|
||||
uint16_t BBp[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
const uint8_t *ct_c1 = &ct[0];
|
||||
const uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8];
|
||||
const uint8_t *sk_s = &sk[0];
|
||||
const uint8_t *sk_pk = &sk[CRYPTO_BYTES];
|
||||
const uint16_t *sk_S = (uint16_t *) &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
|
||||
uint16_t S[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
const uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR];
|
||||
const uint8_t *pk_seedA = &sk_pk[0];
|
||||
const uint8_t *pk_b = &sk_pk[BYTES_SEED_A];
|
||||
uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via muprime
|
||||
uint8_t *pkh = &G2in[0];
|
||||
uint8_t *muprime = &G2in[BYTES_PKHASH]; // contains secret data
|
||||
uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t *seedSEprime = &G2out[0]; // contains secret data
|
||||
uint8_t *kprime = &G2out[CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k
|
||||
uint8_t *Fin_ct = &Fin[0];
|
||||
uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data
|
||||
uint8_t shake_input_seedSEprime[1 + CRYPTO_BYTES]; // contains secret data
|
||||
|
||||
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
|
||||
S[i] = PQCLEAN_FRODOKEM976AES_CLEAN_LE_TO_UINT16(sk_S[i]);
|
||||
}
|
||||
|
||||
// Compute W = C - Bp*S (mod q), and decode the randomness mu
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_unpack(Bp, PARAMS_N * PARAMS_NBAR, ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_unpack(C, PARAMS_NBAR * PARAMS_NBAR, ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_mul_bs(W, Bp, S);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_sub(W, C, W);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_key_decode((uint16_t *)muprime, W);
|
||||
|
||||
// Generate (seedSE' || k') = G_2(pkh || mu')
|
||||
memcpy(pkh, sk_pkh, BYTES_PKHASH);
|
||||
shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);
|
||||
|
||||
// Generate Sp and Ep, and compute BBp = Sp*A + Ep. Generate A on-the-fly
|
||||
shake_input_seedSEprime[0] = 0x96;
|
||||
memcpy(&shake_input_seedSEprime[1], seedSEprime, CRYPTO_BYTES);
|
||||
shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSEprime, 1 + CRYPTO_BYTES);
|
||||
for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) {
|
||||
Sp[i] = PQCLEAN_FRODOKEM976AES_CLEAN_LE_TO_UINT16(Sp[i]);
|
||||
}
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_sample_n(Sp, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_sample_n(Ep, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_mul_add_sa_plus_e(BBp, Sp, Ep, pk_seedA);
|
||||
|
||||
// Generate Epp, and compute W = Sp*B + Epp
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_mul_add_sb_plus_e(W, B, Sp, Epp);
|
||||
|
||||
// Encode mu, and compute CC = W + enc(mu') (mod q)
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_key_encode(CC, (uint16_t *)muprime);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_add(CC, W, CC);
|
||||
|
||||
// Prepare input to F
|
||||
memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);
|
||||
|
||||
// Reducing BBp modulo q
|
||||
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
|
||||
BBp[i] = BBp[i] & ((1 << PARAMS_LOGQ) - 1);
|
||||
}
|
||||
|
||||
// Is (Bp == BBp & C == CC) = true
|
||||
if (memcmp(Bp, BBp, 2 * PARAMS_N * PARAMS_NBAR) == 0 && memcmp(C, CC, 2 * PARAMS_NBAR * PARAMS_NBAR) == 0) {
|
||||
// Load k' to do ss = F(ct || k')
|
||||
memcpy(Fin_k, kprime, CRYPTO_BYTES);
|
||||
} else {
|
||||
// Load s to do ss = F(ct || s)
|
||||
memcpy(Fin_k, sk_s, CRYPTO_BYTES);
|
||||
}
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes((uint8_t *)W, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes(muprime, BYTES_MU);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes(G2out, 2 * CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes(Fin_k, CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes(shake_input_seedSEprime, 1 + CRYPTO_BYTES);
|
||||
return 0;
|
||||
}
|
||||
93
src/kem/frodokem/pqclean_frodokem976aes_clean/matrix_aes.c
Normal file
93
src/kem/frodokem/pqclean_frodokem976aes_clean/matrix_aes.c
Normal file
@ -0,0 +1,93 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: matrix arithmetic functions used by the KEM
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "aes.h"
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
int PQCLEAN_FRODOKEM976AES_CLEAN_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;
|
||||
int16_t A[PARAMS_N * PARAMS_N] = {0};
|
||||
aes128ctx ctx128;
|
||||
|
||||
aes128_keyexp(&ctx128, seed_A);
|
||||
for (i = 0; i < PARAMS_N; i++) {
|
||||
for (j = 0; j < PARAMS_N; j += PARAMS_STRIPE_STEP) {
|
||||
A[i * PARAMS_N + j] = (int16_t) i; // Loading values in the little-endian order
|
||||
A[i * PARAMS_N + j + 1] = (int16_t) j;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
|
||||
A[i] = PQCLEAN_FRODOKEM976AES_CLEAN_UINT16_TO_LE(A[i]);
|
||||
}
|
||||
|
||||
aes128_ecb((uint8_t *) A, (uint8_t *) A, PARAMS_N * PARAMS_N * sizeof(int16_t) / AES_BLOCKBYTES, &ctx128);
|
||||
|
||||
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
|
||||
A[i] = PQCLEAN_FRODOKEM976AES_CLEAN_LE_TO_UINT16(A[i]);
|
||||
}
|
||||
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));
|
||||
|
||||
for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e
|
||||
for (k = 0; k < PARAMS_NBAR; k++) {
|
||||
uint16_t sum = 0;
|
||||
for (j = 0; j < PARAMS_N; j++) {
|
||||
sum += A[i * PARAMS_N + j] * s[k * PARAMS_N + j];
|
||||
}
|
||||
out[i * PARAMS_NBAR + k] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on.
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int PQCLEAN_FRODOKEM976AES_CLEAN_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, k;
|
||||
int16_t A[PARAMS_N * PARAMS_N] = {0};
|
||||
aes128ctx ctx128;
|
||||
|
||||
aes128_keyexp(&ctx128, seed_A);
|
||||
for (i = 0; i < PARAMS_N; i++) {
|
||||
for (j = 0; j < PARAMS_N; j += PARAMS_STRIPE_STEP) {
|
||||
A[i * PARAMS_N + j] = (int16_t) i; // Loading values in the little-endian order
|
||||
A[i * PARAMS_N + j + 1] = (int16_t) j;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
|
||||
A[i] = PQCLEAN_FRODOKEM976AES_CLEAN_UINT16_TO_LE(A[i]);
|
||||
}
|
||||
|
||||
aes128_ecb((uint8_t *) A, (uint8_t *) A, PARAMS_N * PARAMS_N * sizeof(int16_t) / AES_BLOCKBYTES, &ctx128);
|
||||
|
||||
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
|
||||
A[i] = PQCLEAN_FRODOKEM976AES_CLEAN_LE_TO_UINT16(A[i]);
|
||||
}
|
||||
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));
|
||||
|
||||
for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e
|
||||
for (k = 0; k < PARAMS_NBAR; k++) {
|
||||
uint16_t sum = 0;
|
||||
for (j = 0; j < PARAMS_N; j++) {
|
||||
sum += A[j * PARAMS_N + i] * s[k * PARAMS_N + j];
|
||||
}
|
||||
out[k * PARAMS_N + i] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on.
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
35
src/kem/frodokem/pqclean_frodokem976aes_clean/noise.c
Normal file
35
src/kem/frodokem/pqclean_frodokem976aes_clean/noise.c
Normal file
@ -0,0 +1,35 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: noise sampling functions
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
static uint16_t CDF_TABLE[CDF_TABLE_LEN] = CDF_TABLE_DATA;
|
||||
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_sample_n(uint16_t *s, 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.
|
||||
size_t i;
|
||||
unsigned int j;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
uint16_t sample = 0;
|
||||
uint16_t prnd = s[i] >> 1; // Drop the least significant bit
|
||||
uint16_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;
|
||||
}
|
||||
}
|
||||
27
src/kem/frodokem/pqclean_frodokem976aes_clean/params.h
Normal file
27
src/kem/frodokem/pqclean_frodokem976aes_clean/params.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef PARAMS_H
|
||||
#define PARAMS_H
|
||||
|
||||
#define CRYPTO_SECRETKEYBYTES PQCLEAN_FRODOKEM976AES_CLEAN_CRYPTO_SECRETKEYBYTES
|
||||
#define CRYPTO_PUBLICKEYBYTES PQCLEAN_FRODOKEM976AES_CLEAN_CRYPTO_PUBLICKEYBYTES
|
||||
#define CRYPTO_BYTES PQCLEAN_FRODOKEM976AES_CLEAN_CRYPTO_BYTES
|
||||
#define CRYPTO_CIPHERTEXTBYTES PQCLEAN_FRODOKEM976AES_CLEAN_CRYPTO_CIPHERTEXTBYTES
|
||||
|
||||
#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)
|
||||
#define BYTES_PKHASH CRYPTO_BYTES
|
||||
|
||||
// Selecting SHAKE XOF function for the KEM and noise sampling
|
||||
#define shake shake256
|
||||
|
||||
// CDF table
|
||||
#define CDF_TABLE_DATA {5638, 15915, 23689, 28571, 31116, 32217, 32613, 32731, 32760, 32766, 32767}
|
||||
#define CDF_TABLE_LEN 11
|
||||
|
||||
#endif
|
||||
235
src/kem/frodokem/pqclean_frodokem976aes_clean/util.c
Normal file
235
src/kem/frodokem/pqclean_frodokem976aes_clean/util.c
Normal file
@ -0,0 +1,235 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: additional functions for FrodoKEM
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
#define min(x, y) (((x) < (y)) ? (x) : (y))
|
||||
|
||||
uint16_t PQCLEAN_FRODOKEM976AES_CLEAN_LE_TO_UINT16(uint16_t n) {
|
||||
return (((uint8_t *) &n)[0] | (((uint8_t *) &n)[1] << 8));
|
||||
}
|
||||
|
||||
uint16_t PQCLEAN_FRODOKEM976AES_CLEAN_UINT16_TO_LE(uint16_t n) {
|
||||
uint16_t y;
|
||||
uint8_t *z = (uint8_t *) &y;
|
||||
z[0] = n & 0xFF;
|
||||
z[1] = (n & 0xFF00) >> 8;
|
||||
return y;
|
||||
}
|
||||
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_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 (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) {
|
||||
out[i] = (a[i] + b[i]) & ((1 << PARAMS_LOGQ) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_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 (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) {
|
||||
out[i] = (a[i] - b[i]) & ((1 << PARAMS_LOGQ) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t 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
|
||||
uint8_t bits = 0; // the number of lsb in w
|
||||
|
||||
while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) {
|
||||
/*
|
||||
in: | | |********|********|
|
||||
^
|
||||
j
|
||||
w : | ****|
|
||||
^
|
||||
bits
|
||||
out:|**|**|**|**|**|**|**|**|* |
|
||||
^^
|
||||
ib
|
||||
*/
|
||||
uint8_t b = 0; // bits in out[i] already filled in
|
||||
while (b < 8) {
|
||||
int nbits = min(8 - b, bits);
|
||||
uint16_t mask = (1 << nbits) - 1;
|
||||
uint8_t t = (uint8_t) ((w >> (bits - nbits)) & mask); // the bits to copy from w to out
|
||||
out[i] = out[i] + (t << (8 - b - nbits));
|
||||
b += (uint8_t) nbits;
|
||||
bits -= (uint8_t) 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 PQCLEAN_FRODOKEM976AES_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t 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
|
||||
uint8_t w = 0; // the leftover, not yet copied
|
||||
uint8_t 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
|
||||
*/
|
||||
uint8_t b = 0; // bits in out[i] already filled in
|
||||
while (b < lsb) {
|
||||
int nbits = min(lsb - b, bits);
|
||||
uint16_t mask = (1 << nbits) - 1;
|
||||
uint8_t t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out
|
||||
out[i] = out[i] + (t << (lsb - b - nbits));
|
||||
b += (uint8_t) nbits;
|
||||
bits -= (uint8_t) 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes(uint8_t *mem, size_t n) {
|
||||
// Clear 8-bit bytes from memory. "n" indicates the number of bytes to be zeroed.
|
||||
// This function uses the volatile type qualifier to inform the compiler not to optimize out the memory clearing.
|
||||
volatile uint8_t *v = mem;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
v[i] = 0;
|
||||
}
|
||||
}
|
||||
21
src/kem/frodokem/pqclean_frodokem976shake_clean/LICENSE
Normal file
21
src/kem/frodokem/pqclean_frodokem976shake_clean/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
20
src/kem/frodokem/pqclean_frodokem976shake_clean/api.h
Normal file
20
src/kem/frodokem/pqclean_frodokem976shake_clean/api.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef PQCLEAN_FRODOKEM976SHAKE_CLEAN_API_H
|
||||
#define PQCLEAN_FRODOKEM976SHAKE_CLEAN_API_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define PQCLEAN_FRODOKEM976SHAKE_CLEAN_CRYPTO_SECRETKEYBYTES 31296 // sizeof(s) + CRYPTO_PUBLICKEYBYTES + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH
|
||||
#define PQCLEAN_FRODOKEM976SHAKE_CLEAN_CRYPTO_PUBLICKEYBYTES 15632 // sizeof(seed_A) + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8
|
||||
#define PQCLEAN_FRODOKEM976SHAKE_CLEAN_CRYPTO_BYTES 24
|
||||
#define PQCLEAN_FRODOKEM976SHAKE_CLEAN_CRYPTO_CIPHERTEXTBYTES 15744 // (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + (PARAMS_LOGQ*PARAMS_NBAR*PARAMS_NBAR)/8
|
||||
|
||||
#define PQCLEAN_FRODOKEM976SHAKE_CLEAN_CRYPTO_ALGNAME "FrodoKEM-976-SHAKE"
|
||||
|
||||
int PQCLEAN_FRODOKEM976SHAKE_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk);
|
||||
|
||||
int PQCLEAN_FRODOKEM976SHAKE_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
|
||||
|
||||
int PQCLEAN_FRODOKEM976SHAKE_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
|
||||
|
||||
#endif
|
||||
19
src/kem/frodokem/pqclean_frodokem976shake_clean/common.h
Normal file
19
src/kem/frodokem/pqclean_frodokem976shake_clean/common.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
int PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A);
|
||||
int PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A);
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(uint16_t *s, size_t n);
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s);
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e);
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_add(uint16_t *out, const uint16_t *a, const uint16_t *b);
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_sub(uint16_t *out, const uint16_t *a, const uint16_t *b);
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_key_encode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_key_decode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb);
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb);
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(uint8_t *mem, size_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(uint16_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM976SHAKE_CLEAN_UINT16_TO_LE(uint16_t n);
|
||||
|
||||
#endif
|
||||
238
src/kem/frodokem/pqclean_frodokem976shake_clean/kem.c
Normal file
238
src/kem/frodokem/pqclean_frodokem976shake_clean/kem.c
Normal file
@ -0,0 +1,238 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: Key Encapsulation Mechanism (KEM) based on Frodo
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fips202.h"
|
||||
#include "randombytes.h"
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
int PQCLEAN_FRODOKEM976SHAKE_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) {
|
||||
// FrodoKEM'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_PKHASH bytes)
|
||||
uint8_t *pk_seedA = &pk[0];
|
||||
uint8_t *pk_b = &pk[BYTES_SEED_A];
|
||||
uint8_t *sk_s = &sk[0];
|
||||
uint8_t *sk_pk = &sk[CRYPTO_BYTES];
|
||||
uint8_t *sk_S = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
|
||||
uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR];
|
||||
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t S[2 * PARAMS_N * PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t *E = &S[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint8_t randomness[2 * CRYPTO_BYTES + BYTES_SEED_A]; // contains secret data via randomness_s and randomness_seedSE
|
||||
uint8_t *randomness_s = &randomness[0]; // contains secret data
|
||||
uint8_t *randomness_seedSE = &randomness[CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t *randomness_z = &randomness[2 * CRYPTO_BYTES];
|
||||
uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data
|
||||
|
||||
// Generate the secret value s, the seed for S and E, and the seed for the seed for A. Add seed_A to the public key
|
||||
randombytes(randomness, CRYPTO_BYTES + CRYPTO_BYTES + BYTES_SEED_A);
|
||||
shake(pk_seedA, BYTES_SEED_A, randomness_z, BYTES_SEED_A);
|
||||
|
||||
// Generate S and E, and compute B = A*S + E. Generate A on-the-fly
|
||||
shake_input_seedSE[0] = 0x5F;
|
||||
memcpy(&shake_input_seedSE[1], randomness_seedSE, CRYPTO_BYTES);
|
||||
shake((uint8_t *)S, 2 * PARAMS_N * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
for (size_t i = 0; i < 2 * PARAMS_N * PARAMS_NBAR; i++) {
|
||||
S[i] = PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(S[i]);
|
||||
}
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(S, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(E, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_add_as_plus_e(B, S, E, pk);
|
||||
|
||||
// Encode the second part of the public key
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_pack(pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, B, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ);
|
||||
|
||||
// Add s, pk and S to the secret key
|
||||
memcpy(sk_s, randomness_s, CRYPTO_BYTES);
|
||||
memcpy(sk_pk, pk, CRYPTO_PUBLICKEYBYTES);
|
||||
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
|
||||
S[i] = PQCLEAN_FRODOKEM976SHAKE_CLEAN_UINT16_TO_LE(S[i]);
|
||||
}
|
||||
memcpy(sk_S, S, 2 * PARAMS_N * PARAMS_NBAR);
|
||||
|
||||
// Add H(pk) to the secret key
|
||||
shake(sk_pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);
|
||||
|
||||
// Cleanup:
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)E, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(randomness, 2 * CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int PQCLEAN_FRODOKEM976SHAKE_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
|
||||
// FrodoKEM's key encapsulation
|
||||
const uint8_t *pk_seedA = &pk[0];
|
||||
const uint8_t *pk_b = &pk[BYTES_SEED_A];
|
||||
uint8_t *ct_c1 = &ct[0];
|
||||
uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8];
|
||||
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t V[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0};
|
||||
uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via mu
|
||||
uint8_t *pkh = &G2in[0];
|
||||
uint8_t *mu = &G2in[BYTES_PKHASH]; // contains secret data
|
||||
uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t *seedSE = &G2out[0]; // contains secret data
|
||||
uint8_t *k = &G2out[CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k
|
||||
uint8_t *Fin_ct = &Fin[0];
|
||||
uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data
|
||||
uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data
|
||||
|
||||
// pkh <- G_1(pk), generate random mu, compute (seedSE || k) = G_2(pkh || mu)
|
||||
shake(pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);
|
||||
randombytes(mu, BYTES_MU);
|
||||
shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);
|
||||
|
||||
// Generate Sp and Ep, and compute Bp = Sp*A + Ep. Generate A on-the-fly
|
||||
shake_input_seedSE[0] = 0x96;
|
||||
memcpy(&shake_input_seedSE[1], seedSE, CRYPTO_BYTES);
|
||||
shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) {
|
||||
Sp[i] = PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(Sp[i]);
|
||||
}
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(Sp, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(Ep, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_add_sa_plus_e(Bp, Sp, Ep, pk_seedA);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_pack(ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, Bp, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ);
|
||||
|
||||
// Generate Epp, and compute V = Sp*B + Epp
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_add_sb_plus_e(V, B, Sp, Epp);
|
||||
|
||||
// Encode mu, and compute C = V + enc(mu) (mod q)
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_key_encode(C, (uint16_t *)mu);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_add(C, V, C);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_pack(ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, C, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOGQ);
|
||||
|
||||
// Compute ss = F(ct||KK)
|
||||
memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);
|
||||
memcpy(Fin_k, k, CRYPTO_BYTES);
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)V, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(mu, BYTES_MU);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(G2out, 2 * CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(Fin_k, CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int PQCLEAN_FRODOKEM976SHAKE_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
|
||||
// FrodoKEM's key decapsulation
|
||||
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t W[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0};
|
||||
uint16_t CC[PARAMS_NBAR * PARAMS_NBAR] = {0};
|
||||
uint16_t BBp[PARAMS_N * PARAMS_NBAR] = {0};
|
||||
uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data
|
||||
uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
const uint8_t *ct_c1 = &ct[0];
|
||||
const uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8];
|
||||
const uint8_t *sk_s = &sk[0];
|
||||
const uint8_t *sk_pk = &sk[CRYPTO_BYTES];
|
||||
const uint16_t *sk_S = (uint16_t *) &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
|
||||
uint16_t S[PARAMS_N * PARAMS_NBAR]; // contains secret data
|
||||
const uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR];
|
||||
const uint8_t *pk_seedA = &sk_pk[0];
|
||||
const uint8_t *pk_b = &sk_pk[BYTES_SEED_A];
|
||||
uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via muprime
|
||||
uint8_t *pkh = &G2in[0];
|
||||
uint8_t *muprime = &G2in[BYTES_PKHASH]; // contains secret data
|
||||
uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t *seedSEprime = &G2out[0]; // contains secret data
|
||||
uint8_t *kprime = &G2out[CRYPTO_BYTES]; // contains secret data
|
||||
uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k
|
||||
uint8_t *Fin_ct = &Fin[0];
|
||||
uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data
|
||||
uint8_t shake_input_seedSEprime[1 + CRYPTO_BYTES]; // contains secret data
|
||||
|
||||
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
|
||||
S[i] = PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(sk_S[i]);
|
||||
}
|
||||
|
||||
// Compute W = C - Bp*S (mod q), and decode the randomness mu
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_unpack(Bp, PARAMS_N * PARAMS_NBAR, ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_unpack(C, PARAMS_NBAR * PARAMS_NBAR, ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_bs(W, Bp, S);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_sub(W, C, W);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_key_decode((uint16_t *)muprime, W);
|
||||
|
||||
// Generate (seedSE' || k') = G_2(pkh || mu')
|
||||
memcpy(pkh, sk_pkh, BYTES_PKHASH);
|
||||
shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);
|
||||
|
||||
// Generate Sp and Ep, and compute BBp = Sp*A + Ep. Generate A on-the-fly
|
||||
shake_input_seedSEprime[0] = 0x96;
|
||||
memcpy(&shake_input_seedSEprime[1], seedSEprime, CRYPTO_BYTES);
|
||||
shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSEprime, 1 + CRYPTO_BYTES);
|
||||
for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) {
|
||||
Sp[i] = PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(Sp[i]);
|
||||
}
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(Sp, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(Ep, PARAMS_N * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_add_sa_plus_e(BBp, Sp, Ep, pk_seedA);
|
||||
|
||||
// Generate Epp, and compute W = Sp*B + Epp
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_add_sb_plus_e(W, B, Sp, Epp);
|
||||
|
||||
// Encode mu, and compute CC = W + enc(mu') (mod q)
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_key_encode(CC, (uint16_t *)muprime);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_add(CC, W, CC);
|
||||
|
||||
// Prepare input to F
|
||||
memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);
|
||||
|
||||
// Reducing BBp modulo q
|
||||
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
|
||||
BBp[i] = BBp[i] & ((1 << PARAMS_LOGQ) - 1);
|
||||
}
|
||||
|
||||
// Is (Bp == BBp & C == CC) = true
|
||||
if (memcmp(Bp, BBp, 2 * PARAMS_N * PARAMS_NBAR) == 0 && memcmp(C, CC, 2 * PARAMS_NBAR * PARAMS_NBAR) == 0) {
|
||||
// Load k' to do ss = F(ct || k')
|
||||
memcpy(Fin_k, kprime, CRYPTO_BYTES);
|
||||
} else {
|
||||
// Load s to do ss = F(ct || s)
|
||||
memcpy(Fin_k, sk_s, CRYPTO_BYTES);
|
||||
}
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)W, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(muprime, BYTES_MU);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(G2out, 2 * CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(Fin_k, CRYPTO_BYTES);
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(shake_input_seedSEprime, 1 + CRYPTO_BYTES);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: matrix arithmetic functions used by the KEM
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fips202.h"
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
int PQCLEAN_FRODOKEM976SHAKE_CLEAN_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;
|
||||
int16_t A[PARAMS_N * PARAMS_N] = {0};
|
||||
|
||||
uint8_t seed_A_separated[2 + BYTES_SEED_A];
|
||||
uint16_t *seed_A_origin = (uint16_t *)&seed_A_separated;
|
||||
memcpy(&seed_A_separated[2], seed_A, BYTES_SEED_A);
|
||||
for (i = 0; i < PARAMS_N; i++) {
|
||||
seed_A_origin[0] = PQCLEAN_FRODOKEM976SHAKE_CLEAN_UINT16_TO_LE((uint16_t) i);
|
||||
shake128((uint8_t *)(A + i * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A);
|
||||
}
|
||||
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
|
||||
A[i] = PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(A[i]);
|
||||
}
|
||||
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));
|
||||
|
||||
for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e
|
||||
for (k = 0; k < PARAMS_NBAR; k++) {
|
||||
uint16_t sum = 0;
|
||||
for (j = 0; j < PARAMS_N; j++) {
|
||||
sum += A[i * PARAMS_N + j] * s[k * PARAMS_N + j];
|
||||
}
|
||||
out[i * PARAMS_NBAR + k] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on.
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int PQCLEAN_FRODOKEM976SHAKE_CLEAN_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, k;
|
||||
int16_t A[PARAMS_N * PARAMS_N] = {0};
|
||||
|
||||
uint8_t seed_A_separated[2 + BYTES_SEED_A];
|
||||
uint16_t *seed_A_origin = (uint16_t *)&seed_A_separated;
|
||||
memcpy(&seed_A_separated[2], seed_A, BYTES_SEED_A);
|
||||
for (i = 0; i < PARAMS_N; i++) {
|
||||
seed_A_origin[0] = PQCLEAN_FRODOKEM976SHAKE_CLEAN_UINT16_TO_LE((uint16_t) i);
|
||||
shake128((uint8_t *)(A + i * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A);
|
||||
}
|
||||
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
|
||||
A[i] = PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(A[i]);
|
||||
}
|
||||
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));
|
||||
|
||||
for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e
|
||||
for (k = 0; k < PARAMS_NBAR; k++) {
|
||||
uint16_t sum = 0;
|
||||
for (j = 0; j < PARAMS_N; j++) {
|
||||
sum += A[j * PARAMS_N + i] * s[k * PARAMS_N + j];
|
||||
}
|
||||
out[k * PARAMS_N + i] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on.
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
35
src/kem/frodokem/pqclean_frodokem976shake_clean/noise.c
Normal file
35
src/kem/frodokem/pqclean_frodokem976shake_clean/noise.c
Normal file
@ -0,0 +1,35 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: noise sampling functions
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
static uint16_t CDF_TABLE[CDF_TABLE_LEN] = CDF_TABLE_DATA;
|
||||
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(uint16_t *s, 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.
|
||||
size_t i;
|
||||
unsigned int j;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
uint16_t sample = 0;
|
||||
uint16_t prnd = s[i] >> 1; // Drop the least significant bit
|
||||
uint16_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;
|
||||
}
|
||||
}
|
||||
27
src/kem/frodokem/pqclean_frodokem976shake_clean/params.h
Normal file
27
src/kem/frodokem/pqclean_frodokem976shake_clean/params.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef PARAMS_H
|
||||
#define PARAMS_H
|
||||
|
||||
#define CRYPTO_SECRETKEYBYTES PQCLEAN_FRODOKEM976SHAKE_CLEAN_CRYPTO_SECRETKEYBYTES
|
||||
#define CRYPTO_PUBLICKEYBYTES PQCLEAN_FRODOKEM976SHAKE_CLEAN_CRYPTO_PUBLICKEYBYTES
|
||||
#define CRYPTO_BYTES PQCLEAN_FRODOKEM976SHAKE_CLEAN_CRYPTO_BYTES
|
||||
#define CRYPTO_CIPHERTEXTBYTES PQCLEAN_FRODOKEM976SHAKE_CLEAN_CRYPTO_CIPHERTEXTBYTES
|
||||
|
||||
#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)
|
||||
#define BYTES_PKHASH CRYPTO_BYTES
|
||||
|
||||
// Selecting SHAKE XOF function for the KEM and noise sampling
|
||||
#define shake shake256
|
||||
|
||||
// CDF table
|
||||
#define CDF_TABLE_DATA {5638, 15915, 23689, 28571, 31116, 32217, 32613, 32731, 32760, 32766, 32767}
|
||||
#define CDF_TABLE_LEN 11
|
||||
|
||||
#endif
|
||||
235
src/kem/frodokem/pqclean_frodokem976shake_clean/util.c
Normal file
235
src/kem/frodokem/pqclean_frodokem976shake_clean/util.c
Normal file
@ -0,0 +1,235 @@
|
||||
/********************************************************************************************
|
||||
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||
*
|
||||
* Abstract: additional functions for FrodoKEM
|
||||
*********************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "params.h"
|
||||
|
||||
#define min(x, y) (((x) < (y)) ? (x) : (y))
|
||||
|
||||
uint16_t PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(uint16_t n) {
|
||||
return (((uint8_t *) &n)[0] | (((uint8_t *) &n)[1] << 8));
|
||||
}
|
||||
|
||||
uint16_t PQCLEAN_FRODOKEM976SHAKE_CLEAN_UINT16_TO_LE(uint16_t n) {
|
||||
uint16_t y;
|
||||
uint8_t *z = (uint8_t *) &y;
|
||||
z[0] = n & 0xFF;
|
||||
z[1] = (n & 0xFF00) >> 8;
|
||||
return y;
|
||||
}
|
||||
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_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 (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) {
|
||||
out[i] = (a[i] + b[i]) & ((1 << PARAMS_LOGQ) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_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 (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) {
|
||||
out[i] = (a[i] - b[i]) & ((1 << PARAMS_LOGQ) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t 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
|
||||
uint8_t bits = 0; // the number of lsb in w
|
||||
|
||||
while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) {
|
||||
/*
|
||||
in: | | |********|********|
|
||||
^
|
||||
j
|
||||
w : | ****|
|
||||
^
|
||||
bits
|
||||
out:|**|**|**|**|**|**|**|**|* |
|
||||
^^
|
||||
ib
|
||||
*/
|
||||
uint8_t b = 0; // bits in out[i] already filled in
|
||||
while (b < 8) {
|
||||
int nbits = min(8 - b, bits);
|
||||
uint16_t mask = (1 << nbits) - 1;
|
||||
uint8_t t = (uint8_t) ((w >> (bits - nbits)) & mask); // the bits to copy from w to out
|
||||
out[i] = out[i] + (t << (8 - b - nbits));
|
||||
b += (uint8_t) nbits;
|
||||
bits -= (uint8_t) 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 PQCLEAN_FRODOKEM976SHAKE_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t 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
|
||||
uint8_t w = 0; // the leftover, not yet copied
|
||||
uint8_t 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
|
||||
*/
|
||||
uint8_t b = 0; // bits in out[i] already filled in
|
||||
while (b < lsb) {
|
||||
int nbits = min(lsb - b, bits);
|
||||
uint16_t mask = (1 << nbits) - 1;
|
||||
uint8_t t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out
|
||||
out[i] = out[i] + (t << (lsb - b - nbits));
|
||||
b += (uint8_t) nbits;
|
||||
bits -= (uint8_t) 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(uint8_t *mem, size_t n) {
|
||||
// Clear 8-bit bytes from memory. "n" indicates the number of bytes to be zeroed.
|
||||
// This function uses the volatile type qualifier to inform the compiler not to optimize out the memory clearing.
|
||||
volatile uint8_t *v = mem;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
v[i] = 0;
|
||||
}
|
||||
}
|
||||
@ -1,104 +0,0 @@
|
||||
/********************************************************************************************
|
||||
* 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -13,7 +13,7 @@ OQS_API const char *OQS_KEM_alg_identifier(size_t i) {
|
||||
const char *a[OQS_KEM_algs_length] = {
|
||||
OQS_KEM_alg_default,
|
||||
OQS_KEM_alg_bike1_l1, OQS_KEM_alg_bike1_l3, OQS_KEM_alg_bike1_l5, OQS_KEM_alg_bike2_l1, OQS_KEM_alg_bike2_l3, OQS_KEM_alg_bike2_l5, OQS_KEM_alg_bike3_l1, OQS_KEM_alg_bike3_l3, OQS_KEM_alg_bike3_l5,
|
||||
OQS_KEM_alg_frodokem_640_aes, OQS_KEM_alg_frodokem_640_cshake, OQS_KEM_alg_frodokem_976_aes, OQS_KEM_alg_frodokem_976_cshake,
|
||||
OQS_KEM_alg_frodokem_640_aes, OQS_KEM_alg_frodokem_640_shake, OQS_KEM_alg_frodokem_976_aes, OQS_KEM_alg_frodokem_976_shake, OQS_KEM_alg_frodokem_1344_aes, OQS_KEM_alg_frodokem_1344_shake,
|
||||
OQS_KEM_alg_newhope_512_cca_kem, OQS_KEM_alg_newhope_1024_cca_kem,
|
||||
OQS_KEM_alg_kyber_512_cca_kem, OQS_KEM_alg_kyber_768_cca_kem, OQS_KEM_alg_kyber_1024_cca_kem,
|
||||
OQS_KEM_alg_sidh_p503, OQS_KEM_alg_sidh_p751,
|
||||
@ -95,9 +95,9 @@ OQS_API OQS_KEM *OQS_KEM_new(const char *method_name) {
|
||||
#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 if (0 == strcasecmp(method_name, OQS_KEM_alg_frodokem_640_shake)) {
|
||||
#ifdef OQS_ENABLE_KEM_frodokem_640_shake
|
||||
return OQS_KEM_frodokem_640_shake_new();
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
@ -107,9 +107,21 @@ OQS_API OQS_KEM *OQS_KEM_new(const char *method_name) {
|
||||
#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 if (0 == strcasecmp(method_name, OQS_KEM_alg_frodokem_976_shake)) {
|
||||
#ifdef OQS_ENABLE_KEM_frodokem_976_shake
|
||||
return OQS_KEM_frodokem_976_shake_new();
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
} else if (0 == strcasecmp(method_name, OQS_KEM_alg_frodokem_1344_aes)) {
|
||||
#ifdef OQS_ENABLE_KEM_frodokem_1344_aes
|
||||
return OQS_KEM_frodokem_1344_aes_new();
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
} else if (0 == strcasecmp(method_name, OQS_KEM_alg_frodokem_1344_shake)) {
|
||||
#ifdef OQS_ENABLE_KEM_frodokem_1344_shake
|
||||
return OQS_KEM_frodokem_1344_shake_new();
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
@ -47,12 +47,16 @@
|
||||
#define OQS_KEM_alg_bike3_l5 "BIKE3-L5"
|
||||
/** 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-640-SHAKE KEM. */
|
||||
#define OQS_KEM_alg_frodokem_640_shake "FrodoKEM-640-SHAKE"
|
||||
/** 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"
|
||||
/** Algorithm identifier for FrodoKEM-976-SHAKE KEM. */
|
||||
#define OQS_KEM_alg_frodokem_976_shake "FrodoKEM-976-SHAKE"
|
||||
/** Algorithm identifier for FrodoKEM-1344-AES KEM. */
|
||||
#define OQS_KEM_alg_frodokem_1344_aes "FrodoKEM-1344-AES"
|
||||
/** Algorithm identifier for FrodoKEM-1344-SHAKE KEM. */
|
||||
#define OQS_KEM_alg_frodokem_1344_shake "FrodoKEM-1344-SHAKE"
|
||||
/** Algorithm identifier for NewHope-512-CCA-KEM KEM. */
|
||||
#define OQS_KEM_alg_newhope_512_cca_kem "NewHope-512-CCA-KEM"
|
||||
/** Algorithm identifier for NewHope-1024-CCA-KEM KEM. */
|
||||
@ -73,7 +77,7 @@
|
||||
#define OQS_KEM_alg_sike_p751 "Sike-p751"
|
||||
// EDIT-WHEN-ADDING-KEM
|
||||
/** Number of algorithm identifiers above. */
|
||||
#define OQS_KEM_algs_length 23
|
||||
#define OQS_KEM_algs_length 25
|
||||
/** The default KEM. */
|
||||
#define OQS_KEM_DEFAULT OQS_KEM_alg_sike_p503
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user