mirror of
https://github.com/henrydcase/pqc.git
synced 2024-11-26 09:21:28 +00:00
Add FrodoKEM-976-SHAKE and FrodoKEM-1344-SHAKE (#83)
Add FrodoKEM-976-SHAKE and FrodoKEM-1344-SHAKE
This commit is contained in:
commit
27366d6559
24
crypto_kem/frodokem1344shake/META.yml
Normal file
24
crypto_kem/frodokem1344shake/META.yml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
name: FrodoKEM-1344-SHAKE
|
||||||
|
type: kem
|
||||||
|
claimed-nist-level: 5
|
||||||
|
length-public-key: 21520
|
||||||
|
length-ciphertext: 21632
|
||||||
|
length-shared-secret: 32
|
||||||
|
testvectors-sha256: 8b62fc01fc1e4b4e336776b09b37aaf55d161b7c815b3298f39d4444b011e10c
|
||||||
|
principal-submitter: Douglas Stebila, University of Waterloo
|
||||||
|
auxiliary-submitters:
|
||||||
|
- Erdem Alkim
|
||||||
|
- Joppe W. Bos, NXP Semiconductors
|
||||||
|
- Léo Ducas, CWI
|
||||||
|
- Patrick Longa, Microsoft Research
|
||||||
|
- Ilya Mironov, Google
|
||||||
|
- Michael Naehrig, Microsoft Research
|
||||||
|
- Valeria Nikolaenko
|
||||||
|
- Chris Peikert, University of Michigan
|
||||||
|
- Ananth Raghunathan, Google
|
||||||
|
- Karen Easterbrook, Microsoft Research
|
||||||
|
- Brian LaMacchia, Microsoft Research
|
||||||
|
implementations:
|
||||||
|
- name: clean
|
||||||
|
version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/437e228fca580a82435cab09f30ae14b03183119
|
||||||
|
length-secret-key: 43088
|
21
crypto_kem/frodokem1344shake/clean/LICENSE
Normal file
21
crypto_kem/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
|
19
crypto_kem/frodokem1344shake/clean/Makefile
Normal file
19
crypto_kem/frodokem1344shake/clean/Makefile
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# This Makefile can be used with GNU Make or BSD Make
|
||||||
|
|
||||||
|
LIB=libfrodokem1344shake_clean.a
|
||||||
|
HEADERS=api.h params.h common.h
|
||||||
|
OBJECTS=kem.o matrix_shake.o noise.o util.o
|
||||||
|
|
||||||
|
CFLAGS=-Wall -Wextra -Wpedantic -Werror -std=c99 -I../../../common $(EXTRAFLAGS)
|
||||||
|
|
||||||
|
all: $(LIB)
|
||||||
|
|
||||||
|
%.o: %.c $(HEADERS)
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(LIB): $(OBJECTS)
|
||||||
|
$(AR) -r $@ $(OBJECTS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(OBJECTS)
|
||||||
|
$(RM) $(LIB)
|
19
crypto_kem/frodokem1344shake/clean/Makefile.Microsoft_nmake
Normal file
19
crypto_kem/frodokem1344shake/clean/Makefile.Microsoft_nmake
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
|
||||||
|
# nmake /f Makefile.Microsoft_nmake
|
||||||
|
|
||||||
|
LIBRARY=libfrodokem1344shake_clean.lib
|
||||||
|
OBJECTS=kem.obj matrix_shake.obj noise.obj util.obj
|
||||||
|
|
||||||
|
CFLAGS=/nologo /I ..\..\..\common /W4 /WX
|
||||||
|
|
||||||
|
all: $(LIBRARY)
|
||||||
|
|
||||||
|
# Make sure objects are recompiled if headers change.
|
||||||
|
$(OBJECTS): *.h
|
||||||
|
|
||||||
|
$(LIBRARY): $(OBJECTS)
|
||||||
|
LIB.EXE /NOLOGO /WX /OUT:$@ $**
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-DEL $(OBJECTS)
|
||||||
|
-DEL $(LIBRARY)
|
20
crypto_kem/frodokem1344shake/clean/api.h
Normal file
20
crypto_kem/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
crypto_kem/frodokem1344shake/clean/common.h
Normal file
19
crypto_kem/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
crypto_kem/frodokem1344shake/clean/kem.c
Normal file
238
crypto_kem/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;
|
||||||
|
}
|
79
crypto_kem/frodokem1344shake/clean/matrix_shake.c
Normal file
79
crypto_kem/frodokem1344shake/clean/matrix_shake.c
Normal file
@ -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;
|
||||||
|
}
|
33
crypto_kem/frodokem1344shake/clean/noise.c
Normal file
33
crypto_kem/frodokem1344shake/clean/noise.c
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/********************************************************************************************
|
||||||
|
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||||
|
*
|
||||||
|
* Abstract: noise sampling functions
|
||||||
|
*********************************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "api.h"
|
||||||
|
#include "params.h"
|
||||||
|
|
||||||
|
static uint16_t CDF_TABLE[CDF_TABLE_LEN] = CDF_TABLE_DATA;
|
||||||
|
|
||||||
|
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_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;
|
||||||
|
}
|
||||||
|
}
|
27
crypto_kem/frodokem1344shake/clean/params.h
Normal file
27
crypto_kem/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
|
234
crypto_kem/frodokem1344shake/clean/util.c
Normal file
234
crypto_kem/frodokem1344shake/clean/util.c
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
/********************************************************************************************
|
||||||
|
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||||
|
*
|
||||||
|
* Abstract: additional functions for FrodoKEM
|
||||||
|
*********************************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "api.h"
|
||||||
|
#include "params.h"
|
||||||
|
|
||||||
|
#define min(x, y) (((x) < (y)) ? (x) : (y))
|
||||||
|
|
||||||
|
uint16_t PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(const uint16_t n) {
|
||||||
|
return (((uint8_t *) &(n))[0] | (((uint8_t *) &(n))[1] << 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t PQCLEAN_FRODOKEM1344SHAKE_CLEAN_UINT16_TO_LE(const 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, const size_t outlen, const uint16_t *in, const size_t inlen, const 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, const size_t outlen, const uint8_t *in, const size_t inlen, const 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;
|
||||||
|
}
|
||||||
|
}
|
@ -7,18 +7,18 @@ length-shared-secret: 16
|
|||||||
testvectors-sha256: 8f922de02d41005fcc3c4164b2ab74c4c7b588ed69e34e22607d1ae4ab13d2c5
|
testvectors-sha256: 8f922de02d41005fcc3c4164b2ab74c4c7b588ed69e34e22607d1ae4ab13d2c5
|
||||||
principal-submitter: Douglas Stebila, University of Waterloo
|
principal-submitter: Douglas Stebila, University of Waterloo
|
||||||
auxiliary-submitters:
|
auxiliary-submitters:
|
||||||
- Erdem Alkim
|
- Erdem Alkim
|
||||||
- Joppe W. Bos, NXP Semiconductors
|
- Joppe W. Bos, NXP Semiconductors
|
||||||
- Léo Ducas, CWI
|
- Léo Ducas, CWI
|
||||||
- Patrick Longa, Microsoft Research
|
- Patrick Longa, Microsoft Research
|
||||||
- Ilya Mironov, Google
|
- Ilya Mironov, Google
|
||||||
- Michael Naehrig, Microsoft Research
|
- Michael Naehrig, Microsoft Research
|
||||||
- Valeria Nikolaenko
|
- Valeria Nikolaenko
|
||||||
- Chris Peikert, University of Michigan
|
- Chris Peikert, University of Michigan
|
||||||
- Ananth Raghunathan, Google
|
- Ananth Raghunathan, Google
|
||||||
- Karen Easterbrook, Microsoft Research
|
- Karen Easterbrook, Microsoft Research
|
||||||
- Brian LaMacchia, Microsoft Research
|
- Brian LaMacchia, Microsoft Research
|
||||||
implementations:
|
implementations:
|
||||||
- name: clean
|
- name: clean
|
||||||
version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/437e228fca580a82435cab09f30ae14b03183119
|
version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/437e228fca580a82435cab09f30ae14b03183119
|
||||||
length-secret-key: 19888
|
length-secret-key: 19888
|
||||||
|
24
crypto_kem/frodokem976shake/META.yml
Normal file
24
crypto_kem/frodokem976shake/META.yml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
name: FrodoKEM-976-SHAKE
|
||||||
|
type: kem
|
||||||
|
claimed-nist-level: 3
|
||||||
|
length-public-key: 15632
|
||||||
|
length-ciphertext: 15744
|
||||||
|
length-shared-secret: 24
|
||||||
|
testvectors-sha256: 00707dc8158c6e51e70e9a7b23a87054c5f2167b77a2e5940b8e82519834717b
|
||||||
|
principal-submitter: Douglas Stebila, University of Waterloo
|
||||||
|
auxiliary-submitters:
|
||||||
|
- Erdem Alkim
|
||||||
|
- Joppe W. Bos, NXP Semiconductors
|
||||||
|
- Léo Ducas, CWI
|
||||||
|
- Patrick Longa, Microsoft Research
|
||||||
|
- Ilya Mironov, Google
|
||||||
|
- Michael Naehrig, Microsoft Research
|
||||||
|
- Valeria Nikolaenko
|
||||||
|
- Chris Peikert, University of Michigan
|
||||||
|
- Ananth Raghunathan, Google
|
||||||
|
- Karen Easterbrook, Microsoft Research
|
||||||
|
- Brian LaMacchia, Microsoft Research
|
||||||
|
implementations:
|
||||||
|
- name: clean
|
||||||
|
version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/437e228fca580a82435cab09f30ae14b03183119
|
||||||
|
length-secret-key: 31296
|
21
crypto_kem/frodokem976shake/clean/LICENSE
Normal file
21
crypto_kem/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
|
19
crypto_kem/frodokem976shake/clean/Makefile
Normal file
19
crypto_kem/frodokem976shake/clean/Makefile
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# This Makefile can be used with GNU Make or BSD Make
|
||||||
|
|
||||||
|
LIB=libfrodokem976shake_clean.a
|
||||||
|
HEADERS=api.h params.h common.h
|
||||||
|
OBJECTS=kem.o matrix_shake.o noise.o util.o
|
||||||
|
|
||||||
|
CFLAGS=-Wall -Wextra -Wpedantic -Werror -std=c99 -I../../../common $(EXTRAFLAGS)
|
||||||
|
|
||||||
|
all: $(LIB)
|
||||||
|
|
||||||
|
%.o: %.c $(HEADERS)
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(LIB): $(OBJECTS)
|
||||||
|
$(AR) -r $@ $(OBJECTS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(OBJECTS)
|
||||||
|
$(RM) $(LIB)
|
19
crypto_kem/frodokem976shake/clean/Makefile.Microsoft_nmake
Normal file
19
crypto_kem/frodokem976shake/clean/Makefile.Microsoft_nmake
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
|
||||||
|
# nmake /f Makefile.Microsoft_nmake
|
||||||
|
|
||||||
|
LIBRARY=libfrodokem976shake_clean.lib
|
||||||
|
OBJECTS=kem.obj matrix_shake.obj noise.obj util.obj
|
||||||
|
|
||||||
|
CFLAGS=/nologo /I ..\..\..\common /W4 /WX
|
||||||
|
|
||||||
|
all: $(LIBRARY)
|
||||||
|
|
||||||
|
# Make sure objects are recompiled if headers change.
|
||||||
|
$(OBJECTS): *.h
|
||||||
|
|
||||||
|
$(LIBRARY): $(OBJECTS)
|
||||||
|
LIB.EXE /NOLOGO /WX /OUT:$@ $**
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-DEL $(OBJECTS)
|
||||||
|
-DEL $(LIBRARY)
|
20
crypto_kem/frodokem976shake/clean/api.h
Normal file
20
crypto_kem/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
crypto_kem/frodokem976shake/clean/common.h
Normal file
19
crypto_kem/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
crypto_kem/frodokem976shake/clean/kem.c
Normal file
238
crypto_kem/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;
|
||||||
|
}
|
79
crypto_kem/frodokem976shake/clean/matrix_shake.c
Normal file
79
crypto_kem/frodokem976shake/clean/matrix_shake.c
Normal file
@ -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;
|
||||||
|
}
|
33
crypto_kem/frodokem976shake/clean/noise.c
Normal file
33
crypto_kem/frodokem976shake/clean/noise.c
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/********************************************************************************************
|
||||||
|
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||||
|
*
|
||||||
|
* Abstract: noise sampling functions
|
||||||
|
*********************************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "api.h"
|
||||||
|
#include "params.h"
|
||||||
|
|
||||||
|
static uint16_t CDF_TABLE[CDF_TABLE_LEN] = CDF_TABLE_DATA;
|
||||||
|
|
||||||
|
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_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;
|
||||||
|
}
|
||||||
|
}
|
27
crypto_kem/frodokem976shake/clean/params.h
Normal file
27
crypto_kem/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
|
234
crypto_kem/frodokem976shake/clean/util.c
Normal file
234
crypto_kem/frodokem976shake/clean/util.c
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
/********************************************************************************************
|
||||||
|
* FrodoKEM: Learning with Errors Key Encapsulation
|
||||||
|
*
|
||||||
|
* Abstract: additional functions for FrodoKEM
|
||||||
|
*********************************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "api.h"
|
||||||
|
#include "params.h"
|
||||||
|
|
||||||
|
#define min(x, y) (((x) < (y)) ? (x) : (y))
|
||||||
|
|
||||||
|
uint16_t PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(const uint16_t n) {
|
||||||
|
return (((uint8_t *) &(n))[0] | (((uint8_t *) &(n))[1] << 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t PQCLEAN_FRODOKEM976SHAKE_CLEAN_UINT16_TO_LE(const 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, const size_t outlen, const uint16_t *in, const size_t inlen, const 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, const size_t outlen, const uint8_t *in, const size_t inlen, const 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;
|
||||||
|
}
|
||||||
|
}
|
@ -41,13 +41,13 @@ $(DEST_DIR)\functest_$(SCHEME)_$(IMPLEMENTATION).exe: build-scheme $(COMMON_OBJE
|
|||||||
-MKDIR $(DEST_DIR)
|
-MKDIR $(DEST_DIR)
|
||||||
-DEL functest.obj
|
-DEL functest.obj
|
||||||
$(CC) /c crypto_$(TYPE)\functest.c $(CFLAGS) /I $(SCHEME_DIR) /DPQCLEAN_NAMESPACE=PQCLEAN_$(SCHEME_UPPERCASE)_$(IMPLEMENTATION_UPPERCASE)
|
$(CC) /c crypto_$(TYPE)\functest.c $(CFLAGS) /I $(SCHEME_DIR) /DPQCLEAN_NAMESPACE=PQCLEAN_$(SCHEME_UPPERCASE)_$(IMPLEMENTATION_UPPERCASE)
|
||||||
LINK.EXE /OUT:$@ functest.obj $(COMMON_OBJECTS_NOPATH) randombytes.obj $(SCHEME_DIR)\lib$(SCHEME)_$(IMPLEMENTATION).lib Advapi32.lib
|
LINK.EXE /STACK:8192000 /OUT:$@ functest.obj $(COMMON_OBJECTS_NOPATH) randombytes.obj $(SCHEME_DIR)\lib$(SCHEME)_$(IMPLEMENTATION).lib Advapi32.lib
|
||||||
|
|
||||||
$(DEST_DIR)\testvectors_$(SCHEME)_$(IMPLEMENTATION).exe: build-scheme $(COMMON_OBJECTS) $(COMMON_DIR)\notrandombytes.obj
|
$(DEST_DIR)\testvectors_$(SCHEME)_$(IMPLEMENTATION).exe: build-scheme $(COMMON_OBJECTS) $(COMMON_DIR)\notrandombytes.obj
|
||||||
-MKDIR $(DEST_DIR)
|
-MKDIR $(DEST_DIR)
|
||||||
-DEL testvectors.obj
|
-DEL testvectors.obj
|
||||||
$(CC) /c crypto_$(TYPE)\testvectors.c $(CFLAGS) /I $(SCHEME_DIR) /DPQCLEAN_NAMESPACE=PQCLEAN_$(SCHEME_UPPERCASE)_$(IMPLEMENTATION_UPPERCASE)
|
$(CC) /c crypto_$(TYPE)\testvectors.c $(CFLAGS) /I $(SCHEME_DIR) /DPQCLEAN_NAMESPACE=PQCLEAN_$(SCHEME_UPPERCASE)_$(IMPLEMENTATION_UPPERCASE)
|
||||||
LINK.EXE /OUT:$@ testvectors.obj $(COMMON_OBJECTS_NOPATH) notrandombytes.obj $(SCHEME_DIR)\lib$(SCHEME)_$(IMPLEMENTATION).lib
|
LINK.EXE /STACK:8192000 /OUT:$@ testvectors.obj $(COMMON_OBJECTS_NOPATH) notrandombytes.obj $(SCHEME_DIR)\lib$(SCHEME)_$(IMPLEMENTATION).lib
|
||||||
|
|
||||||
$(DEST_DIR)\printparams_$(SCHEME)_$(IMPLEMENTATION).exe: crypto_$(TYPE)\printparams.c $(SCHEME_DIR)\api.h
|
$(DEST_DIR)\printparams_$(SCHEME)_$(IMPLEMENTATION).exe: crypto_$(TYPE)\printparams.c $(SCHEME_DIR)\api.h
|
||||||
-MKDIR $(DEST_DIR)
|
-MKDIR $(DEST_DIR)
|
||||||
|
@ -161,7 +161,7 @@ static int test_invalid_sk_a(void) {
|
|||||||
|
|
||||||
if (!memcmp(key_a, key_b, CRYPTO_BYTES)) {
|
if (!memcmp(key_a, key_b, CRYPTO_BYTES)) {
|
||||||
printf("ERROR invalid sk_a\n");
|
printf("ERROR invalid sk_a\n");
|
||||||
return 1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +199,7 @@ static int test_invalid_ciphertext(void) {
|
|||||||
|
|
||||||
if (!memcmp(key_a, key_b, CRYPTO_BYTES)) {
|
if (!memcmp(key_a, key_b, CRYPTO_BYTES)) {
|
||||||
printf("ERROR invalid ciphertext\n");
|
printf("ERROR invalid ciphertext\n");
|
||||||
return 1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
9
test/duplicate_consistency/frodokem1344shake_clean.yml
Normal file
9
test/duplicate_consistency/frodokem1344shake_clean.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
source:
|
||||||
|
scheme: frodokem640shake
|
||||||
|
implementation: clean
|
||||||
|
files:
|
||||||
|
- common.h
|
||||||
|
- kem.c
|
||||||
|
- matrix_shake.c
|
||||||
|
- noise.c
|
||||||
|
- util.c
|
9
test/duplicate_consistency/frodokem976shake_clean.yml
Normal file
9
test/duplicate_consistency/frodokem976shake_clean.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
source:
|
||||||
|
scheme: frodokem640shake
|
||||||
|
implementation: clean
|
||||||
|
files:
|
||||||
|
- common.h
|
||||||
|
- kem.c
|
||||||
|
- matrix_shake.c
|
||||||
|
- noise.c
|
||||||
|
- util.c
|
@ -70,10 +70,18 @@ class Implementation:
|
|||||||
def __init__(self, scheme, name):
|
def __init__(self, scheme, name):
|
||||||
self.scheme = scheme
|
self.scheme = scheme
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
|
def metadata(self):
|
||||||
|
for i in self.scheme.metadata()['implementations']:
|
||||||
|
if i['name'] == self.name:
|
||||||
|
return i
|
||||||
|
|
||||||
def path(self, base='..') -> str:
|
def path(self, base='..') -> str:
|
||||||
return os.path.join(self.scheme.path(), self.name)
|
return os.path.join(self.scheme.path(), self.name)
|
||||||
|
|
||||||
|
def namespace_prefix(self):
|
||||||
|
return 'PQCLEAN_{}_{}_'.format(self.scheme.name.upper(), self.name.upper()).replace('-', '')
|
||||||
|
|
||||||
def libname(self) -> str:
|
def libname(self) -> str:
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
return "lib{}_{}.lib".format(self.scheme.name, self.name)
|
return "lib{}_{}.lib".format(self.scheme.name, self.name)
|
||||||
|
@ -11,6 +11,10 @@ import helpers
|
|||||||
|
|
||||||
|
|
||||||
def test_char():
|
def test_char():
|
||||||
|
if not(os.path.exists(os.path.join('pycparser', '.git'))):
|
||||||
|
helpers.run_subprocess(
|
||||||
|
['git', 'submodule', 'update', '--init']
|
||||||
|
)
|
||||||
for scheme in pqclean.Scheme.all_schemes():
|
for scheme in pqclean.Scheme.all_schemes():
|
||||||
for implementation in scheme.implementations:
|
for implementation in scheme.implementations:
|
||||||
yield check_char, implementation
|
yield check_char, implementation
|
||||||
|
42
test/test_duplicate_consistency.py
Normal file
42
test/test_duplicate_consistency.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
"""
|
||||||
|
Checks that files duplicated across schemes/implementations are consistent.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import pqclean
|
||||||
|
import helpers
|
||||||
|
import unittest
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
def test_duplicate_consistency():
|
||||||
|
for scheme in pqclean.Scheme.all_schemes():
|
||||||
|
for implementation in scheme.implementations:
|
||||||
|
if os.path.isfile(os.path.join('duplicate_consistency', '{}_{}.yml'.format(scheme.name, implementation.name))):
|
||||||
|
yield check_duplicate_consistency, implementation
|
||||||
|
|
||||||
|
def file_get_contents(filename):
|
||||||
|
with open(filename) as f:
|
||||||
|
return f.read()
|
||||||
|
|
||||||
|
def check_duplicate_consistency(implementation):
|
||||||
|
helpers.skip_windows()
|
||||||
|
metafile = os.path.join('duplicate_consistency', '{}_{}.yml'.format(implementation.scheme.name, implementation.name))
|
||||||
|
with open(metafile, encoding='utf-8') as f:
|
||||||
|
metadata = yaml.load(f.read())
|
||||||
|
source = pqclean.Implementation.by_name(metadata['source']['scheme'], metadata['source']['implementation'])
|
||||||
|
for file in metadata['files']:
|
||||||
|
transformed_src = helpers.run_subprocess(
|
||||||
|
['sed', '-e', 's/{}/{}/g'.format(source.namespace_prefix(), implementation.namespace_prefix()), os.path.join(source.path(), file)]
|
||||||
|
)
|
||||||
|
this_src = file_get_contents(os.path.join(implementation.path(), file))
|
||||||
|
print(os.path.join(implementation.path(), file))
|
||||||
|
print(this_src)
|
||||||
|
assert(transformed_src == this_src)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
import nose2
|
||||||
|
nose2.main()
|
||||||
|
except ImportError:
|
||||||
|
import nose
|
||||||
|
nose.runmodule()
|
@ -72,14 +72,15 @@ SIGNATURE_FIELDS = {
|
|||||||
|
|
||||||
def check_spec(metadata, spec):
|
def check_spec(metadata, spec):
|
||||||
for field, props in spec:
|
for field, props in spec:
|
||||||
if field not in metadata:
|
if field not in metadata and 'optional' not in props:
|
||||||
raise AssertionError("Field '{}' not present.".format(field))
|
raise AssertionError("Field '{}' not present.".format(field))
|
||||||
|
|
||||||
# validate element
|
# validate element
|
||||||
check_element(field, metadata[field], props)
|
if field in metadata:
|
||||||
|
check_element(field, metadata[field], props)
|
||||||
|
|
||||||
# delete it to detect extras
|
# delete it to detect extras
|
||||||
del metadata[field]
|
del metadata[field]
|
||||||
|
|
||||||
# Done checking all specified fields, check if we have extras
|
# Done checking all specified fields, check if we have extras
|
||||||
for field, value in metadata.items():
|
for field, value in metadata.items():
|
||||||
|
Loading…
Reference in New Issue
Block a user