Cleanup PQClean implementations (#803)

* Sync with PQClean commit 90630db2ebada4bacceb5331b0a1a9a356ba65b9

* Delete duplicate implementations due to underscore bug; add MQDSS AVX2

* Delete more duplicate PQClean implementations
This commit is contained in:
Douglas Stebila 2020-08-04 11:54:25 -04:00 committed by GitHub
parent a3f386da31
commit aa7f1dfa3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
341 changed files with 994 additions and 44343 deletions

View File

@ -87,11 +87,11 @@ if(ARCH STREQUAL "x86_64" AND CMAKE_SYSTEM_NAME MATCHES "Linux" AND OQS_USE_AVX2
cmake_dependent_option(OQS_ENABLE_KEM_kyber_512_avx2 "" ON "OQS_ENABLE_KEM_kyber_512" OFF)
endif()
cmake_dependent_option(OQS_ENABLE_KEM_kyber_768 "" ON "OQS_ENABLE_KEM_KYBER" OFF)
if(ARCH STREQUAL "x86_64" AND CMAKE_SYSTEM_NAME MATCHES "Linux" AND OQS_USE_AES_INSTRUCTIONS AND OQS_USE_AVX2_INSTRUCTIONS AND OQS_USE_BMI2_INSTRUCTIONS AND OQS_USE_POPCNT_INSTRUCTIONS)
if(ARCH STREQUAL "x86_64" AND CMAKE_SYSTEM_NAME MATCHES "Linux" AND OQS_USE_AVX2_INSTRUCTIONS AND OQS_USE_BMI2_INSTRUCTIONS AND OQS_USE_POPCNT_INSTRUCTIONS)
cmake_dependent_option(OQS_ENABLE_KEM_kyber_768_avx2 "" ON "OQS_ENABLE_KEM_kyber_768" OFF)
endif()
cmake_dependent_option(OQS_ENABLE_KEM_kyber_1024 "" ON "OQS_ENABLE_KEM_KYBER" OFF)
if(ARCH STREQUAL "x86_64" AND CMAKE_SYSTEM_NAME MATCHES "Linux" AND OQS_USE_AES_INSTRUCTIONS AND OQS_USE_AVX2_INSTRUCTIONS AND OQS_USE_BMI2_INSTRUCTIONS AND OQS_USE_POPCNT_INSTRUCTIONS)
if(ARCH STREQUAL "x86_64" AND CMAKE_SYSTEM_NAME MATCHES "Linux" AND OQS_USE_AVX2_INSTRUCTIONS AND OQS_USE_BMI2_INSTRUCTIONS AND OQS_USE_POPCNT_INSTRUCTIONS)
cmake_dependent_option(OQS_ENABLE_KEM_kyber_1024_avx2 "" ON "OQS_ENABLE_KEM_kyber_1024" OFF)
endif()
cmake_dependent_option(OQS_ENABLE_KEM_kyber_512_90s "" ON "OQS_ENABLE_KEM_KYBER" OFF)
@ -150,7 +150,13 @@ cmake_dependent_option(OQS_ENABLE_SIG_falcon_1024 "" ON "OQS_ENABLE_SIG_FALCON"
option(OQS_ENABLE_SIG_MQDSS "" ON)
cmake_dependent_option(OQS_ENABLE_SIG_mqdss_31_48 "" ON "OQS_ENABLE_SIG_MQDSS" OFF)
if(ARCH STREQUAL "x86_64" AND OQS_USE_AVX2_INSTRUCTIONS)
cmake_dependent_option(OQS_ENABLE_SIG_mqdss_31_48_avx2 "" ON "OQS_ENABLE_SIG_mqdss_31_48" OFF)
endif()
cmake_dependent_option(OQS_ENABLE_SIG_mqdss_31_64 "" ON "OQS_ENABLE_SIG_MQDSS" OFF)
if(ARCH STREQUAL "x86_64" AND OQS_USE_AVX2_INSTRUCTIONS)
cmake_dependent_option(OQS_ENABLE_SIG_mqdss_31_64_avx2 "" ON "OQS_ENABLE_SIG_mqdss_31_64" OFF)
endif()
option(OQS_ENABLE_SIG_RAINBOW "" ON)
cmake_dependent_option(OQS_ENABLE_SIG_rainbow_Ia_classic "" ON "OQS_ENABLE_SIG_RAINBOW" OFF)

View File

@ -11,7 +11,7 @@ Implementation
--------------
- **Source of implementation**: SUPERCOP-20191221, "vec" implementation
- **Implementation version**: https://github.com/PQClean/PQClean/commit/b50dbbf544726006b9a08947e387f8972cb37492
- **Implementation version**: https://github.com/PQClean/PQClean/commit/90630db2ebada4bacceb5331b0a1a9a356ba65b9
- **License**: Public domain
- **Constant-time**: Yes
- **Optimizations**: Portable C

View File

@ -11,7 +11,7 @@ Implementation
--------------
- **Source of implementation**: https://github.com/newhopecrypto
- **Implementation version**: https://github.com/PQClean/PQClean/commit/9023fef55861faccd82146cf599b9e46fb9606aa
- **Implementation version**: https://github.com/PQClean/PQClean/commit/90630db2ebada4bacceb5331b0a1a9a356ba65b9
- **License**: Public domain
- **Constant-time**: Yes
- **Optimizations**: Portable C

View File

@ -11,7 +11,7 @@ Implementation
--------------
- **Source of implementation**: NIST Round 2 submission
- **Implementation version**: https://github.com/PQClean/PQClean/commit/9023fef55861faccd82146cf599b9e46fb9606aa
- **Implementation version**: https://github.com/PQClean/PQClean/commit/90630db2ebada4bacceb5331b0a1a9a356ba65b9
- **License**: Public domain
- **Constant-time**: Yes
- **Optimizations**: Portable C

View File

@ -11,7 +11,7 @@ Implementation
--------------
- **Source of implementation**: https://github.com/KULeuven-COSIC/SABER
- **Implementation version**: https://github.com/PQClean/PQClean/commit/9023fef55861faccd82146cf599b9e46fb9606aa
- **Implementation version**: https://github.com/PQClean/PQClean/commit/90630db2ebada4bacceb5331b0a1a9a356ba65b9
- **License**: Public domain
- **Constant-time**: Yes
- **Optimizations**: Portable C

View File

@ -11,7 +11,7 @@ Implementation
--------------
- **Source of implementation**: https://sourceforge.net/projects/threebears/
- **Implementation version**: https://github.com/PQClean/PQClean/commit/9023fef55861faccd82146cf599b9e46fb9606aa
- **Implementation version**: https://github.com/PQClean/PQClean/commit/90630db2ebada4bacceb5331b0a1a9a356ba65b9
- **License**: MIT License
- **Constant-time**: Yes
- **Optimizations**: Portable C

View File

@ -11,7 +11,7 @@ Implementation
--------------
- **Source of implementation**: https://github.com/pq-crystals/dilithium
- **Implementation version**: https://github.com/PQClean/PQClean/commit/9023fef55861faccd82146cf599b9e46fb9606aa
- **Implementation version**: https://github.com/pq-crystals/dilithium/tree/497a98bc7efe48cb0d18fd20d6d9a4b5629406ef
- **License**: public domain
- **Constant-time**: Yes
- **Optimizations**: Portable C with AVX2, BMI1, and POPCNT instructions (if available at run-time)

View File

@ -11,7 +11,7 @@ Implementation
--------------
- **Source of implementation**: https://falcon-sign.info/impl/falcon.h.html
- **Implementation version**: https://github.com/PQClean/PQClean/commit/9023fef55861faccd82146cf599b9e46fb9606aa
- **Implementation version**: https://github.com/PQClean/PQClean/commit/90630db2ebada4bacceb5331b0a1a9a356ba65b9
- **License**: CC0 1.0 Universal
- **Constant-time**: Yes
- **Optimizations**: Portable C

View File

@ -11,7 +11,7 @@ Implementation
--------------
- **Source of implementation**: https://github.com/joostrijneveld/MQDSS
- **Implementation version**: https://github.com/PQClean/PQClean/commit/9023fef55861faccd82146cf599b9e46fb9606aa
- **Implementation version**: https://github.com/PQClean/PQClean/commit/90630db2ebada4bacceb5331b0a1a9a356ba65b9
- **License**: CC0 1.0 Universal
- **Constant-time**: Yes
- **Optimizations**: Portable C

View File

@ -10,7 +10,7 @@ Implementation
--------------
- **Source of implementation**: https://github.com/fast-crypto-lab/rainbow-submission-round2
- **Implementation version**: https://github.com/PQClean/PQClean/commit/9023fef55861faccd82146cf599b9e46fb9606aa
- **Implementation version**: https://github.com/PQClean/PQClean/commit/90630db2ebada4bacceb5331b0a1a9a356ba65b9
- **License**: CC0 1.0
- **Constant-time**: Yes
- **Optimizations**: Portable C

View File

@ -11,7 +11,7 @@ Implementation
--------------
- **Source of implementation**: https://github.com/sphincs/sphincsplus
- **Implementation version**: https://github.com/PQClean/PQClean/commit/9023fef55861faccd82146cf599b9e46fb9606aa
- **Implementation version**: https://github.com/PQClean/PQClean/commit/90630db2ebada4bacceb5331b0a1a9a356ba65b9
- **License**: CC0 1.0 Universal
- **Constant-time**: Yes
- **Optimizations**: Portable C with AESNI and AVX2 instructions (if available at run-time)

View File

@ -276,6 +276,6 @@ replacer('tests/kat_sig.c', instructions, '/////')
# Finally store KATS away again
for t in ["kem", "sig"]:
with open(os.path.join('tests', 'KATs', t, 'kats.json'), "w") as f:
json.dump(kats[t], f)
json.dump(kats[t], f, indent=2, sort_keys=True)

View File

@ -105,14 +105,10 @@ kems:
scheme: "512cca"
pqclean_scheme: newhope512cca
pretty_name_full: NewHope-512-CCA
implementation: clean
sources: ['cpapke.c', 'kem.c', 'ntt.c', 'poly.c', 'precomp.c', 'reduce.c', 'verify.c']
-
scheme: "1024cca"
pqclean_scheme: newhope1024cca
pretty_name_full: NewHope-1024-CCA
implementation: clean
sources: ['cpapke.c', 'kem.c', 'ntt.c', 'poly.c', 'precomp.c', 'reduce.c', 'verify.c']
-
name: ntru
default_implementation: clean
@ -121,26 +117,18 @@ kems:
scheme: hps2048509
pqclean_scheme: ntruhps2048509
pretty_name_full: NTRU-HPS-2048-509
implementation: clean
sources: ['crypto_sort.c', 'kem.c', 'owcpa.c', 'pack3.c', 'packq.c', 'poly.c', 'sample.c', 'verify.c']
-
scheme: hps2048677
pqclean_scheme: ntruhps2048677
pretty_name_full: NTRU-HPS-2048-677
implementation: clean
sources: ['crypto_sort.c', 'kem.c', 'owcpa.c', 'pack3.c', 'packq.c', 'poly.c', 'sample.c', 'verify.c']
-
scheme: hps4096821
pqclean_scheme: ntruhps4096821
pretty_name_full: NTRU-HPS-4096-821
implementation: clean
sources: ['crypto_sort.c', 'kem.c', 'owcpa.c', 'pack3.c', 'packq.c', 'poly.c', 'sample.c', 'verify.c']
-
scheme: hrss701
pqclean_scheme: ntruhrss701
pretty_name_full: NTRU-HRSS-701
implementation: clean
sources: ['kem.c', 'owcpa.c', 'pack3.c', 'packq.c', 'poly.c', 'sample.c', 'verify.c']
-
name: saber
default_implementation: clean
@ -149,20 +137,14 @@ kems:
scheme: lightsaber
pqclean_scheme: lightsaber
pretty_name_full: LightSaber-KEM
implementation: clean
sources: ['cbd.c', 'kem.c', 'pack_unpack.c', 'poly.c', 'poly_mul.c', 'SABER_indcpa.c', 'verify.c']
-
scheme: saber
pqclean_scheme: saber
pretty_name_full: Saber-KEM
implementation: clean
sources: ['cbd.c', 'kem.c', 'pack_unpack.c', 'poly.c', 'poly_mul.c', 'SABER_indcpa.c', 'verify.c']
-
scheme: firesaber
pqclean_scheme: firesaber
pretty_name_full: FireSaber-KEM
implementation: clean
sources: ['cbd.c', 'kem.c', 'pack_unpack.c', 'poly.c', 'poly_mul.c', 'SABER_indcpa.c', 'verify.c']
-
name: threebears
default_implementation: clean
@ -171,38 +153,26 @@ kems:
scheme: babybear
pqclean_scheme: babybear
pretty_name_full: BabyBear
implementation: clean
sources: ['kem.c', 'melas_fec.c', 'ring.c', 'threebears.c']
-
scheme: babybear_ephem
pqclean_scheme: babybear-ephem
pretty_name_full: BabyBearEphem
implementation: clean
sources: ['kem.c', 'melas_fec.c', 'ring.c', 'threebears.c']
-
scheme: mamabear
pqclean_scheme: mamabear
pretty_name_full: MamaBear
implementation: clean
sources: ['kem.c', 'melas_fec.c', 'ring.c', 'threebears.c']
-
scheme: mamabear_ephem
pqclean_scheme: mamabear-ephem
pretty_name_full: MamaBearEphem
implementation: clean
sources: ['kem.c', 'melas_fec.c', 'ring.c', 'threebears.c']
-
scheme: papabear
pqclean_scheme: papabear
pretty_name_full: PapaBear
implementation: clean
sources: ['kem.c', 'melas_fec.c', 'ring.c', 'threebears.c']
-
scheme: papabear_ephem
pqclean_scheme: papabear-ephem
pretty_name_full: PapaBearEphem
implementation: clean
sources: ['kem.c', 'melas_fec.c', 'ring.c', 'threebears.c']
sigs:
-
name: dilithium
@ -234,15 +204,11 @@ sigs:
scheme: "512"
pqclean_scheme: falcon-512
pretty_name_full: Falcon-512
implementation: clean
sources: ['codec.c', 'common.c', 'fft.c', 'fpr.c', 'keygen.c', 'pqclean.c', 'rng.c', 'sign.c', 'vrfy.c']
signed_msg_order: falcon
-
scheme: "1024"
pqclean_scheme: falcon-1024
pretty_name_full: Falcon-1024
implementation: clean
sources: ['codec.c', 'common.c', 'fft.c', 'fpr.c', 'keygen.c', 'pqclean.c', 'rng.c', 'sign.c', 'vrfy.c']
signed_msg_order: falcon
-
name: mqdss
@ -252,15 +218,11 @@ sigs:
scheme: "31_48"
pqclean_scheme: mqdss-48
pretty_name_full: MQDSS-31-48
implementation: clean
sources: ['gf31.c', 'mq.c', 'sign.c']
signed_msg_order: sig_then_msg
-
scheme: "31_64"
pqclean_scheme: mqdss-64
pretty_name_full: MQDSS-31-64
implementation: clean
sources: ['gf31.c', 'mq.c', 'sign.c']
signed_msg_order: sig_then_msg
-
name: rainbow
@ -270,64 +232,46 @@ sigs:
scheme: "Ia_classic"
pqclean_scheme: rainbowIa-classic
pretty_name_full: Rainbow-Ia-Classic
implementation: clean
sources: ['blas_comm.c', 'parallel_matrix_op.c', 'rainbow.c', 'rainbow_keypair.c', 'rainbow_keypair_computation.c', 'sign.c', 'utils_hash.c', 'utils_prng.c', 'blas.c', 'gf.c']
signed_msg_order: msg_then_sig
-
scheme: "Ia_cyclic"
pqclean_scheme: rainbowIa-cyclic
pretty_name_full: Rainbow-Ia-Cyclic
implementation: clean
sources: ['blas_comm.c', 'parallel_matrix_op.c', 'rainbow.c', 'rainbow_keypair.c', 'rainbow_keypair_computation.c', 'sign.c', 'utils_hash.c', 'utils_prng.c', 'blas.c', 'gf.c']
signed_msg_order: msg_then_sig
-
scheme: "Ia_cyclic_compressed"
pqclean_scheme: rainbowIa-cyclic-compressed
pretty_name_full: Rainbow-Ia-Cyclic-Compressed
implementation: clean
sources: ['blas_comm.c', 'parallel_matrix_op.c', 'rainbow.c', 'rainbow_keypair.c', 'rainbow_keypair_computation.c', 'sign.c', 'utils_hash.c', 'utils_prng.c', 'blas.c', 'gf.c']
signed_msg_order: msg_then_sig
-
scheme: "IIIc_classic"
pqclean_scheme: rainbowIIIc-classic
pretty_name_full: Rainbow-IIIc-Classic
implementation: clean
sources: ['blas_comm.c', 'parallel_matrix_op.c', 'rainbow.c', 'rainbow_keypair.c', 'rainbow_keypair_computation.c', 'sign.c', 'utils_hash.c', 'utils_prng.c', 'blas.c', 'gf.c']
signed_msg_order: msg_then_sig
-
scheme: "IIIc_cyclic"
pqclean_scheme: rainbowIIIc-cyclic
pretty_name_full: Rainbow-IIIc-Cyclic
implementation: clean
sources: ['blas_comm.c', 'parallel_matrix_op.c', 'rainbow.c', 'rainbow_keypair.c', 'rainbow_keypair_computation.c', 'sign.c', 'utils_hash.c', 'utils_prng.c', 'blas.c', 'gf.c']
signed_msg_order: msg_then_sig
-
scheme: "IIIc_cyclic_compressed"
pqclean_scheme: rainbowIIIc-cyclic-compressed
pretty_name_full: Rainbow-IIIc-Cyclic-Compressed
implementation: clean
sources: ['blas_comm.c', 'parallel_matrix_op.c', 'rainbow.c', 'rainbow_keypair.c', 'rainbow_keypair_computation.c', 'sign.c', 'utils_hash.c', 'utils_prng.c', 'blas.c', 'gf.c']
signed_msg_order: msg_then_sig
-
scheme: "Vc_classic"
pqclean_scheme: rainbowVc-classic
pretty_name_full: Rainbow-Vc-Classic
implementation: clean
sources: ['blas_comm.c', 'parallel_matrix_op.c', 'rainbow.c', 'rainbow_keypair.c', 'rainbow_keypair_computation.c', 'sign.c', 'utils_hash.c', 'utils_prng.c', 'blas.c', 'gf.c']
signed_msg_order: msg_then_sig
-
scheme: "Vc_cyclic"
pqclean_scheme: rainbowVc-cyclic
pretty_name_full: Rainbow-Vc-Cyclic
implementation: clean
sources: ['blas_comm.c', 'parallel_matrix_op.c', 'rainbow.c', 'rainbow_keypair.c', 'rainbow_keypair_computation.c', 'sign.c', 'utils_hash.c', 'utils_prng.c', 'blas.c', 'gf.c']
signed_msg_order: msg_then_sig
-
scheme: "Vc_cyclic_compressed"
pqclean_scheme: rainbowVc-cyclic-compressed
pretty_name_full: Rainbow-Vc-Cyclic-Compressed
implementation: clean
sources: ['blas_comm.c', 'parallel_matrix_op.c', 'rainbow.c', 'rainbow_keypair.c', 'rainbow_keypair_computation.c', 'sign.c', 'utils_hash.c', 'utils_prng.c', 'blas.c', 'gf.c']
signed_msg_order: msg_then_sig
-
name: sphincs

View File

@ -13,4 +13,4 @@ for filename in os.listdir("."):
print("added %s with KATSHA %s" % (alg, d[alg]))
with open("kats.json", "w") as f:
json.dump(d, f)
json.dumps(d, f, indent=2, sort_keys=True)

View File

@ -1,16 +0,0 @@
Public Domain.
Authors of Classic McEliece in alphabetical order:
Daniel J. Bernstein, University of Illinois at Chicago
Tung Chou, Osaka University
Tanja Lange, Technische Universiteit Eindhoven
Ingo von Maurich, self
Rafael Misoczki, Intel Corporation
Ruben Niederhagen, Fraunhofer SIT
Edoardo Persichetti, Florida Atlantic University
Christiane Peters, self
Peter Schwabe, Radboud University
Nicolas Sendrier, Inria
Jakub Szefer, Yale University
Wen Wang, Yale University

View File

@ -1,13 +0,0 @@
#include "aes256ctr.h"
void PQCLEAN_MCELIECE348864_CLEAN_aes256ctr(
uint8_t *out,
size_t outlen,
const uint8_t nonce[AESCTR_NONCEBYTES],
const uint8_t key[AES256_KEYBYTES]) {
aes256ctx state;
aes256_keyexp(&state, key);
aes256_ctr(out, outlen, nonce, &state);
aes256_ctx_release(&state);
}

View File

@ -1,17 +0,0 @@
#ifndef PQCLEAN_MCELIECE348864_CLEAN_AES256CTR_H
#define PQCLEAN_MCELIECE348864_CLEAN_AES256CTR_H
#include <stddef.h>
#include <stdint.h>
#include "aes.h"
void PQCLEAN_MCELIECE348864_CLEAN_aes256ctr(
uint8_t *out,
size_t outlen,
const uint8_t nonce[AESCTR_NONCEBYTES],
const uint8_t key[AES256_KEYBYTES]
);
#endif

View File

@ -1,32 +0,0 @@
#ifndef PQCLEAN_MCELIECE348864_CLEAN_API_H
#define PQCLEAN_MCELIECE348864_CLEAN_API_H
#include <stdint.h>
#define PQCLEAN_MCELIECE348864_CLEAN_CRYPTO_ALGNAME "Classic McEliece 348864"
#define PQCLEAN_MCELIECE348864_CLEAN_CRYPTO_PUBLICKEYBYTES 261120
#define PQCLEAN_MCELIECE348864_CLEAN_CRYPTO_SECRETKEYBYTES 6452
#define PQCLEAN_MCELIECE348864_CLEAN_CRYPTO_CIPHERTEXTBYTES 128
#define PQCLEAN_MCELIECE348864_CLEAN_CRYPTO_BYTES 32
int PQCLEAN_MCELIECE348864_CLEAN_crypto_kem_enc(
uint8_t *c,
uint8_t *key,
const uint8_t *pk
);
int PQCLEAN_MCELIECE348864_CLEAN_crypto_kem_dec(
uint8_t *key,
const uint8_t *c,
const uint8_t *sk
);
int PQCLEAN_MCELIECE348864_CLEAN_crypto_kem_keypair
(
uint8_t *pk,
uint8_t *sk
);
#endif

View File

@ -1,139 +0,0 @@
/*
This file is for Benes network related functions
*/
#include "benes.h"
#include "params.h"
#include "transpose.h"
#include "util.h"
/* one layer of the benes network */
static void layer(uint64_t *data, uint64_t *bits, int lgs) {
int i, j, s;
uint64_t d;
s = 1 << lgs;
for (i = 0; i < 64; i += s * 2) {
for (j = i; j < i + s; j++) {
d = (data[j + 0] ^ data[j + s]);
d &= (*bits++);
data[j + 0] ^= d;
data[j + s] ^= d;
}
}
}
/* input: r, sequence of bits to be permuted */
/* bits, condition bits of the Benes network */
/* rev, 0 for normal application; !0 for inverse */
/* output: r, permuted bits */
void PQCLEAN_MCELIECE348864_CLEAN_apply_benes(unsigned char *r, const unsigned char *bits, int rev) {
int i;
const unsigned char *cond_ptr;
int inc, low;
uint64_t bs[64];
uint64_t cond[64];
//
for (i = 0; i < 64; i++) {
bs[i] = PQCLEAN_MCELIECE348864_CLEAN_load8(r + i * 8);
}
if (rev == 0) {
inc = 256;
cond_ptr = bits;
} else {
inc = -256;
cond_ptr = bits + (2 * GFBITS - 2) * 256;
}
//
PQCLEAN_MCELIECE348864_CLEAN_transpose_64x64(bs, bs);
for (low = 0; low <= 5; low++) {
for (i = 0; i < 64; i++) {
cond[i] = PQCLEAN_MCELIECE348864_CLEAN_load4(cond_ptr + i * 4);
}
PQCLEAN_MCELIECE348864_CLEAN_transpose_64x64(cond, cond);
layer(bs, cond, low);
cond_ptr += inc;
}
PQCLEAN_MCELIECE348864_CLEAN_transpose_64x64(bs, bs);
for (low = 0; low <= 5; low++) {
for (i = 0; i < 32; i++) {
cond[i] = PQCLEAN_MCELIECE348864_CLEAN_load8(cond_ptr + i * 8);
}
layer(bs, cond, low);
cond_ptr += inc;
}
for (low = 4; low >= 0; low--) {
for (i = 0; i < 32; i++) {
cond[i] = PQCLEAN_MCELIECE348864_CLEAN_load8(cond_ptr + i * 8);
}
layer(bs, cond, low);
cond_ptr += inc;
}
PQCLEAN_MCELIECE348864_CLEAN_transpose_64x64(bs, bs);
for (low = 5; low >= 0; low--) {
for (i = 0; i < 64; i++) {
cond[i] = PQCLEAN_MCELIECE348864_CLEAN_load4(cond_ptr + i * 4);
}
PQCLEAN_MCELIECE348864_CLEAN_transpose_64x64(cond, cond);
layer(bs, cond, low);
cond_ptr += inc;
}
PQCLEAN_MCELIECE348864_CLEAN_transpose_64x64(bs, bs);
for (i = 0; i < 64; i++) {
PQCLEAN_MCELIECE348864_CLEAN_store8(r + i * 8, bs[i]);
}
}
/* input: condition bits c */
/* output: support s */
void PQCLEAN_MCELIECE348864_CLEAN_support_gen(gf *s, const unsigned char *c) {
gf a;
int i, j;
unsigned char L[ GFBITS ][ (1 << GFBITS) / 8 ];
for (i = 0; i < GFBITS; i++) {
for (j = 0; j < (1 << GFBITS) / 8; j++) {
L[i][j] = 0;
}
}
for (i = 0; i < (1 << GFBITS); i++) {
a = PQCLEAN_MCELIECE348864_CLEAN_bitrev((gf) i);
for (j = 0; j < GFBITS; j++) {
L[j][ i / 8 ] |= ((a >> j) & 1) << (i % 8);
}
}
for (j = 0; j < GFBITS; j++) {
PQCLEAN_MCELIECE348864_CLEAN_apply_benes(L[j], c, 0);
}
for (i = 0; i < SYS_N; i++) {
s[i] = 0;
for (j = GFBITS - 1; j >= 0; j--) {
s[i] <<= 1;
s[i] |= (L[j][i / 8] >> (i % 8)) & 1;
}
}
}

View File

@ -1,14 +0,0 @@
#ifndef PQCLEAN_MCELIECE348864_CLEAN_BENES_H
#define PQCLEAN_MCELIECE348864_CLEAN_BENES_H
/*
This file is for Benes network related functions
*/
#include "gf.h"
void PQCLEAN_MCELIECE348864_CLEAN_apply_benes(unsigned char * /*r*/, const unsigned char * /*bits*/, int /*rev*/);
void PQCLEAN_MCELIECE348864_CLEAN_support_gen(gf * /*s*/, const unsigned char * /*c*/);
#endif

View File

@ -1,83 +0,0 @@
/*
This file is for the Berlekamp-Massey algorithm
see http://crypto.stanford.edu/~mironov/cs359/massey.pdf
*/
#include "bm.h"
#include "params.h"
#define min(a, b) (((a) < (b)) ? (a) : (b))
/* the Berlekamp-Massey algorithm */
/* input: s, sequence of field elements */
/* output: out, minimal polynomial of s */
void PQCLEAN_MCELIECE348864_CLEAN_bm(gf *out, gf *s) {
int i;
uint16_t N = 0;
uint16_t L = 0;
uint16_t mle;
uint16_t mne;
gf T[ SYS_T + 1 ];
gf C[ SYS_T + 1 ];
gf B[ SYS_T + 1 ];
gf b = 1, d, f;
//
for (i = 0; i < SYS_T + 1; i++) {
C[i] = B[i] = 0;
}
B[1] = C[0] = 1;
//
for (N = 0; N < 2 * SYS_T; N++) {
d = 0;
for (i = 0; i <= min(N, SYS_T); i++) {
d ^= PQCLEAN_MCELIECE348864_CLEAN_gf_mul(C[i], s[ N - i]);
}
mne = d;
mne -= 1;
mne >>= 15;
mne -= 1;
mle = N;
mle -= 2 * L;
mle >>= 15;
mle -= 1;
mle &= mne;
for (i = 0; i <= SYS_T; i++) {
T[i] = C[i];
}
f = PQCLEAN_MCELIECE348864_CLEAN_gf_frac(b, d);
for (i = 0; i <= SYS_T; i++) {
C[i] ^= PQCLEAN_MCELIECE348864_CLEAN_gf_mul(f, B[i]) & mne;
}
L = (L & ~mle) | ((N + 1 - L) & mle);
for (i = 0; i <= SYS_T; i++) {
B[i] = (B[i] & ~mle) | (T[i] & mle);
}
b = (b & ~mle) | (d & mle);
for (i = SYS_T; i >= 1; i--) {
B[i] = B[i - 1];
}
B[0] = 0;
}
for (i = 0; i <= SYS_T; i++) {
out[i] = C[ SYS_T - i ];
}
}

View File

@ -1,13 +0,0 @@
#ifndef PQCLEAN_MCELIECE348864_CLEAN_BM_H
#define PQCLEAN_MCELIECE348864_CLEAN_BM_H
/*
This file is for the Berlekamp-Massey algorithm
see http://crypto.stanford.edu/~mironov/cs359/massey.pdf
*/
#include "gf.h"
void PQCLEAN_MCELIECE348864_CLEAN_bm(gf * /*out*/, gf * /*s*/);
#endif

View File

@ -1,274 +0,0 @@
/*
This file is for functions required for generating the control bits of the Benes network w.r.t. a random permutation
see the Lev-Pippenger-Valiant paper https://www.computer.org/csdl/trans/tc/1981/02/06312171.pdf
*/
#include "controlbits.h"
#include "params.h"
#include <stdint.h>
typedef uint8_t bit;
#define N (1 << GFBITS)
static bit is_smaller(uint32_t a, uint32_t b) {
uint32_t ret = 0;
ret = a - b;
ret >>= 31;
return (bit)ret;
}
static bit is_smaller_63b(uint64_t a, uint64_t b) {
uint64_t ret = 0;
ret = a - b;
ret >>= 63;
return (bit)ret;
}
static void cswap(uint32_t *x, uint32_t *y, bit swap) {
uint32_t m;
uint32_t d;
m = swap;
m = 0 - m;
d = (*x ^ *y);
d &= m;
*x ^= d;
*y ^= d;
}
static void cswap_63b(uint64_t *x, uint64_t *y, bit swap) {
uint64_t m;
uint64_t d;
m = swap;
m = 0 - m;
d = (*x ^ *y);
d &= m;
*x ^= d;
*y ^= d;
}
/* output x = min(input x,input y) */
/* output y = max(input x,input y) */
static void minmax(uint32_t *x, uint32_t *y) {
bit m;
m = is_smaller(*y, *x);
cswap(x, y, m);
}
static void minmax_63b(uint64_t *x, uint64_t *y) {
bit m;
m = is_smaller_63b(*y, *x);
cswap_63b(x, y, m);
}
/* merge first half of x[0],x[step],...,x[(2*n-1)*step] with second half */
/* requires n to be a power of 2 */
static void merge(int n, uint32_t *x, int step) {
int i;
if (n == 1) {
minmax(&x[0], &x[step]);
} else {
merge(n / 2, x, step * 2);
merge(n / 2, x + step, step * 2);
for (i = 1; i < 2 * n - 1; i += 2) {
minmax(&x[i * step], &x[(i + 1) * step]);
}
}
}
static void merge_63b(int n, uint64_t *x, int step) {
int i;
if (n == 1) {
minmax_63b(&x[0], &x[step]);
} else {
merge_63b(n / 2, x, step * 2);
merge_63b(n / 2, x + step, step * 2);
for (i = 1; i < 2 * n - 1; i += 2) {
minmax_63b(&x[i * step], &x[(i + 1) * step]);
}
}
}
/* sort x[0],x[1],...,x[n-1] in place */
/* requires n to be a power of 2 */
static void sort(int n, uint32_t *x) {
if (n <= 1) {
return;
}
sort(n / 2, x);
sort(n / 2, x + n / 2);
merge(n / 2, x, 1);
}
void PQCLEAN_MCELIECE348864_CLEAN_sort_63b(int n, uint64_t *x) {
if (n <= 1) {
return;
}
PQCLEAN_MCELIECE348864_CLEAN_sort_63b(n / 2, x);
PQCLEAN_MCELIECE348864_CLEAN_sort_63b(n / 2, x + n / 2);
merge_63b(n / 2, x, 1);
}
/* y[pi[i]] = x[i] */
/* requires n = 2^w */
/* requires pi to be a permutation */
static void composeinv(int n, uint32_t *y, const uint32_t *x, const uint32_t *pi) { // NC
int i;
uint32_t t[2 * N];
for (i = 0; i < n; ++i) {
t[i] = x[i] | (pi[i] << 16);
}
sort(n, t);
for (i = 0; i < n; ++i) {
y[i] = t[i] & 0xFFFF;
}
}
/* ip[i] = j iff pi[i] = j */
/* requires n = 2^w */
/* requires pi to be a permutation */
static void invert(int n, uint32_t *ip, const uint32_t *pi) {
int i;
for (i = 0; i < n; i++) {
ip[i] = i;
}
composeinv(n, ip, ip, pi);
}
static void flow(int w, uint32_t *x, const uint32_t *y, int t) {
bit m0;
bit m1;
uint32_t b;
uint32_t y_copy = *y;
m0 = is_smaller(*y & ((1 << w) - 1), *x & ((1 << w) - 1));
m1 = is_smaller(0, t);
cswap(x, &y_copy, m0);
b = m0 & m1;
*x ^= b << w;
}
/* input: permutation pi */
/* output: (2w-1)n/2 (or 0 if n==1) control bits c[0],c[step],c[2*step],... */
/* requires n = 2^w */
static void controlbitsfrompermutation(int w, int n, int step, int off, unsigned char *c, const uint32_t *pi) {
int i;
int j;
int k;
int t;
uint32_t ip[N] = {0};
uint32_t I[2 * N] = {0};
uint32_t P[2 * N] = {0};
uint32_t PI[2 * N] = {0};
uint32_t T[2 * N] = {0};
uint32_t piflip[N] = {0};
uint32_t subpi[2][N / 2] = {{0}};
if (w == 1) {
c[ off / 8 ] |= (pi[0] & 1) << (off % 8);
}
if (w <= 1) {
return;
}
invert(n, ip, pi);
for (i = 0; i < n; ++i) {
I[i] = ip[i] | (1 << w);
I[n + i] = pi[i];
}
for (i = 0; i < 2 * n; ++i) {
P[i] = (i >> w) + (i & ((1 << w) - 2)) + ((i & 1) << w);
}
for (t = 0; t < w; ++t) {
composeinv(2 * n, PI, P, I);
for (i = 0; i < 2 * n; ++i) {
flow(w, &P[i], &PI[i], t);
}
for (i = 0; i < 2 * n; ++i) {
T[i] = I[i ^ 1];
}
composeinv(2 * n, I, I, T);
for (i = 0; i < 2 * n; ++i) {
T[i] = P[i ^ 1];
}
for (i = 0; i < 2 * n; ++i) {
flow(w, &P[i], &T[i], 1);
}
}
for (i = 0; i < n; ++i) {
for (j = 0; j < w; ++j) {
piflip[i] = pi[i];
}
}
for (i = 0; i < n / 2; ++i) {
c[ (off + i * step) / 8 ] |= ((P[i * 2] >> w) & 1) << ((off + i * step) % 8);
}
for (i = 0; i < n / 2; ++i) {
c[ (off + ((w - 1)*n + i) * step) / 8 ] |= ((P[n + i * 2] >> w) & 1) << ((off + ((w - 1) * n + i) * step) % 8);
}
for (i = 0; i < n / 2; ++i) {
cswap(&piflip[i * 2], &piflip[i * 2 + 1], (P[n + i * 2] >> w) & 1);
}
for (k = 0; k < 2; ++k) {
for (i = 0; i < n / 2; ++i) {
subpi[k][i] = piflip[i * 2 + k] >> 1;
}
}
for (k = 0; k < 2; ++k) {
controlbitsfrompermutation(w - 1, n / 2, step * 2, off + step * (n / 2 + k), c, subpi[k]);
}
}
/* input: pi, a permutation*/
/* output: out, control bits w.r.t. pi */
void PQCLEAN_MCELIECE348864_CLEAN_controlbits(unsigned char *out, const uint32_t *pi) {
unsigned int i;
unsigned char c[ (2 * GFBITS - 1) * (1 << GFBITS) / 16 ];
for (i = 0; i < sizeof(c); i++) {
c[i] = 0;
}
controlbitsfrompermutation(GFBITS, (1 << GFBITS), 1, 0, c, pi);
for (i = 0; i < sizeof(c); i++) {
out[i] = c[i];
}
}

View File

@ -1,15 +0,0 @@
#ifndef PQCLEAN_MCELIECE348864_CLEAN_CONTROLBITS_H
#define PQCLEAN_MCELIECE348864_CLEAN_CONTROLBITS_H
/*
This file is for functions required for generating the control bits of the Benes network w.r.t. a random permutation
see the Lev-Pippenger-Valiant paper https://www.computer.org/csdl/trans/tc/1981/02/06312171.pdf
*/
#include <stdint.h>
void PQCLEAN_MCELIECE348864_CLEAN_sort_63b(int n, uint64_t *x);
void PQCLEAN_MCELIECE348864_CLEAN_controlbits(unsigned char *out, const uint32_t *pi);
#endif

View File

@ -1,7 +0,0 @@
#ifndef PQCLEAN_MCELIECE348864_CLEAN_CRYPTO_HASH_H
#define PQCLEAN_MCELIECE348864_CLEAN_CRYPTO_HASH_H
#include "fips202.h"
#define crypto_hash_32b(out,in,inlen) shake256(out, 32, in, inlen)
#endif

View File

@ -1,90 +0,0 @@
/*
This file is for Niederreiter decryption
*/
#include "decrypt.h"
#include "benes.h"
#include "bm.h"
#include "gf.h"
#include "params.h"
#include "root.h"
#include "synd.h"
#include "util.h"
/* Niederreiter decryption with the Berlekamp decoder */
/* intput: sk, secret key */
/* c, ciphertext */
/* output: e, error vector */
/* return: 0 for success; 1 for failure */
int PQCLEAN_MCELIECE348864_CLEAN_decrypt(unsigned char *e, const unsigned char *sk, const unsigned char *c) {
int i, w = 0;
uint16_t check;
unsigned char r[ SYS_N / 8 ];
gf g[ SYS_T + 1 ];
gf L[ SYS_N ];
gf s[ SYS_T * 2 ];
gf s_cmp[ SYS_T * 2 ];
gf locator[ SYS_T + 1 ];
gf images[ SYS_N ];
gf t;
//
for (i = 0; i < SYND_BYTES; i++) {
r[i] = c[i];
}
for (i = SYND_BYTES; i < SYS_N / 8; i++) {
r[i] = 0;
}
for (i = 0; i < SYS_T; i++) {
g[i] = PQCLEAN_MCELIECE348864_CLEAN_load2(sk);
g[i] &= GFMASK;
sk += 2;
}
g[ SYS_T ] = 1;
PQCLEAN_MCELIECE348864_CLEAN_support_gen(L, sk);
PQCLEAN_MCELIECE348864_CLEAN_synd(s, g, L, r);
PQCLEAN_MCELIECE348864_CLEAN_bm(locator, s);
PQCLEAN_MCELIECE348864_CLEAN_root(images, locator, L);
//
for (i = 0; i < SYS_N / 8; i++) {
e[i] = 0;
}
for (i = 0; i < SYS_N; i++) {
t = PQCLEAN_MCELIECE348864_CLEAN_gf_iszero(images[i]) & 1;
e[ i / 8 ] |= t << (i % 8);
w += t;
}
PQCLEAN_MCELIECE348864_CLEAN_synd(s_cmp, g, L, e);
//
check = (uint16_t)w;
check ^= SYS_T;
for (i = 0; i < SYS_T * 2; i++) {
check |= s[i] ^ s_cmp[i];
}
check -= 1;
check >>= 15;
return check ^ 1;
}

View File

@ -1,10 +0,0 @@
#ifndef PQCLEAN_MCELIECE348864_CLEAN_DECRYPT_H
#define PQCLEAN_MCELIECE348864_CLEAN_DECRYPT_H
/*
This file is for Nieddereiter decryption
*/
int PQCLEAN_MCELIECE348864_CLEAN_decrypt(unsigned char * /*e*/, const unsigned char * /*sk*/, const unsigned char * /*c*/);
#endif

View File

@ -1,138 +0,0 @@
/*
This file is for Niederreiter encryption
*/
#include "encrypt.h"
#include "params.h"
#include "randombytes.h"
#include "util.h"
#include <stdint.h>
#include <string.h>
#include "gf.h"
static inline uint8_t same_mask(uint16_t x, uint16_t y) {
uint32_t mask;
mask = x ^ y;
mask -= 1;
mask >>= 31;
mask = -mask;
return (uint8_t)mask;
}
/* output: e, an error vector of weight t */
static void gen_e(unsigned char *e) {
size_t i, j;
int eq, count;
uint16_t ind_[ SYS_T * 2 ];
uint8_t *ind_8 = (uint8_t *)ind_;
uint16_t ind[ SYS_T * 2 ];
uint8_t mask;
unsigned char val[ SYS_T ];
while (1) {
randombytes(ind_8, sizeof(ind_));
// Copy to uint16_t ind_ in a little-endian way
for (i = 0; i < sizeof(ind_); i += 2) {
ind_[i / 2] = ((uint16_t)ind_8[i + 1]) << 8 | (uint16_t)ind_8[i];
}
for (i = 0; i < SYS_T * 2; i++) {
ind_[i] &= GFMASK;
}
// moving and counting indices in the correct range
count = 0;
for (i = 0; i < SYS_T * 2; i++) {
if (ind_[i] < SYS_N) {
ind[ count++ ] = ind_[i];
}
}
if (count < SYS_T) {
continue;
}
// check for repetition
eq = 0;
for (i = 1; i < SYS_T; i++) {
for (j = 0; j < i; j++) {
if (ind[i] == ind[j]) {
eq = 1;
}
}
}
if (eq == 0) {
break;
}
}
for (j = 0; j < SYS_T; j++) {
val[j] = 1 << (ind[j] & 7);
}
for (i = 0; i < SYS_N / 8; i++) {
e[i] = 0;
for (j = 0; j < SYS_T; j++) {
mask = same_mask((uint16_t)i, (ind[j] >> 3));
e[i] |= val[j] & mask;
}
}
}
/* input: public key pk, error vector e */
/* output: syndrome s */
static void syndrome(unsigned char *s, const unsigned char *pk, const unsigned char *e) {
unsigned char b, row[SYS_N / 8];
const unsigned char *pk_ptr = pk;
int i, j;
for (i = 0; i < SYND_BYTES; i++) {
s[i] = 0;
}
for (i = 0; i < PK_NROWS; i++) {
for (j = 0; j < SYS_N / 8; j++) {
row[j] = 0;
}
for (j = 0; j < PK_ROW_BYTES; j++) {
row[ SYS_N / 8 - PK_ROW_BYTES + j ] = pk_ptr[j];
}
row[i / 8] |= 1 << (i % 8);
b = 0;
for (j = 0; j < SYS_N / 8; j++) {
b ^= row[j] & e[j];
}
b ^= b >> 4;
b ^= b >> 2;
b ^= b >> 1;
b &= 1;
s[ i / 8 ] |= (b << (i % 8));
pk_ptr += PK_ROW_BYTES;
}
}
void PQCLEAN_MCELIECE348864_CLEAN_encrypt(unsigned char *s, unsigned char *e, const unsigned char *pk) {
gen_e(e);
syndrome(s, pk, e);
}

View File

@ -1,11 +0,0 @@
#ifndef PQCLEAN_MCELIECE348864_CLEAN_ENCRYPT_H
#define PQCLEAN_MCELIECE348864_CLEAN_ENCRYPT_H
/*
This file is for Niederreiter encryption
*/
void PQCLEAN_MCELIECE348864_CLEAN_encrypt(unsigned char * /*s*/, unsigned char * /*e*/, const unsigned char * /*pk*/);
#endif

View File

@ -1,139 +0,0 @@
/*
This file is for functions for field arithmetic
*/
#include "gf.h"
#include "params.h"
gf PQCLEAN_MCELIECE348864_CLEAN_gf_iszero(gf a) {
uint32_t t = a;
t -= 1;
t >>= 19;
return (gf) t;
}
gf PQCLEAN_MCELIECE348864_CLEAN_gf_add(gf in0, gf in1) {
return in0 ^ in1;
}
gf PQCLEAN_MCELIECE348864_CLEAN_gf_mul(gf in0, gf in1) {
int i;
uint32_t tmp;
uint32_t t0;
uint32_t t1;
uint32_t t;
t0 = in0;
t1 = in1;
tmp = t0 * (t1 & 1);
for (i = 1; i < GFBITS; i++) {
tmp ^= (t0 * (t1 & (1 << i)));
}
t = tmp & 0x7FC000;
tmp ^= t >> 9;
tmp ^= t >> 12;
t = tmp & 0x3000;
tmp ^= t >> 9;
tmp ^= t >> 12;
return tmp & ((1 << GFBITS) - 1);
}
/* input: field element in */
/* return: in^2 */
static inline gf gf_sq(gf in) {
const uint32_t B[] = {0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF};
uint32_t x = in;
uint32_t t;
x = (x | (x << 8)) & B[3];
x = (x | (x << 4)) & B[2];
x = (x | (x << 2)) & B[1];
x = (x | (x << 1)) & B[0];
t = x & 0x7FC000;
x ^= t >> 9;
x ^= t >> 12;
t = x & 0x3000;
x ^= t >> 9;
x ^= t >> 12;
return x & ((1 << GFBITS) - 1);
}
gf PQCLEAN_MCELIECE348864_CLEAN_gf_inv(gf in) {
gf tmp_11;
gf tmp_1111;
gf out = in;
out = gf_sq(out);
tmp_11 = PQCLEAN_MCELIECE348864_CLEAN_gf_mul(out, in); // 11
out = gf_sq(tmp_11);
out = gf_sq(out);
tmp_1111 = PQCLEAN_MCELIECE348864_CLEAN_gf_mul(out, tmp_11); // 1111
out = gf_sq(tmp_1111);
out = gf_sq(out);
out = gf_sq(out);
out = gf_sq(out);
out = PQCLEAN_MCELIECE348864_CLEAN_gf_mul(out, tmp_1111); // 11111111
out = gf_sq(out);
out = gf_sq(out);
out = PQCLEAN_MCELIECE348864_CLEAN_gf_mul(out, tmp_11); // 1111111111
out = gf_sq(out);
out = PQCLEAN_MCELIECE348864_CLEAN_gf_mul(out, in); // 11111111111
return gf_sq(out); // 111111111110
}
/* input: field element den, num */
/* return: (num/den) */
gf PQCLEAN_MCELIECE348864_CLEAN_gf_frac(gf den, gf num) {
return PQCLEAN_MCELIECE348864_CLEAN_gf_mul(PQCLEAN_MCELIECE348864_CLEAN_gf_inv(den), num);
}
/* input: in0, in1 in GF((2^m)^t)*/
/* output: out = in0*in1 */
void PQCLEAN_MCELIECE348864_CLEAN_GF_mul(gf *out, const gf *in0, const gf *in1) {
int i, j;
gf prod[ SYS_T * 2 - 1 ];
for (i = 0; i < SYS_T * 2 - 1; i++) {
prod[i] = 0;
}
for (i = 0; i < SYS_T; i++) {
for (j = 0; j < SYS_T; j++) {
prod[i + j] ^= PQCLEAN_MCELIECE348864_CLEAN_gf_mul(in0[i], in1[j]);
}
}
//
for (i = (SYS_T - 1) * 2; i >= SYS_T; i--) {
prod[i - SYS_T + 9] ^= PQCLEAN_MCELIECE348864_CLEAN_gf_mul(prod[i], (gf) 877);
prod[i - SYS_T + 7] ^= PQCLEAN_MCELIECE348864_CLEAN_gf_mul(prod[i], (gf) 2888);
prod[i - SYS_T + 5] ^= PQCLEAN_MCELIECE348864_CLEAN_gf_mul(prod[i], (gf) 1781);
prod[i - SYS_T + 0] ^= PQCLEAN_MCELIECE348864_CLEAN_gf_mul(prod[i], (gf) 373);
}
for (i = 0; i < SYS_T; i++) {
out[i] = prod[i];
}
}

View File

@ -1,22 +0,0 @@
#ifndef PQCLEAN_MCELIECE348864_CLEAN_GF_H
#define PQCLEAN_MCELIECE348864_CLEAN_GF_H
/*
This file is for functions for field arithmetic
*/
#include <stdint.h>
typedef uint16_t gf;
gf PQCLEAN_MCELIECE348864_CLEAN_gf_iszero(gf a);
gf PQCLEAN_MCELIECE348864_CLEAN_gf_add(gf in0, gf in1);
gf PQCLEAN_MCELIECE348864_CLEAN_gf_mul(gf in0, gf in1);
gf PQCLEAN_MCELIECE348864_CLEAN_gf_frac(gf den, gf num);
gf PQCLEAN_MCELIECE348864_CLEAN_gf_inv(gf in);
uint64_t PQCLEAN_MCELIECE348864_CLEAN_gf_mul2(gf a, gf b0, gf b1);
void PQCLEAN_MCELIECE348864_CLEAN_GF_mul(gf *out, const gf *in0, const gf *in1);
#endif

View File

@ -1,136 +0,0 @@
#include "api.h"
#include "aes256ctr.h"
#include "controlbits.h"
#include "crypto_hash.h"
#include "decrypt.h"
#include "encrypt.h"
#include "params.h"
#include "pk_gen.h"
#include "randombytes.h"
#include "sk_gen.h"
#include "util.h"
#include <stdint.h>
#include <string.h>
int PQCLEAN_MCELIECE348864_CLEAN_crypto_kem_enc(
uint8_t *c,
uint8_t *key,
const uint8_t *pk
) {
uint8_t two_e[ 1 + SYS_N / 8 ] = {2};
uint8_t *e = two_e + 1;
uint8_t one_ec[ 1 + SYS_N / 8 + (SYND_BYTES + 32) ] = {1};
PQCLEAN_MCELIECE348864_CLEAN_encrypt(c, e, pk);
crypto_hash_32b(c + SYND_BYTES, two_e, sizeof(two_e));
memcpy(one_ec + 1, e, SYS_N / 8);
memcpy(one_ec + 1 + SYS_N / 8, c, SYND_BYTES + 32);
crypto_hash_32b(key, one_ec, sizeof(one_ec));
return 0;
}
int PQCLEAN_MCELIECE348864_CLEAN_crypto_kem_dec(
uint8_t *key,
const uint8_t *c,
const uint8_t *sk
) {
int i;
uint8_t ret_confirm = 0;
uint8_t ret_decrypt = 0;
uint16_t m;
uint8_t conf[32];
uint8_t two_e[ 1 + SYS_N / 8 ] = {2};
uint8_t *e = two_e + 1;
uint8_t preimage[ 1 + SYS_N / 8 + (SYND_BYTES + 32) ];
uint8_t *x = preimage;
//
ret_decrypt = (uint8_t)PQCLEAN_MCELIECE348864_CLEAN_decrypt(e, sk + SYS_N / 8, c);
crypto_hash_32b(conf, two_e, sizeof(two_e));
for (i = 0; i < 32; i++) {
ret_confirm |= conf[i] ^ c[SYND_BYTES + i];
}
m = ret_decrypt | ret_confirm;
m -= 1;
m >>= 8;
*x++ = (~m & 0) | (m & 1);
for (i = 0; i < SYS_N / 8; i++) {
*x++ = (~m & sk[i]) | (m & e[i]);
}
for (i = 0; i < SYND_BYTES + 32; i++) {
*x++ = c[i];
}
crypto_hash_32b(key, preimage, sizeof(preimage));
return 0;
}
int PQCLEAN_MCELIECE348864_CLEAN_crypto_kem_keypair
(
uint8_t *pk,
uint8_t *sk
) {
int i;
uint8_t seed[ 32 ];
uint8_t r[ SYS_T * 2 + (1 << GFBITS)*sizeof(uint32_t) + SYS_N / 8 + 32 ];
uint8_t nonce[ 16 ] = {0};
uint8_t *rp;
gf f[ SYS_T ]; // element in GF(2^mt)
gf irr[ SYS_T ]; // Goppa polynomial
uint32_t perm[ 1 << GFBITS ]; // random permutation
randombytes(seed, sizeof(seed));
while (1) {
rp = r;
PQCLEAN_MCELIECE348864_CLEAN_aes256ctr(r, sizeof(r), nonce, seed);
memcpy(seed, &r[ sizeof(r) - 32 ], 32);
for (i = 0; i < SYS_T; i++) {
f[i] = PQCLEAN_MCELIECE348864_CLEAN_load2(rp + i * 2);
}
rp += sizeof(f);
if (PQCLEAN_MCELIECE348864_CLEAN_genpoly_gen(irr, f)) {
continue;
}
for (i = 0; i < (1 << GFBITS); i++) {
perm[i] = PQCLEAN_MCELIECE348864_CLEAN_load4(rp + i * 4);
}
rp += sizeof(perm);
if (PQCLEAN_MCELIECE348864_CLEAN_perm_check(perm)) {
continue;
}
for (i = 0; i < SYS_T; i++) {
PQCLEAN_MCELIECE348864_CLEAN_store2(sk + SYS_N / 8 + i * 2, irr[i]);
}
if (PQCLEAN_MCELIECE348864_CLEAN_pk_gen(pk, perm, sk + SYS_N / 8)) {
continue;
}
memcpy(sk, rp, SYS_N / 8);
PQCLEAN_MCELIECE348864_CLEAN_controlbits(sk + SYS_N / 8 + IRR_BYTES, perm);
break;
}
return 0;
}

View File

@ -1,21 +0,0 @@
#ifndef PQCLEAN_MCELIECE348864_CLEAN_PARAMS_H
#define PQCLEAN_MCELIECE348864_CLEAN_PARAMS_H
#define GFBITS 12
#define SYS_N 3488
#define SYS_T 64
#define COND_BYTES ((1 << (GFBITS-4))*(2*GFBITS - 1))
#define IRR_BYTES (SYS_T * 2)
#define PK_NROWS (SYS_T*GFBITS)
#define PK_NCOLS (SYS_N - PK_NROWS)
#define PK_ROW_BYTES ((PK_NCOLS + 7)/8)
#define SK_BYTES (SYS_N/8 + IRR_BYTES + COND_BYTES)
#define SYND_BYTES ((PK_NROWS + 7)/8)
#define GFMASK ((1 << GFBITS) - 1)
#endif

View File

@ -1,144 +0,0 @@
/*
This file is for public-key generation
*/
#include <string.h>
#include "benes.h"
#include "controlbits.h"
#include "gf.h"
#include "params.h"
#include "pk_gen.h"
#include "root.h"
#include "util.h"
/* input: secret key sk */
/* output: public key pk */
int PQCLEAN_MCELIECE348864_CLEAN_pk_gen(uint8_t *pk, uint32_t *perm, const uint8_t *sk) {
int i, j, k;
int row, c;
uint64_t buf[ 1 << GFBITS ];
uint8_t mat[ GFBITS * SYS_T ][ SYS_N / 8 ];
uint8_t mask;
uint8_t b;
gf g[ SYS_T + 1 ]; // Goppa polynomial
gf L[ SYS_N ]; // support
gf inv[ SYS_N ];
//
g[ SYS_T ] = 1;
for (i = 0; i < SYS_T; i++) {
g[i] = PQCLEAN_MCELIECE348864_CLEAN_load2(sk);
g[i] &= GFMASK;
sk += 2;
}
for (i = 0; i < (1 << GFBITS); i++) {
buf[i] = perm[i];
buf[i] <<= 31;
buf[i] |= i;
}
PQCLEAN_MCELIECE348864_CLEAN_sort_63b(1 << GFBITS, buf);
for (i = 0; i < (1 << GFBITS); i++) {
perm[i] = buf[i] & GFMASK;
}
for (i = 0; i < SYS_N; i++) {
L[i] = PQCLEAN_MCELIECE348864_CLEAN_bitrev((gf)perm[i]);
}
// filling the matrix
PQCLEAN_MCELIECE348864_CLEAN_root(inv, g, L);
for (i = 0; i < SYS_N; i++) {
inv[i] = PQCLEAN_MCELIECE348864_CLEAN_gf_inv(inv[i]);
}
for (i = 0; i < PK_NROWS; i++) {
for (j = 0; j < SYS_N / 8; j++) {
mat[i][j] = 0;
}
}
for (i = 0; i < SYS_T; i++) {
for (j = 0; j < SYS_N; j += 8) {
for (k = 0; k < GFBITS; k++) {
b = (inv[j + 7] >> k) & 1;
b <<= 1;
b |= (inv[j + 6] >> k) & 1;
b <<= 1;
b |= (inv[j + 5] >> k) & 1;
b <<= 1;
b |= (inv[j + 4] >> k) & 1;
b <<= 1;
b |= (inv[j + 3] >> k) & 1;
b <<= 1;
b |= (inv[j + 2] >> k) & 1;
b <<= 1;
b |= (inv[j + 1] >> k) & 1;
b <<= 1;
b |= (inv[j + 0] >> k) & 1;
mat[ i * GFBITS + k ][ j / 8 ] = b;
}
}
for (j = 0; j < SYS_N; j++) {
inv[j] = PQCLEAN_MCELIECE348864_CLEAN_gf_mul(inv[j], L[j]);
}
}
// gaussian elimination
for (i = 0; i < (GFBITS * SYS_T + 7) / 8; i++) {
for (j = 0; j < 8; j++) {
row = i * 8 + j;
if (row >= GFBITS * SYS_T) {
break;
}
for (k = row + 1; k < GFBITS * SYS_T; k++) {
mask = mat[ row ][ i ] ^ mat[ k ][ i ];
mask >>= j;
mask &= 1;
mask = -mask;
for (c = 0; c < SYS_N / 8; c++) {
mat[ row ][ c ] ^= mat[ k ][ c ] & mask;
}
}
if ( ((mat[ row ][ i ] >> j) & 1) == 0 ) { // return if not systematic
return -1;
}
for (k = 0; k < GFBITS * SYS_T; k++) {
if (k != row) {
mask = mat[ k ][ i ] >> j;
mask &= 1;
mask = -mask;
for (c = 0; c < SYS_N / 8; c++) {
mat[ k ][ c ] ^= mat[ row ][ c ] & mask;
}
}
}
}
}
for (i = 0; i < PK_NROWS; i++) {
memcpy(pk + i * PK_ROW_BYTES, mat[i] + PK_NROWS / 8, PK_ROW_BYTES);
}
return 0;
}

View File

@ -1,13 +0,0 @@
#ifndef PQCLEAN_MCELIECE348864_CLEAN_PK_GEN_H
#define PQCLEAN_MCELIECE348864_CLEAN_PK_GEN_H
/*
This file is for public-key generation
*/
#include <stdint.h>
int PQCLEAN_MCELIECE348864_CLEAN_pk_gen(uint8_t * /*pk*/, uint32_t * /*perm*/, const uint8_t * /*sk*/);
#endif

View File

@ -1,33 +0,0 @@
/*
This file is for evaluating a polynomial at one or more field elements
*/
#include "root.h"
#include "params.h"
/* input: polynomial f and field element a */
/* return f(a) */
gf PQCLEAN_MCELIECE348864_CLEAN_eval(gf *f, gf a) {
int i;
gf r;
r = f[ SYS_T ];
for (i = SYS_T - 1; i >= 0; i--) {
r = PQCLEAN_MCELIECE348864_CLEAN_gf_mul(r, a);
r = PQCLEAN_MCELIECE348864_CLEAN_gf_add(r, f[i]);
}
return r;
}
/* input: polynomial f and list of field elements L */
/* output: out = [ f(a) for a in L ] */
void PQCLEAN_MCELIECE348864_CLEAN_root(gf *out, gf *f, gf *L) {
int i;
for (i = 0; i < SYS_N; i++) {
out[i] = PQCLEAN_MCELIECE348864_CLEAN_eval(f, L[i]);
}
}

View File

@ -1,14 +0,0 @@
#ifndef PQCLEAN_MCELIECE348864_CLEAN_ROOT_H
#define PQCLEAN_MCELIECE348864_CLEAN_ROOT_H
/*
This file is for evaluating a polynomial at one or more field elements
*/
#include "gf.h"
gf PQCLEAN_MCELIECE348864_CLEAN_eval(gf * /*f*/, gf /*a*/);
void PQCLEAN_MCELIECE348864_CLEAN_root(gf * /*out*/, gf * /*f*/, gf * /*L*/);
#endif

View File

@ -1,98 +0,0 @@
/*
This file is for secret-key generation
*/
#include "sk_gen.h"
#include "controlbits.h"
#include "gf.h"
#include "params.h"
#include "util.h"
/* input: f, element in GF((2^m)^t) */
/* output: out, minimal polynomial of f */
/* return: 0 for success and -1 for failure */
int PQCLEAN_MCELIECE348864_CLEAN_genpoly_gen(gf *out, gf *f) {
int i, j, k, c;
gf mat[ SYS_T + 1 ][ SYS_T ];
gf mask, inv, t;
// fill matrix
mat[0][0] = 1;
for (i = 1; i < SYS_T; i++) {
mat[0][i] = 0;
}
for (i = 0; i < SYS_T; i++) {
mat[1][i] = f[i];
}
for (j = 2; j <= SYS_T; j++) {
PQCLEAN_MCELIECE348864_CLEAN_GF_mul(mat[j], mat[j - 1], f);
}
// gaussian
for (j = 0; j < SYS_T; j++) {
for (k = j + 1; k < SYS_T; k++) {
mask = PQCLEAN_MCELIECE348864_CLEAN_gf_iszero(mat[ j ][ j ]);
for (c = j; c < SYS_T + 1; c++) {
mat[ c ][ j ] ^= mat[ c ][ k ] & mask;
}
}
if ( mat[ j ][ j ] == 0 ) { // return if not systematic
return -1;
}
inv = PQCLEAN_MCELIECE348864_CLEAN_gf_inv(mat[j][j]);
for (c = j; c < SYS_T + 1; c++) {
mat[ c ][ j ] = PQCLEAN_MCELIECE348864_CLEAN_gf_mul(mat[ c ][ j ], inv) ;
}
for (k = 0; k < SYS_T; k++) {
if (k != j) {
t = mat[ j ][ k ];
for (c = j; c < SYS_T + 1; c++) {
mat[ c ][ k ] ^= PQCLEAN_MCELIECE348864_CLEAN_gf_mul(mat[ c ][ j ], t);
}
}
}
}
for (i = 0; i < SYS_T; i++) {
out[i] = mat[ SYS_T ][ i ];
}
return 0;
}
/* input: permutation p represented as a list of 32-bit intergers */
/* output: -1 if some interger repeats in p */
/* 0 otherwise */
int PQCLEAN_MCELIECE348864_CLEAN_perm_check(const uint32_t *p) {
int i;
uint64_t list[1 << GFBITS];
for (i = 0; i < (1 << GFBITS); i++) {
list[i] = p[i];
}
PQCLEAN_MCELIECE348864_CLEAN_sort_63b(1 << GFBITS, list);
for (i = 1; i < (1 << GFBITS); i++) {
if (list[i - 1] == list[i]) {
return -1;
}
}
return 0;
}

View File

@ -1,16 +0,0 @@
#ifndef PQCLEAN_MCELIECE348864_CLEAN_SK_GEN_H
#define PQCLEAN_MCELIECE348864_CLEAN_SK_GEN_H
/*
This file is for secret-key generation
*/
#include "gf.h"
#include <stdint.h>
int PQCLEAN_MCELIECE348864_CLEAN_genpoly_gen(gf * /*out*/, gf * /*f*/);
int PQCLEAN_MCELIECE348864_CLEAN_perm_check(const uint32_t * /*p*/);
#endif

View File

@ -1,33 +0,0 @@
/*
This file is for syndrome computation
*/
#include "synd.h"
#include "params.h"
#include "root.h"
/* input: Goppa polynomial f, support L, received word r */
/* output: out, the syndrome of length 2t */
void PQCLEAN_MCELIECE348864_CLEAN_synd(gf *out, gf *f, gf *L, const unsigned char *r) {
int i, j;
gf e, e_inv, c;
for (j = 0; j < 2 * SYS_T; j++) {
out[j] = 0;
}
for (i = 0; i < SYS_N; i++) {
c = (r[i / 8] >> (i % 8)) & 1;
e = PQCLEAN_MCELIECE348864_CLEAN_eval(f, L[i]);
e_inv = PQCLEAN_MCELIECE348864_CLEAN_gf_inv(PQCLEAN_MCELIECE348864_CLEAN_gf_mul(e, e));
for (j = 0; j < 2 * SYS_T; j++) {
out[j] = PQCLEAN_MCELIECE348864_CLEAN_gf_add(out[j], PQCLEAN_MCELIECE348864_CLEAN_gf_mul(e_inv, c));
e_inv = PQCLEAN_MCELIECE348864_CLEAN_gf_mul(e_inv, L[i]);
}
}
}

View File

@ -1,12 +0,0 @@
#ifndef PQCLEAN_MCELIECE348864_CLEAN_SYND_H
#define PQCLEAN_MCELIECE348864_CLEAN_SYND_H
/*
This file is for syndrome computation
*/
#include "gf.h"
void PQCLEAN_MCELIECE348864_CLEAN_synd(gf * /*out*/, gf * /*f*/, gf * /*L*/, const unsigned char * /*r*/);
#endif

View File

@ -1,42 +0,0 @@
/*
This file is for matrix transposition
*/
#include "transpose.h"
#include <stdint.h>
/* input: in, a 64x64 matrix over GF(2) */
/* output: out, transpose of in */
void PQCLEAN_MCELIECE348864_CLEAN_transpose_64x64(uint64_t *out, const uint64_t *in) {
int i, j, s, d;
uint64_t x, y;
uint64_t masks[6][2] = {
{0x5555555555555555, 0xAAAAAAAAAAAAAAAA},
{0x3333333333333333, 0xCCCCCCCCCCCCCCCC},
{0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0},
{0x00FF00FF00FF00FF, 0xFF00FF00FF00FF00},
{0x0000FFFF0000FFFF, 0xFFFF0000FFFF0000},
{0x00000000FFFFFFFF, 0xFFFFFFFF00000000}
};
for (i = 0; i < 64; i++) {
out[i] = in[i];
}
for (d = 5; d >= 0; d--) {
s = 1 << d;
for (i = 0; i < 64; i += s * 2) {
for (j = i; j < i + s; j++) {
x = (out[j] & masks[d][0]) | ((out[j + s] & masks[d][0]) << s);
y = ((out[j] & masks[d][1]) >> s) | (out[j + s] & masks[d][1]);
out[j + 0] = x;
out[j + s] = y;
}
}
}
}

View File

@ -1,13 +0,0 @@
#ifndef PQCLEAN_MCELIECE348864_CLEAN_TRANSPOSE_H
#define PQCLEAN_MCELIECE348864_CLEAN_TRANSPOSE_H
/*
This file is for matrix transposition
*/
#include <stdint.h>
void PQCLEAN_MCELIECE348864_CLEAN_transpose_64x64(uint64_t * /*out*/, const uint64_t * /*in*/);
#endif

View File

@ -1,67 +0,0 @@
/*
This file is for loading/storing data in a little-endian fashion
*/
#include "util.h"
#include "params.h"
void PQCLEAN_MCELIECE348864_CLEAN_store2(unsigned char *dest, gf a) {
dest[0] = a & 0xFF;
dest[1] = a >> 8;
}
uint16_t PQCLEAN_MCELIECE348864_CLEAN_load2(const unsigned char *src) {
uint16_t a;
a = src[1];
a <<= 8;
a |= src[0];
return a & GFMASK;
}
uint32_t PQCLEAN_MCELIECE348864_CLEAN_load4(const unsigned char *in) {
int i;
uint32_t ret = in[3];
for (i = 2; i >= 0; i--) {
ret <<= 8;
ret |= in[i];
}
return ret;
}
void PQCLEAN_MCELIECE348864_CLEAN_store8(unsigned char *out, uint64_t in) {
out[0] = (in >> 0x00) & 0xFF;
out[1] = (in >> 0x08) & 0xFF;
out[2] = (in >> 0x10) & 0xFF;
out[3] = (in >> 0x18) & 0xFF;
out[4] = (in >> 0x20) & 0xFF;
out[5] = (in >> 0x28) & 0xFF;
out[6] = (in >> 0x30) & 0xFF;
out[7] = (in >> 0x38) & 0xFF;
}
uint64_t PQCLEAN_MCELIECE348864_CLEAN_load8(const unsigned char *in) {
int i;
uint64_t ret = in[7];
for (i = 6; i >= 0; i--) {
ret <<= 8;
ret |= in[i];
}
return ret;
}
gf PQCLEAN_MCELIECE348864_CLEAN_bitrev(gf a) {
a = ((a & 0x00FF) << 8) | ((a & 0xFF00) >> 8);
a = ((a & 0x0F0F) << 4) | ((a & 0xF0F0) >> 4);
a = ((a & 0x3333) << 2) | ((a & 0xCCCC) >> 2);
a = ((a & 0x5555) << 1) | ((a & 0xAAAA) >> 1);
return a >> 4;
}

View File

@ -1,22 +0,0 @@
#ifndef PQCLEAN_MCELIECE348864_CLEAN_UTIL_H
#define PQCLEAN_MCELIECE348864_CLEAN_UTIL_H
/*
This file is for loading/storing data in a little-endian fashion
*/
#include "gf.h"
#include <stdint.h>
void PQCLEAN_MCELIECE348864_CLEAN_store2(unsigned char * /*dest*/, gf /*a*/);
uint16_t PQCLEAN_MCELIECE348864_CLEAN_load2(const unsigned char * /*src*/);
uint32_t PQCLEAN_MCELIECE348864_CLEAN_load4(const unsigned char * /*in*/);
void PQCLEAN_MCELIECE348864_CLEAN_store8(unsigned char * /*out*/, uint64_t /*in*/);
uint64_t PQCLEAN_MCELIECE348864_CLEAN_load8(const unsigned char * /*in*/);
gf PQCLEAN_MCELIECE348864_CLEAN_bitrev(gf /*a*/);
#endif

View File

@ -29,7 +29,7 @@ if(OQS_ENABLE_KEM_kyber_768_avx2)
add_library(kyber_768_avx2 OBJECT pqclean_kyber768_avx2/basemul.S pqclean_kyber768_avx2/cbd.c pqclean_kyber768_avx2/consts.c pqclean_kyber768_avx2/fips202x4.c pqclean_kyber768_avx2/fq.s pqclean_kyber768_avx2/indcpa.c pqclean_kyber768_avx2/invntt.s pqclean_kyber768_avx2/kem.c pqclean_kyber768_avx2/ntt.s pqclean_kyber768_avx2/poly.c pqclean_kyber768_avx2/polyvec.c pqclean_kyber768_avx2/rejsample.c pqclean_kyber768_avx2/shuffle.s pqclean_kyber768_avx2/symmetric-fips202.c pqclean_kyber768_avx2/verify.c)
target_include_directories(kyber_768_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/pqclean_kyber768_avx2)
target_include_directories(kyber_768_avx2 PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims)
target_compile_options(kyber_768_avx2 PRIVATE -maes -mavx2 -mbmi2 -mpopcnt)
target_compile_options(kyber_768_avx2 PRIVATE -mavx2 -mbmi2 -mpopcnt)
set(_KYBER_OBJS ${_KYBER_OBJS} $<TARGET_OBJECTS:kyber_768_avx2>)
endif()
@ -44,7 +44,7 @@ if(OQS_ENABLE_KEM_kyber_1024_avx2)
add_library(kyber_1024_avx2 OBJECT pqclean_kyber1024_avx2/basemul.S pqclean_kyber1024_avx2/cbd.c pqclean_kyber1024_avx2/consts.c pqclean_kyber1024_avx2/fips202x4.c pqclean_kyber1024_avx2/fq.s pqclean_kyber1024_avx2/indcpa.c pqclean_kyber1024_avx2/invntt.s pqclean_kyber1024_avx2/kem.c pqclean_kyber1024_avx2/ntt.s pqclean_kyber1024_avx2/poly.c pqclean_kyber1024_avx2/polyvec.c pqclean_kyber1024_avx2/rejsample.c pqclean_kyber1024_avx2/shuffle.s pqclean_kyber1024_avx2/symmetric-fips202.c pqclean_kyber1024_avx2/verify.c)
target_include_directories(kyber_1024_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/pqclean_kyber1024_avx2)
target_include_directories(kyber_1024_avx2 PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims)
target_compile_options(kyber_1024_avx2 PRIVATE -maes -mavx2 -mbmi2 -mpopcnt)
target_compile_options(kyber_1024_avx2 PRIVATE -mavx2 -mbmi2 -mpopcnt)
set(_KYBER_OBJS ${_KYBER_OBJS} $<TARGET_OBJECTS:kyber_1024_avx2>)
endif()

View File

@ -44,7 +44,7 @@ OQS_API OQS_STATUS OQS_KEM_kyber_1024_keypair(uint8_t *public_key, uint8_t *secr
#if defined(OQS_ENABLE_KEM_kyber_1024_avx2)
#if defined(OQS_PORTABLE_BUILD)
OQS_CPU_EXTENSIONS available_cpu_extensions = OQS_get_available_CPU_extensions();
if (available_cpu_extensions.AES_ENABLED && available_cpu_extensions.AVX2_ENABLED && available_cpu_extensions.BMI2_ENABLED && available_cpu_extensions.POPCNT_ENABLED) {
if (available_cpu_extensions.AVX2_ENABLED && available_cpu_extensions.BMI2_ENABLED && available_cpu_extensions.POPCNT_ENABLED) {
#endif /* OQS_PORTABLE_BUILD */
return (OQS_STATUS) PQCLEAN_KYBER1024_AVX2_crypto_kem_keypair(public_key, secret_key);
#if defined(OQS_PORTABLE_BUILD)
@ -61,7 +61,7 @@ OQS_API OQS_STATUS OQS_KEM_kyber_1024_encaps(uint8_t *ciphertext, uint8_t *share
#if defined(OQS_ENABLE_KEM_kyber_1024_avx2)
#if defined(OQS_PORTABLE_BUILD)
OQS_CPU_EXTENSIONS available_cpu_extensions = OQS_get_available_CPU_extensions();
if (available_cpu_extensions.AES_ENABLED && available_cpu_extensions.AVX2_ENABLED && available_cpu_extensions.BMI2_ENABLED && available_cpu_extensions.POPCNT_ENABLED) {
if (available_cpu_extensions.AVX2_ENABLED && available_cpu_extensions.BMI2_ENABLED && available_cpu_extensions.POPCNT_ENABLED) {
#endif /* OQS_PORTABLE_BUILD */
return (OQS_STATUS) PQCLEAN_KYBER1024_AVX2_crypto_kem_enc(ciphertext, shared_secret, public_key);
#if defined(OQS_PORTABLE_BUILD)
@ -78,7 +78,7 @@ OQS_API OQS_STATUS OQS_KEM_kyber_1024_decaps(uint8_t *shared_secret, const unsig
#if defined(OQS_ENABLE_KEM_kyber_1024_avx2)
#if defined(OQS_PORTABLE_BUILD)
OQS_CPU_EXTENSIONS available_cpu_extensions = OQS_get_available_CPU_extensions();
if (available_cpu_extensions.AES_ENABLED && available_cpu_extensions.AVX2_ENABLED && available_cpu_extensions.BMI2_ENABLED && available_cpu_extensions.POPCNT_ENABLED) {
if (available_cpu_extensions.AVX2_ENABLED && available_cpu_extensions.BMI2_ENABLED && available_cpu_extensions.POPCNT_ENABLED) {
#endif /* OQS_PORTABLE_BUILD */
return (OQS_STATUS) PQCLEAN_KYBER1024_AVX2_crypto_kem_dec(shared_secret, ciphertext, secret_key);
#if defined(OQS_PORTABLE_BUILD)

View File

@ -44,7 +44,7 @@ OQS_API OQS_STATUS OQS_KEM_kyber_768_keypair(uint8_t *public_key, uint8_t *secre
#if defined(OQS_ENABLE_KEM_kyber_768_avx2)
#if defined(OQS_PORTABLE_BUILD)
OQS_CPU_EXTENSIONS available_cpu_extensions = OQS_get_available_CPU_extensions();
if (available_cpu_extensions.AES_ENABLED && available_cpu_extensions.AVX2_ENABLED && available_cpu_extensions.BMI2_ENABLED && available_cpu_extensions.POPCNT_ENABLED) {
if (available_cpu_extensions.AVX2_ENABLED && available_cpu_extensions.BMI2_ENABLED && available_cpu_extensions.POPCNT_ENABLED) {
#endif /* OQS_PORTABLE_BUILD */
return (OQS_STATUS) PQCLEAN_KYBER768_AVX2_crypto_kem_keypair(public_key, secret_key);
#if defined(OQS_PORTABLE_BUILD)
@ -61,7 +61,7 @@ OQS_API OQS_STATUS OQS_KEM_kyber_768_encaps(uint8_t *ciphertext, uint8_t *shared
#if defined(OQS_ENABLE_KEM_kyber_768_avx2)
#if defined(OQS_PORTABLE_BUILD)
OQS_CPU_EXTENSIONS available_cpu_extensions = OQS_get_available_CPU_extensions();
if (available_cpu_extensions.AES_ENABLED && available_cpu_extensions.AVX2_ENABLED && available_cpu_extensions.BMI2_ENABLED && available_cpu_extensions.POPCNT_ENABLED) {
if (available_cpu_extensions.AVX2_ENABLED && available_cpu_extensions.BMI2_ENABLED && available_cpu_extensions.POPCNT_ENABLED) {
#endif /* OQS_PORTABLE_BUILD */
return (OQS_STATUS) PQCLEAN_KYBER768_AVX2_crypto_kem_enc(ciphertext, shared_secret, public_key);
#if defined(OQS_PORTABLE_BUILD)
@ -78,7 +78,7 @@ OQS_API OQS_STATUS OQS_KEM_kyber_768_decaps(uint8_t *shared_secret, const unsign
#if defined(OQS_ENABLE_KEM_kyber_768_avx2)
#if defined(OQS_PORTABLE_BUILD)
OQS_CPU_EXTENSIONS available_cpu_extensions = OQS_get_available_CPU_extensions();
if (available_cpu_extensions.AES_ENABLED && available_cpu_extensions.AVX2_ENABLED && available_cpu_extensions.BMI2_ENABLED && available_cpu_extensions.POPCNT_ENABLED) {
if (available_cpu_extensions.AVX2_ENABLED && available_cpu_extensions.BMI2_ENABLED && available_cpu_extensions.POPCNT_ENABLED) {
#endif /* OQS_PORTABLE_BUILD */
return (OQS_STATUS) PQCLEAN_KYBER768_AVX2_crypto_kem_dec(shared_secret, ciphertext, secret_key);
#if defined(OQS_PORTABLE_BUILD)

View File

@ -101,8 +101,9 @@ void PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_keypair(unsigned char *pk,
unsigned char *publicseed = z;
unsigned char *noiseseed = z + NEWHOPE_SYMBYTES;
randombytes(z, NEWHOPE_SYMBYTES);
shake256(z, 2 * NEWHOPE_SYMBYTES, z, NEWHOPE_SYMBYTES);
z[0] = 0x01;
randombytes(z + 1, NEWHOPE_SYMBYTES);
shake256(z, 2 * NEWHOPE_SYMBYTES, z, NEWHOPE_SYMBYTES + 1);
gen_a(&ahat, publicseed);

View File

@ -52,16 +52,18 @@ int PQCLEAN_NEWHOPE1024CCA_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned
**************************************************/
int PQCLEAN_NEWHOPE1024CCA_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk) {
unsigned char k_coins_d[3 * NEWHOPE_SYMBYTES]; /* Will contain key, coins, qrom-hash */
unsigned char buf[2 * NEWHOPE_SYMBYTES];
unsigned char buf[2 * NEWHOPE_SYMBYTES + 1];
int i;
randombytes(buf, NEWHOPE_SYMBYTES);
buf[0] = 0x04;
randombytes(buf + 1, NEWHOPE_SYMBYTES);
shake256(buf, NEWHOPE_SYMBYTES, buf, NEWHOPE_SYMBYTES); /* Don't release system RNG output */
shake256(buf + NEWHOPE_SYMBYTES, NEWHOPE_SYMBYTES, pk, NEWHOPE_CCAKEM_PUBLICKEYBYTES); /* Multitarget countermeasure for coins + contributory KEM */
shake256(k_coins_d, 3 * NEWHOPE_SYMBYTES, buf, 2 * NEWHOPE_SYMBYTES);
shake256(buf + 1, NEWHOPE_SYMBYTES, buf, NEWHOPE_SYMBYTES + 1); /* Don't release system RNG output */
shake256(buf + 1 + NEWHOPE_SYMBYTES, NEWHOPE_SYMBYTES, pk, NEWHOPE_CCAKEM_PUBLICKEYBYTES); /* Multitarget countermeasure for coins + contributory KEM */
buf[0] = 0x08;
shake256(k_coins_d, 3 * NEWHOPE_SYMBYTES, buf, 2 * NEWHOPE_SYMBYTES + 1);
PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_enc(ct, buf, pk, k_coins_d + NEWHOPE_SYMBYTES); /* coins are in k_coins_d+NEWHOPE_SYMBYTES */
PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_enc(ct, buf + 1, pk, k_coins_d + NEWHOPE_SYMBYTES); /* coins are in k_coins_d+NEWHOPE_SYMBYTES */
for (i = 0; i < NEWHOPE_SYMBYTES; i++) {
ct[i + NEWHOPE_CPAPKE_CIPHERTEXTBYTES] = k_coins_d[i + 2 * NEWHOPE_SYMBYTES]; /* copy Targhi-Unruh hash into ct */
@ -89,18 +91,19 @@ int PQCLEAN_NEWHOPE1024CCA_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char
int PQCLEAN_NEWHOPE1024CCA_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk) {
int i, fail;
unsigned char ct_cmp[NEWHOPE_CCAKEM_CIPHERTEXTBYTES];
unsigned char buf[2 * NEWHOPE_SYMBYTES];
unsigned char buf[2 * NEWHOPE_SYMBYTES + 1];
unsigned char k_coins_d[3 * NEWHOPE_SYMBYTES]; /* Will contain key, coins, qrom-hash */
const unsigned char *pk = sk + NEWHOPE_CPAPKE_SECRETKEYBYTES;
PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_dec(buf, ct, sk);
buf[0] = 0x08;
PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_dec(buf + 1, ct, sk);
for (i = 0; i < NEWHOPE_SYMBYTES; i++) { /* Use hash of pk stored in sk */
buf[NEWHOPE_SYMBYTES + i] = sk[NEWHOPE_CCAKEM_SECRETKEYBYTES - 2 * NEWHOPE_SYMBYTES + i];
buf[1 + NEWHOPE_SYMBYTES + i] = sk[NEWHOPE_CCAKEM_SECRETKEYBYTES - 2 * NEWHOPE_SYMBYTES + i];
}
shake256(k_coins_d, 3 * NEWHOPE_SYMBYTES, buf, 2 * NEWHOPE_SYMBYTES);
shake256(k_coins_d, 3 * NEWHOPE_SYMBYTES, buf, 2 * NEWHOPE_SYMBYTES + 1);
PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_enc(ct_cmp, buf, pk, k_coins_d + NEWHOPE_SYMBYTES); /* coins are in k_coins_d+NEWHOPE_SYMBYTES */
PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_enc(ct_cmp, buf + 1, pk, k_coins_d + NEWHOPE_SYMBYTES); /* coins are in k_coins_d+NEWHOPE_SYMBYTES */
for (i = 0; i < NEWHOPE_SYMBYTES; i++) {
ct_cmp[i + NEWHOPE_CPAPKE_CIPHERTEXTBYTES] = k_coins_d[i + 2 * NEWHOPE_SYMBYTES];

View File

@ -101,8 +101,9 @@ void PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_keypair(unsigned char *pk,
unsigned char *publicseed = z;
unsigned char *noiseseed = z + NEWHOPE_SYMBYTES;
randombytes(z, NEWHOPE_SYMBYTES);
shake256(z, 2 * NEWHOPE_SYMBYTES, z, NEWHOPE_SYMBYTES);
z[0] = 0x01;
randombytes(z + 1, NEWHOPE_SYMBYTES);
shake256(z, 2 * NEWHOPE_SYMBYTES, z, NEWHOPE_SYMBYTES + 1);
gen_a(&ahat, publicseed);

View File

@ -52,16 +52,18 @@ int PQCLEAN_NEWHOPE512CCA_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned c
**************************************************/
int PQCLEAN_NEWHOPE512CCA_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk) {
unsigned char k_coins_d[3 * NEWHOPE_SYMBYTES]; /* Will contain key, coins, qrom-hash */
unsigned char buf[2 * NEWHOPE_SYMBYTES];
unsigned char buf[2 * NEWHOPE_SYMBYTES + 1];
int i;
randombytes(buf, NEWHOPE_SYMBYTES);
buf[0] = 0x04;
randombytes(buf + 1, NEWHOPE_SYMBYTES);
shake256(buf, NEWHOPE_SYMBYTES, buf, NEWHOPE_SYMBYTES); /* Don't release system RNG output */
shake256(buf + NEWHOPE_SYMBYTES, NEWHOPE_SYMBYTES, pk, NEWHOPE_CCAKEM_PUBLICKEYBYTES); /* Multitarget countermeasure for coins + contributory KEM */
shake256(k_coins_d, 3 * NEWHOPE_SYMBYTES, buf, 2 * NEWHOPE_SYMBYTES);
shake256(buf + 1, NEWHOPE_SYMBYTES, buf, NEWHOPE_SYMBYTES + 1); /* Don't release system RNG output */
shake256(buf + 1 + NEWHOPE_SYMBYTES, NEWHOPE_SYMBYTES, pk, NEWHOPE_CCAKEM_PUBLICKEYBYTES); /* Multitarget countermeasure for coins + contributory KEM */
buf[0] = 0x08;
shake256(k_coins_d, 3 * NEWHOPE_SYMBYTES, buf, 2 * NEWHOPE_SYMBYTES + 1);
PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_enc(ct, buf, pk, k_coins_d + NEWHOPE_SYMBYTES); /* coins are in k_coins_d+NEWHOPE_SYMBYTES */
PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_enc(ct, buf + 1, pk, k_coins_d + NEWHOPE_SYMBYTES); /* coins are in k_coins_d+NEWHOPE_SYMBYTES */
for (i = 0; i < NEWHOPE_SYMBYTES; i++) {
ct[i + NEWHOPE_CPAPKE_CIPHERTEXTBYTES] = k_coins_d[i + 2 * NEWHOPE_SYMBYTES]; /* copy Targhi-Unruh hash into ct */
@ -89,18 +91,19 @@ int PQCLEAN_NEWHOPE512CCA_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char
int PQCLEAN_NEWHOPE512CCA_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk) {
int i, fail;
unsigned char ct_cmp[NEWHOPE_CCAKEM_CIPHERTEXTBYTES];
unsigned char buf[2 * NEWHOPE_SYMBYTES];
unsigned char buf[2 * NEWHOPE_SYMBYTES + 1];
unsigned char k_coins_d[3 * NEWHOPE_SYMBYTES]; /* Will contain key, coins, qrom-hash */
const unsigned char *pk = sk + NEWHOPE_CPAPKE_SECRETKEYBYTES;
PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_dec(buf, ct, sk);
buf[0] = 0x08;
PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_dec(buf + 1, ct, sk);
for (i = 0; i < NEWHOPE_SYMBYTES; i++) { /* Use hash of pk stored in sk */
buf[NEWHOPE_SYMBYTES + i] = sk[NEWHOPE_CCAKEM_SECRETKEYBYTES - 2 * NEWHOPE_SYMBYTES + i];
buf[1 + NEWHOPE_SYMBYTES + i] = sk[NEWHOPE_CCAKEM_SECRETKEYBYTES - 2 * NEWHOPE_SYMBYTES + i];
}
shake256(k_coins_d, 3 * NEWHOPE_SYMBYTES, buf, 2 * NEWHOPE_SYMBYTES);
shake256(k_coins_d, 3 * NEWHOPE_SYMBYTES, buf, 2 * NEWHOPE_SYMBYTES + 1);
PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_enc(ct_cmp, buf, pk, k_coins_d + NEWHOPE_SYMBYTES); /* coins are in k_coins_d+NEWHOPE_SYMBYTES */
PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_enc(ct_cmp, buf + 1, pk, k_coins_d + NEWHOPE_SYMBYTES); /* coins are in k_coins_d+NEWHOPE_SYMBYTES */
for (i = 0; i < NEWHOPE_SYMBYTES; i++) {
ct_cmp[i + NEWHOPE_CPAPKE_CIPHERTEXTBYTES] = k_coins_d[i + 2 * NEWHOPE_SYMBYTES];

View File

@ -1,24 +0,0 @@
Copyright (c) 2016-2019 Rambus, Inc.
and licensed under the following MIT license.
The MIT License (MIT)
Copyright (c) 2016-2019 Rambus Inc.
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.

View File

@ -1,18 +0,0 @@
#ifndef PQCLEAN_BABYBEAREPHEM_CLEAN_API_H
#define PQCLEAN_BABYBEAREPHEM_CLEAN_API_H
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#define PQCLEAN_BABYBEAREPHEM_CLEAN_CRYPTO_SECRETKEYBYTES 40
#define PQCLEAN_BABYBEAREPHEM_CLEAN_CRYPTO_PUBLICKEYBYTES 804
#define PQCLEAN_BABYBEAREPHEM_CLEAN_CRYPTO_BYTES 32
#define PQCLEAN_BABYBEAREPHEM_CLEAN_CRYPTO_CIPHERTEXTBYTES 917
#define PQCLEAN_BABYBEAREPHEM_CLEAN_CRYPTO_ALGNAME "BabyBearEphem"
int PQCLEAN_BABYBEAREPHEM_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk);
int PQCLEAN_BABYBEAREPHEM_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
int PQCLEAN_BABYBEAREPHEM_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
#endif

View File

@ -1,22 +0,0 @@
#include "api.h"
#include "params.h"
#include "randombytes.h"
#include "threebears.h"
int PQCLEAN_BABYBEAREPHEM_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) {
randombytes(sk, PRIVATE_KEY_BYTES);
PQCLEAN_BABYBEAREPHEM_CLEAN_get_pubkey(pk, sk);
return 0;
}
int PQCLEAN_BABYBEAREPHEM_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
uint8_t seed[ENC_SEED_BYTES + IV_BYTES];
randombytes(seed, sizeof(seed));
encapsulate(ss, ct, pk, seed);
return 0;
}
int PQCLEAN_BABYBEAREPHEM_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
PQCLEAN_BABYBEAREPHEM_CLEAN_decapsulate(ss, ct, sk);
return 0;
}

View File

@ -1,87 +0,0 @@
/* Melas forward error correction, reference code (as implemented in the paper) */
#include "melas_fec.h"
/* Return s/2^n mod R */
static fec_gf_t step(size_t n, fec_gf_t R, fec_gf_t s) {
for (; n; n--) {
s = (s ^ ((s & 1) * R)) >> 1;
}
return s;
}
/* Compute syndrome(data), where data has length len */
#define syndrome18(data,len) s18update(0,data,len)
static fec_gf_t s18update(fec_gf_t r, const uint8_t *data, size_t len) {
for (size_t i = 0; i < len; i++) {
r = step(8, 0x46231, r ^ data[i]);
}
return r;
}
/* Append 3 bytes of FEC(data) to data, so that the FEC becomes 0 */
void PQCLEAN_BABYBEAREPHEM_CLEAN_melas_fec_set(
uint8_t out[MELAS_FEC_BYTES],
const uint8_t *data,
size_t len
) {
fec_gf_t fec = syndrome18(data, len);
for (size_t i = 0; i < MELAS_FEC_BYTES; i++, fec >>= 8) {
out[i] = (uint8_t)fec;
}
}
/* Return a*b mod Q */
static fec_gf_t mul(fec_gf_t a, fec_gf_t b) {
fec_gf_t r = 0;
for (size_t i = 0; i < 9; i++) {
r ^= ((b >> (8 - i)) & 1) * a;
a = step(1, Q, a);
}
return r;
}
/* Reverse an 18-bit number x */
static fec_gf_t reverse18(fec_gf_t x) {
fec_gf_t ret = 0;
for (size_t i = 0; i < 18; i++) {
ret ^= ((x >> i) & 1) << (17 - i);
}
return ret;
}
/* Correct data to have the given FEC */
void PQCLEAN_BABYBEAREPHEM_CLEAN_melas_fec_correct (
uint8_t *data,
size_t len,
const uint8_t fec[MELAS_FEC_BYTES]
) {
fec_gf_t a = s18update(syndrome18(data, len), fec, MELAS_FEC_BYTES);
fec_gf_t c, r, htr;
size_t i;
const uint8_t table[9] = {36, 10, 43, 215, 52, 11, 116, 244, 0};
fec_gf_t e0, e1;
/* Form a quadratic equation from the syndrome */
c = mul(step(9, Q, a), step(9, Q, reverse18(a)));
for (i = 0, r = 0x100; i < 510; i++) {
r = mul(r, c);
}
r = step(17, Q, r);
a = step(511 - (len + MELAS_FEC_BYTES) * 8, Q, a);
/* Solve using the half trace */
for (i = 0, htr = 0; i < 9; i++) {
htr ^= ((r >> i) & 1) * table[i];
}
e0 = mul(a, htr);
e1 = e0 ^ a;
/* Correct the errors using the locators */
for (i = 0; i < len; i++) {
data[i] ^= (uint8_t)(e0 & (((e0 & (e0 - 1)) - 1) >> 9));
data[i] ^= (uint8_t)(e1 & (((e1 & (e1 - 1)) - 1) >> 9));
e0 = step(8, Q, e0);
e1 = step(8, Q, e1);
}
}

View File

@ -1,26 +0,0 @@
#ifndef __THREEBEARS_MELAS_FEC_H__
#define __THREEBEARS_MELAS_FEC_H__
#include "api.h"
#define MELAS_FEC_BYTES 3
#define MELAS_FEC_BITS 18
typedef uint32_t fec_gf_t;
static const fec_gf_t Q = 0x211;
/* Append 3 bytes of FEC(data) to data, so that the FEC becomes 0 */
void PQCLEAN_BABYBEAREPHEM_CLEAN_melas_fec_set(
uint8_t out[MELAS_FEC_BYTES],
const uint8_t *data,
size_t len
);
/* Append 3 bytes of FEC(data) to data, so that the FEC becomes 0 */
void PQCLEAN_BABYBEAREPHEM_CLEAN_melas_fec_correct(
uint8_t *data,
size_t len,
const uint8_t fec[MELAS_FEC_BYTES]
);
#endif

View File

@ -1,29 +0,0 @@
#ifndef __THREEBEARS_PARAMS_H__
#define __THREEBEARS_PARAMS_H__
#define VERSION 1
#define MATRIX_SEED_BYTES 24
#define ENC_SEED_BYTES 32
#define IV_BYTES 0
#define LGX 10
#define DIGITS 312
#define DIM 2
#define VAR_TIMES_128 128
#define LPR_BITS 4
#define FEC_BITS 18
#define CCA 0
#define SHARED_SECRET_BYTES 32
#define PRIVATE_KEY_BYTES 40
#define PRF_KEY_BYTES PRIVATE_KEY_BYTES
#define BEAR_NAME "BabyBearEphem"
#define encapsulate PQCLEAN_BABYBEAREPHEM_CLEAN_encapsulate
#define decapsulate PQCLEAN_BABYBEAREPHEM_CLEAN_decapsulate
#define get_pubkey PQCLEAN_BABYBEAREPHEM_CLEAN_get_pubkey
#define GF_BYTES ((LGX*DIGITS+7)/8)
#define PUBLIC_KEY_BYTES (MATRIX_SEED_BYTES + DIM*GF_BYTES)
#define CAPSULE_BYTES \
(DIM*GF_BYTES + IV_BYTES + ((ENC_SEED_BYTES*8+FEC_BITS)*LPR_BITS+7)/8)
#endif

View File

@ -1,107 +0,0 @@
/** Ring arithmetic implementation */
#include "ring.h"
/** Return the i'th limb of the modulus */
limb_t PQCLEAN_BABYBEAREPHEM_CLEAN_modulus(size_t i) {
return (i == DIGITS / 2) ? LMASK - 1 : LMASK;
}
/** Multiply and accumulate c += a*b */
void PQCLEAN_BABYBEAREPHEM_CLEAN_mac(gf_t c, const gf_t a, const gf_t b) {
/* Reference non-Karatsuba MAC */
dslimb_t accum[2 * DIGITS] = {0};
dslimb_t chain;
size_t i, j;
/* Initialize accumulator = unclarify(c) */
for (i = 0; i < DIGITS; i++) {
accum[i + DIGITS / 2] = c[i];
}
/* Multiply */
for (i = 0; i < DIGITS; i++) {
for (j = 0; j < DIGITS; j++) {
accum[i + j] += (dslimb_t)a[i] * b[j];
}
}
/* Clarify and reduce */
for (i = 0; i < DIGITS / 2; i++) {
accum[i + DIGITS / 2] -= accum[i];
accum[i + DIGITS] += accum[i];
accum[i + DIGITS / 2] += accum[i + 3 * DIGITS / 2];
accum[i + DIGITS] += accum[i + 3 * DIGITS / 2];
}
/* Carry propagate */
chain = accum[3 * DIGITS / 2 - 1];
accum[3 * DIGITS / 2 - 1] = chain & LMASK;
chain >>= LGX;
accum[DIGITS] += chain;
for (i = DIGITS / 2; i < 3 * DIGITS / 2; i++) {
chain += accum[i];
c[i - DIGITS / 2] = chain & LMASK;
chain >>= LGX;
}
c[0] = (limb_t) (c[0] + chain);
c[DIGITS / 2] = (limb_t) (c[DIGITS / 2] + chain);
}
/** Reduce a gf_t to canonical form, i.e. strictly less than N. */
void PQCLEAN_BABYBEAREPHEM_CLEAN_canon(gf_t c) {
const limb_t DELTA = (limb_t)1 << (LGX - 1);
slimb_t hi;
dslimb_t scarry;
dlimb_t carry;
/* Reduce to 0..2p */
hi = (slimb_t) (c[DIGITS - 1] - DELTA);
c[DIGITS - 1] = (limb_t) ((hi & LMASK) + DELTA);
c[DIGITS / 2] = (limb_t) (c[DIGITS / 2] + (hi >> LGX));
/* Strong reduce. First subtract modulus */
scarry = hi >> LGX;
for (size_t i = 0; i < DIGITS; i++) {
scarry = scarry + (slimb_t)c[i] - PQCLEAN_BABYBEAREPHEM_CLEAN_modulus(i);
c[i] = scarry & LMASK;
scarry >>= LGX;
}
/* add it back */
carry = 0;
for (size_t i = 0; i < DIGITS; i++) {
carry = carry + c[i] + ((dlimb_t)scarry & PQCLEAN_BABYBEAREPHEM_CLEAN_modulus(i));
c[i] = carry & LMASK;
carry >>= LGX;
}
}
/** Serialize a gf_t to bytes */
void PQCLEAN_BABYBEAREPHEM_CLEAN_contract(uint8_t ch[GF_BYTES], gf_t a) {
size_t pos;
PQCLEAN_BABYBEAREPHEM_CLEAN_canon(a);
for (size_t i = 0; i < GF_BYTES; i++) {
pos = (i * 8) / LGX;
ch[i] = (uint8_t)(a[pos] >> ((i * 8) % LGX));
if (i < GF_BYTES - 1) {
ch[i] |= (uint8_t)(a[pos + 1] << (LGX - ((i * 8) % LGX)));
}
}
}
/** Deserialize a gf_t from bytes */
void PQCLEAN_BABYBEAREPHEM_CLEAN_expand(gf_t ll, const uint8_t ch[GF_BYTES]) {
limb_t tmp, buffer = 0;
for (size_t i = 0, j = 0, bbits = 0; i < GF_BYTES; i++) {
tmp = ch[i];
buffer |= (limb_t)(tmp << bbits);
bbits += 8;
if (bbits >= LGX) {
ll[j++] = buffer & LMASK;
buffer = (limb_t)(tmp >> (LGX - (bbits - 8)));
bbits = bbits - LGX;
}
}
}

View File

@ -1,29 +0,0 @@
#ifndef __THREEBEARS_RING_H__
#define __THREEBEARS_RING_H__
#include "api.h"
#include "params.h"
typedef uint16_t limb_t;
typedef int16_t slimb_t;
typedef uint32_t dlimb_t;
typedef int32_t dslimb_t;
#define LMASK (((limb_t)1<<LGX)-1)
typedef limb_t gf_t[DIGITS];
/* Serialize a gf_t */
void PQCLEAN_BABYBEAREPHEM_CLEAN_contract(uint8_t ch[GF_BYTES], gf_t a);
/* Deserialize a gf_t */
void PQCLEAN_BABYBEAREPHEM_CLEAN_expand(gf_t ll, const uint8_t ch[GF_BYTES]);
/* Multiply and accumulate c = c + a*b */
void PQCLEAN_BABYBEAREPHEM_CLEAN_mac(gf_t c, const gf_t a, const gf_t b);
/* Reduce ring element to canonical form */
void PQCLEAN_BABYBEAREPHEM_CLEAN_canon(gf_t c);
/** Return the i'th limb of the modulus */
limb_t PQCLEAN_BABYBEAREPHEM_CLEAN_modulus(size_t i);
#endif

View File

@ -1,219 +0,0 @@
/** ThreeBears reference implementation */
#include "api.h"
#include "melas_fec.h"
#include "params.h"
#include "ring.h"
#include "sp800-185.h"
#include "threebears.h"
#define FEC_BYTES ((FEC_BITS+7)/8)
#define ENC_BITS (ENC_SEED_BYTES*8 + FEC_BITS)
enum { HASH_PURPOSE_UNIFORM = 0, HASH_PURPOSE_KEYGEN = 1, HASH_PURPOSE_ENCAPS = 2, HASH_PURPOSE_PRF = 3 };
/** Initialize the hash function with a given purpose */
static void threebears_hash_init(
shake256incctx *ctx,
uint8_t purpose
) {
const unsigned char S[] = "ThreeBears";
const uint8_t pblock[15] = {
VERSION, PRIVATE_KEY_BYTES, MATRIX_SEED_BYTES, ENC_SEED_BYTES,
IV_BYTES, SHARED_SECRET_BYTES, LGX, DIGITS & 0xFF, DIGITS >> 8, DIM,
VAR_TIMES_128 - 1, LPR_BITS, FEC_BITS, CCA, 0 /* padding */
};
cshake256_inc_init(ctx, NULL, 0, (const uint8_t *)S, sizeof(S) - 1);
cshake256_inc_absorb(ctx, (const uint8_t *)pblock, sizeof(pblock));
cshake256_inc_absorb(ctx, &purpose, 1);
}
/** Sample n gf_t's uniformly from a seed */
static void uniform(gf_t matrix, const uint8_t *seed, uint8_t iv) {
uint8_t c[GF_BYTES];
shake256incctx ctx;
threebears_hash_init(&ctx, HASH_PURPOSE_UNIFORM);
cshake256_inc_absorb(&ctx, seed, MATRIX_SEED_BYTES);
cshake256_inc_absorb(&ctx, &iv, 1);
cshake256_inc_finalize(&ctx);
cshake256_inc_squeeze(c, sizeof(c), &ctx);
cshake256_inc_ctx_release(&ctx);
PQCLEAN_BABYBEAREPHEM_CLEAN_expand(matrix, c);
}
/** The ThreeBears error distribution */
static slimb_t psi(uint8_t ci) {
int sample = 0, var = VAR_TIMES_128;
for (; var > 64; var -= 64, ci = (uint8_t)(ci << 2)) {
sample += ((ci + 64) >> 8) + ((ci - 64) >> 8);
}
return (slimb_t)(sample + ((ci + var) >> 8) + ((ci - var) >> 8));
}
/** Sample a vector of n noise elements */
static void noise(gf_t x, const shake256incctx *ctx, uint8_t iv) {
uint8_t c[DIGITS];
shake256incctx ctx2;
cshake256_inc_ctx_clone(&ctx2, ctx);
cshake256_inc_absorb(&ctx2, &iv, 1);
cshake256_inc_finalize(&ctx2);
cshake256_inc_squeeze(c, DIGITS, &ctx2);
for (size_t i = 0; i < DIGITS; i++) {
x[i] = (limb_t)(psi(c[i]) + PQCLEAN_BABYBEAREPHEM_CLEAN_modulus(i));
}
cshake256_inc_ctx_release(&ctx2);
}
/* Expand public key from private key */
void PQCLEAN_BABYBEAREPHEM_CLEAN_get_pubkey(uint8_t *pk, const uint8_t *sk) {
shake256incctx ctx;
shake256incctx ctx2;
gf_t sk_expanded[DIM], b, c;
threebears_hash_init(&ctx, HASH_PURPOSE_KEYGEN);
cshake256_inc_absorb(&ctx, sk, PRIVATE_KEY_BYTES);
cshake256_inc_ctx_clone(&ctx2, &ctx);
cshake256_inc_finalize(&ctx2);
cshake256_inc_squeeze(pk, MATRIX_SEED_BYTES, &ctx2);
cshake256_inc_ctx_release(&ctx2);
for (uint8_t i = 0; i < DIM; i++) {
noise(sk_expanded[i], &ctx, i);
}
for (uint8_t i = 0; i < DIM; i++) {
noise(c, &ctx, (uint8_t)(i + DIM));
for (uint8_t j = 0; j < DIM; j++) {
uniform(b, pk, (uint8_t) (i + DIM * j));
PQCLEAN_BABYBEAREPHEM_CLEAN_mac(c, b, sk_expanded[j]);
}
PQCLEAN_BABYBEAREPHEM_CLEAN_contract(&pk[MATRIX_SEED_BYTES + i * GF_BYTES], c);
}
cshake256_inc_ctx_release(&ctx);
}
/* Encapsulate a shared secret and return it */
void PQCLEAN_BABYBEAREPHEM_CLEAN_encapsulate(
uint8_t *shared_secret,
uint8_t *capsule,
const uint8_t *pk,
const uint8_t *seed
) {
uint8_t *lpr_data = &capsule[GF_BYTES * DIM];
shake256incctx ctx;
gf_t sk_expanded[DIM], b, c;
uint8_t tbi[ENC_SEED_BYTES + FEC_BYTES];
dlimb_t rlimb0, rlimb1;
limb_t h;
uint8_t *iv = &lpr_data[(ENC_BITS * LPR_BITS + 7) / 8];
memcpy(iv, &seed[ENC_SEED_BYTES], IV_BYTES);
threebears_hash_init(&ctx, HASH_PURPOSE_ENCAPS);
cshake256_inc_absorb(&ctx, pk, MATRIX_SEED_BYTES);
cshake256_inc_absorb(&ctx, seed, ENC_SEED_BYTES + IV_BYTES);
for (uint8_t i = 0; i < DIM; i++) {
noise(sk_expanded[i], &ctx, i);
}
for (uint8_t i = 0; i < DIM; i++) {
noise(c, &ctx, (uint8_t)(i + DIM));
for (uint8_t j = 0; j < DIM; j++) {
uniform(b, pk, (uint8_t)(j + DIM * i));
PQCLEAN_BABYBEAREPHEM_CLEAN_mac(c, b, sk_expanded[j]);
}
PQCLEAN_BABYBEAREPHEM_CLEAN_contract(&capsule[i * GF_BYTES], c);
}
noise(c, &ctx, (uint8_t)(2 * DIM));
/* Calculate approximate shared secret */
for (uint8_t i = 0; i < DIM; i++) {
PQCLEAN_BABYBEAREPHEM_CLEAN_expand(b, &pk[MATRIX_SEED_BYTES + i * GF_BYTES]);
PQCLEAN_BABYBEAREPHEM_CLEAN_mac(c, b, sk_expanded[i]);
}
PQCLEAN_BABYBEAREPHEM_CLEAN_canon(c);
cshake256_inc_finalize(&ctx);
cshake256_inc_squeeze(tbi, ENC_SEED_BYTES, &ctx);
cshake256_inc_ctx_release(&ctx);
threebears_hash_init(&ctx, HASH_PURPOSE_ENCAPS);
cshake256_inc_absorb(&ctx, pk, MATRIX_SEED_BYTES);
cshake256_inc_absorb(&ctx, tbi, ENC_SEED_BYTES);
cshake256_inc_absorb(&ctx, iv, IV_BYTES);
PQCLEAN_BABYBEAREPHEM_CLEAN_melas_fec_set(&tbi[ENC_SEED_BYTES], tbi, ENC_SEED_BYTES);
/* Export with rounding */
for (size_t i = 0; i < ENC_BITS; i += 2) {
h = (limb_t)(tbi[i / 8] >> (i % 8));
rlimb0 = (dlimb_t)((c[i / 2] >> (LGX - LPR_BITS)) + (h << 3));
rlimb1 = (dlimb_t)((c[DIGITS - i / 2 - 1] >> (LGX - LPR_BITS)) + ((h >> 1) << 3));
lpr_data[i / 2] = (uint8_t)((rlimb0 & 0xF) | rlimb1 << 4);
}
cshake256_inc_finalize(&ctx);
cshake256_inc_squeeze(shared_secret, SHARED_SECRET_BYTES, &ctx);
cshake256_inc_ctx_release(&ctx);
}
/* Decapsulate a shared secret and return it */
void PQCLEAN_BABYBEAREPHEM_CLEAN_decapsulate(
uint8_t shared_secret[SHARED_SECRET_BYTES],
const uint8_t capsule[CAPSULE_BYTES],
const uint8_t sk[PRIVATE_KEY_BYTES]
) {
const uint8_t *lpr_data = &capsule[GF_BYTES * DIM];
shake256incctx ctx;
gf_t ska, b, c = {0};
uint8_t seed[ENC_SEED_BYTES + FEC_BYTES + IV_BYTES];
limb_t rounding, out;
size_t j;
limb_t our_rlimb, their_rlimb, delta;
uint8_t matrix_seed[MATRIX_SEED_BYTES];
/* Calculate approximate shared secret */
threebears_hash_init(&ctx, HASH_PURPOSE_KEYGEN);
cshake256_inc_absorb(&ctx, sk, PRIVATE_KEY_BYTES);
for (uint8_t i = 0; i < DIM; i++) {
PQCLEAN_BABYBEAREPHEM_CLEAN_expand(b, &capsule[i * GF_BYTES]);
noise(ska, &ctx, i);
PQCLEAN_BABYBEAREPHEM_CLEAN_mac(c, ska, b);
}
/* Recover seed from LPR data */
PQCLEAN_BABYBEAREPHEM_CLEAN_canon(c);
rounding = 1 << (LPR_BITS - 1);
out = 0;
for (int32_t i = ENC_BITS - 1; i >= 0; i--) {
j = (size_t) ((i & 1) ? DIGITS - i / 2 - 1 : i / 2);
our_rlimb = (limb_t)(c[j] >> (LGX - LPR_BITS - 1));
their_rlimb = (limb_t)(lpr_data[i * LPR_BITS / 8] >> ((i * LPR_BITS) % 8));
delta = (limb_t)(their_rlimb * 2 - our_rlimb + rounding);
out |= (limb_t)(((delta >> LPR_BITS) & 1) << (i % 8));
if (i % 8 == 0) {
seed[i / 8] = (uint8_t)out;
out = 0;
}
}
PQCLEAN_BABYBEAREPHEM_CLEAN_melas_fec_correct(seed, ENC_SEED_BYTES, &seed[ENC_SEED_BYTES]);
/* Recalculate matrix seed */
cshake256_inc_finalize(&ctx);
cshake256_inc_squeeze(matrix_seed, MATRIX_SEED_BYTES, &ctx);
cshake256_inc_ctx_release(&ctx);
/* Re-run the key derivation from encaps */
threebears_hash_init(&ctx, HASH_PURPOSE_ENCAPS);
cshake256_inc_absorb(&ctx, matrix_seed, MATRIX_SEED_BYTES);
cshake256_inc_absorb(&ctx, seed, ENC_SEED_BYTES);
cshake256_inc_absorb(&ctx, &lpr_data[(ENC_BITS * LPR_BITS + 7) / 8], IV_BYTES);
cshake256_inc_finalize(&ctx);
cshake256_inc_squeeze(shared_secret, SHARED_SECRET_BYTES, &ctx);
cshake256_inc_ctx_release(&ctx);
}

View File

@ -1,60 +0,0 @@
#ifndef __THREE_BEARS_BABYBEAREPHEM_H__
#define __THREE_BEARS_BABYBEAREPHEM_H__
#include <stddef.h> /* for size_t */
#include <stdint.h>
#define BABYBEAREPHEM_KEYGEN_SEED_BYTES 40
#define BABYBEAREPHEM_PRIVATE_KEY_BYTES BABYBEAREPHEM_KEYGEN_SEED_BYTES
#define BABYBEAREPHEM_SHARED_SECRET_BYTES 32
#define BABYBEAREPHEM_ENC_SEED_AND_IV_BYTES 32
#define BABYBEAREPHEM_PUBLIC_KEY_BYTES 804
#define BABYBEAREPHEM_CAPSULE_BYTES 917
/**
* Expand a secret seed to a public/private keypair.
*
* @param[out] pk The public key.
* @param[in] sk The private key, which must be uniformly random.
*/
void PQCLEAN_BABYBEAREPHEM_CLEAN_get_pubkey (
uint8_t pk[BABYBEAREPHEM_PUBLIC_KEY_BYTES],
const uint8_t sk[BABYBEAREPHEM_PRIVATE_KEY_BYTES]
);
/**
* Create a shared secret using a random seed and another party's public key.
*
* Input and output parameters may not alias.
*
* @param[out] shared_secret The shared secret key.
* @param[out] capsule A ciphertext to send to the other party.
* @param[in] pk The other party's public key.
* @param[in] seed A random seed.
*/
void PQCLEAN_BABYBEAREPHEM_CLEAN_encapsulate (
uint8_t shared_secret[BABYBEAREPHEM_SHARED_SECRET_BYTES],
uint8_t capsule[BABYBEAREPHEM_CAPSULE_BYTES],
const uint8_t pk[BABYBEAREPHEM_PUBLIC_KEY_BYTES],
const uint8_t seed[BABYBEAREPHEM_ENC_SEED_AND_IV_BYTES]
);
/**
* Extract the shared secret from a capsule using the private key.
* Has a negligible but nonzero probability of failure.
*
* Input and output parameters may not alias.
*
* @param[out] shared_secret The shared secret.
* @param[in] capsule The capsule produced by encapsulate_cca2.
* @param[in] sk The private key.
* @return -1 on failure, 0 on success.
* @warning The value of shared_secret must not be used on failure
*/
void PQCLEAN_BABYBEAREPHEM_CLEAN_decapsulate (
uint8_t shared_secret[BABYBEAREPHEM_SHARED_SECRET_BYTES],
const uint8_t capsule[BABYBEAREPHEM_CAPSULE_BYTES],
const uint8_t sk[BABYBEAREPHEM_PRIVATE_KEY_BYTES]
);
#endif

View File

@ -1,24 +0,0 @@
Copyright (c) 2016-2019 Rambus, Inc.
and licensed under the following MIT license.
The MIT License (MIT)
Copyright (c) 2016-2019 Rambus Inc.
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.

View File

@ -1,18 +0,0 @@
#ifndef PQCLEAN_MAMABEAREPHEM_CLEAN_API_H
#define PQCLEAN_MAMABEAREPHEM_CLEAN_API_H
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#define PQCLEAN_MAMABEAREPHEM_CLEAN_CRYPTO_SECRETKEYBYTES 40
#define PQCLEAN_MAMABEAREPHEM_CLEAN_CRYPTO_PUBLICKEYBYTES 1194
#define PQCLEAN_MAMABEAREPHEM_CLEAN_CRYPTO_BYTES 32
#define PQCLEAN_MAMABEAREPHEM_CLEAN_CRYPTO_CIPHERTEXTBYTES 1307
#define PQCLEAN_MAMABEAREPHEM_CLEAN_CRYPTO_ALGNAME "MamaBearEphem"
int PQCLEAN_MAMABEAREPHEM_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk);
int PQCLEAN_MAMABEAREPHEM_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
int PQCLEAN_MAMABEAREPHEM_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
#endif

View File

@ -1,22 +0,0 @@
#include "api.h"
#include "params.h"
#include "randombytes.h"
#include "threebears.h"
int PQCLEAN_MAMABEAREPHEM_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) {
randombytes(sk, PRIVATE_KEY_BYTES);
PQCLEAN_MAMABEAREPHEM_CLEAN_get_pubkey(pk, sk);
return 0;
}
int PQCLEAN_MAMABEAREPHEM_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
uint8_t seed[ENC_SEED_BYTES + IV_BYTES];
randombytes(seed, sizeof(seed));
encapsulate(ss, ct, pk, seed);
return 0;
}
int PQCLEAN_MAMABEAREPHEM_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
PQCLEAN_MAMABEAREPHEM_CLEAN_decapsulate(ss, ct, sk);
return 0;
}

View File

@ -1,87 +0,0 @@
/* Melas forward error correction, reference code (as implemented in the paper) */
#include "melas_fec.h"
/* Return s/2^n mod R */
static fec_gf_t step(size_t n, fec_gf_t R, fec_gf_t s) {
for (; n; n--) {
s = (s ^ ((s & 1) * R)) >> 1;
}
return s;
}
/* Compute syndrome(data), where data has length len */
#define syndrome18(data,len) s18update(0,data,len)
static fec_gf_t s18update(fec_gf_t r, const uint8_t *data, size_t len) {
for (size_t i = 0; i < len; i++) {
r = step(8, 0x46231, r ^ data[i]);
}
return r;
}
/* Append 3 bytes of FEC(data) to data, so that the FEC becomes 0 */
void PQCLEAN_MAMABEAREPHEM_CLEAN_melas_fec_set(
uint8_t out[MELAS_FEC_BYTES],
const uint8_t *data,
size_t len
) {
fec_gf_t fec = syndrome18(data, len);
for (size_t i = 0; i < MELAS_FEC_BYTES; i++, fec >>= 8) {
out[i] = (uint8_t)fec;
}
}
/* Return a*b mod Q */
static fec_gf_t mul(fec_gf_t a, fec_gf_t b) {
fec_gf_t r = 0;
for (size_t i = 0; i < 9; i++) {
r ^= ((b >> (8 - i)) & 1) * a;
a = step(1, Q, a);
}
return r;
}
/* Reverse an 18-bit number x */
static fec_gf_t reverse18(fec_gf_t x) {
fec_gf_t ret = 0;
for (size_t i = 0; i < 18; i++) {
ret ^= ((x >> i) & 1) << (17 - i);
}
return ret;
}
/* Correct data to have the given FEC */
void PQCLEAN_MAMABEAREPHEM_CLEAN_melas_fec_correct (
uint8_t *data,
size_t len,
const uint8_t fec[MELAS_FEC_BYTES]
) {
fec_gf_t a = s18update(syndrome18(data, len), fec, MELAS_FEC_BYTES);
fec_gf_t c, r, htr;
size_t i;
const uint8_t table[9] = {36, 10, 43, 215, 52, 11, 116, 244, 0};
fec_gf_t e0, e1;
/* Form a quadratic equation from the syndrome */
c = mul(step(9, Q, a), step(9, Q, reverse18(a)));
for (i = 0, r = 0x100; i < 510; i++) {
r = mul(r, c);
}
r = step(17, Q, r);
a = step(511 - (len + MELAS_FEC_BYTES) * 8, Q, a);
/* Solve using the half trace */
for (i = 0, htr = 0; i < 9; i++) {
htr ^= ((r >> i) & 1) * table[i];
}
e0 = mul(a, htr);
e1 = e0 ^ a;
/* Correct the errors using the locators */
for (i = 0; i < len; i++) {
data[i] ^= (uint8_t)(e0 & (((e0 & (e0 - 1)) - 1) >> 9));
data[i] ^= (uint8_t)(e1 & (((e1 & (e1 - 1)) - 1) >> 9));
e0 = step(8, Q, e0);
e1 = step(8, Q, e1);
}
}

View File

@ -1,26 +0,0 @@
#ifndef __THREEBEARS_MELAS_FEC_H__
#define __THREEBEARS_MELAS_FEC_H__
#include "api.h"
#define MELAS_FEC_BYTES 3
#define MELAS_FEC_BITS 18
typedef uint32_t fec_gf_t;
static const fec_gf_t Q = 0x211;
/* Append 3 bytes of FEC(data) to data, so that the FEC becomes 0 */
void PQCLEAN_MAMABEAREPHEM_CLEAN_melas_fec_set(
uint8_t out[MELAS_FEC_BYTES],
const uint8_t *data,
size_t len
);
/* Append 3 bytes of FEC(data) to data, so that the FEC becomes 0 */
void PQCLEAN_MAMABEAREPHEM_CLEAN_melas_fec_correct(
uint8_t *data,
size_t len,
const uint8_t fec[MELAS_FEC_BYTES]
);
#endif

View File

@ -1,29 +0,0 @@
#ifndef __THREEBEARS_PARAMS_H__
#define __THREEBEARS_PARAMS_H__
#define VERSION 1
#define MATRIX_SEED_BYTES 24
#define ENC_SEED_BYTES 32
#define IV_BYTES 0
#define LGX 10
#define DIGITS 312
#define DIM 3
#define VAR_TIMES_128 112
#define LPR_BITS 4
#define FEC_BITS 18
#define CCA 0
#define SHARED_SECRET_BYTES 32
#define PRIVATE_KEY_BYTES 40
#define PRF_KEY_BYTES PRIVATE_KEY_BYTES
#define BEAR_NAME "MamaBearEphem"
#define encapsulate PQCLEAN_MAMABEAREPHEM_CLEAN_encapsulate
#define decapsulate PQCLEAN_MAMABEAREPHEM_CLEAN_decapsulate
#define get_pubkey PQCLEAN_MAMABEAREPHEM_CLEAN_get_pubkey
#define GF_BYTES ((LGX*DIGITS+7)/8)
#define PUBLIC_KEY_BYTES (MATRIX_SEED_BYTES + DIM*GF_BYTES)
#define CAPSULE_BYTES \
(DIM*GF_BYTES + IV_BYTES + ((ENC_SEED_BYTES*8+FEC_BITS)*LPR_BITS+7)/8)
#endif

View File

@ -1,107 +0,0 @@
/** Ring arithmetic implementation */
#include "ring.h"
/** Return the i'th limb of the modulus */
limb_t PQCLEAN_MAMABEAREPHEM_CLEAN_modulus(size_t i) {
return (i == DIGITS / 2) ? LMASK - 1 : LMASK;
}
/** Multiply and accumulate c += a*b */
void PQCLEAN_MAMABEAREPHEM_CLEAN_mac(gf_t c, const gf_t a, const gf_t b) {
/* Reference non-Karatsuba MAC */
dslimb_t accum[2 * DIGITS] = {0};
dslimb_t chain;
size_t i, j;
/* Initialize accumulator = unclarify(c) */
for (i = 0; i < DIGITS; i++) {
accum[i + DIGITS / 2] = c[i];
}
/* Multiply */
for (i = 0; i < DIGITS; i++) {
for (j = 0; j < DIGITS; j++) {
accum[i + j] += (dslimb_t)a[i] * b[j];
}
}
/* Clarify and reduce */
for (i = 0; i < DIGITS / 2; i++) {
accum[i + DIGITS / 2] -= accum[i];
accum[i + DIGITS] += accum[i];
accum[i + DIGITS / 2] += accum[i + 3 * DIGITS / 2];
accum[i + DIGITS] += accum[i + 3 * DIGITS / 2];
}
/* Carry propagate */
chain = accum[3 * DIGITS / 2 - 1];
accum[3 * DIGITS / 2 - 1] = chain & LMASK;
chain >>= LGX;
accum[DIGITS] += chain;
for (i = DIGITS / 2; i < 3 * DIGITS / 2; i++) {
chain += accum[i];
c[i - DIGITS / 2] = chain & LMASK;
chain >>= LGX;
}
c[0] = (limb_t) (c[0] + chain);
c[DIGITS / 2] = (limb_t) (c[DIGITS / 2] + chain);
}
/** Reduce a gf_t to canonical form, i.e. strictly less than N. */
void PQCLEAN_MAMABEAREPHEM_CLEAN_canon(gf_t c) {
const limb_t DELTA = (limb_t)1 << (LGX - 1);
slimb_t hi;
dslimb_t scarry;
dlimb_t carry;
/* Reduce to 0..2p */
hi = (slimb_t) (c[DIGITS - 1] - DELTA);
c[DIGITS - 1] = (limb_t) ((hi & LMASK) + DELTA);
c[DIGITS / 2] = (limb_t) (c[DIGITS / 2] + (hi >> LGX));
/* Strong reduce. First subtract modulus */
scarry = hi >> LGX;
for (size_t i = 0; i < DIGITS; i++) {
scarry = scarry + (slimb_t)c[i] - PQCLEAN_MAMABEAREPHEM_CLEAN_modulus(i);
c[i] = scarry & LMASK;
scarry >>= LGX;
}
/* add it back */
carry = 0;
for (size_t i = 0; i < DIGITS; i++) {
carry = carry + c[i] + ((dlimb_t)scarry & PQCLEAN_MAMABEAREPHEM_CLEAN_modulus(i));
c[i] = carry & LMASK;
carry >>= LGX;
}
}
/** Serialize a gf_t to bytes */
void PQCLEAN_MAMABEAREPHEM_CLEAN_contract(uint8_t ch[GF_BYTES], gf_t a) {
size_t pos;
PQCLEAN_MAMABEAREPHEM_CLEAN_canon(a);
for (size_t i = 0; i < GF_BYTES; i++) {
pos = (i * 8) / LGX;
ch[i] = (uint8_t)(a[pos] >> ((i * 8) % LGX));
if (i < GF_BYTES - 1) {
ch[i] |= (uint8_t)(a[pos + 1] << (LGX - ((i * 8) % LGX)));
}
}
}
/** Deserialize a gf_t from bytes */
void PQCLEAN_MAMABEAREPHEM_CLEAN_expand(gf_t ll, const uint8_t ch[GF_BYTES]) {
limb_t tmp, buffer = 0;
for (size_t i = 0, j = 0, bbits = 0; i < GF_BYTES; i++) {
tmp = ch[i];
buffer |= (limb_t)(tmp << bbits);
bbits += 8;
if (bbits >= LGX) {
ll[j++] = buffer & LMASK;
buffer = (limb_t)(tmp >> (LGX - (bbits - 8)));
bbits = bbits - LGX;
}
}
}

View File

@ -1,29 +0,0 @@
#ifndef __THREEBEARS_RING_H__
#define __THREEBEARS_RING_H__
#include "api.h"
#include "params.h"
typedef uint16_t limb_t;
typedef int16_t slimb_t;
typedef uint32_t dlimb_t;
typedef int32_t dslimb_t;
#define LMASK (((limb_t)1<<LGX)-1)
typedef limb_t gf_t[DIGITS];
/* Serialize a gf_t */
void PQCLEAN_MAMABEAREPHEM_CLEAN_contract(uint8_t ch[GF_BYTES], gf_t a);
/* Deserialize a gf_t */
void PQCLEAN_MAMABEAREPHEM_CLEAN_expand(gf_t ll, const uint8_t ch[GF_BYTES]);
/* Multiply and accumulate c = c + a*b */
void PQCLEAN_MAMABEAREPHEM_CLEAN_mac(gf_t c, const gf_t a, const gf_t b);
/* Reduce ring element to canonical form */
void PQCLEAN_MAMABEAREPHEM_CLEAN_canon(gf_t c);
/** Return the i'th limb of the modulus */
limb_t PQCLEAN_MAMABEAREPHEM_CLEAN_modulus(size_t i);
#endif

View File

@ -1,219 +0,0 @@
/** ThreeBears reference implementation */
#include "api.h"
#include "melas_fec.h"
#include "params.h"
#include "ring.h"
#include "sp800-185.h"
#include "threebears.h"
#define FEC_BYTES ((FEC_BITS+7)/8)
#define ENC_BITS (ENC_SEED_BYTES*8 + FEC_BITS)
enum { HASH_PURPOSE_UNIFORM = 0, HASH_PURPOSE_KEYGEN = 1, HASH_PURPOSE_ENCAPS = 2, HASH_PURPOSE_PRF = 3 };
/** Initialize the hash function with a given purpose */
static void threebears_hash_init(
shake256incctx *ctx,
uint8_t purpose
) {
const unsigned char S[] = "ThreeBears";
const uint8_t pblock[15] = {
VERSION, PRIVATE_KEY_BYTES, MATRIX_SEED_BYTES, ENC_SEED_BYTES,
IV_BYTES, SHARED_SECRET_BYTES, LGX, DIGITS & 0xFF, DIGITS >> 8, DIM,
VAR_TIMES_128 - 1, LPR_BITS, FEC_BITS, CCA, 0 /* padding */
};
cshake256_inc_init(ctx, NULL, 0, (const uint8_t *)S, sizeof(S) - 1);
cshake256_inc_absorb(ctx, (const uint8_t *)pblock, sizeof(pblock));
cshake256_inc_absorb(ctx, &purpose, 1);
}
/** Sample n gf_t's uniformly from a seed */
static void uniform(gf_t matrix, const uint8_t *seed, uint8_t iv) {
uint8_t c[GF_BYTES];
shake256incctx ctx;
threebears_hash_init(&ctx, HASH_PURPOSE_UNIFORM);
cshake256_inc_absorb(&ctx, seed, MATRIX_SEED_BYTES);
cshake256_inc_absorb(&ctx, &iv, 1);
cshake256_inc_finalize(&ctx);
cshake256_inc_squeeze(c, sizeof(c), &ctx);
cshake256_inc_ctx_release(&ctx);
PQCLEAN_MAMABEAREPHEM_CLEAN_expand(matrix, c);
}
/** The ThreeBears error distribution */
static slimb_t psi(uint8_t ci) {
int sample = 0, var = VAR_TIMES_128;
for (; var > 64; var -= 64, ci = (uint8_t)(ci << 2)) {
sample += ((ci + 64) >> 8) + ((ci - 64) >> 8);
}
return (slimb_t)(sample + ((ci + var) >> 8) + ((ci - var) >> 8));
}
/** Sample a vector of n noise elements */
static void noise(gf_t x, const shake256incctx *ctx, uint8_t iv) {
uint8_t c[DIGITS];
shake256incctx ctx2;
cshake256_inc_ctx_clone(&ctx2, ctx);
cshake256_inc_absorb(&ctx2, &iv, 1);
cshake256_inc_finalize(&ctx2);
cshake256_inc_squeeze(c, DIGITS, &ctx2);
for (size_t i = 0; i < DIGITS; i++) {
x[i] = (limb_t)(psi(c[i]) + PQCLEAN_MAMABEAREPHEM_CLEAN_modulus(i));
}
cshake256_inc_ctx_release(&ctx2);
}
/* Expand public key from private key */
void PQCLEAN_MAMABEAREPHEM_CLEAN_get_pubkey(uint8_t *pk, const uint8_t *sk) {
shake256incctx ctx;
shake256incctx ctx2;
gf_t sk_expanded[DIM], b, c;
threebears_hash_init(&ctx, HASH_PURPOSE_KEYGEN);
cshake256_inc_absorb(&ctx, sk, PRIVATE_KEY_BYTES);
cshake256_inc_ctx_clone(&ctx2, &ctx);
cshake256_inc_finalize(&ctx2);
cshake256_inc_squeeze(pk, MATRIX_SEED_BYTES, &ctx2);
cshake256_inc_ctx_release(&ctx2);
for (uint8_t i = 0; i < DIM; i++) {
noise(sk_expanded[i], &ctx, i);
}
for (uint8_t i = 0; i < DIM; i++) {
noise(c, &ctx, (uint8_t)(i + DIM));
for (uint8_t j = 0; j < DIM; j++) {
uniform(b, pk, (uint8_t) (i + DIM * j));
PQCLEAN_MAMABEAREPHEM_CLEAN_mac(c, b, sk_expanded[j]);
}
PQCLEAN_MAMABEAREPHEM_CLEAN_contract(&pk[MATRIX_SEED_BYTES + i * GF_BYTES], c);
}
cshake256_inc_ctx_release(&ctx);
}
/* Encapsulate a shared secret and return it */
void PQCLEAN_MAMABEAREPHEM_CLEAN_encapsulate(
uint8_t *shared_secret,
uint8_t *capsule,
const uint8_t *pk,
const uint8_t *seed
) {
uint8_t *lpr_data = &capsule[GF_BYTES * DIM];
shake256incctx ctx;
gf_t sk_expanded[DIM], b, c;
uint8_t tbi[ENC_SEED_BYTES + FEC_BYTES];
dlimb_t rlimb0, rlimb1;
limb_t h;
uint8_t *iv = &lpr_data[(ENC_BITS * LPR_BITS + 7) / 8];
memcpy(iv, &seed[ENC_SEED_BYTES], IV_BYTES);
threebears_hash_init(&ctx, HASH_PURPOSE_ENCAPS);
cshake256_inc_absorb(&ctx, pk, MATRIX_SEED_BYTES);
cshake256_inc_absorb(&ctx, seed, ENC_SEED_BYTES + IV_BYTES);
for (uint8_t i = 0; i < DIM; i++) {
noise(sk_expanded[i], &ctx, i);
}
for (uint8_t i = 0; i < DIM; i++) {
noise(c, &ctx, (uint8_t)(i + DIM));
for (uint8_t j = 0; j < DIM; j++) {
uniform(b, pk, (uint8_t)(j + DIM * i));
PQCLEAN_MAMABEAREPHEM_CLEAN_mac(c, b, sk_expanded[j]);
}
PQCLEAN_MAMABEAREPHEM_CLEAN_contract(&capsule[i * GF_BYTES], c);
}
noise(c, &ctx, (uint8_t)(2 * DIM));
/* Calculate approximate shared secret */
for (uint8_t i = 0; i < DIM; i++) {
PQCLEAN_MAMABEAREPHEM_CLEAN_expand(b, &pk[MATRIX_SEED_BYTES + i * GF_BYTES]);
PQCLEAN_MAMABEAREPHEM_CLEAN_mac(c, b, sk_expanded[i]);
}
PQCLEAN_MAMABEAREPHEM_CLEAN_canon(c);
cshake256_inc_finalize(&ctx);
cshake256_inc_squeeze(tbi, ENC_SEED_BYTES, &ctx);
cshake256_inc_ctx_release(&ctx);
threebears_hash_init(&ctx, HASH_PURPOSE_ENCAPS);
cshake256_inc_absorb(&ctx, pk, MATRIX_SEED_BYTES);
cshake256_inc_absorb(&ctx, tbi, ENC_SEED_BYTES);
cshake256_inc_absorb(&ctx, iv, IV_BYTES);
PQCLEAN_MAMABEAREPHEM_CLEAN_melas_fec_set(&tbi[ENC_SEED_BYTES], tbi, ENC_SEED_BYTES);
/* Export with rounding */
for (size_t i = 0; i < ENC_BITS; i += 2) {
h = (limb_t)(tbi[i / 8] >> (i % 8));
rlimb0 = (dlimb_t)((c[i / 2] >> (LGX - LPR_BITS)) + (h << 3));
rlimb1 = (dlimb_t)((c[DIGITS - i / 2 - 1] >> (LGX - LPR_BITS)) + ((h >> 1) << 3));
lpr_data[i / 2] = (uint8_t)((rlimb0 & 0xF) | rlimb1 << 4);
}
cshake256_inc_finalize(&ctx);
cshake256_inc_squeeze(shared_secret, SHARED_SECRET_BYTES, &ctx);
cshake256_inc_ctx_release(&ctx);
}
/* Decapsulate a shared secret and return it */
void PQCLEAN_MAMABEAREPHEM_CLEAN_decapsulate(
uint8_t shared_secret[SHARED_SECRET_BYTES],
const uint8_t capsule[CAPSULE_BYTES],
const uint8_t sk[PRIVATE_KEY_BYTES]
) {
const uint8_t *lpr_data = &capsule[GF_BYTES * DIM];
shake256incctx ctx;
gf_t ska, b, c = {0};
uint8_t seed[ENC_SEED_BYTES + FEC_BYTES + IV_BYTES];
limb_t rounding, out;
size_t j;
limb_t our_rlimb, their_rlimb, delta;
uint8_t matrix_seed[MATRIX_SEED_BYTES];
/* Calculate approximate shared secret */
threebears_hash_init(&ctx, HASH_PURPOSE_KEYGEN);
cshake256_inc_absorb(&ctx, sk, PRIVATE_KEY_BYTES);
for (uint8_t i = 0; i < DIM; i++) {
PQCLEAN_MAMABEAREPHEM_CLEAN_expand(b, &capsule[i * GF_BYTES]);
noise(ska, &ctx, i);
PQCLEAN_MAMABEAREPHEM_CLEAN_mac(c, ska, b);
}
/* Recover seed from LPR data */
PQCLEAN_MAMABEAREPHEM_CLEAN_canon(c);
rounding = 1 << (LPR_BITS - 1);
out = 0;
for (int32_t i = ENC_BITS - 1; i >= 0; i--) {
j = (size_t) ((i & 1) ? DIGITS - i / 2 - 1 : i / 2);
our_rlimb = (limb_t)(c[j] >> (LGX - LPR_BITS - 1));
their_rlimb = (limb_t)(lpr_data[i * LPR_BITS / 8] >> ((i * LPR_BITS) % 8));
delta = (limb_t)(their_rlimb * 2 - our_rlimb + rounding);
out |= (limb_t)(((delta >> LPR_BITS) & 1) << (i % 8));
if (i % 8 == 0) {
seed[i / 8] = (uint8_t)out;
out = 0;
}
}
PQCLEAN_MAMABEAREPHEM_CLEAN_melas_fec_correct(seed, ENC_SEED_BYTES, &seed[ENC_SEED_BYTES]);
/* Recalculate matrix seed */
cshake256_inc_finalize(&ctx);
cshake256_inc_squeeze(matrix_seed, MATRIX_SEED_BYTES, &ctx);
cshake256_inc_ctx_release(&ctx);
/* Re-run the key derivation from encaps */
threebears_hash_init(&ctx, HASH_PURPOSE_ENCAPS);
cshake256_inc_absorb(&ctx, matrix_seed, MATRIX_SEED_BYTES);
cshake256_inc_absorb(&ctx, seed, ENC_SEED_BYTES);
cshake256_inc_absorb(&ctx, &lpr_data[(ENC_BITS * LPR_BITS + 7) / 8], IV_BYTES);
cshake256_inc_finalize(&ctx);
cshake256_inc_squeeze(shared_secret, SHARED_SECRET_BYTES, &ctx);
cshake256_inc_ctx_release(&ctx);
}

View File

@ -1,60 +0,0 @@
#ifndef __THREE_BEARS_MAMABEAREPHEM_H__
#define __THREE_BEARS_MAMABEAREPHEM_H__
#include <stddef.h> /* for size_t */
#include <stdint.h>
#define MAMABEAREPHEM_KEYGEN_SEED_BYTES 40
#define MAMABEAREPHEM_PRIVATE_KEY_BYTES MAMABEAREPHEM_KEYGEN_SEED_BYTES
#define MAMABEAREPHEM_SHARED_SECRET_BYTES 32
#define MAMABEAREPHEM_ENC_SEED_AND_IV_BYTES 32
#define MAMABEAREPHEM_PUBLIC_KEY_BYTES 1194
#define MAMABEAREPHEM_CAPSULE_BYTES 1307
/**
* Expand a secret seed to a public/private keypair.
*
* @param[out] pk The public key.
* @param[in] sk The private key, which must be uniformly random.
*/
void PQCLEAN_MAMABEAREPHEM_CLEAN_get_pubkey (
uint8_t pk[MAMABEAREPHEM_PUBLIC_KEY_BYTES],
const uint8_t sk[MAMABEAREPHEM_PRIVATE_KEY_BYTES]
);
/**
* Create a shared secret using a random seed and another party's public key.
*
* Input and output parameters may not alias.
*
* @param[out] shared_secret The shared secret key.
* @param[out] capsule A ciphertext to send to the other party.
* @param[in] pk The other party's public key.
* @param[in] seed A random seed.
*/
void PQCLEAN_MAMABEAREPHEM_CLEAN_encapsulate (
uint8_t shared_secret[MAMABEAREPHEM_SHARED_SECRET_BYTES],
uint8_t capsule[MAMABEAREPHEM_CAPSULE_BYTES],
const uint8_t pk[MAMABEAREPHEM_PUBLIC_KEY_BYTES],
const uint8_t seed[MAMABEAREPHEM_ENC_SEED_AND_IV_BYTES]
);
/**
* Extract the shared secret from a capsule using the private key.
* Has a negligible but nonzero probability of failure.
*
* Input and output parameters may not alias.
*
* @param[out] shared_secret The shared secret.
* @param[in] capsule The capsule produced by encapsulate_cca2.
* @param[in] sk The private key.
* @return -1 on failure, 0 on success.
* @warning The value of shared_secret must not be used on failure
*/
void PQCLEAN_MAMABEAREPHEM_CLEAN_decapsulate (
uint8_t shared_secret[MAMABEAREPHEM_SHARED_SECRET_BYTES],
const uint8_t capsule[MAMABEAREPHEM_CAPSULE_BYTES],
const uint8_t sk[MAMABEAREPHEM_PRIVATE_KEY_BYTES]
);
#endif

View File

@ -1,24 +0,0 @@
Copyright (c) 2016-2019 Rambus, Inc.
and licensed under the following MIT license.
The MIT License (MIT)
Copyright (c) 2016-2019 Rambus Inc.
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.

View File

@ -1,18 +0,0 @@
#ifndef PQCLEAN_PAPABEAREPHEM_CLEAN_API_H
#define PQCLEAN_PAPABEAREPHEM_CLEAN_API_H
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#define PQCLEAN_PAPABEAREPHEM_CLEAN_CRYPTO_SECRETKEYBYTES 40
#define PQCLEAN_PAPABEAREPHEM_CLEAN_CRYPTO_PUBLICKEYBYTES 1584
#define PQCLEAN_PAPABEAREPHEM_CLEAN_CRYPTO_BYTES 32
#define PQCLEAN_PAPABEAREPHEM_CLEAN_CRYPTO_CIPHERTEXTBYTES 1697
#define PQCLEAN_PAPABEAREPHEM_CLEAN_CRYPTO_ALGNAME "PapaBearEphem"
int PQCLEAN_PAPABEAREPHEM_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk);
int PQCLEAN_PAPABEAREPHEM_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
int PQCLEAN_PAPABEAREPHEM_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
#endif

View File

@ -1,22 +0,0 @@
#include "api.h"
#include "params.h"
#include "randombytes.h"
#include "threebears.h"
int PQCLEAN_PAPABEAREPHEM_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) {
randombytes(sk, PRIVATE_KEY_BYTES);
PQCLEAN_PAPABEAREPHEM_CLEAN_get_pubkey(pk, sk);
return 0;
}
int PQCLEAN_PAPABEAREPHEM_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
uint8_t seed[ENC_SEED_BYTES + IV_BYTES];
randombytes(seed, sizeof(seed));
encapsulate(ss, ct, pk, seed);
return 0;
}
int PQCLEAN_PAPABEAREPHEM_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
PQCLEAN_PAPABEAREPHEM_CLEAN_decapsulate(ss, ct, sk);
return 0;
}

View File

@ -1,87 +0,0 @@
/* Melas forward error correction, reference code (as implemented in the paper) */
#include "melas_fec.h"
/* Return s/2^n mod R */
static fec_gf_t step(size_t n, fec_gf_t R, fec_gf_t s) {
for (; n; n--) {
s = (s ^ ((s & 1) * R)) >> 1;
}
return s;
}
/* Compute syndrome(data), where data has length len */
#define syndrome18(data,len) s18update(0,data,len)
static fec_gf_t s18update(fec_gf_t r, const uint8_t *data, size_t len) {
for (size_t i = 0; i < len; i++) {
r = step(8, 0x46231, r ^ data[i]);
}
return r;
}
/* Append 3 bytes of FEC(data) to data, so that the FEC becomes 0 */
void PQCLEAN_PAPABEAREPHEM_CLEAN_melas_fec_set(
uint8_t out[MELAS_FEC_BYTES],
const uint8_t *data,
size_t len
) {
fec_gf_t fec = syndrome18(data, len);
for (size_t i = 0; i < MELAS_FEC_BYTES; i++, fec >>= 8) {
out[i] = (uint8_t)fec;
}
}
/* Return a*b mod Q */
static fec_gf_t mul(fec_gf_t a, fec_gf_t b) {
fec_gf_t r = 0;
for (size_t i = 0; i < 9; i++) {
r ^= ((b >> (8 - i)) & 1) * a;
a = step(1, Q, a);
}
return r;
}
/* Reverse an 18-bit number x */
static fec_gf_t reverse18(fec_gf_t x) {
fec_gf_t ret = 0;
for (size_t i = 0; i < 18; i++) {
ret ^= ((x >> i) & 1) << (17 - i);
}
return ret;
}
/* Correct data to have the given FEC */
void PQCLEAN_PAPABEAREPHEM_CLEAN_melas_fec_correct (
uint8_t *data,
size_t len,
const uint8_t fec[MELAS_FEC_BYTES]
) {
fec_gf_t a = s18update(syndrome18(data, len), fec, MELAS_FEC_BYTES);
fec_gf_t c, r, htr;
size_t i;
const uint8_t table[9] = {36, 10, 43, 215, 52, 11, 116, 244, 0};
fec_gf_t e0, e1;
/* Form a quadratic equation from the syndrome */
c = mul(step(9, Q, a), step(9, Q, reverse18(a)));
for (i = 0, r = 0x100; i < 510; i++) {
r = mul(r, c);
}
r = step(17, Q, r);
a = step(511 - (len + MELAS_FEC_BYTES) * 8, Q, a);
/* Solve using the half trace */
for (i = 0, htr = 0; i < 9; i++) {
htr ^= ((r >> i) & 1) * table[i];
}
e0 = mul(a, htr);
e1 = e0 ^ a;
/* Correct the errors using the locators */
for (i = 0; i < len; i++) {
data[i] ^= (uint8_t)(e0 & (((e0 & (e0 - 1)) - 1) >> 9));
data[i] ^= (uint8_t)(e1 & (((e1 & (e1 - 1)) - 1) >> 9));
e0 = step(8, Q, e0);
e1 = step(8, Q, e1);
}
}

View File

@ -1,26 +0,0 @@
#ifndef __THREEBEARS_MELAS_FEC_H__
#define __THREEBEARS_MELAS_FEC_H__
#include "api.h"
#define MELAS_FEC_BYTES 3
#define MELAS_FEC_BITS 18
typedef uint32_t fec_gf_t;
static const fec_gf_t Q = 0x211;
/* Append 3 bytes of FEC(data) to data, so that the FEC becomes 0 */
void PQCLEAN_PAPABEAREPHEM_CLEAN_melas_fec_set(
uint8_t out[MELAS_FEC_BYTES],
const uint8_t *data,
size_t len
);
/* Append 3 bytes of FEC(data) to data, so that the FEC becomes 0 */
void PQCLEAN_PAPABEAREPHEM_CLEAN_melas_fec_correct(
uint8_t *data,
size_t len,
const uint8_t fec[MELAS_FEC_BYTES]
);
#endif

View File

@ -1,29 +0,0 @@
#ifndef __THREEBEARS_PARAMS_H__
#define __THREEBEARS_PARAMS_H__
#define VERSION 1
#define MATRIX_SEED_BYTES 24
#define ENC_SEED_BYTES 32
#define IV_BYTES 0
#define LGX 10
#define DIGITS 312
#define DIM 4
#define VAR_TIMES_128 96
#define LPR_BITS 4
#define FEC_BITS 18
#define CCA 0
#define SHARED_SECRET_BYTES 32
#define PRIVATE_KEY_BYTES 40
#define PRF_KEY_BYTES PRIVATE_KEY_BYTES
#define BEAR_NAME "PapaBearEphem"
#define encapsulate PQCLEAN_PAPABEAREPHEM_CLEAN_encapsulate
#define decapsulate PQCLEAN_PAPABEAREPHEM_CLEAN_decapsulate
#define get_pubkey PQCLEAN_PAPABEAREPHEM_CLEAN_get_pubkey
#define GF_BYTES ((LGX*DIGITS+7)/8)
#define PUBLIC_KEY_BYTES (MATRIX_SEED_BYTES + DIM*GF_BYTES)
#define CAPSULE_BYTES \
(DIM*GF_BYTES + IV_BYTES + ((ENC_SEED_BYTES*8+FEC_BITS)*LPR_BITS+7)/8)
#endif

View File

@ -1,107 +0,0 @@
/** Ring arithmetic implementation */
#include "ring.h"
/** Return the i'th limb of the modulus */
limb_t PQCLEAN_PAPABEAREPHEM_CLEAN_modulus(size_t i) {
return (i == DIGITS / 2) ? LMASK - 1 : LMASK;
}
/** Multiply and accumulate c += a*b */
void PQCLEAN_PAPABEAREPHEM_CLEAN_mac(gf_t c, const gf_t a, const gf_t b) {
/* Reference non-Karatsuba MAC */
dslimb_t accum[2 * DIGITS] = {0};
dslimb_t chain;
size_t i, j;
/* Initialize accumulator = unclarify(c) */
for (i = 0; i < DIGITS; i++) {
accum[i + DIGITS / 2] = c[i];
}
/* Multiply */
for (i = 0; i < DIGITS; i++) {
for (j = 0; j < DIGITS; j++) {
accum[i + j] += (dslimb_t)a[i] * b[j];
}
}
/* Clarify and reduce */
for (i = 0; i < DIGITS / 2; i++) {
accum[i + DIGITS / 2] -= accum[i];
accum[i + DIGITS] += accum[i];
accum[i + DIGITS / 2] += accum[i + 3 * DIGITS / 2];
accum[i + DIGITS] += accum[i + 3 * DIGITS / 2];
}
/* Carry propagate */
chain = accum[3 * DIGITS / 2 - 1];
accum[3 * DIGITS / 2 - 1] = chain & LMASK;
chain >>= LGX;
accum[DIGITS] += chain;
for (i = DIGITS / 2; i < 3 * DIGITS / 2; i++) {
chain += accum[i];
c[i - DIGITS / 2] = chain & LMASK;
chain >>= LGX;
}
c[0] = (limb_t) (c[0] + chain);
c[DIGITS / 2] = (limb_t) (c[DIGITS / 2] + chain);
}
/** Reduce a gf_t to canonical form, i.e. strictly less than N. */
void PQCLEAN_PAPABEAREPHEM_CLEAN_canon(gf_t c) {
const limb_t DELTA = (limb_t)1 << (LGX - 1);
slimb_t hi;
dslimb_t scarry;
dlimb_t carry;
/* Reduce to 0..2p */
hi = (slimb_t) (c[DIGITS - 1] - DELTA);
c[DIGITS - 1] = (limb_t) ((hi & LMASK) + DELTA);
c[DIGITS / 2] = (limb_t) (c[DIGITS / 2] + (hi >> LGX));
/* Strong reduce. First subtract modulus */
scarry = hi >> LGX;
for (size_t i = 0; i < DIGITS; i++) {
scarry = scarry + (slimb_t)c[i] - PQCLEAN_PAPABEAREPHEM_CLEAN_modulus(i);
c[i] = scarry & LMASK;
scarry >>= LGX;
}
/* add it back */
carry = 0;
for (size_t i = 0; i < DIGITS; i++) {
carry = carry + c[i] + ((dlimb_t)scarry & PQCLEAN_PAPABEAREPHEM_CLEAN_modulus(i));
c[i] = carry & LMASK;
carry >>= LGX;
}
}
/** Serialize a gf_t to bytes */
void PQCLEAN_PAPABEAREPHEM_CLEAN_contract(uint8_t ch[GF_BYTES], gf_t a) {
size_t pos;
PQCLEAN_PAPABEAREPHEM_CLEAN_canon(a);
for (size_t i = 0; i < GF_BYTES; i++) {
pos = (i * 8) / LGX;
ch[i] = (uint8_t)(a[pos] >> ((i * 8) % LGX));
if (i < GF_BYTES - 1) {
ch[i] |= (uint8_t)(a[pos + 1] << (LGX - ((i * 8) % LGX)));
}
}
}
/** Deserialize a gf_t from bytes */
void PQCLEAN_PAPABEAREPHEM_CLEAN_expand(gf_t ll, const uint8_t ch[GF_BYTES]) {
limb_t tmp, buffer = 0;
for (size_t i = 0, j = 0, bbits = 0; i < GF_BYTES; i++) {
tmp = ch[i];
buffer |= (limb_t)(tmp << bbits);
bbits += 8;
if (bbits >= LGX) {
ll[j++] = buffer & LMASK;
buffer = (limb_t)(tmp >> (LGX - (bbits - 8)));
bbits = bbits - LGX;
}
}
}

View File

@ -1,29 +0,0 @@
#ifndef __THREEBEARS_RING_H__
#define __THREEBEARS_RING_H__
#include "api.h"
#include "params.h"
typedef uint16_t limb_t;
typedef int16_t slimb_t;
typedef uint32_t dlimb_t;
typedef int32_t dslimb_t;
#define LMASK (((limb_t)1<<LGX)-1)
typedef limb_t gf_t[DIGITS];
/* Serialize a gf_t */
void PQCLEAN_PAPABEAREPHEM_CLEAN_contract(uint8_t ch[GF_BYTES], gf_t a);
/* Deserialize a gf_t */
void PQCLEAN_PAPABEAREPHEM_CLEAN_expand(gf_t ll, const uint8_t ch[GF_BYTES]);
/* Multiply and accumulate c = c + a*b */
void PQCLEAN_PAPABEAREPHEM_CLEAN_mac(gf_t c, const gf_t a, const gf_t b);
/* Reduce ring element to canonical form */
void PQCLEAN_PAPABEAREPHEM_CLEAN_canon(gf_t c);
/** Return the i'th limb of the modulus */
limb_t PQCLEAN_PAPABEAREPHEM_CLEAN_modulus(size_t i);
#endif

View File

@ -1,219 +0,0 @@
/** ThreeBears reference implementation */
#include "api.h"
#include "melas_fec.h"
#include "params.h"
#include "ring.h"
#include "sp800-185.h"
#include "threebears.h"
#define FEC_BYTES ((FEC_BITS+7)/8)
#define ENC_BITS (ENC_SEED_BYTES*8 + FEC_BITS)
enum { HASH_PURPOSE_UNIFORM = 0, HASH_PURPOSE_KEYGEN = 1, HASH_PURPOSE_ENCAPS = 2, HASH_PURPOSE_PRF = 3 };
/** Initialize the hash function with a given purpose */
static void threebears_hash_init(
shake256incctx *ctx,
uint8_t purpose
) {
const unsigned char S[] = "ThreeBears";
const uint8_t pblock[15] = {
VERSION, PRIVATE_KEY_BYTES, MATRIX_SEED_BYTES, ENC_SEED_BYTES,
IV_BYTES, SHARED_SECRET_BYTES, LGX, DIGITS & 0xFF, DIGITS >> 8, DIM,
VAR_TIMES_128 - 1, LPR_BITS, FEC_BITS, CCA, 0 /* padding */
};
cshake256_inc_init(ctx, NULL, 0, (const uint8_t *)S, sizeof(S) - 1);
cshake256_inc_absorb(ctx, (const uint8_t *)pblock, sizeof(pblock));
cshake256_inc_absorb(ctx, &purpose, 1);
}
/** Sample n gf_t's uniformly from a seed */
static void uniform(gf_t matrix, const uint8_t *seed, uint8_t iv) {
uint8_t c[GF_BYTES];
shake256incctx ctx;
threebears_hash_init(&ctx, HASH_PURPOSE_UNIFORM);
cshake256_inc_absorb(&ctx, seed, MATRIX_SEED_BYTES);
cshake256_inc_absorb(&ctx, &iv, 1);
cshake256_inc_finalize(&ctx);
cshake256_inc_squeeze(c, sizeof(c), &ctx);
cshake256_inc_ctx_release(&ctx);
PQCLEAN_PAPABEAREPHEM_CLEAN_expand(matrix, c);
}
/** The ThreeBears error distribution */
static slimb_t psi(uint8_t ci) {
int sample = 0, var = VAR_TIMES_128;
for (; var > 64; var -= 64, ci = (uint8_t)(ci << 2)) {
sample += ((ci + 64) >> 8) + ((ci - 64) >> 8);
}
return (slimb_t)(sample + ((ci + var) >> 8) + ((ci - var) >> 8));
}
/** Sample a vector of n noise elements */
static void noise(gf_t x, const shake256incctx *ctx, uint8_t iv) {
uint8_t c[DIGITS];
shake256incctx ctx2;
cshake256_inc_ctx_clone(&ctx2, ctx);
cshake256_inc_absorb(&ctx2, &iv, 1);
cshake256_inc_finalize(&ctx2);
cshake256_inc_squeeze(c, DIGITS, &ctx2);
for (size_t i = 0; i < DIGITS; i++) {
x[i] = (limb_t)(psi(c[i]) + PQCLEAN_PAPABEAREPHEM_CLEAN_modulus(i));
}
cshake256_inc_ctx_release(&ctx2);
}
/* Expand public key from private key */
void PQCLEAN_PAPABEAREPHEM_CLEAN_get_pubkey(uint8_t *pk, const uint8_t *sk) {
shake256incctx ctx;
shake256incctx ctx2;
gf_t sk_expanded[DIM], b, c;
threebears_hash_init(&ctx, HASH_PURPOSE_KEYGEN);
cshake256_inc_absorb(&ctx, sk, PRIVATE_KEY_BYTES);
cshake256_inc_ctx_clone(&ctx2, &ctx);
cshake256_inc_finalize(&ctx2);
cshake256_inc_squeeze(pk, MATRIX_SEED_BYTES, &ctx2);
cshake256_inc_ctx_release(&ctx2);
for (uint8_t i = 0; i < DIM; i++) {
noise(sk_expanded[i], &ctx, i);
}
for (uint8_t i = 0; i < DIM; i++) {
noise(c, &ctx, (uint8_t)(i + DIM));
for (uint8_t j = 0; j < DIM; j++) {
uniform(b, pk, (uint8_t) (i + DIM * j));
PQCLEAN_PAPABEAREPHEM_CLEAN_mac(c, b, sk_expanded[j]);
}
PQCLEAN_PAPABEAREPHEM_CLEAN_contract(&pk[MATRIX_SEED_BYTES + i * GF_BYTES], c);
}
cshake256_inc_ctx_release(&ctx);
}
/* Encapsulate a shared secret and return it */
void PQCLEAN_PAPABEAREPHEM_CLEAN_encapsulate(
uint8_t *shared_secret,
uint8_t *capsule,
const uint8_t *pk,
const uint8_t *seed
) {
uint8_t *lpr_data = &capsule[GF_BYTES * DIM];
shake256incctx ctx;
gf_t sk_expanded[DIM], b, c;
uint8_t tbi[ENC_SEED_BYTES + FEC_BYTES];
dlimb_t rlimb0, rlimb1;
limb_t h;
uint8_t *iv = &lpr_data[(ENC_BITS * LPR_BITS + 7) / 8];
memcpy(iv, &seed[ENC_SEED_BYTES], IV_BYTES);
threebears_hash_init(&ctx, HASH_PURPOSE_ENCAPS);
cshake256_inc_absorb(&ctx, pk, MATRIX_SEED_BYTES);
cshake256_inc_absorb(&ctx, seed, ENC_SEED_BYTES + IV_BYTES);
for (uint8_t i = 0; i < DIM; i++) {
noise(sk_expanded[i], &ctx, i);
}
for (uint8_t i = 0; i < DIM; i++) {
noise(c, &ctx, (uint8_t)(i + DIM));
for (uint8_t j = 0; j < DIM; j++) {
uniform(b, pk, (uint8_t)(j + DIM * i));
PQCLEAN_PAPABEAREPHEM_CLEAN_mac(c, b, sk_expanded[j]);
}
PQCLEAN_PAPABEAREPHEM_CLEAN_contract(&capsule[i * GF_BYTES], c);
}
noise(c, &ctx, (uint8_t)(2 * DIM));
/* Calculate approximate shared secret */
for (uint8_t i = 0; i < DIM; i++) {
PQCLEAN_PAPABEAREPHEM_CLEAN_expand(b, &pk[MATRIX_SEED_BYTES + i * GF_BYTES]);
PQCLEAN_PAPABEAREPHEM_CLEAN_mac(c, b, sk_expanded[i]);
}
PQCLEAN_PAPABEAREPHEM_CLEAN_canon(c);
cshake256_inc_finalize(&ctx);
cshake256_inc_squeeze(tbi, ENC_SEED_BYTES, &ctx);
cshake256_inc_ctx_release(&ctx);
threebears_hash_init(&ctx, HASH_PURPOSE_ENCAPS);
cshake256_inc_absorb(&ctx, pk, MATRIX_SEED_BYTES);
cshake256_inc_absorb(&ctx, tbi, ENC_SEED_BYTES);
cshake256_inc_absorb(&ctx, iv, IV_BYTES);
PQCLEAN_PAPABEAREPHEM_CLEAN_melas_fec_set(&tbi[ENC_SEED_BYTES], tbi, ENC_SEED_BYTES);
/* Export with rounding */
for (size_t i = 0; i < ENC_BITS; i += 2) {
h = (limb_t)(tbi[i / 8] >> (i % 8));
rlimb0 = (dlimb_t)((c[i / 2] >> (LGX - LPR_BITS)) + (h << 3));
rlimb1 = (dlimb_t)((c[DIGITS - i / 2 - 1] >> (LGX - LPR_BITS)) + ((h >> 1) << 3));
lpr_data[i / 2] = (uint8_t)((rlimb0 & 0xF) | rlimb1 << 4);
}
cshake256_inc_finalize(&ctx);
cshake256_inc_squeeze(shared_secret, SHARED_SECRET_BYTES, &ctx);
cshake256_inc_ctx_release(&ctx);
}
/* Decapsulate a shared secret and return it */
void PQCLEAN_PAPABEAREPHEM_CLEAN_decapsulate(
uint8_t shared_secret[SHARED_SECRET_BYTES],
const uint8_t capsule[CAPSULE_BYTES],
const uint8_t sk[PRIVATE_KEY_BYTES]
) {
const uint8_t *lpr_data = &capsule[GF_BYTES * DIM];
shake256incctx ctx;
gf_t ska, b, c = {0};
uint8_t seed[ENC_SEED_BYTES + FEC_BYTES + IV_BYTES];
limb_t rounding, out;
size_t j;
limb_t our_rlimb, their_rlimb, delta;
uint8_t matrix_seed[MATRIX_SEED_BYTES];
/* Calculate approximate shared secret */
threebears_hash_init(&ctx, HASH_PURPOSE_KEYGEN);
cshake256_inc_absorb(&ctx, sk, PRIVATE_KEY_BYTES);
for (uint8_t i = 0; i < DIM; i++) {
PQCLEAN_PAPABEAREPHEM_CLEAN_expand(b, &capsule[i * GF_BYTES]);
noise(ska, &ctx, i);
PQCLEAN_PAPABEAREPHEM_CLEAN_mac(c, ska, b);
}
/* Recover seed from LPR data */
PQCLEAN_PAPABEAREPHEM_CLEAN_canon(c);
rounding = 1 << (LPR_BITS - 1);
out = 0;
for (int32_t i = ENC_BITS - 1; i >= 0; i--) {
j = (size_t) ((i & 1) ? DIGITS - i / 2 - 1 : i / 2);
our_rlimb = (limb_t)(c[j] >> (LGX - LPR_BITS - 1));
their_rlimb = (limb_t)(lpr_data[i * LPR_BITS / 8] >> ((i * LPR_BITS) % 8));
delta = (limb_t)(their_rlimb * 2 - our_rlimb + rounding);
out |= (limb_t)(((delta >> LPR_BITS) & 1) << (i % 8));
if (i % 8 == 0) {
seed[i / 8] = (uint8_t)out;
out = 0;
}
}
PQCLEAN_PAPABEAREPHEM_CLEAN_melas_fec_correct(seed, ENC_SEED_BYTES, &seed[ENC_SEED_BYTES]);
/* Recalculate matrix seed */
cshake256_inc_finalize(&ctx);
cshake256_inc_squeeze(matrix_seed, MATRIX_SEED_BYTES, &ctx);
cshake256_inc_ctx_release(&ctx);
/* Re-run the key derivation from encaps */
threebears_hash_init(&ctx, HASH_PURPOSE_ENCAPS);
cshake256_inc_absorb(&ctx, matrix_seed, MATRIX_SEED_BYTES);
cshake256_inc_absorb(&ctx, seed, ENC_SEED_BYTES);
cshake256_inc_absorb(&ctx, &lpr_data[(ENC_BITS * LPR_BITS + 7) / 8], IV_BYTES);
cshake256_inc_finalize(&ctx);
cshake256_inc_squeeze(shared_secret, SHARED_SECRET_BYTES, &ctx);
cshake256_inc_ctx_release(&ctx);
}

View File

@ -1,60 +0,0 @@
#ifndef __THREE_BEARS_PAPABEAREPHEM_H__
#define __THREE_BEARS_PAPABEAREPHEM_H__
#include <stddef.h> /* for size_t */
#include <stdint.h>
#define PAPABEAREPHEM_KEYGEN_SEED_BYTES 40
#define PAPABEAREPHEM_PRIVATE_KEY_BYTES PAPABEAREPHEM_KEYGEN_SEED_BYTES
#define PAPABEAREPHEM_SHARED_SECRET_BYTES 32
#define PAPABEAREPHEM_ENC_SEED_AND_IV_BYTES 32
#define PAPABEAREPHEM_PUBLIC_KEY_BYTES 1584
#define PAPABEAREPHEM_CAPSULE_BYTES 1697
/**
* Expand a secret seed to a public/private keypair.
*
* @param[out] pk The public key.
* @param[in] sk The private key, which must be uniformly random.
*/
void PQCLEAN_PAPABEAREPHEM_CLEAN_get_pubkey (
uint8_t pk[PAPABEAREPHEM_PUBLIC_KEY_BYTES],
const uint8_t sk[PAPABEAREPHEM_PRIVATE_KEY_BYTES]
);
/**
* Create a shared secret using a random seed and another party's public key.
*
* Input and output parameters may not alias.
*
* @param[out] shared_secret The shared secret key.
* @param[out] capsule A ciphertext to send to the other party.
* @param[in] pk The other party's public key.
* @param[in] seed A random seed.
*/
void PQCLEAN_PAPABEAREPHEM_CLEAN_encapsulate (
uint8_t shared_secret[PAPABEAREPHEM_SHARED_SECRET_BYTES],
uint8_t capsule[PAPABEAREPHEM_CAPSULE_BYTES],
const uint8_t pk[PAPABEAREPHEM_PUBLIC_KEY_BYTES],
const uint8_t seed[PAPABEAREPHEM_ENC_SEED_AND_IV_BYTES]
);
/**
* Extract the shared secret from a capsule using the private key.
* Has a negligible but nonzero probability of failure.
*
* Input and output parameters may not alias.
*
* @param[out] shared_secret The shared secret.
* @param[in] capsule The capsule produced by encapsulate_cca2.
* @param[in] sk The private key.
* @return -1 on failure, 0 on success.
* @warning The value of shared_secret must not be used on failure
*/
void PQCLEAN_PAPABEAREPHEM_CLEAN_decapsulate (
uint8_t shared_secret[PAPABEAREPHEM_SHARED_SECRET_BYTES],
const uint8_t capsule[PAPABEAREPHEM_CAPSULE_BYTES],
const uint8_t sk[PAPABEAREPHEM_PRIVATE_KEY_BYTES]
);
#endif

View File

@ -143,7 +143,9 @@
#cmakedefine OQS_ENABLE_SIG_MQDSS 1
#cmakedefine OQS_ENABLE_SIG_mqdss_31_48 1
#cmakedefine OQS_ENABLE_SIG_mqdss_31_48_avx2 1
#cmakedefine OQS_ENABLE_SIG_mqdss_31_64 1
#cmakedefine OQS_ENABLE_SIG_mqdss_31_64_avx2 1
#cmakedefine OQS_ENABLE_SIG_RAINBOW 1
#cmakedefine OQS_ENABLE_SIG_rainbow_Ia_classic 1

View File

@ -1,22 +0,0 @@
MIT License
Copyright (c) 2017-2019 Falcon Project
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.

View File

@ -1,80 +0,0 @@
#ifndef PQCLEAN_FALCON1024_CLEAN_API_H
#define PQCLEAN_FALCON1024_CLEAN_API_H
#include <stddef.h>
#include <stdint.h>
#define PQCLEAN_FALCON1024_CLEAN_CRYPTO_SECRETKEYBYTES 2305
#define PQCLEAN_FALCON1024_CLEAN_CRYPTO_PUBLICKEYBYTES 1793
#define PQCLEAN_FALCON1024_CLEAN_CRYPTO_BYTES 1330
#define PQCLEAN_FALCON1024_CLEAN_CRYPTO_ALGNAME "Falcon-1024"
/*
* Generate a new key pair. Public key goes into pk[], private key in sk[].
* Key sizes are exact (in bytes):
* public (pk): PQCLEAN_FALCON1024_CLEAN_CRYPTO_PUBLICKEYBYTES
* private (sk): PQCLEAN_FALCON1024_CLEAN_CRYPTO_SECRETKEYBYTES
*
* Return value: 0 on success, -1 on error.
*/
int PQCLEAN_FALCON1024_CLEAN_crypto_sign_keypair(
uint8_t *pk, uint8_t *sk);
/*
* Compute a signature on a provided message (m, mlen), with a given
* private key (sk). Signature is written in sig[], with length written
* into *siglen. Signature length is variable; maximum signature length
* (in bytes) is PQCLEAN_FALCON1024_CLEAN_CRYPTO_BYTES.
*
* sig[], m[] and sk[] may overlap each other arbitrarily.
*
* Return value: 0 on success, -1 on error.
*/
int PQCLEAN_FALCON1024_CLEAN_crypto_sign_signature(
uint8_t *sig, size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *sk);
/*
* Verify a signature (sig, siglen) on a message (m, mlen) with a given
* public key (pk).
*
* sig[], m[] and pk[] may overlap each other arbitrarily.
*
* Return value: 0 on success, -1 on error.
*/
int PQCLEAN_FALCON1024_CLEAN_crypto_sign_verify(
const uint8_t *sig, size_t siglen,
const uint8_t *m, size_t mlen, const uint8_t *pk);
/*
* Compute a signature on a message and pack the signature and message
* into a single object, written into sm[]. The length of that output is
* written in *smlen; that length may be larger than the message length
* (mlen) by up to PQCLEAN_FALCON1024_CLEAN_CRYPTO_BYTES.
*
* sm[] and m[] may overlap each other arbitrarily; however, sm[] shall
* not overlap with sk[].
*
* Return value: 0 on success, -1 on error.
*/
int PQCLEAN_FALCON1024_CLEAN_crypto_sign(
uint8_t *sm, size_t *smlen,
const uint8_t *m, size_t mlen, const uint8_t *sk);
/*
* Open a signed message object (sm, smlen) and verify the signature;
* on success, the message itself is written into m[] and its length
* into *mlen. The message is shorter than the signed message object,
* but the size difference depends on the signature value; the difference
* may range up to PQCLEAN_FALCON1024_CLEAN_CRYPTO_BYTES.
*
* m[], sm[] and pk[] may overlap each other arbitrarily.
*
* Return value: 0 on success, -1 on error.
*/
int PQCLEAN_FALCON1024_CLEAN_crypto_sign_open(
uint8_t *m, size_t *mlen,
const uint8_t *sm, size_t smlen, const uint8_t *pk);
#endif

View File

@ -1,551 +0,0 @@
/*
* Encoding/decoding of keys and signatures.
*
* ==========================(LICENSE BEGIN)============================
*
* Copyright (c) 2017-2019 Falcon Project
*
* 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.
*
* ===========================(LICENSE END)=============================
*
* @author Thomas Pornin <thomas.pornin@nccgroup.com>
*/
#include "inner.h"
/* see inner.h */
size_t
PQCLEAN_FALCON1024_CLEAN_modq_encode(
void *out, size_t max_out_len,
const uint16_t *x, unsigned logn) {
size_t n, out_len, u;
uint8_t *buf;
uint32_t acc;
int acc_len;
n = (size_t)1 << logn;
for (u = 0; u < n; u ++) {
if (x[u] >= 12289) {
return 0;
}
}
out_len = ((n * 14) + 7) >> 3;
if (out == NULL) {
return out_len;
}
if (out_len > max_out_len) {
return 0;
}
buf = out;
acc = 0;
acc_len = 0;
for (u = 0; u < n; u ++) {
acc = (acc << 14) | x[u];
acc_len += 14;
while (acc_len >= 8) {
acc_len -= 8;
*buf ++ = (uint8_t)(acc >> acc_len);
}
}
if (acc_len > 0) {
*buf = (uint8_t)(acc << (8 - acc_len));
}
return out_len;
}
/* see inner.h */
size_t
PQCLEAN_FALCON1024_CLEAN_modq_decode(
uint16_t *x, unsigned logn,
const void *in, size_t max_in_len) {
size_t n, in_len, u;
const uint8_t *buf;
uint32_t acc;
int acc_len;
n = (size_t)1 << logn;
in_len = ((n * 14) + 7) >> 3;
if (in_len > max_in_len) {
return 0;
}
buf = in;
acc = 0;
acc_len = 0;
u = 0;
while (u < n) {
acc = (acc << 8) | (*buf ++);
acc_len += 8;
if (acc_len >= 14) {
unsigned w;
acc_len -= 14;
w = (acc >> acc_len) & 0x3FFF;
if (w >= 12289) {
return 0;
}
x[u ++] = (uint16_t)w;
}
}
if ((acc & (((uint32_t)1 << acc_len) - 1)) != 0) {
return 0;
}
return in_len;
}
/* see inner.h */
size_t
PQCLEAN_FALCON1024_CLEAN_trim_i16_encode(
void *out, size_t max_out_len,
const int16_t *x, unsigned logn, unsigned bits) {
size_t n, u, out_len;
int minv, maxv;
uint8_t *buf;
uint32_t acc, mask;
unsigned acc_len;
n = (size_t)1 << logn;
maxv = (1 << (bits - 1)) - 1;
minv = -maxv;
for (u = 0; u < n; u ++) {
if (x[u] < minv || x[u] > maxv) {
return 0;
}
}
out_len = ((n * bits) + 7) >> 3;
if (out == NULL) {
return out_len;
}
if (out_len > max_out_len) {
return 0;
}
buf = out;
acc = 0;
acc_len = 0;
mask = ((uint32_t)1 << bits) - 1;
for (u = 0; u < n; u ++) {
acc = (acc << bits) | ((uint16_t)x[u] & mask);
acc_len += bits;
while (acc_len >= 8) {
acc_len -= 8;
*buf ++ = (uint8_t)(acc >> acc_len);
}
}
if (acc_len > 0) {
*buf ++ = (uint8_t)(acc << (8 - acc_len));
}
return out_len;
}
/* see inner.h */
size_t
PQCLEAN_FALCON1024_CLEAN_trim_i16_decode(
int16_t *x, unsigned logn, unsigned bits,
const void *in, size_t max_in_len) {
size_t n, in_len;
const uint8_t *buf;
size_t u;
uint32_t acc, mask1, mask2;
unsigned acc_len;
n = (size_t)1 << logn;
in_len = ((n * bits) + 7) >> 3;
if (in_len > max_in_len) {
return 0;
}
buf = in;
u = 0;
acc = 0;
acc_len = 0;
mask1 = ((uint32_t)1 << bits) - 1;
mask2 = (uint32_t)1 << (bits - 1);
while (u < n) {
acc = (acc << 8) | *buf ++;
acc_len += 8;
while (acc_len >= bits && u < n) {
uint32_t w;
acc_len -= bits;
w = (acc >> acc_len) & mask1;
w |= -(w & mask2);
if (w == -mask2) {
/*
* The -2^(bits-1) value is forbidden.
*/
return 0;
}
w |= -(w & mask2);
x[u ++] = (int16_t) * (int32_t *)&w;
}
}
if ((acc & (((uint32_t)1 << acc_len) - 1)) != 0) {
/*
* Extra bits in the last byte must be zero.
*/
return 0;
}
return in_len;
}
/* see inner.h */
size_t
PQCLEAN_FALCON1024_CLEAN_trim_i8_encode(
void *out, size_t max_out_len,
const int8_t *x, unsigned logn, unsigned bits) {
size_t n, u, out_len;
int minv, maxv;
uint8_t *buf;
uint32_t acc, mask;
unsigned acc_len;
n = (size_t)1 << logn;
maxv = (1 << (bits - 1)) - 1;
minv = -maxv;
for (u = 0; u < n; u ++) {
if (x[u] < minv || x[u] > maxv) {
return 0;
}
}
out_len = ((n * bits) + 7) >> 3;
if (out == NULL) {
return out_len;
}
if (out_len > max_out_len) {
return 0;
}
buf = out;
acc = 0;
acc_len = 0;
mask = ((uint32_t)1 << bits) - 1;
for (u = 0; u < n; u ++) {
acc = (acc << bits) | ((uint8_t)x[u] & mask);
acc_len += bits;
while (acc_len >= 8) {
acc_len -= 8;
*buf ++ = (uint8_t)(acc >> acc_len);
}
}
if (acc_len > 0) {
*buf ++ = (uint8_t)(acc << (8 - acc_len));
}
return out_len;
}
/* see inner.h */
size_t
PQCLEAN_FALCON1024_CLEAN_trim_i8_decode(
int8_t *x, unsigned logn, unsigned bits,
const void *in, size_t max_in_len) {
size_t n, in_len;
const uint8_t *buf;
size_t u;
uint32_t acc, mask1, mask2;
unsigned acc_len;
n = (size_t)1 << logn;
in_len = ((n * bits) + 7) >> 3;
if (in_len > max_in_len) {
return 0;
}
buf = in;
u = 0;
acc = 0;
acc_len = 0;
mask1 = ((uint32_t)1 << bits) - 1;
mask2 = (uint32_t)1 << (bits - 1);
while (u < n) {
acc = (acc << 8) | *buf ++;
acc_len += 8;
while (acc_len >= bits && u < n) {
uint32_t w;
acc_len -= bits;
w = (acc >> acc_len) & mask1;
w |= -(w & mask2);
if (w == -mask2) {
/*
* The -2^(bits-1) value is forbidden.
*/
return 0;
}
x[u ++] = (int8_t) * (int32_t *)&w;
}
}
if ((acc & (((uint32_t)1 << acc_len) - 1)) != 0) {
/*
* Extra bits in the last byte must be zero.
*/
return 0;
}
return in_len;
}
/* see inner.h */
size_t
PQCLEAN_FALCON1024_CLEAN_comp_encode(
void *out, size_t max_out_len,
const int16_t *x, unsigned logn) {
uint8_t *buf;
size_t n, u, v;
uint32_t acc;
unsigned acc_len;
n = (size_t)1 << logn;
buf = out;
/*
* Make sure that all values are within the -2047..+2047 range.
*/
for (u = 0; u < n; u ++) {
if (x[u] < -2047 || x[u] > +2047) {
return 0;
}
}
acc = 0;
acc_len = 0;
v = 0;
for (u = 0; u < n; u ++) {
int t;
unsigned w;
/*
* Get sign and absolute value of next integer; push the
* sign bit.
*/
acc <<= 1;
t = x[u];
if (t < 0) {
t = -t;
acc |= 1;
}
w = (unsigned)t;
/*
* Push the low 7 bits of the absolute value.
*/
acc <<= 7;
acc |= w & 127u;
w >>= 7;
/*
* We pushed exactly 8 bits.
*/
acc_len += 8;
/*
* Push as many zeros as necessary, then a one. Since the
* absolute value is at most 2047, w can only range up to
* 15 at this point, thus we will add at most 16 bits
* here. With the 8 bits above and possibly up to 7 bits
* from previous iterations, we may go up to 31 bits, which
* will fit in the accumulator, which is an uint32_t.
*/
acc <<= (w + 1);
acc |= 1;
acc_len += w + 1;
/*
* Produce all full bytes.
*/
while (acc_len >= 8) {
acc_len -= 8;
if (buf != NULL) {
if (v >= max_out_len) {
return 0;
}
buf[v] = (uint8_t)(acc >> acc_len);
}
v ++;
}
}
/*
* Flush remaining bits (if any).
*/
if (acc_len > 0) {
if (buf != NULL) {
if (v >= max_out_len) {
return 0;
}
buf[v] = (uint8_t)(acc << (8 - acc_len));
}
v ++;
}
return v;
}
/* see inner.h */
size_t
PQCLEAN_FALCON1024_CLEAN_comp_decode(
int16_t *x, unsigned logn,
const void *in, size_t max_in_len) {
const uint8_t *buf;
size_t n, u, v;
uint32_t acc;
unsigned acc_len;
n = (size_t)1 << logn;
buf = in;
acc = 0;
acc_len = 0;
v = 0;
for (u = 0; u < n; u ++) {
unsigned b, s, m;
/*
* Get next eight bits: sign and low seven bits of the
* absolute value.
*/
if (v >= max_in_len) {
return 0;
}
acc = (acc << 8) | (uint32_t)buf[v ++];
b = acc >> acc_len;
s = b & 128;
m = b & 127;
/*
* Get next bits until a 1 is reached.
*/
for (;;) {
if (acc_len == 0) {
if (v >= max_in_len) {
return 0;
}
acc = (acc << 8) | (uint32_t)buf[v ++];
acc_len = 8;
}
acc_len --;
if (((acc >> acc_len) & 1) != 0) {
break;
}
m += 128;
if (m > 2047) {
return 0;
}
}
x[u] = (int16_t)(s ? -(int)m : (int)m);
}
return v;
}
/*
* Key elements and signatures are polynomials with small integer
* coefficients. Here are some statistics gathered over many
* generated key pairs (10000 or more for each degree):
*
* log(n) n max(f,g) std(f,g) max(F,G) std(F,G)
* 1 2 129 56.31 143 60.02
* 2 4 123 40.93 160 46.52
* 3 8 97 28.97 159 38.01
* 4 16 100 21.48 154 32.50
* 5 32 71 15.41 151 29.36
* 6 64 59 11.07 138 27.77
* 7 128 39 7.91 144 27.00
* 8 256 32 5.63 148 26.61
* 9 512 22 4.00 137 26.46
* 10 1024 15 2.84 146 26.41
*
* We want a compact storage format for private key, and, as part of
* key generation, we are allowed to reject some keys which would
* otherwise be fine (this does not induce any noticeable vulnerability
* as long as we reject only a small proportion of possible keys).
* Hence, we enforce at key generation time maximum values for the
* elements of f, g, F and G, so that their encoding can be expressed
* in fixed-width values. Limits have been chosen so that generated
* keys are almost always within bounds, thus not impacting neither
* security or performance.
*
* IMPORTANT: the code assumes that all coefficients of f, g, F and G
* ultimately fit in the -127..+127 range. Thus, none of the elements
* of max_fg_bits[] and max_FG_bits[] shall be greater than 8.
*/
const uint8_t PQCLEAN_FALCON1024_CLEAN_max_fg_bits[] = {
0, /* unused */
8,
8,
8,
8,
8,
7,
7,
6,
6,
5
};
const uint8_t PQCLEAN_FALCON1024_CLEAN_max_FG_bits[] = {
0, /* unused */
8,
8,
8,
8,
8,
8,
8,
8,
8,
8
};
/*
* When generating a new key pair, we can always reject keys which
* feature an abnormally large coefficient. This can also be done for
* signatures, albeit with some care: in case the signature process is
* used in a derandomized setup (explicitly seeded with the message and
* private key), we have to follow the specification faithfully, and the
* specification only enforces a limit on the L2 norm of the signature
* vector. The limit on the L2 norm implies that the absolute value of
* a coefficient of the signature cannot be more than the following:
*
* log(n) n max sig coeff (theoretical)
* 1 2 412
* 2 4 583
* 3 8 824
* 4 16 1166
* 5 32 1649
* 6 64 2332
* 7 128 3299
* 8 256 4665
* 9 512 6598
* 10 1024 9331
*
* However, the largest observed signature coefficients during our
* experiments was 1077 (in absolute value), hence we can assume that,
* with overwhelming probability, signature coefficients will fit
* in -2047..2047, i.e. 12 bits.
*/
const uint8_t PQCLEAN_FALCON1024_CLEAN_max_sig_bits[] = {
0, /* unused */
10,
11,
11,
12,
12,
12,
12,
12,
12,
12
};

View File

@ -1,293 +0,0 @@
/*
* Support functions for signatures (hash-to-point, norm).
*
* ==========================(LICENSE BEGIN)============================
*
* Copyright (c) 2017-2019 Falcon Project
*
* 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.
*
* ===========================(LICENSE END)=============================
*
* @author Thomas Pornin <thomas.pornin@nccgroup.com>
*/
#include "inner.h"
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_hash_to_point_vartime(
inner_shake256_context *sc,
uint16_t *x, unsigned logn) {
/*
* This is the straightforward per-the-spec implementation. It
* is not constant-time, thus it might reveal information on the
* plaintext (at least, enough to check the plaintext against a
* list of potential plaintexts) in a scenario where the
* attacker does not have access to the signature value or to
* the public key, but knows the nonce (without knowledge of the
* nonce, the hashed output cannot be matched against potential
* plaintexts).
*/
size_t n;
n = (size_t)1 << logn;
while (n > 0) {
uint8_t buf[2];
uint32_t w;
inner_shake256_extract(sc, (void *)buf, sizeof buf);
w = ((unsigned)buf[0] << 8) | (unsigned)buf[1];
if (w < 61445) {
while (w >= 12289) {
w -= 12289;
}
*x ++ = (uint16_t)w;
n --;
}
}
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_hash_to_point_ct(
inner_shake256_context *sc,
uint16_t *x, unsigned logn, uint8_t *tmp) {
/*
* Each 16-bit sample is a value in 0..65535. The value is
* kept if it falls in 0..61444 (because 61445 = 5*12289)
* and rejected otherwise; thus, each sample has probability
* about 0.93758 of being selected.
*
* We want to oversample enough to be sure that we will
* have enough values with probability at least 1 - 2^(-256).
* Depending on degree N, this leads to the following
* required oversampling:
*
* logn n oversampling
* 1 2 65
* 2 4 67
* 3 8 71
* 4 16 77
* 5 32 86
* 6 64 100
* 7 128 122
* 8 256 154
* 9 512 205
* 10 1024 287
*
* If logn >= 7, then the provided temporary buffer is large
* enough. Otherwise, we use a stack buffer of 63 entries
* (i.e. 126 bytes) for the values that do not fit in tmp[].
*/
static const uint16_t overtab[] = {
0, /* unused */
65,
67,
71,
77,
86,
100,
122,
154,
205,
287
};
unsigned n, n2, u, m, p, over;
uint16_t *tt1, tt2[63];
/*
* We first generate m 16-bit value. Values 0..n-1 go to x[].
* Values n..2*n-1 go to tt1[]. Values 2*n and later go to tt2[].
* We also reduce modulo q the values; rejected values are set
* to 0xFFFF.
*/
n = 1U << logn;
n2 = n << 1;
over = overtab[logn];
m = n + over;
tt1 = (uint16_t *)tmp;
for (u = 0; u < m; u ++) {
uint8_t buf[2];
uint32_t w, wr;
inner_shake256_extract(sc, buf, sizeof buf);
w = ((uint32_t)buf[0] << 8) | (uint32_t)buf[1];
wr = w - ((uint32_t)24578 & (((w - 24578) >> 31) - 1));
wr = wr - ((uint32_t)24578 & (((wr - 24578) >> 31) - 1));
wr = wr - ((uint32_t)12289 & (((wr - 12289) >> 31) - 1));
wr |= ((w - 61445) >> 31) - 1;
if (u < n) {
x[u] = (uint16_t)wr;
} else if (u < n2) {
tt1[u - n] = (uint16_t)wr;
} else {
tt2[u - n2] = (uint16_t)wr;
}
}
/*
* Now we must "squeeze out" the invalid values. We do this in
* a logarithmic sequence of passes; each pass computes where a
* value should go, and moves it down by 'p' slots if necessary,
* where 'p' uses an increasing powers-of-two scale. It can be
* shown that in all cases where the loop decides that a value
* has to be moved down by p slots, the destination slot is
* "free" (i.e. contains an invalid value).
*/
for (p = 1; p <= over; p <<= 1) {
unsigned v;
/*
* In the loop below:
*
* - v contains the index of the final destination of
* the value; it is recomputed dynamically based on
* whether values are valid or not.
*
* - u is the index of the value we consider ("source");
* its address is s.
*
* - The loop may swap the value with the one at index
* u-p. The address of the swap destination is d.
*/
v = 0;
for (u = 0; u < m; u ++) {
uint16_t *s, *d;
unsigned j, sv, dv, mk;
if (u < n) {
s = &x[u];
} else if (u < n2) {
s = &tt1[u - n];
} else {
s = &tt2[u - n2];
}
sv = *s;
/*
* The value in sv should ultimately go to
* address v, i.e. jump back by u-v slots.
*/
j = u - v;
/*
* We increment v for the next iteration, but
* only if the source value is valid. The mask
* 'mk' is -1 if the value is valid, 0 otherwise,
* so we _subtract_ mk.
*/
mk = (sv >> 15) - 1U;
v -= mk;
/*
* In this loop we consider jumps by p slots; if
* u < p then there is nothing more to do.
*/
if (u < p) {
continue;
}
/*
* Destination for the swap: value at address u-p.
*/
if ((u - p) < n) {
d = &x[u - p];
} else if ((u - p) < n2) {
d = &tt1[(u - p) - n];
} else {
d = &tt2[(u - p) - n2];
}
dv = *d;
/*
* The swap should be performed only if the source
* is valid AND the jump j has its 'p' bit set.
*/
mk &= -(((j & p) + 0x1FF) >> 9);
*s = (uint16_t)(sv ^ (mk & (sv ^ dv)));
*d = (uint16_t)(dv ^ (mk & (sv ^ dv)));
}
}
}
/* see inner.h */
int
PQCLEAN_FALCON1024_CLEAN_is_short(
const int16_t *s1, const int16_t *s2, unsigned logn) {
/*
* We use the l2-norm. Code below uses only 32-bit operations to
* compute the square of the norm with saturation to 2^32-1 if
* the value exceeds 2^31-1.
*/
size_t n, u;
uint32_t s, ng;
n = (size_t)1 << logn;
s = 0;
ng = 0;
for (u = 0; u < n; u ++) {
int32_t z;
z = s1[u];
s += (uint32_t)(z * z);
ng |= s;
z = s2[u];
s += (uint32_t)(z * z);
ng |= s;
}
s |= -(ng >> 31);
/*
* Acceptance bound on the l2-norm is:
* 1.2*1.55*sqrt(q)*sqrt(2*N)
* Value 7085 is floor((1.2^2)*(1.55^2)*2*1024).
*/
return s < (((uint32_t)7085 * (uint32_t)12289) >> (10 - logn));
}
/* see inner.h */
int
PQCLEAN_FALCON1024_CLEAN_is_short_half(
uint32_t sqn, const int16_t *s2, unsigned logn) {
size_t n, u;
uint32_t ng;
n = (size_t)1 << logn;
ng = -(sqn >> 31);
for (u = 0; u < n; u ++) {
int32_t z;
z = s2[u];
sqn += (uint32_t)(z * z);
ng |= sqn;
}
sqn |= -(ng >> 31);
/*
* Acceptance bound on the l2-norm is:
* 1.2*1.55*sqrt(q)*sqrt(2*N)
* Value 7085 is floor((1.2^2)*(1.55^2)*2*1024).
*/
return sqn < (((uint32_t)7085 * (uint32_t)12289) >> (10 - logn));
}

View File

@ -1,699 +0,0 @@
/*
* FFT code.
*
* ==========================(LICENSE BEGIN)============================
*
* Copyright (c) 2017-2019 Falcon Project
*
* 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.
*
* ===========================(LICENSE END)=============================
*
* @author Thomas Pornin <thomas.pornin@nccgroup.com>
*/
#include "inner.h"
/*
* Rules for complex number macros:
* --------------------------------
*
* Operand order is: destination, source1, source2...
*
* Each operand is a real and an imaginary part.
*
* All overlaps are allowed.
*/
/*
* Addition of two complex numbers (d = a + b).
*/
#define FPC_ADD(d_re, d_im, a_re, a_im, b_re, b_im) do { \
fpr fpct_re, fpct_im; \
fpct_re = fpr_add(a_re, b_re); \
fpct_im = fpr_add(a_im, b_im); \
(d_re) = fpct_re; \
(d_im) = fpct_im; \
} while (0)
/*
* Subtraction of two complex numbers (d = a - b).
*/
#define FPC_SUB(d_re, d_im, a_re, a_im, b_re, b_im) do { \
fpr fpct_re, fpct_im; \
fpct_re = fpr_sub(a_re, b_re); \
fpct_im = fpr_sub(a_im, b_im); \
(d_re) = fpct_re; \
(d_im) = fpct_im; \
} while (0)
/*
* Multplication of two complex numbers (d = a * b).
*/
#define FPC_MUL(d_re, d_im, a_re, a_im, b_re, b_im) do { \
fpr fpct_a_re, fpct_a_im; \
fpr fpct_b_re, fpct_b_im; \
fpr fpct_d_re, fpct_d_im; \
fpct_a_re = (a_re); \
fpct_a_im = (a_im); \
fpct_b_re = (b_re); \
fpct_b_im = (b_im); \
fpct_d_re = fpr_sub( \
fpr_mul(fpct_a_re, fpct_b_re), \
fpr_mul(fpct_a_im, fpct_b_im)); \
fpct_d_im = fpr_add( \
fpr_mul(fpct_a_re, fpct_b_im), \
fpr_mul(fpct_a_im, fpct_b_re)); \
(d_re) = fpct_d_re; \
(d_im) = fpct_d_im; \
} while (0)
/*
* Squaring of a complex number (d = a * a).
*/
#define FPC_SQR(d_re, d_im, a_re, a_im) do { \
fpr fpct_a_re, fpct_a_im; \
fpr fpct_d_re, fpct_d_im; \
fpct_a_re = (a_re); \
fpct_a_im = (a_im); \
fpct_d_re = fpr_sub(fpr_sqr(fpct_a_re), fpr_sqr(fpct_a_im)); \
fpct_d_im = fpr_double(fpr_mul(fpct_a_re, fpct_a_im)); \
(d_re) = fpct_d_re; \
(d_im) = fpct_d_im; \
} while (0)
/*
* Inversion of a complex number (d = 1 / a).
*/
#define FPC_INV(d_re, d_im, a_re, a_im) do { \
fpr fpct_a_re, fpct_a_im; \
fpr fpct_d_re, fpct_d_im; \
fpr fpct_m; \
fpct_a_re = (a_re); \
fpct_a_im = (a_im); \
fpct_m = fpr_add(fpr_sqr(fpct_a_re), fpr_sqr(fpct_a_im)); \
fpct_m = fpr_inv(fpct_m); \
fpct_d_re = fpr_mul(fpct_a_re, fpct_m); \
fpct_d_im = fpr_mul(fpr_neg(fpct_a_im), fpct_m); \
(d_re) = fpct_d_re; \
(d_im) = fpct_d_im; \
} while (0)
/*
* Division of complex numbers (d = a / b).
*/
#define FPC_DIV(d_re, d_im, a_re, a_im, b_re, b_im) do { \
fpr fpct_a_re, fpct_a_im; \
fpr fpct_b_re, fpct_b_im; \
fpr fpct_d_re, fpct_d_im; \
fpr fpct_m; \
fpct_a_re = (a_re); \
fpct_a_im = (a_im); \
fpct_b_re = (b_re); \
fpct_b_im = (b_im); \
fpct_m = fpr_add(fpr_sqr(fpct_b_re), fpr_sqr(fpct_b_im)); \
fpct_m = fpr_inv(fpct_m); \
fpct_b_re = fpr_mul(fpct_b_re, fpct_m); \
fpct_b_im = fpr_mul(fpr_neg(fpct_b_im), fpct_m); \
fpct_d_re = fpr_sub( \
fpr_mul(fpct_a_re, fpct_b_re), \
fpr_mul(fpct_a_im, fpct_b_im)); \
fpct_d_im = fpr_add( \
fpr_mul(fpct_a_re, fpct_b_im), \
fpr_mul(fpct_a_im, fpct_b_re)); \
(d_re) = fpct_d_re; \
(d_im) = fpct_d_im; \
} while (0)
/*
* Let w = exp(i*pi/N); w is a primitive 2N-th root of 1. We define the
* values w_j = w^(2j+1) for all j from 0 to N-1: these are the roots
* of X^N+1 in the field of complex numbers. A crucial property is that
* w_{N-1-j} = conj(w_j) = 1/w_j for all j.
*
* FFT representation of a polynomial f (taken modulo X^N+1) is the
* set of values f(w_j). Since f is real, conj(f(w_j)) = f(conj(w_j)),
* thus f(w_{N-1-j}) = conj(f(w_j)). We thus store only half the values,
* for j = 0 to N/2-1; the other half can be recomputed easily when (if)
* needed. A consequence is that FFT representation has the same size
* as normal representation: N/2 complex numbers use N real numbers (each
* complex number is the combination of a real and an imaginary part).
*
* We use a specific ordering which makes computations easier. Let rev()
* be the bit-reversal function over log(N) bits. For j in 0..N/2-1, we
* store the real and imaginary parts of f(w_j) in slots:
*
* Re(f(w_j)) -> slot rev(j)/2
* Im(f(w_j)) -> slot rev(j)/2+N/2
*
* (Note that rev(j) is even for j < N/2.)
*/
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_FFT(fpr *f, unsigned logn) {
/*
* FFT algorithm in bit-reversal order uses the following
* iterative algorithm:
*
* t = N
* for m = 1; m < N; m *= 2:
* ht = t/2
* for i1 = 0; i1 < m; i1 ++:
* j1 = i1 * t
* s = GM[m + i1]
* for j = j1; j < (j1 + ht); j ++:
* x = f[j]
* y = s * f[j + ht]
* f[j] = x + y
* f[j + ht] = x - y
* t = ht
*
* GM[k] contains w^rev(k) for primitive root w = exp(i*pi/N).
*
* In the description above, f[] is supposed to contain complex
* numbers. In our in-memory representation, the real and
* imaginary parts of f[k] are in array slots k and k+N/2.
*
* We only keep the first half of the complex numbers. We can
* see that after the first iteration, the first and second halves
* of the array of complex numbers have separate lives, so we
* simply ignore the second part.
*/
unsigned u;
size_t t, n, hn, m;
/*
* First iteration: compute f[j] + i * f[j+N/2] for all j < N/2
* (because GM[1] = w^rev(1) = w^(N/2) = i).
* In our chosen representation, this is a no-op: everything is
* already where it should be.
*/
/*
* Subsequent iterations are truncated to use only the first
* half of values.
*/
n = (size_t)1 << logn;
hn = n >> 1;
t = hn;
for (u = 1, m = 2; u < logn; u ++, m <<= 1) {
size_t ht, hm, i1, j1;
ht = t >> 1;
hm = m >> 1;
for (i1 = 0, j1 = 0; i1 < hm; i1 ++, j1 += t) {
size_t j, j2;
j2 = j1 + ht;
fpr s_re, s_im;
s_re = fpr_gm_tab[((m + i1) << 1) + 0];
s_im = fpr_gm_tab[((m + i1) << 1) + 1];
for (j = j1; j < j2; j ++) {
fpr x_re, x_im, y_re, y_im;
x_re = f[j];
x_im = f[j + hn];
y_re = f[j + ht];
y_im = f[j + ht + hn];
FPC_MUL(y_re, y_im, y_re, y_im, s_re, s_im);
FPC_ADD(f[j], f[j + hn],
x_re, x_im, y_re, y_im);
FPC_SUB(f[j + ht], f[j + ht + hn],
x_re, x_im, y_re, y_im);
}
}
t = ht;
}
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_iFFT(fpr *f, unsigned logn) {
/*
* Inverse FFT algorithm in bit-reversal order uses the following
* iterative algorithm:
*
* t = 1
* for m = N; m > 1; m /= 2:
* hm = m/2
* dt = t*2
* for i1 = 0; i1 < hm; i1 ++:
* j1 = i1 * dt
* s = iGM[hm + i1]
* for j = j1; j < (j1 + t); j ++:
* x = f[j]
* y = f[j + t]
* f[j] = x + y
* f[j + t] = s * (x - y)
* t = dt
* for i1 = 0; i1 < N; i1 ++:
* f[i1] = f[i1] / N
*
* iGM[k] contains (1/w)^rev(k) for primitive root w = exp(i*pi/N)
* (actually, iGM[k] = 1/GM[k] = conj(GM[k])).
*
* In the main loop (not counting the final division loop), in
* all iterations except the last, the first and second half of f[]
* (as an array of complex numbers) are separate. In our chosen
* representation, we do not keep the second half.
*
* The last iteration recombines the recomputed half with the
* implicit half, and should yield only real numbers since the
* target polynomial is real; moreover, s = i at that step.
* Thus, when considering x and y:
* y = conj(x) since the final f[j] must be real
* Therefore, f[j] is filled with 2*Re(x), and f[j + t] is
* filled with 2*Im(x).
* But we already have Re(x) and Im(x) in array slots j and j+t
* in our chosen representation. That last iteration is thus a
* simple doubling of the values in all the array.
*
* We make the last iteration a no-op by tweaking the final
* division into a division by N/2, not N.
*/
size_t u, n, hn, t, m;
n = (size_t)1 << logn;
t = 1;
m = n;
hn = n >> 1;
for (u = logn; u > 1; u --) {
size_t hm, dt, i1, j1;
hm = m >> 1;
dt = t << 1;
for (i1 = 0, j1 = 0; j1 < hn; i1 ++, j1 += dt) {
size_t j, j2;
j2 = j1 + t;
fpr s_re, s_im;
s_re = fpr_gm_tab[((hm + i1) << 1) + 0];
s_im = fpr_neg(fpr_gm_tab[((hm + i1) << 1) + 1]);
for (j = j1; j < j2; j ++) {
fpr x_re, x_im, y_re, y_im;
x_re = f[j];
x_im = f[j + hn];
y_re = f[j + t];
y_im = f[j + t + hn];
FPC_ADD(f[j], f[j + hn],
x_re, x_im, y_re, y_im);
FPC_SUB(x_re, x_im, x_re, x_im, y_re, y_im);
FPC_MUL(f[j + t], f[j + t + hn],
x_re, x_im, s_re, s_im);
}
}
t = dt;
m = hm;
}
/*
* Last iteration is a no-op, provided that we divide by N/2
* instead of N. We need to make a special case for logn = 0.
*/
if (logn > 0) {
fpr ni;
ni = fpr_p2_tab[logn];
for (u = 0; u < n; u ++) {
f[u] = fpr_mul(f[u], ni);
}
}
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_poly_add(
fpr *a, const fpr *b, unsigned logn) {
size_t n, u;
n = (size_t)1 << logn;
for (u = 0; u < n; u ++) {
a[u] = fpr_add(a[u], b[u]);
}
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_poly_sub(
fpr *a, const fpr *b, unsigned logn) {
size_t n, u;
n = (size_t)1 << logn;
for (u = 0; u < n; u ++) {
a[u] = fpr_sub(a[u], b[u]);
}
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_poly_neg(fpr *a, unsigned logn) {
size_t n, u;
n = (size_t)1 << logn;
for (u = 0; u < n; u ++) {
a[u] = fpr_neg(a[u]);
}
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_poly_adj_fft(fpr *a, unsigned logn) {
size_t n, u;
n = (size_t)1 << logn;
for (u = (n >> 1); u < n; u ++) {
a[u] = fpr_neg(a[u]);
}
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_poly_mul_fft(
fpr *a, const fpr *b, unsigned logn) {
size_t n, hn, u;
n = (size_t)1 << logn;
hn = n >> 1;
for (u = 0; u < hn; u ++) {
fpr a_re, a_im, b_re, b_im;
a_re = a[u];
a_im = a[u + hn];
b_re = b[u];
b_im = b[u + hn];
FPC_MUL(a[u], a[u + hn], a_re, a_im, b_re, b_im);
}
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_poly_muladj_fft(
fpr *a, const fpr *b, unsigned logn) {
size_t n, hn, u;
n = (size_t)1 << logn;
hn = n >> 1;
for (u = 0; u < hn; u ++) {
fpr a_re, a_im, b_re, b_im;
a_re = a[u];
a_im = a[u + hn];
b_re = b[u];
b_im = fpr_neg(b[u + hn]);
FPC_MUL(a[u], a[u + hn], a_re, a_im, b_re, b_im);
}
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_poly_mulselfadj_fft(fpr *a, unsigned logn) {
/*
* Since each coefficient is multiplied with its own conjugate,
* the result contains only real values.
*/
size_t n, hn, u;
n = (size_t)1 << logn;
hn = n >> 1;
for (u = 0; u < hn; u ++) {
fpr a_re, a_im;
a_re = a[u];
a_im = a[u + hn];
a[u] = fpr_add(fpr_sqr(a_re), fpr_sqr(a_im));
a[u + hn] = fpr_zero;
}
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_poly_mulconst(fpr *a, fpr x, unsigned logn) {
size_t n, u;
n = (size_t)1 << logn;
for (u = 0; u < n; u ++) {
a[u] = fpr_mul(a[u], x);
}
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_poly_div_fft(
fpr *a, const fpr *b, unsigned logn) {
size_t n, hn, u;
n = (size_t)1 << logn;
hn = n >> 1;
for (u = 0; u < hn; u ++) {
fpr a_re, a_im, b_re, b_im;
a_re = a[u];
a_im = a[u + hn];
b_re = b[u];
b_im = b[u + hn];
FPC_DIV(a[u], a[u + hn], a_re, a_im, b_re, b_im);
}
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_poly_invnorm2_fft(fpr *d,
const fpr *a, const fpr *b, unsigned logn) {
size_t n, hn, u;
n = (size_t)1 << logn;
hn = n >> 1;
for (u = 0; u < hn; u ++) {
fpr a_re, a_im;
fpr b_re, b_im;
a_re = a[u];
a_im = a[u + hn];
b_re = b[u];
b_im = b[u + hn];
d[u] = fpr_inv(fpr_add(
fpr_add(fpr_sqr(a_re), fpr_sqr(a_im)),
fpr_add(fpr_sqr(b_re), fpr_sqr(b_im))));
}
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_poly_add_muladj_fft(fpr *d,
const fpr *F, const fpr *G,
const fpr *f, const fpr *g, unsigned logn) {
size_t n, hn, u;
n = (size_t)1 << logn;
hn = n >> 1;
for (u = 0; u < hn; u ++) {
fpr F_re, F_im, G_re, G_im;
fpr f_re, f_im, g_re, g_im;
fpr a_re, a_im, b_re, b_im;
F_re = F[u];
F_im = F[u + hn];
G_re = G[u];
G_im = G[u + hn];
f_re = f[u];
f_im = f[u + hn];
g_re = g[u];
g_im = g[u + hn];
FPC_MUL(a_re, a_im, F_re, F_im, f_re, fpr_neg(f_im));
FPC_MUL(b_re, b_im, G_re, G_im, g_re, fpr_neg(g_im));
d[u] = fpr_add(a_re, b_re);
d[u + hn] = fpr_add(a_im, b_im);
}
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_poly_mul_autoadj_fft(
fpr *a, const fpr *b, unsigned logn) {
size_t n, hn, u;
n = (size_t)1 << logn;
hn = n >> 1;
for (u = 0; u < hn; u ++) {
a[u] = fpr_mul(a[u], b[u]);
a[u + hn] = fpr_mul(a[u + hn], b[u]);
}
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_poly_div_autoadj_fft(
fpr *a, const fpr *b, unsigned logn) {
size_t n, hn, u;
n = (size_t)1 << logn;
hn = n >> 1;
for (u = 0; u < hn; u ++) {
fpr ib;
ib = fpr_inv(b[u]);
a[u] = fpr_mul(a[u], ib);
a[u + hn] = fpr_mul(a[u + hn], ib);
}
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_poly_LDL_fft(
const fpr *g00,
fpr *g01, fpr *g11, unsigned logn) {
size_t n, hn, u;
n = (size_t)1 << logn;
hn = n >> 1;
for (u = 0; u < hn; u ++) {
fpr g00_re, g00_im, g01_re, g01_im, g11_re, g11_im;
fpr mu_re, mu_im;
g00_re = g00[u];
g00_im = g00[u + hn];
g01_re = g01[u];
g01_im = g01[u + hn];
g11_re = g11[u];
g11_im = g11[u + hn];
FPC_DIV(mu_re, mu_im, g01_re, g01_im, g00_re, g00_im);
FPC_MUL(g01_re, g01_im, mu_re, mu_im, g01_re, fpr_neg(g01_im));
FPC_SUB(g11[u], g11[u + hn], g11_re, g11_im, g01_re, g01_im);
g01[u] = mu_re;
g01[u + hn] = fpr_neg(mu_im);
}
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_poly_LDLmv_fft(
fpr *d11, fpr *l10,
const fpr *g00, const fpr *g01,
const fpr *g11, unsigned logn) {
size_t n, hn, u;
n = (size_t)1 << logn;
hn = n >> 1;
for (u = 0; u < hn; u ++) {
fpr g00_re, g00_im, g01_re, g01_im, g11_re, g11_im;
fpr mu_re, mu_im;
g00_re = g00[u];
g00_im = g00[u + hn];
g01_re = g01[u];
g01_im = g01[u + hn];
g11_re = g11[u];
g11_im = g11[u + hn];
FPC_DIV(mu_re, mu_im, g01_re, g01_im, g00_re, g00_im);
FPC_MUL(g01_re, g01_im, mu_re, mu_im, g01_re, fpr_neg(g01_im));
FPC_SUB(d11[u], d11[u + hn], g11_re, g11_im, g01_re, g01_im);
l10[u] = mu_re;
l10[u + hn] = fpr_neg(mu_im);
}
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_poly_split_fft(
fpr *f0, fpr *f1,
const fpr *f, unsigned logn) {
/*
* The FFT representation we use is in bit-reversed order
* (element i contains f(w^(rev(i))), where rev() is the
* bit-reversal function over the ring degree. This changes
* indexes with regards to the Falcon specification.
*/
size_t n, hn, qn, u;
n = (size_t)1 << logn;
hn = n >> 1;
qn = hn >> 1;
/*
* We process complex values by pairs. For logn = 1, there is only
* one complex value (the other one is the implicit conjugate),
* so we add the two lines below because the loop will be
* skipped.
*/
f0[0] = f[0];
f1[0] = f[hn];
for (u = 0; u < qn; u ++) {
fpr a_re, a_im, b_re, b_im;
fpr t_re, t_im;
a_re = f[(u << 1) + 0];
a_im = f[(u << 1) + 0 + hn];
b_re = f[(u << 1) + 1];
b_im = f[(u << 1) + 1 + hn];
FPC_ADD(t_re, t_im, a_re, a_im, b_re, b_im);
f0[u] = fpr_half(t_re);
f0[u + qn] = fpr_half(t_im);
FPC_SUB(t_re, t_im, a_re, a_im, b_re, b_im);
FPC_MUL(t_re, t_im, t_re, t_im,
fpr_gm_tab[((u + hn) << 1) + 0],
fpr_neg(fpr_gm_tab[((u + hn) << 1) + 1]));
f1[u] = fpr_half(t_re);
f1[u + qn] = fpr_half(t_im);
}
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_poly_merge_fft(
fpr *f,
const fpr *f0, const fpr *f1, unsigned logn) {
size_t n, hn, qn, u;
n = (size_t)1 << logn;
hn = n >> 1;
qn = hn >> 1;
/*
* An extra copy to handle the special case logn = 1.
*/
f[0] = f0[0];
f[hn] = f1[0];
for (u = 0; u < qn; u ++) {
fpr a_re, a_im, b_re, b_im;
fpr t_re, t_im;
a_re = f0[u];
a_im = f0[u + qn];
FPC_MUL(b_re, b_im, f1[u], f1[u + qn],
fpr_gm_tab[((u + hn) << 1) + 0],
fpr_gm_tab[((u + hn) << 1) + 1]);
FPC_ADD(t_re, t_im, a_re, a_im, b_re, b_im);
f[(u << 1) + 0] = t_re;
f[(u << 1) + 0 + hn] = t_im;
FPC_SUB(t_re, t_im, a_re, a_im, b_re, b_im);
f[(u << 1) + 1] = t_re;
f[(u << 1) + 1 + hn] = t_im;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,458 +0,0 @@
/*
* Floating-point operations.
*
* ==========================(LICENSE BEGIN)============================
*
* Copyright (c) 2017-2019 Falcon Project
*
* 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.
*
* ===========================(LICENSE END)=============================
*
* @author Thomas Pornin <thomas.pornin@nccgroup.com>
*/
/* ====================================================================== */
/*
* Custom floating-point implementation with integer arithmetics. We
* use IEEE-754 "binary64" format, with some simplifications:
*
* - Top bit is s = 1 for negative, 0 for positive.
*
* - Exponent e uses the next 11 bits (bits 52 to 62, inclusive).
*
* - Mantissa m uses the 52 low bits.
*
* Encoded value is, in general: (-1)^s * 2^(e-1023) * (1 + m*2^(-52))
* i.e. the mantissa really is a 53-bit number (less than 2.0, but not
* less than 1.0), but the top bit (equal to 1 by definition) is omitted
* in the encoding.
*
* In IEEE-754, there are some special values:
*
* - If e = 2047, then the value is either an infinite (m = 0) or
* a NaN (m != 0).
*
* - If e = 0, then the value is either a zero (m = 0) or a subnormal,
* aka "denormalized number" (m != 0).
*
* Of these, we only need the zeros. The caller is responsible for not
* providing operands that would lead to infinites, NaNs or subnormals.
* If inputs are such that values go out of range, then indeterminate
* values are returned (it would still be deterministic, but no specific
* value may be relied upon).
*
* At the C level, the three parts are stored in a 64-bit unsigned
* word.
*
* One may note that a property of the IEEE-754 format is that order
* is preserved for positive values: if two positive floating-point
* values x and y are such that x < y, then their respective encodings
* as _signed_ 64-bit integers i64(x) and i64(y) will be such that
* i64(x) < i64(y). For negative values, order is reversed: if x < 0,
* y < 0, and x < y, then ia64(x) > ia64(y).
*
* IMPORTANT ASSUMPTIONS:
* ======================
*
* For proper computations, and constant-time behaviour, we assume the
* following:
*
* - 32x32->64 multiplication (unsigned) has an execution time that
* is independent of its operands. This is true of most modern
* x86 and ARM cores. Notable exceptions are the ARM Cortex M0, M0+
* and M3 (in the M0 and M0+, this is done in software, so it depends
* on that routine), and the PowerPC cores from the G3/G4 lines.
* For more info, see: https://www.bearssl.org/ctmul.html
*
* - Left-shifts and right-shifts of 32-bit values have an execution
* time which does not depend on the shifted value nor on the
* shift count. An historical exception is the Pentium IV, but most
* modern CPU have barrel shifters. Some small microcontrollers
* might have varying-time shifts (not the ARM Cortex M*, though).
*
* - Right-shift of a signed negative value performs a sign extension.
* As per the C standard, this operation returns an
* implementation-defined result (this is NOT an "undefined
* behaviour"). On most/all systems, an arithmetic shift is
* performed, because this is what makes most sense.
*/
/*
* Normally we should declare the 'fpr' type to be a struct or union
* around the internal 64-bit value; however, we want to use the
* direct 64-bit integer type to enable a lighter call convention on
* ARM platforms. This means that direct (invalid) use of operators
* such as '*' or '+' will not be caught by the compiler. We rely on
* the "normal" (non-emulated) code to detect such instances.
*/
typedef uint64_t fpr;
/*
* For computations, we split values into an integral mantissa in the
* 2^54..2^55 range, and an (adjusted) exponent. The lowest bit is
* "sticky" (it is set to 1 if any of the bits below it is 1); when
* re-encoding, the low two bits are dropped, but may induce an
* increment in the value for proper rounding.
*/
/*
* Right-shift a 64-bit unsigned value by a possibly secret shift count.
* We assumed that the underlying architecture had a barrel shifter for
* 32-bit shifts, but for 64-bit shifts on a 32-bit system, this will
* typically invoke a software routine that is not necessarily
* constant-time; hence the function below.
*
* Shift count n MUST be in the 0..63 range.
*/
static inline uint64_t
fpr_ursh(uint64_t x, int n) {
x ^= (x ^ (x >> 32)) & -(uint64_t)(n >> 5);
return x >> (n & 31);
}
/*
* Right-shift a 64-bit signed value by a possibly secret shift count
* (see fpr_ursh() for the rationale).
*
* Shift count n MUST be in the 0..63 range.
*/
static inline int64_t
fpr_irsh(int64_t x, int n) {
x ^= (x ^ (x >> 32)) & -(int64_t)(n >> 5);
return x >> (n & 31);
}
/*
* Left-shift a 64-bit unsigned value by a possibly secret shift count
* (see fpr_ursh() for the rationale).
*
* Shift count n MUST be in the 0..63 range.
*/
static inline uint64_t
fpr_ulsh(uint64_t x, int n) {
x ^= (x ^ (x << 32)) & -(uint64_t)(n >> 5);
return x << (n & 31);
}
/*
* Expectations:
* s = 0 or 1
* exponent e is "arbitrary" and unbiased
* 2^54 <= m < 2^55
* Numerical value is (-1)^2 * m * 2^e
*
* Exponents which are too low lead to value zero. If the exponent is
* too large, the returned value is indeterminate.
*
* If m = 0, then a zero is returned (using the provided sign).
* If e < -1076, then a zero is returned (regardless of the value of m).
* If e >= -1076 and e != 0, m must be within the expected range
* (2^54 to 2^55-1).
*/
static inline fpr
FPR(int s, int e, uint64_t m) {
fpr x;
uint32_t t;
unsigned f;
/*
* If e >= -1076, then the value is "normal"; otherwise, it
* should be a subnormal, which we clamp down to zero.
*/
e += 1076;
t = (uint32_t)e >> 31;
m &= (uint64_t)t - 1;
/*
* If m = 0 then we want a zero; make e = 0 too, but conserve
* the sign.
*/
t = (uint32_t)(m >> 54);
e &= -(int)t;
/*
* The 52 mantissa bits come from m. Value m has its top bit set
* (unless it is a zero); we leave it "as is": the top bit will
* increment the exponent by 1, except when m = 0, which is
* exactly what we want.
*/
x = (((uint64_t)s << 63) | (m >> 2)) + ((uint64_t)(uint32_t)e << 52);
/*
* Rounding: if the low three bits of m are 011, 110 or 111,
* then the value should be incremented to get the next
* representable value. This implements the usual
* round-to-nearest rule (with preference to even values in case
* of a tie). Note that the increment may make a carry spill
* into the exponent field, which is again exactly what we want
* in that case.
*/
f = (unsigned)m & 7U;
x += (0xC8U >> f) & 1;
return x;
}
#define fpr_scaled PQCLEAN_FALCON1024_CLEAN_fpr_scaled
fpr fpr_scaled(int64_t i, int sc);
static inline fpr
fpr_of(int64_t i) {
return fpr_scaled(i, 0);
}
static const fpr fpr_q = 4667981563525332992;
static const fpr fpr_inverse_of_q = 4545632735260551042;
static const fpr fpr_inv_2sqrsigma0 = 4594603506513722306;
static const fpr fpr_inv_sigma = 4573359825155195350;
static const fpr fpr_sigma_min_9 = 4608495221497168882;
static const fpr fpr_sigma_min_10 = 4608586345619182117;
static const fpr fpr_log2 = 4604418534313441775;
static const fpr fpr_inv_log2 = 4609176140021203710;
static const fpr fpr_bnorm_max = 4670353323383631276;
static const fpr fpr_zero = 0;
static const fpr fpr_one = 4607182418800017408;
static const fpr fpr_two = 4611686018427387904;
static const fpr fpr_onehalf = 4602678819172646912;
static const fpr fpr_invsqrt2 = 4604544271217802189;
static const fpr fpr_invsqrt8 = 4600040671590431693;
static const fpr fpr_ptwo31 = 4746794007248502784;
static const fpr fpr_ptwo31m1 = 4746794007244308480;
static const fpr fpr_mtwo31m1 = 13970166044099084288U;
static const fpr fpr_ptwo63m1 = 4890909195324358656;
static const fpr fpr_mtwo63m1 = 14114281232179134464U;
static const fpr fpr_ptwo63 = 4890909195324358656;
static inline int64_t
fpr_rint(fpr x) {
uint64_t m, d;
int e;
uint32_t s, dd, f;
/*
* We assume that the value fits in -(2^63-1)..+(2^63-1). We can
* thus extract the mantissa as a 63-bit integer, then right-shift
* it as needed.
*/
m = ((x << 10) | ((uint64_t)1 << 62)) & (((uint64_t)1 << 63) - 1);
e = 1085 - ((int)(x >> 52) & 0x7FF);
/*
* If a shift of more than 63 bits is needed, then simply set m
* to zero. This also covers the case of an input operand equal
* to zero.
*/
m &= -(uint64_t)((uint32_t)(e - 64) >> 31);
e &= 63;
/*
* Right-shift m as needed. Shift count is e. Proper rounding
* mandates that:
* - If the highest dropped bit is zero, then round low.
* - If the highest dropped bit is one, and at least one of the
* other dropped bits is one, then round up.
* - If the highest dropped bit is one, and all other dropped
* bits are zero, then round up if the lowest kept bit is 1,
* or low otherwise (i.e. ties are broken by "rounding to even").
*
* We thus first extract a word consisting of all the dropped bit
* AND the lowest kept bit; then we shrink it down to three bits,
* the lowest being "sticky".
*/
d = fpr_ulsh(m, 63 - e);
dd = (uint32_t)d | ((uint32_t)(d >> 32) & 0x1FFFFFFF);
f = (uint32_t)(d >> 61) | ((dd | -dd) >> 31);
m = fpr_ursh(m, e) + (uint64_t)((0xC8U >> f) & 1U);
/*
* Apply the sign bit.
*/
s = (uint32_t)(x >> 63);
return ((int64_t)m ^ -(int64_t)s) + (int64_t)s;
}
static inline int64_t
fpr_floor(fpr x) {
uint64_t t;
int64_t xi;
int e, cc;
/*
* We extract the integer as a _signed_ 64-bit integer with
* a scaling factor. Since we assume that the value fits
* in the -(2^63-1)..+(2^63-1) range, we can left-shift the
* absolute value to make it in the 2^62..2^63-1 range: we
* will only need a right-shift afterwards.
*/
e = (int)(x >> 52) & 0x7FF;
t = x >> 63;
xi = (int64_t)(((x << 10) | ((uint64_t)1 << 62))
& (((uint64_t)1 << 63) - 1));
xi = (xi ^ -(int64_t)t) + (int64_t)t;
cc = 1085 - e;
/*
* We perform an arithmetic right-shift on the value. This
* applies floor() semantics on both positive and negative values
* (rounding toward minus infinity).
*/
xi = fpr_irsh(xi, cc & 63);
/*
* If the true shift count was 64 or more, then we should instead
* replace xi with 0 (if nonnegative) or -1 (if negative). Edge
* case: -0 will be floored to -1, not 0 (whether this is correct
* is debatable; in any case, the other functions normalize zero
* to +0).
*
* For an input of zero, the non-shifted xi was incorrect (we used
* a top implicit bit of value 1, not 0), but this does not matter
* since this operation will clamp it down.
*/
xi ^= (xi ^ -(int64_t)t) & -(int64_t)((uint32_t)(63 - cc) >> 31);
return xi;
}
static inline int64_t
fpr_trunc(fpr x) {
uint64_t t, xu;
int e, cc;
/*
* Extract the absolute value. Since we assume that the value
* fits in the -(2^63-1)..+(2^63-1) range, we can left-shift
* the absolute value into the 2^62..2^63-1 range, and then
* do a right shift afterwards.
*/
e = (int)(x >> 52) & 0x7FF;
xu = ((x << 10) | ((uint64_t)1 << 62)) & (((uint64_t)1 << 63) - 1);
cc = 1085 - e;
xu = fpr_ursh(xu, cc & 63);
/*
* If the exponent is too low (cc > 63), then the shift was wrong
* and we must clamp the value to 0. This also covers the case
* of an input equal to zero.
*/
xu &= -(uint64_t)((uint32_t)(cc - 64) >> 31);
/*
* Apply back the sign, if the source value is negative.
*/
t = x >> 63;
xu = (xu ^ -t) + t;
return *(int64_t *)&xu;
}
#define fpr_add PQCLEAN_FALCON1024_CLEAN_fpr_add
fpr fpr_add(fpr x, fpr y);
static inline fpr
fpr_sub(fpr x, fpr y) {
y ^= (uint64_t)1 << 63;
return fpr_add(x, y);
}
static inline fpr
fpr_neg(fpr x) {
x ^= (uint64_t)1 << 63;
return x;
}
static inline fpr
fpr_half(fpr x) {
/*
* To divide a value by 2, we just have to subtract 1 from its
* exponent, but we have to take care of zero.
*/
uint32_t t;
x -= (uint64_t)1 << 52;
t = (((uint32_t)(x >> 52) & 0x7FF) + 1) >> 11;
x &= (uint64_t)t - 1;
return x;
}
static inline fpr
fpr_double(fpr x) {
/*
* To double a value, we just increment by one the exponent. We
* don't care about infinites or NaNs; however, 0 is a
* special case.
*/
x += (uint64_t)((((unsigned)(x >> 52) & 0x7FFU) + 0x7FFU) >> 11) << 52;
return x;
}
#define fpr_mul PQCLEAN_FALCON1024_CLEAN_fpr_mul
fpr fpr_mul(fpr x, fpr y);
static inline fpr
fpr_sqr(fpr x) {
return fpr_mul(x, x);
}
#define fpr_div PQCLEAN_FALCON1024_CLEAN_fpr_div
fpr fpr_div(fpr x, fpr y);
static inline fpr
fpr_inv(fpr x) {
return fpr_div(4607182418800017408u, x);
}
#define fpr_sqrt PQCLEAN_FALCON1024_CLEAN_fpr_sqrt
fpr fpr_sqrt(fpr x);
static inline int
fpr_lt(fpr x, fpr y) {
/*
* If x >= 0 or y >= 0, a signed comparison yields the proper
* result:
* - For positive values, the order is preserved.
* - The sign bit is at the same place as in integers, so
* sign is preserved.
*
* If both x and y are negative, then the order is reversed.
* We cannot simply invert the comparison result in that case
* because it would not handle the edge case x = y properly.
*/
int cc0, cc1;
cc0 = *(int64_t *)&x < *(int64_t *)&y;
cc1 = *(int64_t *)&x > *(int64_t *)&y;
return cc0 ^ ((cc0 ^ cc1) & (int)((x & y) >> 63));
}
/*
* Compute exp(x) for x such that |x| <= ln 2. We want a precision of 50
* bits or so.
*/
#define fpr_expm_p63 PQCLEAN_FALCON1024_CLEAN_fpr_expm_p63
uint64_t fpr_expm_p63(fpr x, fpr ccs);
#define fpr_gm_tab PQCLEAN_FALCON1024_CLEAN_fpr_gm_tab
extern const fpr fpr_gm_tab[];
#define fpr_p2_tab PQCLEAN_FALCON1024_CLEAN_fpr_p2_tab
extern const fpr fpr_p2_tab[];
/* ====================================================================== */

View File

@ -1,835 +0,0 @@
#ifndef FALCON_INNER_H__
#define FALCON_INNER_H__
/*
* Internal functions for Falcon. This is not the API intended to be
* used by applications; instead, this internal API provides all the
* primitives on which wrappers build to provide external APIs.
*
* ==========================(LICENSE BEGIN)============================
*
* Copyright (c) 2017-2019 Falcon Project
*
* 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.
*
* ===========================(LICENSE END)=============================
*
* @author Thomas Pornin <thomas.pornin@nccgroup.com>
*/
/*
* IMPORTANT API RULES
* -------------------
*
* This API has some non-trivial usage rules:
*
*
* - All public functions (i.e. the non-static ones) must be referenced
* with the PQCLEAN_FALCON1024_CLEAN_ macro (e.g. PQCLEAN_FALCON1024_CLEAN_verify_raw for the verify_raw()
* function). That macro adds a prefix to the name, which is
* configurable with the FALCON_PREFIX macro. This allows compiling
* the code into a specific "namespace" and potentially including
* several versions of this code into a single application (e.g. to
* have an AVX2 and a non-AVX2 variants and select the one to use at
* runtime based on availability of AVX2 opcodes).
*
* - Functions that need temporary buffers expects them as a final
* tmp[] array of type uint8_t*, with a size which is documented for
* each function. However, most have some alignment requirements,
* because they will use the array to store 16-bit, 32-bit or 64-bit
* values (e.g. uint64_t or double). The caller must ensure proper
* alignment. What happens on unaligned access depends on the
* underlying architecture, ranging from a slight time penalty
* to immediate termination of the process.
*
* - Some functions rely on specific rounding rules and precision for
* floating-point numbers. On some systems (in particular 32-bit x86
* with the 387 FPU), this requires setting an hardware control
* word. The caller MUST use set_fpu_cw() to ensure proper precision:
*
* oldcw = set_fpu_cw(2);
* PQCLEAN_FALCON1024_CLEAN_sign_dyn(...);
* set_fpu_cw(oldcw);
*
* On systems where the native floating-point precision is already
* proper, or integer-based emulation is used, the set_fpu_cw()
* function does nothing, so it can be called systematically.
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
/*
* Some computations with floating-point elements, in particular
* rounding to the nearest integer, rely on operations using _exactly_
* the precision of IEEE-754 binary64 type (i.e. 52 bits). On 32-bit
* x86, the 387 FPU may be used (depending on the target OS) and, in
* that case, may use more precision bits (i.e. 64 bits, for an 80-bit
* total type length); to prevent miscomputations, we define an explicit
* function that modifies the precision in the FPU control word.
*
* set_fpu_cw() sets the precision to the provided value, and returns
* the previously set precision; callers are supposed to restore the
* previous precision on exit. The correct (52-bit) precision is
* configured with the value "2". On unsupported compilers, or on
* targets other than 32-bit x86, or when the native 'double' type is
* not used, the set_fpu_cw() function does nothing at all.
*/
static inline unsigned
set_fpu_cw(unsigned x) {
return x;
}
/* ==================================================================== */
/*
* SHAKE256 implementation (shake.c).
*
* API is defined to be easily replaced with the fips202.h API defined
* as part of PQClean.
*/
#include "fips202.h"
#define inner_shake256_context shake256incctx
#define inner_shake256_init(sc) shake256_inc_init(sc)
#define inner_shake256_inject(sc, in, len) shake256_inc_absorb(sc, in, len)
#define inner_shake256_flip(sc) shake256_inc_finalize(sc)
#define inner_shake256_extract(sc, out, len) shake256_inc_squeeze(out, len, sc)
#define inner_shake256_ctx_release(sc) shake256_inc_ctx_release(sc)
/* ==================================================================== */
/*
* Encoding/decoding functions (codec.c).
*
* Encoding functions take as parameters an output buffer (out) with
* a given maximum length (max_out_len); returned value is the actual
* number of bytes which have been written. If the output buffer is
* not large enough, then 0 is returned (some bytes may have been
* written to the buffer). If 'out' is NULL, then 'max_out_len' is
* ignored; instead, the function computes and returns the actual
* required output length (in bytes).
*
* Decoding functions take as parameters an input buffer (in) with
* its maximum length (max_in_len); returned value is the actual number
* of bytes that have been read from the buffer. If the provided length
* is too short, then 0 is returned.
*
* Values to encode or decode are vectors of integers, with N = 2^logn
* elements.
*
* Three encoding formats are defined:
*
* - modq: sequence of values modulo 12289, each encoded over exactly
* 14 bits. The encoder and decoder verify that integers are within
* the valid range (0..12288). Values are arrays of uint16.
*
* - trim: sequence of signed integers, a specified number of bits
* each. The number of bits is provided as parameter and includes
* the sign bit. Each integer x must be such that |x| < 2^(bits-1)
* (which means that the -2^(bits-1) value is forbidden); encode and
* decode functions check that property. Values are arrays of
* int16_t or int8_t, corresponding to names 'trim_i16' and
* 'trim_i8', respectively.
*
* - comp: variable-length encoding for signed integers; each integer
* uses a minimum of 9 bits, possibly more. This is normally used
* only for signatures.
*
*/
size_t PQCLEAN_FALCON1024_CLEAN_modq_encode(void *out, size_t max_out_len,
const uint16_t *x, unsigned logn);
size_t PQCLEAN_FALCON1024_CLEAN_trim_i16_encode(void *out, size_t max_out_len,
const int16_t *x, unsigned logn, unsigned bits);
size_t PQCLEAN_FALCON1024_CLEAN_trim_i8_encode(void *out, size_t max_out_len,
const int8_t *x, unsigned logn, unsigned bits);
size_t PQCLEAN_FALCON1024_CLEAN_comp_encode(void *out, size_t max_out_len,
const int16_t *x, unsigned logn);
size_t PQCLEAN_FALCON1024_CLEAN_modq_decode(uint16_t *x, unsigned logn,
const void *in, size_t max_in_len);
size_t PQCLEAN_FALCON1024_CLEAN_trim_i16_decode(int16_t *x, unsigned logn, unsigned bits,
const void *in, size_t max_in_len);
size_t PQCLEAN_FALCON1024_CLEAN_trim_i8_decode(int8_t *x, unsigned logn, unsigned bits,
const void *in, size_t max_in_len);
size_t PQCLEAN_FALCON1024_CLEAN_comp_decode(int16_t *x, unsigned logn,
const void *in, size_t max_in_len);
/*
* Number of bits for key elements, indexed by logn (1 to 10). This
* is at most 8 bits for all degrees, but some degrees may have shorter
* elements.
*/
extern const uint8_t PQCLEAN_FALCON1024_CLEAN_max_fg_bits[];
extern const uint8_t PQCLEAN_FALCON1024_CLEAN_max_FG_bits[];
/*
* Maximum size, in bits, of elements in a signature, indexed by logn
* (1 to 10). The size includes the sign bit.
*/
extern const uint8_t PQCLEAN_FALCON1024_CLEAN_max_sig_bits[];
/* ==================================================================== */
/*
* Support functions used for both signature generation and signature
* verification (common.c).
*/
/*
* From a SHAKE256 context (must be already flipped), produce a new
* point. This is the non-constant-time version, which may leak enough
* information to serve as a stop condition on a brute force attack on
* the hashed message (provided that the nonce value is known).
*/
void PQCLEAN_FALCON1024_CLEAN_hash_to_point_vartime(inner_shake256_context *sc,
uint16_t *x, unsigned logn);
/*
* From a SHAKE256 context (must be already flipped), produce a new
* point. The temporary buffer (tmp) must have room for 2*2^logn bytes.
* This function is constant-time but is typically more expensive than
* PQCLEAN_FALCON1024_CLEAN_hash_to_point_vartime().
*
* tmp[] must have 16-bit alignment.
*/
void PQCLEAN_FALCON1024_CLEAN_hash_to_point_ct(inner_shake256_context *sc,
uint16_t *x, unsigned logn, uint8_t *tmp);
/*
* Tell whether a given vector (2N coordinates, in two halves) is
* acceptable as a signature. This compares the appropriate norm of the
* vector with the acceptance bound. Returned value is 1 on success
* (vector is short enough to be acceptable), 0 otherwise.
*/
int PQCLEAN_FALCON1024_CLEAN_is_short(const int16_t *s1, const int16_t *s2, unsigned logn);
/*
* Tell whether a given vector (2N coordinates, in two halves) is
* acceptable as a signature. Instead of the first half s1, this
* function receives the "saturated squared norm" of s1, i.e. the
* sum of the squares of the coordinates of s1 (saturated at 2^32-1
* if the sum exceeds 2^31-1).
*
* Returned value is 1 on success (vector is short enough to be
* acceptable), 0 otherwise.
*/
int PQCLEAN_FALCON1024_CLEAN_is_short_half(uint32_t sqn, const int16_t *s2, unsigned logn);
/* ==================================================================== */
/*
* Signature verification functions (vrfy.c).
*/
/*
* Convert a public key to NTT + Montgomery format. Conversion is done
* in place.
*/
void PQCLEAN_FALCON1024_CLEAN_to_ntt_monty(uint16_t *h, unsigned logn);
/*
* Internal signature verification code:
* c0[] contains the hashed nonce+message
* s2[] is the decoded signature
* h[] contains the public key, in NTT + Montgomery format
* logn is the degree log
* tmp[] temporary, must have at least 2*2^logn bytes
* Returned value is 1 on success, 0 on error.
*
* tmp[] must have 16-bit alignment.
*/
int PQCLEAN_FALCON1024_CLEAN_verify_raw(const uint16_t *c0, const int16_t *s2,
const uint16_t *h, unsigned logn, uint8_t *tmp);
/*
* Compute the public key h[], given the private key elements f[] and
* g[]. This computes h = g/f mod phi mod q, where phi is the polynomial
* modulus. This function returns 1 on success, 0 on error (an error is
* reported if f is not invertible mod phi mod q).
*
* The tmp[] array must have room for at least 2*2^logn elements.
* tmp[] must have 16-bit alignment.
*/
int PQCLEAN_FALCON1024_CLEAN_compute_public(uint16_t *h,
const int8_t *f, const int8_t *g, unsigned logn, uint8_t *tmp);
/*
* Recompute the fourth private key element. Private key consists in
* four polynomials with small coefficients f, g, F and G, which are
* such that fG - gF = q mod phi; furthermore, f is invertible modulo
* phi and modulo q. This function recomputes G from f, g and F.
*
* The tmp[] array must have room for at least 4*2^logn bytes.
*
* Returned value is 1 in success, 0 on error (f not invertible).
* tmp[] must have 16-bit alignment.
*/
int PQCLEAN_FALCON1024_CLEAN_complete_private(int8_t *G,
const int8_t *f, const int8_t *g, const int8_t *F,
unsigned logn, uint8_t *tmp);
/*
* Test whether a given polynomial is invertible modulo phi and q.
* Polynomial coefficients are small integers.
*
* tmp[] must have 16-bit alignment.
*/
int PQCLEAN_FALCON1024_CLEAN_is_invertible(
const int16_t *s2, unsigned logn, uint8_t *tmp);
/*
* Count the number of elements of value zero in the NTT representation
* of the given polynomial: this is the number of primitive 2n-th roots
* of unity (modulo q = 12289) that are roots of the provided polynomial
* (taken modulo q).
*
* tmp[] must have 16-bit alignment.
*/
int PQCLEAN_FALCON1024_CLEAN_count_nttzero(const int16_t *sig, unsigned logn, uint8_t *tmp);
/*
* Internal signature verification with public key recovery:
* h[] receives the public key (NOT in NTT/Montgomery format)
* c0[] contains the hashed nonce+message
* s1[] is the first signature half
* s2[] is the second signature half
* logn is the degree log
* tmp[] temporary, must have at least 2*2^logn bytes
* Returned value is 1 on success, 0 on error. Success is returned if
* the signature is a short enough vector; in that case, the public
* key has been written to h[]. However, the caller must still
* verify that h[] is the correct value (e.g. with regards to a known
* hash of the public key).
*
* h[] may not overlap with any of the other arrays.
*
* tmp[] must have 16-bit alignment.
*/
int PQCLEAN_FALCON1024_CLEAN_verify_recover(uint16_t *h,
const uint16_t *c0, const int16_t *s1, const int16_t *s2,
unsigned logn, uint8_t *tmp);
/* ==================================================================== */
/*
* Implementation of floating-point real numbers (fpr.h, fpr.c).
*/
/*
* Real numbers are implemented by an extra header file, included below.
* This is meant to support pluggable implementations. The default
* implementation relies on the C type 'double'.
*
* The included file must define the following types, functions and
* constants:
*
* fpr
* type for a real number
*
* fpr fpr_of(int64_t i)
* cast an integer into a real number; source must be in the
* -(2^63-1)..+(2^63-1) range
*
* fpr fpr_scaled(int64_t i, int sc)
* compute i*2^sc as a real number; source 'i' must be in the
* -(2^63-1)..+(2^63-1) range
*
* fpr fpr_ldexp(fpr x, int e)
* compute x*2^e
*
* int64_t fpr_rint(fpr x)
* round x to the nearest integer; x must be in the -(2^63-1)
* to +(2^63-1) range
*
* int64_t fpr_trunc(fpr x)
* round to an integer; this rounds towards zero; value must
* be in the -(2^63-1) to +(2^63-1) range
*
* fpr fpr_add(fpr x, fpr y)
* compute x + y
*
* fpr fpr_sub(fpr x, fpr y)
* compute x - y
*
* fpr fpr_neg(fpr x)
* compute -x
*
* fpr fpr_half(fpr x)
* compute x/2
*
* fpr fpr_double(fpr x)
* compute x*2
*
* fpr fpr_mul(fpr x, fpr y)
* compute x * y
*
* fpr fpr_sqr(fpr x)
* compute x * x
*
* fpr fpr_inv(fpr x)
* compute 1/x
*
* fpr fpr_div(fpr x, fpr y)
* compute x/y
*
* fpr fpr_sqrt(fpr x)
* compute the square root of x
*
* int fpr_lt(fpr x, fpr y)
* return 1 if x < y, 0 otherwise
*
* uint64_t fpr_expm_p63(fpr x)
* return exp(x), assuming that 0 <= x < log(2). Returned value
* is scaled to 63 bits (i.e. it really returns 2^63*exp(-x),
* rounded to the nearest integer). Computation should have a
* precision of at least 45 bits.
*
* const fpr fpr_gm_tab[]
* array of constants for FFT / iFFT
*
* const fpr fpr_p2_tab[]
* precomputed powers of 2 (by index, 0 to 10)
*
* Constants of type 'fpr':
*
* fpr fpr_q 12289
* fpr fpr_inverse_of_q 1/12289
* fpr fpr_inv_2sqrsigma0 1/(2*(1.8205^2))
* fpr fpr_inv_sigma 1/(1.55*sqrt(12289))
* fpr fpr_sigma_min_9 1.291500756233514568549480827642
* fpr fpr_sigma_min_10 1.311734375905083682667395805765
* fpr fpr_log2 log(2)
* fpr fpr_inv_log2 1/log(2)
* fpr fpr_bnorm_max 16822.4121
* fpr fpr_zero 0
* fpr fpr_one 1
* fpr fpr_two 2
* fpr fpr_onehalf 0.5
* fpr fpr_ptwo31 2^31
* fpr fpr_ptwo31m1 2^31-1
* fpr fpr_mtwo31m1 -(2^31-1)
* fpr fpr_ptwo63m1 2^63-1
* fpr fpr_mtwo63m1 -(2^63-1)
* fpr fpr_ptwo63 2^63
*/
#include "fpr.h"
/* ==================================================================== */
/*
* RNG (rng.c).
*
* A PRNG based on ChaCha20 is implemented; it is seeded from a SHAKE256
* context (flipped) and is used for bulk pseudorandom generation.
* A system-dependent seed generator is also provided.
*/
/*
* Obtain a random seed from the system RNG.
*
* Returned value is 1 on success, 0 on error.
*/
int PQCLEAN_FALCON1024_CLEAN_get_seed(void *seed, size_t seed_len);
/*
* Structure for a PRNG. This includes a large buffer so that values
* get generated in advance. The 'state' is used to keep the current
* PRNG algorithm state (contents depend on the selected algorithm).
*
* The unions with 'dummy_u64' are there to ensure proper alignment for
* 64-bit direct access.
*/
typedef struct {
union {
uint8_t d[512]; /* MUST be 512, exactly */
uint64_t dummy_u64;
} buf;
size_t ptr;
union {
uint8_t d[256];
uint64_t dummy_u64;
} state;
int type;
} prng;
/*
* Instantiate a PRNG. That PRNG will feed over the provided SHAKE256
* context (in "flipped" state) to obtain its initial state.
*/
void PQCLEAN_FALCON1024_CLEAN_prng_init(prng *p, inner_shake256_context *src);
/*
* Refill the PRNG buffer. This is normally invoked automatically, and
* is declared here only so that prng_get_u64() may be inlined.
*/
void PQCLEAN_FALCON1024_CLEAN_prng_refill(prng *p);
/*
* Get some bytes from a PRNG.
*/
void PQCLEAN_FALCON1024_CLEAN_prng_get_bytes(prng *p, void *dst, size_t len);
/*
* Get a 64-bit random value from a PRNG.
*/
static inline uint64_t
prng_get_u64(prng *p) {
size_t u;
/*
* If there are less than 9 bytes in the buffer, we refill it.
* This means that we may drop the last few bytes, but this allows
* for faster extraction code. Also, it means that we never leave
* an empty buffer.
*/
u = p->ptr;
if (u >= (sizeof p->buf.d) - 9) {
PQCLEAN_FALCON1024_CLEAN_prng_refill(p);
u = 0;
}
p->ptr = u + 8;
/*
* On systems that use little-endian encoding and allow
* unaligned accesses, we can simply read the data where it is.
*/
return (uint64_t)p->buf.d[u + 0]
| ((uint64_t)p->buf.d[u + 1] << 8)
| ((uint64_t)p->buf.d[u + 2] << 16)
| ((uint64_t)p->buf.d[u + 3] << 24)
| ((uint64_t)p->buf.d[u + 4] << 32)
| ((uint64_t)p->buf.d[u + 5] << 40)
| ((uint64_t)p->buf.d[u + 6] << 48)
| ((uint64_t)p->buf.d[u + 7] << 56);
}
/*
* Get an 8-bit random value from a PRNG.
*/
static inline unsigned
prng_get_u8(prng *p) {
unsigned v;
v = p->buf.d[p->ptr ++];
if (p->ptr == sizeof p->buf.d) {
PQCLEAN_FALCON1024_CLEAN_prng_refill(p);
}
return v;
}
/* ==================================================================== */
/*
* FFT (falcon-fft.c).
*
* A real polynomial is represented as an array of N 'fpr' elements.
* The FFT representation of a real polynomial contains N/2 complex
* elements; each is stored as two real numbers, for the real and
* imaginary parts, respectively. See falcon-fft.c for details on the
* internal representation.
*/
/*
* Compute FFT in-place: the source array should contain a real
* polynomial (N coefficients); its storage area is reused to store
* the FFT representation of that polynomial (N/2 complex numbers).
*
* 'logn' MUST lie between 1 and 10 (inclusive).
*/
void PQCLEAN_FALCON1024_CLEAN_FFT(fpr *f, unsigned logn);
/*
* Compute the inverse FFT in-place: the source array should contain the
* FFT representation of a real polynomial (N/2 elements); the resulting
* real polynomial (N coefficients of type 'fpr') is written over the
* array.
*
* 'logn' MUST lie between 1 and 10 (inclusive).
*/
void PQCLEAN_FALCON1024_CLEAN_iFFT(fpr *f, unsigned logn);
/*
* Add polynomial b to polynomial a. a and b MUST NOT overlap. This
* function works in both normal and FFT representations.
*/
void PQCLEAN_FALCON1024_CLEAN_poly_add(fpr *a, const fpr *b, unsigned logn);
/*
* Subtract polynomial b from polynomial a. a and b MUST NOT overlap. This
* function works in both normal and FFT representations.
*/
void PQCLEAN_FALCON1024_CLEAN_poly_sub(fpr *a, const fpr *b, unsigned logn);
/*
* Negate polynomial a. This function works in both normal and FFT
* representations.
*/
void PQCLEAN_FALCON1024_CLEAN_poly_neg(fpr *a, unsigned logn);
/*
* Compute adjoint of polynomial a. This function works only in FFT
* representation.
*/
void PQCLEAN_FALCON1024_CLEAN_poly_adj_fft(fpr *a, unsigned logn);
/*
* Multiply polynomial a with polynomial b. a and b MUST NOT overlap.
* This function works only in FFT representation.
*/
void PQCLEAN_FALCON1024_CLEAN_poly_mul_fft(fpr *a, const fpr *b, unsigned logn);
/*
* Multiply polynomial a with the adjoint of polynomial b. a and b MUST NOT
* overlap. This function works only in FFT representation.
*/
void PQCLEAN_FALCON1024_CLEAN_poly_muladj_fft(fpr *a, const fpr *b, unsigned logn);
/*
* Multiply polynomial with its own adjoint. This function works only in FFT
* representation.
*/
void PQCLEAN_FALCON1024_CLEAN_poly_mulselfadj_fft(fpr *a, unsigned logn);
/*
* Multiply polynomial with a real constant. This function works in both
* normal and FFT representations.
*/
void PQCLEAN_FALCON1024_CLEAN_poly_mulconst(fpr *a, fpr x, unsigned logn);
/*
* Divide polynomial a by polynomial b, modulo X^N+1 (FFT representation).
* a and b MUST NOT overlap.
*/
void PQCLEAN_FALCON1024_CLEAN_poly_div_fft(fpr *a, const fpr *b, unsigned logn);
/*
* Given f and g (in FFT representation), compute 1/(f*adj(f)+g*adj(g))
* (also in FFT representation). Since the result is auto-adjoint, all its
* coordinates in FFT representation are real; as such, only the first N/2
* values of d[] are filled (the imaginary parts are skipped).
*
* Array d MUST NOT overlap with either a or b.
*/
void PQCLEAN_FALCON1024_CLEAN_poly_invnorm2_fft(fpr *d,
const fpr *a, const fpr *b, unsigned logn);
/*
* Given F, G, f and g (in FFT representation), compute F*adj(f)+G*adj(g)
* (also in FFT representation). Destination d MUST NOT overlap with
* any of the source arrays.
*/
void PQCLEAN_FALCON1024_CLEAN_poly_add_muladj_fft(fpr *d,
const fpr *F, const fpr *G,
const fpr *f, const fpr *g, unsigned logn);
/*
* Multiply polynomial a by polynomial b, where b is autoadjoint. Both
* a and b are in FFT representation. Since b is autoadjoint, all its
* FFT coefficients are real, and the array b contains only N/2 elements.
* a and b MUST NOT overlap.
*/
void PQCLEAN_FALCON1024_CLEAN_poly_mul_autoadj_fft(fpr *a,
const fpr *b, unsigned logn);
/*
* Divide polynomial a by polynomial b, where b is autoadjoint. Both
* a and b are in FFT representation. Since b is autoadjoint, all its
* FFT coefficients are real, and the array b contains only N/2 elements.
* a and b MUST NOT overlap.
*/
void PQCLEAN_FALCON1024_CLEAN_poly_div_autoadj_fft(fpr *a,
const fpr *b, unsigned logn);
/*
* Perform an LDL decomposition of an auto-adjoint matrix G, in FFT
* representation. On input, g00, g01 and g11 are provided (where the
* matrix G = [[g00, g01], [adj(g01), g11]]). On output, the d00, l10
* and d11 values are written in g00, g01 and g11, respectively
* (with D = [[d00, 0], [0, d11]] and L = [[1, 0], [l10, 1]]).
* (In fact, d00 = g00, so the g00 operand is left unmodified.)
*/
void PQCLEAN_FALCON1024_CLEAN_poly_LDL_fft(const fpr *g00,
fpr *g01, fpr *g11, unsigned logn);
/*
* Perform an LDL decomposition of an auto-adjoint matrix G, in FFT
* representation. This is identical to poly_LDL_fft() except that
* g00, g01 and g11 are unmodified; the outputs d11 and l10 are written
* in two other separate buffers provided as extra parameters.
*/
void PQCLEAN_FALCON1024_CLEAN_poly_LDLmv_fft(fpr *d11, fpr *l10,
const fpr *g00, const fpr *g01,
const fpr *g11, unsigned logn);
/*
* Apply "split" operation on a polynomial in FFT representation:
* f = f0(x^2) + x*f1(x^2), for half-size polynomials f0 and f1
* (polynomials modulo X^(N/2)+1). f0, f1 and f MUST NOT overlap.
*/
void PQCLEAN_FALCON1024_CLEAN_poly_split_fft(fpr *f0, fpr *f1,
const fpr *f, unsigned logn);
/*
* Apply "merge" operation on two polynomials in FFT representation:
* given f0 and f1, polynomials moduo X^(N/2)+1, this function computes
* f = f0(x^2) + x*f1(x^2), in FFT representation modulo X^N+1.
* f MUST NOT overlap with either f0 or f1.
*/
void PQCLEAN_FALCON1024_CLEAN_poly_merge_fft(fpr *f,
const fpr *f0, const fpr *f1, unsigned logn);
/* ==================================================================== */
/*
* Key pair generation.
*/
/*
* Required sizes of the temporary buffer (in bytes).
*
* This size is 28*2^logn bytes, except for degrees 2 and 4 (logn = 1
* or 2) where it is slightly greater.
*/
#define FALCON_KEYGEN_TEMP_1 136
#define FALCON_KEYGEN_TEMP_2 272
#define FALCON_KEYGEN_TEMP_3 224
#define FALCON_KEYGEN_TEMP_4 448
#define FALCON_KEYGEN_TEMP_5 896
#define FALCON_KEYGEN_TEMP_6 1792
#define FALCON_KEYGEN_TEMP_7 3584
#define FALCON_KEYGEN_TEMP_8 7168
#define FALCON_KEYGEN_TEMP_9 14336
#define FALCON_KEYGEN_TEMP_10 28672
/*
* Generate a new key pair. Randomness is extracted from the provided
* SHAKE256 context, which must have already been seeded and flipped.
* The tmp[] array must have suitable size (see FALCON_KEYGEN_TEMP_*
* macros) and be aligned for the uint32_t, uint64_t and fpr types.
*
* The private key elements are written in f, g, F and G, and the
* public key is written in h. Either or both of G and h may be NULL,
* in which case the corresponding element is not returned (they can
* be recomputed from f, g and F).
*
* tmp[] must have 64-bit alignment.
* This function uses floating-point rounding (see set_fpu_cw()).
*/
void PQCLEAN_FALCON1024_CLEAN_keygen(inner_shake256_context *rng,
int8_t *f, int8_t *g, int8_t *F, int8_t *G, uint16_t *h,
unsigned logn, uint8_t *tmp);
/* ==================================================================== */
/*
* Signature generation.
*/
/*
* Expand a private key into the B0 matrix in FFT representation and
* the LDL tree. All the values are written in 'expanded_key', for
* a total of (8*logn+40)*2^logn bytes.
*
* The tmp[] array must have room for at least 48*2^logn bytes.
*
* tmp[] must have 64-bit alignment.
* This function uses floating-point rounding (see set_fpu_cw()).
*/
void PQCLEAN_FALCON1024_CLEAN_expand_privkey(fpr *expanded_key,
const int8_t *f, const int8_t *g, const int8_t *F, const int8_t *G,
unsigned logn, uint8_t *tmp);
/*
* Compute a signature over the provided hashed message (hm); the
* signature value is one short vector. This function uses an
* expanded key (as generated by PQCLEAN_FALCON1024_CLEAN_expand_privkey()).
*
* The sig[] and hm[] buffers may overlap.
*
* On successful output, the start of the tmp[] buffer contains the s1
* vector (as int16_t elements).
*
* The minimal size (in bytes) of tmp[] is 48*2^logn bytes.
*
* tmp[] must have 64-bit alignment.
* This function uses floating-point rounding (see set_fpu_cw()).
*/
void PQCLEAN_FALCON1024_CLEAN_sign_tree(int16_t *sig, inner_shake256_context *rng,
const fpr *expanded_key,
const uint16_t *hm, unsigned logn, uint8_t *tmp);
/*
* Compute a signature over the provided hashed message (hm); the
* signature value is one short vector. This function uses a raw
* key and dynamically recompute the B0 matrix and LDL tree; this
* saves RAM since there is no needed for an expanded key, but
* increases the signature cost.
*
* The sig[] and hm[] buffers may overlap.
*
* On successful output, the start of the tmp[] buffer contains the s1
* vector (as int16_t elements).
*
* The minimal size (in bytes) of tmp[] is 72*2^logn bytes.
*
* tmp[] must have 64-bit alignment.
* This function uses floating-point rounding (see set_fpu_cw()).
*/
void PQCLEAN_FALCON1024_CLEAN_sign_dyn(int16_t *sig, inner_shake256_context *rng,
const int8_t *f, const int8_t *g,
const int8_t *F, const int8_t *G,
const uint16_t *hm, unsigned logn, uint8_t *tmp);
/*
* Internal sampler engine. Exported for tests.
*
* sampler_context wraps around a source of random numbers (PRNG) and
* the sigma_min value (nominally dependent on the degree).
*
* sampler() takes as parameters:
* ctx pointer to the sampler_context structure
* mu center for the distribution
* isigma inverse of the distribution standard deviation
* It returns an integer sampled along the Gaussian distribution centered
* on mu and of standard deviation sigma = 1/isigma.
*
* gaussian0_sampler() takes as parameter a pointer to a PRNG, and
* returns an integer sampled along a half-Gaussian with standard
* deviation sigma0 = 1.8205 (center is 0, returned value is
* nonnegative).
*/
typedef struct {
prng p;
fpr sigma_min;
} sampler_context;
int PQCLEAN_FALCON1024_CLEAN_sampler(void *ctx, fpr mu, fpr isigma);
int PQCLEAN_FALCON1024_CLEAN_gaussian0_sampler(prng *p);
/* ==================================================================== */
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,385 +0,0 @@
/*
* Wrapper for implementing the PQClean API.
*/
#include <stddef.h>
#include <string.h>
#include "api.h"
#include "inner.h"
#define NONCELEN 40
#include "randombytes.h"
/*
* Encoding formats (nnnn = log of degree, 9 for Falcon-512, 10 for Falcon-1024)
*
* private key:
* header byte: 0101nnnn
* private f (6 or 5 bits by element, depending on degree)
* private g (6 or 5 bits by element, depending on degree)
* private F (8 bits by element)
*
* public key:
* header byte: 0000nnnn
* public h (14 bits by element)
*
* signature:
* header byte: 0011nnnn
* nonce 40 bytes
* value (12 bits by element)
*
* message + signature:
* signature length (2 bytes, big-endian)
* nonce 40 bytes
* message
* header byte: 0010nnnn
* value (12 bits by element)
* (signature length is 1+len(value), not counting the nonce)
*/
/* see api.h */
int
PQCLEAN_FALCON1024_CLEAN_crypto_sign_keypair(
uint8_t *pk, uint8_t *sk) {
union {
uint8_t b[FALCON_KEYGEN_TEMP_10];
uint64_t dummy_u64;
fpr dummy_fpr;
} tmp;
int8_t f[1024], g[1024], F[1024];
uint16_t h[1024];
unsigned char seed[48];
inner_shake256_context rng;
size_t u, v;
/*
* Generate key pair.
*/
randombytes(seed, sizeof seed);
inner_shake256_init(&rng);
inner_shake256_inject(&rng, seed, sizeof seed);
inner_shake256_flip(&rng);
PQCLEAN_FALCON1024_CLEAN_keygen(&rng, f, g, F, NULL, h, 10, tmp.b);
inner_shake256_ctx_release(&rng);
/*
* Encode private key.
*/
sk[0] = 0x50 + 10;
u = 1;
v = PQCLEAN_FALCON1024_CLEAN_trim_i8_encode(
sk + u, PQCLEAN_FALCON1024_CLEAN_CRYPTO_SECRETKEYBYTES - u,
f, 10, PQCLEAN_FALCON1024_CLEAN_max_fg_bits[10]);
if (v == 0) {
return -1;
}
u += v;
v = PQCLEAN_FALCON1024_CLEAN_trim_i8_encode(
sk + u, PQCLEAN_FALCON1024_CLEAN_CRYPTO_SECRETKEYBYTES - u,
g, 10, PQCLEAN_FALCON1024_CLEAN_max_fg_bits[10]);
if (v == 0) {
return -1;
}
u += v;
v = PQCLEAN_FALCON1024_CLEAN_trim_i8_encode(
sk + u, PQCLEAN_FALCON1024_CLEAN_CRYPTO_SECRETKEYBYTES - u,
F, 10, PQCLEAN_FALCON1024_CLEAN_max_FG_bits[10]);
if (v == 0) {
return -1;
}
u += v;
if (u != PQCLEAN_FALCON1024_CLEAN_CRYPTO_SECRETKEYBYTES) {
return -1;
}
/*
* Encode public key.
*/
pk[0] = 0x00 + 10;
v = PQCLEAN_FALCON1024_CLEAN_modq_encode(
pk + 1, PQCLEAN_FALCON1024_CLEAN_CRYPTO_PUBLICKEYBYTES - 1,
h, 10);
if (v != PQCLEAN_FALCON1024_CLEAN_CRYPTO_PUBLICKEYBYTES - 1) {
return -1;
}
return 0;
}
/*
* Compute the signature. nonce[] receives the nonce and must have length
* NONCELEN bytes. sigbuf[] receives the signature value (without nonce
* or header byte), with *sigbuflen providing the maximum value length and
* receiving the actual value length.
*
* If a signature could be computed but not encoded because it would
* exceed the output buffer size, then a new signature is computed. If
* the provided buffer size is too low, this could loop indefinitely, so
* the caller must provide a size that can accommodate signatures with a
* large enough probability.
*
* Return value: 0 on success, -1 on error.
*/
static int
do_sign(uint8_t *nonce, uint8_t *sigbuf, size_t *sigbuflen,
const uint8_t *m, size_t mlen, const uint8_t *sk) {
union {
uint8_t b[72 * 1024];
uint64_t dummy_u64;
fpr dummy_fpr;
} tmp;
int8_t f[1024], g[1024], F[1024], G[1024];
union {
int16_t sig[1024];
uint16_t hm[1024];
} r;
unsigned char seed[48];
inner_shake256_context sc;
size_t u, v;
/*
* Decode the private key.
*/
if (sk[0] != 0x50 + 10) {
return -1;
}
u = 1;
v = PQCLEAN_FALCON1024_CLEAN_trim_i8_decode(
f, 10, PQCLEAN_FALCON1024_CLEAN_max_fg_bits[10],
sk + u, PQCLEAN_FALCON1024_CLEAN_CRYPTO_SECRETKEYBYTES - u);
if (v == 0) {
return -1;
}
u += v;
v = PQCLEAN_FALCON1024_CLEAN_trim_i8_decode(
g, 10, PQCLEAN_FALCON1024_CLEAN_max_fg_bits[10],
sk + u, PQCLEAN_FALCON1024_CLEAN_CRYPTO_SECRETKEYBYTES - u);
if (v == 0) {
return -1;
}
u += v;
v = PQCLEAN_FALCON1024_CLEAN_trim_i8_decode(
F, 10, PQCLEAN_FALCON1024_CLEAN_max_FG_bits[10],
sk + u, PQCLEAN_FALCON1024_CLEAN_CRYPTO_SECRETKEYBYTES - u);
if (v == 0) {
return -1;
}
u += v;
if (u != PQCLEAN_FALCON1024_CLEAN_CRYPTO_SECRETKEYBYTES) {
return -1;
}
if (!PQCLEAN_FALCON1024_CLEAN_complete_private(G, f, g, F, 10, tmp.b)) {
return -1;
}
/*
* Create a random nonce (40 bytes).
*/
randombytes(nonce, NONCELEN);
/*
* Hash message nonce + message into a vector.
*/
inner_shake256_init(&sc);
inner_shake256_inject(&sc, nonce, NONCELEN);
inner_shake256_inject(&sc, m, mlen);
inner_shake256_flip(&sc);
PQCLEAN_FALCON1024_CLEAN_hash_to_point_ct(&sc, r.hm, 10, tmp.b);
inner_shake256_ctx_release(&sc);
/*
* Initialize a RNG.
*/
randombytes(seed, sizeof seed);
inner_shake256_init(&sc);
inner_shake256_inject(&sc, seed, sizeof seed);
inner_shake256_flip(&sc);
/*
* Compute and return the signature. This loops until a signature
* value is found that fits in the provided buffer.
*/
for (;;) {
PQCLEAN_FALCON1024_CLEAN_sign_dyn(r.sig, &sc, f, g, F, G, r.hm, 10, tmp.b);
v = PQCLEAN_FALCON1024_CLEAN_comp_encode(sigbuf, *sigbuflen, r.sig, 10);
if (v != 0) {
inner_shake256_ctx_release(&sc);
*sigbuflen = v;
return 0;
}
}
}
/*
* Verify a sigature. The nonce has size NONCELEN bytes. sigbuf[]
* (of size sigbuflen) contains the signature value, not including the
* header byte or nonce. Return value is 0 on success, -1 on error.
*/
static int
do_verify(
const uint8_t *nonce, const uint8_t *sigbuf, size_t sigbuflen,
const uint8_t *m, size_t mlen, const uint8_t *pk) {
union {
uint8_t b[2 * 1024];
uint64_t dummy_u64;
fpr dummy_fpr;
} tmp;
uint16_t h[1024], hm[1024];
int16_t sig[1024];
inner_shake256_context sc;
/*
* Decode public key.
*/
if (pk[0] != 0x00 + 10) {
return -1;
}
if (PQCLEAN_FALCON1024_CLEAN_modq_decode(h, 10,
pk + 1, PQCLEAN_FALCON1024_CLEAN_CRYPTO_PUBLICKEYBYTES - 1)
!= PQCLEAN_FALCON1024_CLEAN_CRYPTO_PUBLICKEYBYTES - 1) {
return -1;
}
PQCLEAN_FALCON1024_CLEAN_to_ntt_monty(h, 10);
/*
* Decode signature.
*/
if (sigbuflen == 0) {
return -1;
}
if (PQCLEAN_FALCON1024_CLEAN_comp_decode(sig, 10, sigbuf, sigbuflen) != sigbuflen) {
return -1;
}
/*
* Hash nonce + message into a vector.
*/
inner_shake256_init(&sc);
inner_shake256_inject(&sc, nonce, NONCELEN);
inner_shake256_inject(&sc, m, mlen);
inner_shake256_flip(&sc);
PQCLEAN_FALCON1024_CLEAN_hash_to_point_ct(&sc, hm, 10, tmp.b);
inner_shake256_ctx_release(&sc);
/*
* Verify signature.
*/
if (!PQCLEAN_FALCON1024_CLEAN_verify_raw(hm, sig, h, 10, tmp.b)) {
return -1;
}
return 0;
}
/* see api.h */
int
PQCLEAN_FALCON1024_CLEAN_crypto_sign_signature(
uint8_t *sig, size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *sk) {
/*
* The PQCLEAN_FALCON1024_CLEAN_CRYPTO_BYTES constant is used for
* the signed message object (as produced by crypto_sign())
* and includes a two-byte length value, so we take care here
* to only generate signatures that are two bytes shorter than
* the maximum. This is done to ensure that crypto_sign()
* and crypto_sign_signature() produce the exact same signature
* value, if used on the same message, with the same private key,
* and using the same output from randombytes() (this is for
* reproducibility of tests).
*/
size_t vlen;
vlen = PQCLEAN_FALCON1024_CLEAN_CRYPTO_BYTES - NONCELEN - 3;
if (do_sign(sig + 1, sig + 1 + NONCELEN, &vlen, m, mlen, sk) < 0) {
return -1;
}
sig[0] = 0x30 + 10;
*siglen = 1 + NONCELEN + vlen;
return 0;
}
/* see api.h */
int
PQCLEAN_FALCON1024_CLEAN_crypto_sign_verify(
const uint8_t *sig, size_t siglen,
const uint8_t *m, size_t mlen, const uint8_t *pk) {
if (siglen < 1 + NONCELEN) {
return -1;
}
if (sig[0] != 0x30 + 10) {
return -1;
}
return do_verify(sig + 1,
sig + 1 + NONCELEN, siglen - 1 - NONCELEN, m, mlen, pk);
}
/* see api.h */
int
PQCLEAN_FALCON1024_CLEAN_crypto_sign(
uint8_t *sm, size_t *smlen,
const uint8_t *m, size_t mlen, const uint8_t *sk) {
uint8_t *pm, *sigbuf;
size_t sigbuflen;
/*
* Move the message to its final location; this is a memmove() so
* it handles overlaps properly.
*/
memmove(sm + 2 + NONCELEN, m, mlen);
pm = sm + 2 + NONCELEN;
sigbuf = pm + 1 + mlen;
sigbuflen = PQCLEAN_FALCON1024_CLEAN_CRYPTO_BYTES - NONCELEN - 3;
if (do_sign(sm + 2, sigbuf, &sigbuflen, pm, mlen, sk) < 0) {
return -1;
}
pm[mlen] = 0x20 + 10;
sigbuflen ++;
sm[0] = (uint8_t)(sigbuflen >> 8);
sm[1] = (uint8_t)sigbuflen;
*smlen = mlen + 2 + NONCELEN + sigbuflen;
return 0;
}
/* see api.h */
int
PQCLEAN_FALCON1024_CLEAN_crypto_sign_open(
uint8_t *m, size_t *mlen,
const uint8_t *sm, size_t smlen, const uint8_t *pk) {
const uint8_t *sigbuf;
size_t pmlen, sigbuflen;
if (smlen < 3 + NONCELEN) {
return -1;
}
sigbuflen = ((size_t)sm[0] << 8) | (size_t)sm[1];
if (sigbuflen < 2 || sigbuflen > (smlen - NONCELEN - 2)) {
return -1;
}
sigbuflen --;
pmlen = smlen - NONCELEN - 3 - sigbuflen;
if (sm[2 + NONCELEN + pmlen] != 0x20 + 10) {
return -1;
}
sigbuf = sm + 2 + NONCELEN + pmlen + 1;
/*
* The 2-byte length header and the one-byte signature header
* have been verified. Nonce is at sm+2, followed by the message
* itself. Message length is in pmlen. sigbuf/sigbuflen point to
* the signature value (excluding the header byte).
*/
if (do_verify(sm + 2, sigbuf, sigbuflen,
sm + 2 + NONCELEN, pmlen, pk) < 0) {
return -1;
}
/*
* Signature is correct, we just have to copy/move the message
* to its final destination. The memmove() properly handles
* overlaps.
*/
memmove(m, sm + 2 + NONCELEN, pmlen);
*mlen = pmlen;
return 0;
}

View File

@ -1,190 +0,0 @@
/*
* PRNG and interface to the system RNG.
*
* ==========================(LICENSE BEGIN)============================
*
* Copyright (c) 2017-2019 Falcon Project
*
* 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.
*
* ===========================(LICENSE END)=============================
*
* @author Thomas Pornin <thomas.pornin@nccgroup.com>
*/
#include <assert.h>
#include "inner.h"
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_prng_init(prng *p, inner_shake256_context *src) {
/*
* To ensure reproducibility for a given seed, we
* must enforce little-endian interpretation of
* the state words.
*/
uint8_t tmp[56];
uint64_t th, tl;
int i;
uint32_t *d32 = (uint32_t *) p->state.d;
uint64_t *d64 = (uint64_t *) p->state.d;
inner_shake256_extract(src, tmp, 56);
for (i = 0; i < 14; i ++) {
uint32_t w;
w = (uint32_t)tmp[(i << 2) + 0]
| ((uint32_t)tmp[(i << 2) + 1] << 8)
| ((uint32_t)tmp[(i << 2) + 2] << 16)
| ((uint32_t)tmp[(i << 2) + 3] << 24);
d32[i] = w;
}
tl = d32[48 / sizeof(uint32_t)];
th = d32[52 / sizeof(uint32_t)];
d64[48 / sizeof(uint64_t)] = tl + (th << 32);
PQCLEAN_FALCON1024_CLEAN_prng_refill(p);
}
/*
* PRNG based on ChaCha20.
*
* State consists in key (32 bytes) then IV (16 bytes) and block counter
* (8 bytes). Normally, we should not care about local endianness (this
* is for a PRNG), but for the NIST competition we need reproducible KAT
* vectors that work across architectures, so we enforce little-endian
* interpretation where applicable. Moreover, output words are "spread
* out" over the output buffer with the interleaving pattern that is
* naturally obtained from the AVX2 implementation that runs eight
* ChaCha20 instances in parallel.
*
* The block counter is XORed into the first 8 bytes of the IV.
*/
void
PQCLEAN_FALCON1024_CLEAN_prng_refill(prng *p) {
static const uint32_t CW[] = {
0x61707865, 0x3320646e, 0x79622d32, 0x6b206574
};
uint64_t cc;
size_t u;
uint32_t *d32 = (uint32_t *) p->state.d;
uint64_t *d64 = (uint64_t *) p->state.d;
/*
* State uses local endianness. Only the output bytes must be
* converted to little endian (if used on a big-endian machine).
*/
cc = d64[48 / sizeof(uint64_t)];
for (u = 0; u < 8; u ++) {
uint32_t state[16];
size_t v;
int i;
memcpy(&state[0], CW, sizeof CW);
memcpy(&state[4], p->state.d, 48);
state[14] ^= (uint32_t)cc;
state[15] ^= (uint32_t)(cc >> 32);
for (i = 0; i < 10; i ++) {
#define QROUND(a, b, c, d) do { \
state[a] += state[b]; \
state[d] ^= state[a]; \
state[d] = (state[d] << 16) | (state[d] >> 16); \
state[c] += state[d]; \
state[b] ^= state[c]; \
state[b] = (state[b] << 12) | (state[b] >> 20); \
state[a] += state[b]; \
state[d] ^= state[a]; \
state[d] = (state[d] << 8) | (state[d] >> 24); \
state[c] += state[d]; \
state[b] ^= state[c]; \
state[b] = (state[b] << 7) | (state[b] >> 25); \
} while (0)
QROUND( 0, 4, 8, 12);
QROUND( 1, 5, 9, 13);
QROUND( 2, 6, 10, 14);
QROUND( 3, 7, 11, 15);
QROUND( 0, 5, 10, 15);
QROUND( 1, 6, 11, 12);
QROUND( 2, 7, 8, 13);
QROUND( 3, 4, 9, 14);
#undef QROUND
}
for (v = 0; v < 4; v ++) {
state[v] += CW[v];
}
for (v = 4; v < 14; v ++) {
state[v] += d32[v - 4];
}
state[14] += d32[10] ^ (uint32_t)cc;
state[15] += d32[11] ^ (uint32_t)(cc >> 32);
cc ++;
/*
* We mimic the interleaving that is used in the AVX2
* implementation.
*/
for (v = 0; v < 16; v ++) {
p->buf.d[(u << 2) + (v << 5) + 0] =
(uint8_t)state[v];
p->buf.d[(u << 2) + (v << 5) + 1] =
(uint8_t)(state[v] >> 8);
p->buf.d[(u << 2) + (v << 5) + 2] =
(uint8_t)(state[v] >> 16);
p->buf.d[(u << 2) + (v << 5) + 3] =
(uint8_t)(state[v] >> 24);
}
}
d64[48 / sizeof(uint64_t)] = cc;
p->ptr = 0;
}
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_prng_get_bytes(prng *p, void *dst, size_t len) {
uint8_t *buf;
buf = dst;
while (len > 0) {
size_t clen;
clen = (sizeof p->buf.d) - p->ptr;
if (clen > len) {
clen = len;
}
memcpy(buf, p->buf.d, clen);
buf += clen;
len -= clen;
p->ptr += clen;
if (p->ptr == sizeof p->buf.d) {
PQCLEAN_FALCON1024_CLEAN_prng_refill(p);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,852 +0,0 @@
/*
* Falcon signature verification.
*
* ==========================(LICENSE BEGIN)============================
*
* Copyright (c) 2017-2019 Falcon Project
*
* 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.
*
* ===========================(LICENSE END)=============================
*
* @author Thomas Pornin <thomas.pornin@nccgroup.com>
*/
#include "inner.h"
/* ===================================================================== */
/*
* Constants for NTT.
*
* n = 2^logn (2 <= n <= 1024)
* phi = X^n + 1
* q = 12289
* q0i = -1/q mod 2^16
* R = 2^16 mod q
* R2 = 2^32 mod q
*/
#define Q 12289
#define Q0I 12287
#define R 4091
#define R2 10952
/*
* Table for NTT, binary case:
* GMb[x] = R*(g^rev(x)) mod q
* where g = 7 (it is a 2048-th primitive root of 1 modulo q)
* and rev() is the bit-reversal function over 10 bits.
*/
static const uint16_t GMb[] = {
4091, 7888, 11060, 11208, 6960, 4342, 6275, 9759,
1591, 6399, 9477, 5266, 586, 5825, 7538, 9710,
1134, 6407, 1711, 965, 7099, 7674, 3743, 6442,
10414, 8100, 1885, 1688, 1364, 10329, 10164, 9180,
12210, 6240, 997, 117, 4783, 4407, 1549, 7072,
2829, 6458, 4431, 8877, 7144, 2564, 5664, 4042,
12189, 432, 10751, 1237, 7610, 1534, 3983, 7863,
2181, 6308, 8720, 6570, 4843, 1690, 14, 3872,
5569, 9368, 12163, 2019, 7543, 2315, 4673, 7340,
1553, 1156, 8401, 11389, 1020, 2967, 10772, 7045,
3316, 11236, 5285, 11578, 10637, 10086, 9493, 6180,
9277, 6130, 3323, 883, 10469, 489, 1502, 2851,
11061, 9729, 2742, 12241, 4970, 10481, 10078, 1195,
730, 1762, 3854, 2030, 5892, 10922, 9020, 5274,
9179, 3604, 3782, 10206, 3180, 3467, 4668, 2446,
7613, 9386, 834, 7703, 6836, 3403, 5351, 12276,
3580, 1739, 10820, 9787, 10209, 4070, 12250, 8525,
10401, 2749, 7338, 10574, 6040, 943, 9330, 1477,
6865, 9668, 3585, 6633, 12145, 4063, 3684, 7680,
8188, 6902, 3533, 9807, 6090, 727, 10099, 7003,
6945, 1949, 9731, 10559, 6057, 378, 7871, 8763,
8901, 9229, 8846, 4551, 9589, 11664, 7630, 8821,
5680, 4956, 6251, 8388, 10156, 8723, 2341, 3159,
1467, 5460, 8553, 7783, 2649, 2320, 9036, 6188,
737, 3698, 4699, 5753, 9046, 3687, 16, 914,
5186, 10531, 4552, 1964, 3509, 8436, 7516, 5381,
10733, 3281, 7037, 1060, 2895, 7156, 8887, 5357,
6409, 8197, 2962, 6375, 5064, 6634, 5625, 278,
932, 10229, 8927, 7642, 351, 9298, 237, 5858,
7692, 3146, 12126, 7586, 2053, 11285, 3802, 5204,
4602, 1748, 11300, 340, 3711, 4614, 300, 10993,
5070, 10049, 11616, 12247, 7421, 10707, 5746, 5654,
3835, 5553, 1224, 8476, 9237, 3845, 250, 11209,
4225, 6326, 9680, 12254, 4136, 2778, 692, 8808,
6410, 6718, 10105, 10418, 3759, 7356, 11361, 8433,
6437, 3652, 6342, 8978, 5391, 2272, 6476, 7416,
8418, 10824, 11986, 5733, 876, 7030, 2167, 2436,
3442, 9217, 8206, 4858, 5964, 2746, 7178, 1434,
7389, 8879, 10661, 11457, 4220, 1432, 10832, 4328,
8557, 1867, 9454, 2416, 3816, 9076, 686, 5393,
2523, 4339, 6115, 619, 937, 2834, 7775, 3279,
2363, 7488, 6112, 5056, 824, 10204, 11690, 1113,
2727, 9848, 896, 2028, 5075, 2654, 10464, 7884,
12169, 5434, 3070, 6400, 9132, 11672, 12153, 4520,
1273, 9739, 11468, 9937, 10039, 9720, 2262, 9399,
11192, 315, 4511, 1158, 6061, 6751, 11865, 357,
7367, 4550, 983, 8534, 8352, 10126, 7530, 9253,
4367, 5221, 3999, 8777, 3161, 6990, 4130, 11652,
3374, 11477, 1753, 292, 8681, 2806, 10378, 12188,
5800, 11811, 3181, 1988, 1024, 9340, 2477, 10928,
4582, 6750, 3619, 5503, 5233, 2463, 8470, 7650,
7964, 6395, 1071, 1272, 3474, 11045, 3291, 11344,
8502, 9478, 9837, 1253, 1857, 6233, 4720, 11561,
6034, 9817, 3339, 1797, 2879, 6242, 5200, 2114,
7962, 9353, 11363, 5475, 6084, 9601, 4108, 7323,
10438, 9471, 1271, 408, 6911, 3079, 360, 8276,
11535, 9156, 9049, 11539, 850, 8617, 784, 7919,
8334, 12170, 1846, 10213, 12184, 7827, 11903, 5600,
9779, 1012, 721, 2784, 6676, 6552, 5348, 4424,
6816, 8405, 9959, 5150, 2356, 5552, 5267, 1333,
8801, 9661, 7308, 5788, 4910, 909, 11613, 4395,
8238, 6686, 4302, 3044, 2285, 12249, 1963, 9216,
4296, 11918, 695, 4371, 9793, 4884, 2411, 10230,
2650, 841, 3890, 10231, 7248, 8505, 11196, 6688,
4059, 6060, 3686, 4722, 11853, 5816, 7058, 6868,
11137, 7926, 4894, 12284, 4102, 3908, 3610, 6525,
7938, 7982, 11977, 6755, 537, 4562, 1623, 8227,
11453, 7544, 906, 11816, 9548, 10858, 9703, 2815,
11736, 6813, 6979, 819, 8903, 6271, 10843, 348,
7514, 8339, 6439, 694, 852, 5659, 2781, 3716,
11589, 3024, 1523, 8659, 4114, 10738, 3303, 5885,
2978, 7289, 11884, 9123, 9323, 11830, 98, 2526,
2116, 4131, 11407, 1844, 3645, 3916, 8133, 2224,
10871, 8092, 9651, 5989, 7140, 8480, 1670, 159,
10923, 4918, 128, 7312, 725, 9157, 5006, 6393,
3494, 6043, 10972, 6181, 11838, 3423, 10514, 7668,
3693, 6658, 6905, 11953, 10212, 11922, 9101, 8365,
5110, 45, 2400, 1921, 4377, 2720, 1695, 51,
2808, 650, 1896, 9997, 9971, 11980, 8098, 4833,
4135, 4257, 5838, 4765, 10985, 11532, 590, 12198,
482, 12173, 2006, 7064, 10018, 3912, 12016, 10519,
11362, 6954, 2210, 284, 5413, 6601, 3865, 10339,
11188, 6231, 517, 9564, 11281, 3863, 1210, 4604,
8160, 11447, 153, 7204, 5763, 5089, 9248, 12154,
11748, 1354, 6672, 179, 5532, 2646, 5941, 12185,
862, 3158, 477, 7279, 5678, 7914, 4254, 302,
2893, 10114, 6890, 9560, 9647, 11905, 4098, 9824,
10269, 1353, 10715, 5325, 6254, 3951, 1807, 6449,
5159, 1308, 8315, 3404, 1877, 1231, 112, 6398,
11724, 12272, 7286, 1459, 12274, 9896, 3456, 800,
1397, 10678, 103, 7420, 7976, 936, 764, 632,
7996, 8223, 8445, 7758, 10870, 9571, 2508, 1946,
6524, 10158, 1044, 4338, 2457, 3641, 1659, 4139,
4688, 9733, 11148, 3946, 2082, 5261, 2036, 11850,
7636, 12236, 5366, 2380, 1399, 7720, 2100, 3217,
10912, 8898, 7578, 11995, 2791, 1215, 3355, 2711,
2267, 2004, 8568, 10176, 3214, 2337, 1750, 4729,
4997, 7415, 6315, 12044, 4374, 7157, 4844, 211,
8003, 10159, 9290, 11481, 1735, 2336, 5793, 9875,
8192, 986, 7527, 1401, 870, 3615, 8465, 2756,
9770, 2034, 10168, 3264, 6132, 54, 2880, 4763,
11805, 3074, 8286, 9428, 4881, 6933, 1090, 10038,
2567, 708, 893, 6465, 4962, 10024, 2090, 5718,
10743, 780, 4733, 4623, 2134, 2087, 4802, 884,
5372, 5795, 5938, 4333, 6559, 7549, 5269, 10664,
4252, 3260, 5917, 10814, 5768, 9983, 8096, 7791,
6800, 7491, 6272, 1907, 10947, 6289, 11803, 6032,
11449, 1171, 9201, 7933, 2479, 7970, 11337, 7062,
8911, 6728, 6542, 8114, 8828, 6595, 3545, 4348,
4610, 2205, 6999, 8106, 5560, 10390, 9321, 2499,
2413, 7272, 6881, 10582, 9308, 9437, 3554, 3326,
5991, 11969, 3415, 12283, 9838, 12063, 4332, 7830,
11329, 6605, 12271, 2044, 11611, 7353, 11201, 11582,
3733, 8943, 9978, 1627, 7168, 3935, 5050, 2762,
7496, 10383, 755, 1654, 12053, 4952, 10134, 4394,
6592, 7898, 7497, 8904, 12029, 3581, 10748, 5674,
10358, 4901, 7414, 8771, 710, 6764, 8462, 7193,
5371, 7274, 11084, 290, 7864, 6827, 11822, 2509,
6578, 4026, 5807, 1458, 5721, 5762, 4178, 2105,
11621, 4852, 8897, 2856, 11510, 9264, 2520, 8776,
7011, 2647, 1898, 7039, 5950, 11163, 5488, 6277,
9182, 11456, 633, 10046, 11554, 5633, 9587, 2333,
7008, 7084, 5047, 7199, 9865, 8997, 569, 6390,
10845, 9679, 8268, 11472, 4203, 1997, 2, 9331,
162, 6182, 2000, 3649, 9792, 6363, 7557, 6187,
8510, 9935, 5536, 9019, 3706, 12009, 1452, 3067,
5494, 9692, 4865, 6019, 7106, 9610, 4588, 10165,
6261, 5887, 2652, 10172, 1580, 10379, 4638, 9949
};
/*
* Table for inverse NTT, binary case:
* iGMb[x] = R*((1/g)^rev(x)) mod q
* Since g = 7, 1/g = 8778 mod 12289.
*/
static const uint16_t iGMb[] = {
4091, 4401, 1081, 1229, 2530, 6014, 7947, 5329,
2579, 4751, 6464, 11703, 7023, 2812, 5890, 10698,
3109, 2125, 1960, 10925, 10601, 10404, 4189, 1875,
5847, 8546, 4615, 5190, 11324, 10578, 5882, 11155,
8417, 12275, 10599, 7446, 5719, 3569, 5981, 10108,
4426, 8306, 10755, 4679, 11052, 1538, 11857, 100,
8247, 6625, 9725, 5145, 3412, 7858, 5831, 9460,
5217, 10740, 7882, 7506, 12172, 11292, 6049, 79,
13, 6938, 8886, 5453, 4586, 11455, 2903, 4676,
9843, 7621, 8822, 9109, 2083, 8507, 8685, 3110,
7015, 3269, 1367, 6397, 10259, 8435, 10527, 11559,
11094, 2211, 1808, 7319, 48, 9547, 2560, 1228,
9438, 10787, 11800, 1820, 11406, 8966, 6159, 3012,
6109, 2796, 2203, 1652, 711, 7004, 1053, 8973,
5244, 1517, 9322, 11269, 900, 3888, 11133, 10736,
4949, 7616, 9974, 4746, 10270, 126, 2921, 6720,
6635, 6543, 1582, 4868, 42, 673, 2240, 7219,
1296, 11989, 7675, 8578, 11949, 989, 10541, 7687,
7085, 8487, 1004, 10236, 4703, 163, 9143, 4597,
6431, 12052, 2991, 11938, 4647, 3362, 2060, 11357,
12011, 6664, 5655, 7225, 5914, 9327, 4092, 5880,
6932, 3402, 5133, 9394, 11229, 5252, 9008, 1556,
6908, 4773, 3853, 8780, 10325, 7737, 1758, 7103,
11375, 12273, 8602, 3243, 6536, 7590, 8591, 11552,
6101, 3253, 9969, 9640, 4506, 3736, 6829, 10822,
9130, 9948, 3566, 2133, 3901, 6038, 7333, 6609,
3468, 4659, 625, 2700, 7738, 3443, 3060, 3388,
3526, 4418, 11911, 6232, 1730, 2558, 10340, 5344,
5286, 2190, 11562, 6199, 2482, 8756, 5387, 4101,
4609, 8605, 8226, 144, 5656, 8704, 2621, 5424,
10812, 2959, 11346, 6249, 1715, 4951, 9540, 1888,
3764, 39, 8219, 2080, 2502, 1469, 10550, 8709,
5601, 1093, 3784, 5041, 2058, 8399, 11448, 9639,
2059, 9878, 7405, 2496, 7918, 11594, 371, 7993,
3073, 10326, 40, 10004, 9245, 7987, 5603, 4051,
7894, 676, 11380, 7379, 6501, 4981, 2628, 3488,
10956, 7022, 6737, 9933, 7139, 2330, 3884, 5473,
7865, 6941, 5737, 5613, 9505, 11568, 11277, 2510,
6689, 386, 4462, 105, 2076, 10443, 119, 3955,
4370, 11505, 3672, 11439, 750, 3240, 3133, 754,
4013, 11929, 9210, 5378, 11881, 11018, 2818, 1851,
4966, 8181, 2688, 6205, 6814, 926, 2936, 4327,
10175, 7089, 6047, 9410, 10492, 8950, 2472, 6255,
728, 7569, 6056, 10432, 11036, 2452, 2811, 3787,
945, 8998, 1244, 8815, 11017, 11218, 5894, 4325,
4639, 3819, 9826, 7056, 6786, 8670, 5539, 7707,
1361, 9812, 2949, 11265, 10301, 9108, 478, 6489,
101, 1911, 9483, 3608, 11997, 10536, 812, 8915,
637, 8159, 5299, 9128, 3512, 8290, 7068, 7922,
3036, 4759, 2163, 3937, 3755, 11306, 7739, 4922,
11932, 424, 5538, 6228, 11131, 7778, 11974, 1097,
2890, 10027, 2569, 2250, 2352, 821, 2550, 11016,
7769, 136, 617, 3157, 5889, 9219, 6855, 120,
4405, 1825, 9635, 7214, 10261, 11393, 2441, 9562,
11176, 599, 2085, 11465, 7233, 6177, 4801, 9926,
9010, 4514, 9455, 11352, 11670, 6174, 7950, 9766,
6896, 11603, 3213, 8473, 9873, 2835, 10422, 3732,
7961, 1457, 10857, 8069, 832, 1628, 3410, 4900,
10855, 5111, 9543, 6325, 7431, 4083, 3072, 8847,
9853, 10122, 5259, 11413, 6556, 303, 1465, 3871,
4873, 5813, 10017, 6898, 3311, 5947, 8637, 5852,
3856, 928, 4933, 8530, 1871, 2184, 5571, 5879,
3481, 11597, 9511, 8153, 35, 2609, 5963, 8064,
1080, 12039, 8444, 3052, 3813, 11065, 6736, 8454,
2340, 7651, 1910, 10709, 2117, 9637, 6402, 6028,
2124, 7701, 2679, 5183, 6270, 7424, 2597, 6795,
9222, 10837, 280, 8583, 3270, 6753, 2354, 3779,
6102, 4732, 5926, 2497, 8640, 10289, 6107, 12127,
2958, 12287, 10292, 8086, 817, 4021, 2610, 1444,
5899, 11720, 3292, 2424, 5090, 7242, 5205, 5281,
9956, 2702, 6656, 735, 2243, 11656, 833, 3107,
6012, 6801, 1126, 6339, 5250, 10391, 9642, 5278,
3513, 9769, 3025, 779, 9433, 3392, 7437, 668,
10184, 8111, 6527, 6568, 10831, 6482, 8263, 5711,
9780, 467, 5462, 4425, 11999, 1205, 5015, 6918,
5096, 3827, 5525, 11579, 3518, 4875, 7388, 1931,
6615, 1541, 8708, 260, 3385, 4792, 4391, 5697,
7895, 2155, 7337, 236, 10635, 11534, 1906, 4793,
9527, 7239, 8354, 5121, 10662, 2311, 3346, 8556,
707, 1088, 4936, 678, 10245, 18, 5684, 960,
4459, 7957, 226, 2451, 6, 8874, 320, 6298,
8963, 8735, 2852, 2981, 1707, 5408, 5017, 9876,
9790, 2968, 1899, 6729, 4183, 5290, 10084, 7679,
7941, 8744, 5694, 3461, 4175, 5747, 5561, 3378,
5227, 952, 4319, 9810, 4356, 3088, 11118, 840,
6257, 486, 6000, 1342, 10382, 6017, 4798, 5489,
4498, 4193, 2306, 6521, 1475, 6372, 9029, 8037,
1625, 7020, 4740, 5730, 7956, 6351, 6494, 6917,
11405, 7487, 10202, 10155, 7666, 7556, 11509, 1546,
6571, 10199, 2265, 7327, 5824, 11396, 11581, 9722,
2251, 11199, 5356, 7408, 2861, 4003, 9215, 484,
7526, 9409, 12235, 6157, 9025, 2121, 10255, 2519,
9533, 3824, 8674, 11419, 10888, 4762, 11303, 4097,
2414, 6496, 9953, 10554, 808, 2999, 2130, 4286,
12078, 7445, 5132, 7915, 245, 5974, 4874, 7292,
7560, 10539, 9952, 9075, 2113, 3721, 10285, 10022,
9578, 8934, 11074, 9498, 294, 4711, 3391, 1377,
9072, 10189, 4569, 10890, 9909, 6923, 53, 4653,
439, 10253, 7028, 10207, 8343, 1141, 2556, 7601,
8150, 10630, 8648, 9832, 7951, 11245, 2131, 5765,
10343, 9781, 2718, 1419, 4531, 3844, 4066, 4293,
11657, 11525, 11353, 4313, 4869, 12186, 1611, 10892,
11489, 8833, 2393, 15, 10830, 5003, 17, 565,
5891, 12177, 11058, 10412, 8885, 3974, 10981, 7130,
5840, 10482, 8338, 6035, 6964, 1574, 10936, 2020,
2465, 8191, 384, 2642, 2729, 5399, 2175, 9396,
11987, 8035, 4375, 6611, 5010, 11812, 9131, 11427,
104, 6348, 9643, 6757, 12110, 5617, 10935, 541,
135, 3041, 7200, 6526, 5085, 12136, 842, 4129,
7685, 11079, 8426, 1008, 2725, 11772, 6058, 1101,
1950, 8424, 5688, 6876, 12005, 10079, 5335, 927,
1770, 273, 8377, 2271, 5225, 10283, 116, 11807,
91, 11699, 757, 1304, 7524, 6451, 8032, 8154,
7456, 4191, 309, 2318, 2292, 10393, 11639, 9481,
12238, 10594, 9569, 7912, 10368, 9889, 12244, 7179,
3924, 3188, 367, 2077, 336, 5384, 5631, 8596,
4621, 1775, 8866, 451, 6108, 1317, 6246, 8795,
5896, 7283, 3132, 11564, 4977, 12161, 7371, 1366,
12130, 10619, 3809, 5149, 6300, 2638, 4197, 1418,
10065, 4156, 8373, 8644, 10445, 882, 8158, 10173,
9763, 12191, 459, 2966, 3166, 405, 5000, 9311,
6404, 8986, 1551, 8175, 3630, 10766, 9265, 700,
8573, 9508, 6630, 11437, 11595, 5850, 3950, 4775,
11941, 1446, 6018, 3386, 11470, 5310, 5476, 553,
9474, 2586, 1431, 2741, 473, 11383, 4745, 836,
4062, 10666, 7727, 11752, 5534, 312, 4307, 4351,
5764, 8679, 8381, 8187, 5, 7395, 4363, 1152,
5421, 5231, 6473, 436, 7567, 8603, 6229, 8230
};
/*
* Reduce a small signed integer modulo q. The source integer MUST
* be between -q/2 and +q/2.
*/
static inline uint32_t
mq_conv_small(int x) {
/*
* If x < 0, the cast to uint32_t will set the high bit to 1.
*/
uint32_t y;
y = (uint32_t)x;
y += Q & -(y >> 31);
return y;
}
/*
* Addition modulo q. Operands must be in the 0..q-1 range.
*/
static inline uint32_t
mq_add(uint32_t x, uint32_t y) {
/*
* We compute x + y - q. If the result is negative, then the
* high bit will be set, and 'd >> 31' will be equal to 1;
* thus '-(d >> 31)' will be an all-one pattern. Otherwise,
* it will be an all-zero pattern. In other words, this
* implements a conditional addition of q.
*/
uint32_t d;
d = x + y - Q;
d += Q & -(d >> 31);
return d;
}
/*
* Subtraction modulo q. Operands must be in the 0..q-1 range.
*/
static inline uint32_t
mq_sub(uint32_t x, uint32_t y) {
/*
* As in mq_add(), we use a conditional addition to ensure the
* result is in the 0..q-1 range.
*/
uint32_t d;
d = x - y;
d += Q & -(d >> 31);
return d;
}
/*
* Division by 2 modulo q. Operand must be in the 0..q-1 range.
*/
static inline uint32_t
mq_rshift1(uint32_t x) {
x += Q & -(x & 1);
return (x >> 1);
}
/*
* Montgomery multiplication modulo q. If we set R = 2^16 mod q, then
* this function computes: x * y / R mod q
* Operands must be in the 0..q-1 range.
*/
static inline uint32_t
mq_montymul(uint32_t x, uint32_t y) {
uint32_t z, w;
/*
* We compute x*y + k*q with a value of k chosen so that the 16
* low bits of the result are 0. We can then shift the value.
* After the shift, result may still be larger than q, but it
* will be lower than 2*q, so a conditional subtraction works.
*/
z = x * y;
w = ((z * Q0I) & 0xFFFF) * Q;
/*
* When adding z and w, the result will have its low 16 bits
* equal to 0. Since x, y and z are lower than q, the sum will
* be no more than (2^15 - 1) * q + (q - 1)^2, which will
* fit on 29 bits.
*/
z = (z + w) >> 16;
/*
* After the shift, analysis shows that the value will be less
* than 2q. We do a subtraction then conditional subtraction to
* ensure the result is in the expected range.
*/
z -= Q;
z += Q & -(z >> 31);
return z;
}
/*
* Montgomery squaring (computes (x^2)/R).
*/
static inline uint32_t
mq_montysqr(uint32_t x) {
return mq_montymul(x, x);
}
/*
* Divide x by y modulo q = 12289.
*/
static inline uint32_t
mq_div_12289(uint32_t x, uint32_t y) {
/*
* We invert y by computing y^(q-2) mod q.
*
* We use the following addition chain for exponent e = 12287:
*
* e0 = 1
* e1 = 2 * e0 = 2
* e2 = e1 + e0 = 3
* e3 = e2 + e1 = 5
* e4 = 2 * e3 = 10
* e5 = 2 * e4 = 20
* e6 = 2 * e5 = 40
* e7 = 2 * e6 = 80
* e8 = 2 * e7 = 160
* e9 = e8 + e2 = 163
* e10 = e9 + e8 = 323
* e11 = 2 * e10 = 646
* e12 = 2 * e11 = 1292
* e13 = e12 + e9 = 1455
* e14 = 2 * e13 = 2910
* e15 = 2 * e14 = 5820
* e16 = e15 + e10 = 6143
* e17 = 2 * e16 = 12286
* e18 = e17 + e0 = 12287
*
* Additions on exponents are converted to Montgomery
* multiplications. We define all intermediate results as so
* many local variables, and let the C compiler work out which
* must be kept around.
*/
uint32_t y0, y1, y2, y3, y4, y5, y6, y7, y8, y9;
uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18;
y0 = mq_montymul(y, R2);
y1 = mq_montysqr(y0);
y2 = mq_montymul(y1, y0);
y3 = mq_montymul(y2, y1);
y4 = mq_montysqr(y3);
y5 = mq_montysqr(y4);
y6 = mq_montysqr(y5);
y7 = mq_montysqr(y6);
y8 = mq_montysqr(y7);
y9 = mq_montymul(y8, y2);
y10 = mq_montymul(y9, y8);
y11 = mq_montysqr(y10);
y12 = mq_montysqr(y11);
y13 = mq_montymul(y12, y9);
y14 = mq_montysqr(y13);
y15 = mq_montysqr(y14);
y16 = mq_montymul(y15, y10);
y17 = mq_montysqr(y16);
y18 = mq_montymul(y17, y0);
/*
* Final multiplication with x, which is not in Montgomery
* representation, computes the correct division result.
*/
return mq_montymul(y18, x);
}
/*
* Compute NTT on a ring element.
*/
static void
mq_NTT(uint16_t *a, unsigned logn) {
size_t n, t, m;
n = (size_t)1 << logn;
t = n;
for (m = 1; m < n; m <<= 1) {
size_t ht, i, j1;
ht = t >> 1;
for (i = 0, j1 = 0; i < m; i ++, j1 += t) {
size_t j, j2;
uint32_t s;
s = GMb[m + i];
j2 = j1 + ht;
for (j = j1; j < j2; j ++) {
uint32_t u, v;
u = a[j];
v = mq_montymul(a[j + ht], s);
a[j] = (uint16_t)mq_add(u, v);
a[j + ht] = (uint16_t)mq_sub(u, v);
}
}
t = ht;
}
}
/*
* Compute the inverse NTT on a ring element, binary case.
*/
static void
mq_iNTT(uint16_t *a, unsigned logn) {
size_t n, t, m;
uint32_t ni;
n = (size_t)1 << logn;
t = 1;
m = n;
while (m > 1) {
size_t hm, dt, i, j1;
hm = m >> 1;
dt = t << 1;
for (i = 0, j1 = 0; i < hm; i ++, j1 += dt) {
size_t j, j2;
uint32_t s;
j2 = j1 + t;
s = iGMb[hm + i];
for (j = j1; j < j2; j ++) {
uint32_t u, v, w;
u = a[j];
v = a[j + t];
a[j] = (uint16_t)mq_add(u, v);
w = mq_sub(u, v);
a[j + t] = (uint16_t)
mq_montymul(w, s);
}
}
t = dt;
m = hm;
}
/*
* To complete the inverse NTT, we must now divide all values by
* n (the vector size). We thus need the inverse of n, i.e. we
* need to divide 1 by 2 logn times. But we also want it in
* Montgomery representation, i.e. we also want to multiply it
* by R = 2^16. In the common case, this should be a simple right
* shift. The loop below is generic and works also in corner cases;
* its computation time is negligible.
*/
ni = R;
for (m = n; m > 1; m >>= 1) {
ni = mq_rshift1(ni);
}
for (m = 0; m < n; m ++) {
a[m] = (uint16_t)mq_montymul(a[m], ni);
}
}
/*
* Convert a polynomial (mod q) to Montgomery representation.
*/
static void
mq_poly_tomonty(uint16_t *f, unsigned logn) {
size_t u, n;
n = (size_t)1 << logn;
for (u = 0; u < n; u ++) {
f[u] = (uint16_t)mq_montymul(f[u], R2);
}
}
/*
* Multiply two polynomials together (NTT representation, and using
* a Montgomery multiplication). Result f*g is written over f.
*/
static void
mq_poly_montymul_ntt(uint16_t *f, const uint16_t *g, unsigned logn) {
size_t u, n;
n = (size_t)1 << logn;
for (u = 0; u < n; u ++) {
f[u] = (uint16_t)mq_montymul(f[u], g[u]);
}
}
/*
* Subtract polynomial g from polynomial f.
*/
static void
mq_poly_sub(uint16_t *f, const uint16_t *g, unsigned logn) {
size_t u, n;
n = (size_t)1 << logn;
for (u = 0; u < n; u ++) {
f[u] = (uint16_t)mq_sub(f[u], g[u]);
}
}
/* ===================================================================== */
/* see inner.h */
void
PQCLEAN_FALCON1024_CLEAN_to_ntt_monty(uint16_t *h, unsigned logn) {
mq_NTT(h, logn);
mq_poly_tomonty(h, logn);
}
/* see inner.h */
int
PQCLEAN_FALCON1024_CLEAN_verify_raw(const uint16_t *c0, const int16_t *s2,
const uint16_t *h, unsigned logn, uint8_t *tmp) {
size_t u, n;
uint16_t *tt;
n = (size_t)1 << logn;
tt = (uint16_t *)tmp;
/*
* Reduce s2 elements modulo q ([0..q-1] range).
*/
for (u = 0; u < n; u ++) {
uint32_t w;
w = (uint32_t)s2[u];
w += Q & -(w >> 31);
tt[u] = (uint16_t)w;
}
/*
* Compute -s1 = s2*h - c0 mod phi mod q (in tt[]).
*/
mq_NTT(tt, logn);
mq_poly_montymul_ntt(tt, h, logn);
mq_iNTT(tt, logn);
mq_poly_sub(tt, c0, logn);
/*
* Normalize -s1 elements into the [-q/2..q/2] range.
*/
for (u = 0; u < n; u ++) {
int32_t w;
w = (int32_t)tt[u];
w -= (int32_t)(Q & -(((Q >> 1) - (uint32_t)w) >> 31));
((int16_t *)tt)[u] = (int16_t)w;
}
/*
* Signature is valid if and only if the aggregate (-s1,s2) vector
* is short enough.
*/
return PQCLEAN_FALCON1024_CLEAN_is_short((int16_t *)tt, s2, logn);
}
/* see inner.h */
int
PQCLEAN_FALCON1024_CLEAN_compute_public(uint16_t *h,
const int8_t *f, const int8_t *g, unsigned logn, uint8_t *tmp) {
size_t u, n;
uint16_t *tt;
n = (size_t)1 << logn;
tt = (uint16_t *)tmp;
for (u = 0; u < n; u ++) {
tt[u] = (uint16_t)mq_conv_small(f[u]);
h[u] = (uint16_t)mq_conv_small(g[u]);
}
mq_NTT(h, logn);
mq_NTT(tt, logn);
for (u = 0; u < n; u ++) {
if (tt[u] == 0) {
return 0;
}
h[u] = (uint16_t)mq_div_12289(h[u], tt[u]);
}
mq_iNTT(h, logn);
return 1;
}
/* see inner.h */
int
PQCLEAN_FALCON1024_CLEAN_complete_private(int8_t *G,
const int8_t *f, const int8_t *g, const int8_t *F,
unsigned logn, uint8_t *tmp) {
size_t u, n;
uint16_t *t1, *t2;
n = (size_t)1 << logn;
t1 = (uint16_t *)tmp;
t2 = t1 + n;
for (u = 0; u < n; u ++) {
t1[u] = (uint16_t)mq_conv_small(g[u]);
t2[u] = (uint16_t)mq_conv_small(F[u]);
}
mq_NTT(t1, logn);
mq_NTT(t2, logn);
mq_poly_tomonty(t1, logn);
mq_poly_montymul_ntt(t1, t2, logn);
for (u = 0; u < n; u ++) {
t2[u] = (uint16_t)mq_conv_small(f[u]);
}
mq_NTT(t2, logn);
for (u = 0; u < n; u ++) {
if (t2[u] == 0) {
return 0;
}
t1[u] = (uint16_t)mq_div_12289(t1[u], t2[u]);
}
mq_iNTT(t1, logn);
for (u = 0; u < n; u ++) {
uint32_t w;
int32_t gi;
w = t1[u];
w -= (Q & ~ -((w - (Q >> 1)) >> 31));
gi = *(int32_t *)&w;
if (gi < -127 || gi > +127) {
return 0;
}
G[u] = (int8_t)gi;
}
return 1;
}
/* see inner.h */
int
PQCLEAN_FALCON1024_CLEAN_is_invertible(
const int16_t *s2, unsigned logn, uint8_t *tmp) {
size_t u, n;
uint16_t *tt;
uint32_t r;
n = (size_t)1 << logn;
tt = (uint16_t *)tmp;
for (u = 0; u < n; u ++) {
uint32_t w;
w = (uint32_t)s2[u];
w += Q & -(w >> 31);
tt[u] = (uint16_t)w;
}
mq_NTT(tt, logn);
r = 0;
for (u = 0; u < n; u ++) {
r |= (uint32_t)(tt[u] - 1);
}
return (int)(1u - (r >> 31));
}
/* see inner.h */
int
PQCLEAN_FALCON1024_CLEAN_verify_recover(uint16_t *h,
const uint16_t *c0, const int16_t *s1, const int16_t *s2,
unsigned logn, uint8_t *tmp) {
size_t u, n;
uint16_t *tt;
uint32_t r;
n = (size_t)1 << logn;
/*
* Reduce elements of s1 and s2 modulo q; then write s2 into tt[]
* and c0 - s1 into h[].
*/
tt = (uint16_t *)tmp;
for (u = 0; u < n; u ++) {
uint32_t w;
w = (uint32_t)s2[u];
w += Q & -(w >> 31);
tt[u] = (uint16_t)w;
w = (uint32_t)s1[u];
w += Q & -(w >> 31);
w = mq_sub(c0[u], w);
h[u] = (uint16_t)w;
}
/*
* Compute h = (c0 - s1) / s2. If one of the coefficients of s2
* is zero (in NTT representation) then the operation fails. We
* keep that information into a flag so that we do not deviate
* from strict constant-time processing; if all coefficients of
* s2 are non-zero, then the high bit of r will be zero.
*/
mq_NTT(tt, logn);
mq_NTT(h, logn);
r = 0;
for (u = 0; u < n; u ++) {
r |= (uint32_t)(tt[u] - 1);
h[u] = (uint16_t)mq_div_12289(h[u], tt[u]);
}
mq_iNTT(h, logn);
/*
* Signature is acceptable if and only if it is short enough,
* and s2 was invertible mod phi mod q. The caller must still
* check that the rebuilt public key matches the expected
* value (e.g. through a hash).
*/
r = ~r & (uint32_t) - PQCLEAN_FALCON1024_CLEAN_is_short(s1, s2, logn);
return (int)(r >> 31);
}
/* see inner.h */
int
PQCLEAN_FALCON1024_CLEAN_count_nttzero(const int16_t *sig, unsigned logn, uint8_t *tmp) {
uint16_t *s2;
size_t u, n;
uint32_t r;
n = (size_t)1 << logn;
s2 = (uint16_t *)tmp;
for (u = 0; u < n; u ++) {
uint32_t w;
w = (uint32_t)sig[u];
w += Q & -(w >> 31);
s2[u] = (uint16_t)w;
}
mq_NTT(s2, logn);
r = 0;
for (u = 0; u < n; u ++) {
uint32_t w;
w = (uint32_t)s2[u] - 1u;
r += (w >> 31);
}
return (int)r;
}

View File

@ -1,22 +0,0 @@
MIT License
Copyright (c) 2017-2019 Falcon Project
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.

View File

@ -1,80 +0,0 @@
#ifndef PQCLEAN_FALCON512_CLEAN_API_H
#define PQCLEAN_FALCON512_CLEAN_API_H
#include <stddef.h>
#include <stdint.h>
#define PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES 1281
#define PQCLEAN_FALCON512_CLEAN_CRYPTO_PUBLICKEYBYTES 897
#define PQCLEAN_FALCON512_CLEAN_CRYPTO_BYTES 690
#define PQCLEAN_FALCON512_CLEAN_CRYPTO_ALGNAME "Falcon-512"
/*
* Generate a new key pair. Public key goes into pk[], private key in sk[].
* Key sizes are exact (in bytes):
* public (pk): PQCLEAN_FALCON512_CLEAN_CRYPTO_PUBLICKEYBYTES
* private (sk): PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES
*
* Return value: 0 on success, -1 on error.
*/
int PQCLEAN_FALCON512_CLEAN_crypto_sign_keypair(
uint8_t *pk, uint8_t *sk);
/*
* Compute a signature on a provided message (m, mlen), with a given
* private key (sk). Signature is written in sig[], with length written
* into *siglen. Signature length is variable; maximum signature length
* (in bytes) is PQCLEAN_FALCON512_CLEAN_CRYPTO_BYTES.
*
* sig[], m[] and sk[] may overlap each other arbitrarily.
*
* Return value: 0 on success, -1 on error.
*/
int PQCLEAN_FALCON512_CLEAN_crypto_sign_signature(
uint8_t *sig, size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *sk);
/*
* Verify a signature (sig, siglen) on a message (m, mlen) with a given
* public key (pk).
*
* sig[], m[] and pk[] may overlap each other arbitrarily.
*
* Return value: 0 on success, -1 on error.
*/
int PQCLEAN_FALCON512_CLEAN_crypto_sign_verify(
const uint8_t *sig, size_t siglen,
const uint8_t *m, size_t mlen, const uint8_t *pk);
/*
* Compute a signature on a message and pack the signature and message
* into a single object, written into sm[]. The length of that output is
* written in *smlen; that length may be larger than the message length
* (mlen) by up to PQCLEAN_FALCON512_CLEAN_CRYPTO_BYTES.
*
* sm[] and m[] may overlap each other arbitrarily; however, sm[] shall
* not overlap with sk[].
*
* Return value: 0 on success, -1 on error.
*/
int PQCLEAN_FALCON512_CLEAN_crypto_sign(
uint8_t *sm, size_t *smlen,
const uint8_t *m, size_t mlen, const uint8_t *sk);
/*
* Open a signed message object (sm, smlen) and verify the signature;
* on success, the message itself is written into m[] and its length
* into *mlen. The message is shorter than the signed message object,
* but the size difference depends on the signature value; the difference
* may range up to PQCLEAN_FALCON512_CLEAN_CRYPTO_BYTES.
*
* m[], sm[] and pk[] may overlap each other arbitrarily.
*
* Return value: 0 on success, -1 on error.
*/
int PQCLEAN_FALCON512_CLEAN_crypto_sign_open(
uint8_t *m, size_t *mlen,
const uint8_t *sm, size_t smlen, const uint8_t *pk);
#endif

View File

@ -1,551 +0,0 @@
/*
* Encoding/decoding of keys and signatures.
*
* ==========================(LICENSE BEGIN)============================
*
* Copyright (c) 2017-2019 Falcon Project
*
* 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.
*
* ===========================(LICENSE END)=============================
*
* @author Thomas Pornin <thomas.pornin@nccgroup.com>
*/
#include "inner.h"
/* see inner.h */
size_t
PQCLEAN_FALCON512_CLEAN_modq_encode(
void *out, size_t max_out_len,
const uint16_t *x, unsigned logn) {
size_t n, out_len, u;
uint8_t *buf;
uint32_t acc;
int acc_len;
n = (size_t)1 << logn;
for (u = 0; u < n; u ++) {
if (x[u] >= 12289) {
return 0;
}
}
out_len = ((n * 14) + 7) >> 3;
if (out == NULL) {
return out_len;
}
if (out_len > max_out_len) {
return 0;
}
buf = out;
acc = 0;
acc_len = 0;
for (u = 0; u < n; u ++) {
acc = (acc << 14) | x[u];
acc_len += 14;
while (acc_len >= 8) {
acc_len -= 8;
*buf ++ = (uint8_t)(acc >> acc_len);
}
}
if (acc_len > 0) {
*buf = (uint8_t)(acc << (8 - acc_len));
}
return out_len;
}
/* see inner.h */
size_t
PQCLEAN_FALCON512_CLEAN_modq_decode(
uint16_t *x, unsigned logn,
const void *in, size_t max_in_len) {
size_t n, in_len, u;
const uint8_t *buf;
uint32_t acc;
int acc_len;
n = (size_t)1 << logn;
in_len = ((n * 14) + 7) >> 3;
if (in_len > max_in_len) {
return 0;
}
buf = in;
acc = 0;
acc_len = 0;
u = 0;
while (u < n) {
acc = (acc << 8) | (*buf ++);
acc_len += 8;
if (acc_len >= 14) {
unsigned w;
acc_len -= 14;
w = (acc >> acc_len) & 0x3FFF;
if (w >= 12289) {
return 0;
}
x[u ++] = (uint16_t)w;
}
}
if ((acc & (((uint32_t)1 << acc_len) - 1)) != 0) {
return 0;
}
return in_len;
}
/* see inner.h */
size_t
PQCLEAN_FALCON512_CLEAN_trim_i16_encode(
void *out, size_t max_out_len,
const int16_t *x, unsigned logn, unsigned bits) {
size_t n, u, out_len;
int minv, maxv;
uint8_t *buf;
uint32_t acc, mask;
unsigned acc_len;
n = (size_t)1 << logn;
maxv = (1 << (bits - 1)) - 1;
minv = -maxv;
for (u = 0; u < n; u ++) {
if (x[u] < minv || x[u] > maxv) {
return 0;
}
}
out_len = ((n * bits) + 7) >> 3;
if (out == NULL) {
return out_len;
}
if (out_len > max_out_len) {
return 0;
}
buf = out;
acc = 0;
acc_len = 0;
mask = ((uint32_t)1 << bits) - 1;
for (u = 0; u < n; u ++) {
acc = (acc << bits) | ((uint16_t)x[u] & mask);
acc_len += bits;
while (acc_len >= 8) {
acc_len -= 8;
*buf ++ = (uint8_t)(acc >> acc_len);
}
}
if (acc_len > 0) {
*buf ++ = (uint8_t)(acc << (8 - acc_len));
}
return out_len;
}
/* see inner.h */
size_t
PQCLEAN_FALCON512_CLEAN_trim_i16_decode(
int16_t *x, unsigned logn, unsigned bits,
const void *in, size_t max_in_len) {
size_t n, in_len;
const uint8_t *buf;
size_t u;
uint32_t acc, mask1, mask2;
unsigned acc_len;
n = (size_t)1 << logn;
in_len = ((n * bits) + 7) >> 3;
if (in_len > max_in_len) {
return 0;
}
buf = in;
u = 0;
acc = 0;
acc_len = 0;
mask1 = ((uint32_t)1 << bits) - 1;
mask2 = (uint32_t)1 << (bits - 1);
while (u < n) {
acc = (acc << 8) | *buf ++;
acc_len += 8;
while (acc_len >= bits && u < n) {
uint32_t w;
acc_len -= bits;
w = (acc >> acc_len) & mask1;
w |= -(w & mask2);
if (w == -mask2) {
/*
* The -2^(bits-1) value is forbidden.
*/
return 0;
}
w |= -(w & mask2);
x[u ++] = (int16_t) * (int32_t *)&w;
}
}
if ((acc & (((uint32_t)1 << acc_len) - 1)) != 0) {
/*
* Extra bits in the last byte must be zero.
*/
return 0;
}
return in_len;
}
/* see inner.h */
size_t
PQCLEAN_FALCON512_CLEAN_trim_i8_encode(
void *out, size_t max_out_len,
const int8_t *x, unsigned logn, unsigned bits) {
size_t n, u, out_len;
int minv, maxv;
uint8_t *buf;
uint32_t acc, mask;
unsigned acc_len;
n = (size_t)1 << logn;
maxv = (1 << (bits - 1)) - 1;
minv = -maxv;
for (u = 0; u < n; u ++) {
if (x[u] < minv || x[u] > maxv) {
return 0;
}
}
out_len = ((n * bits) + 7) >> 3;
if (out == NULL) {
return out_len;
}
if (out_len > max_out_len) {
return 0;
}
buf = out;
acc = 0;
acc_len = 0;
mask = ((uint32_t)1 << bits) - 1;
for (u = 0; u < n; u ++) {
acc = (acc << bits) | ((uint8_t)x[u] & mask);
acc_len += bits;
while (acc_len >= 8) {
acc_len -= 8;
*buf ++ = (uint8_t)(acc >> acc_len);
}
}
if (acc_len > 0) {
*buf ++ = (uint8_t)(acc << (8 - acc_len));
}
return out_len;
}
/* see inner.h */
size_t
PQCLEAN_FALCON512_CLEAN_trim_i8_decode(
int8_t *x, unsigned logn, unsigned bits,
const void *in, size_t max_in_len) {
size_t n, in_len;
const uint8_t *buf;
size_t u;
uint32_t acc, mask1, mask2;
unsigned acc_len;
n = (size_t)1 << logn;
in_len = ((n * bits) + 7) >> 3;
if (in_len > max_in_len) {
return 0;
}
buf = in;
u = 0;
acc = 0;
acc_len = 0;
mask1 = ((uint32_t)1 << bits) - 1;
mask2 = (uint32_t)1 << (bits - 1);
while (u < n) {
acc = (acc << 8) | *buf ++;
acc_len += 8;
while (acc_len >= bits && u < n) {
uint32_t w;
acc_len -= bits;
w = (acc >> acc_len) & mask1;
w |= -(w & mask2);
if (w == -mask2) {
/*
* The -2^(bits-1) value is forbidden.
*/
return 0;
}
x[u ++] = (int8_t) * (int32_t *)&w;
}
}
if ((acc & (((uint32_t)1 << acc_len) - 1)) != 0) {
/*
* Extra bits in the last byte must be zero.
*/
return 0;
}
return in_len;
}
/* see inner.h */
size_t
PQCLEAN_FALCON512_CLEAN_comp_encode(
void *out, size_t max_out_len,
const int16_t *x, unsigned logn) {
uint8_t *buf;
size_t n, u, v;
uint32_t acc;
unsigned acc_len;
n = (size_t)1 << logn;
buf = out;
/*
* Make sure that all values are within the -2047..+2047 range.
*/
for (u = 0; u < n; u ++) {
if (x[u] < -2047 || x[u] > +2047) {
return 0;
}
}
acc = 0;
acc_len = 0;
v = 0;
for (u = 0; u < n; u ++) {
int t;
unsigned w;
/*
* Get sign and absolute value of next integer; push the
* sign bit.
*/
acc <<= 1;
t = x[u];
if (t < 0) {
t = -t;
acc |= 1;
}
w = (unsigned)t;
/*
* Push the low 7 bits of the absolute value.
*/
acc <<= 7;
acc |= w & 127u;
w >>= 7;
/*
* We pushed exactly 8 bits.
*/
acc_len += 8;
/*
* Push as many zeros as necessary, then a one. Since the
* absolute value is at most 2047, w can only range up to
* 15 at this point, thus we will add at most 16 bits
* here. With the 8 bits above and possibly up to 7 bits
* from previous iterations, we may go up to 31 bits, which
* will fit in the accumulator, which is an uint32_t.
*/
acc <<= (w + 1);
acc |= 1;
acc_len += w + 1;
/*
* Produce all full bytes.
*/
while (acc_len >= 8) {
acc_len -= 8;
if (buf != NULL) {
if (v >= max_out_len) {
return 0;
}
buf[v] = (uint8_t)(acc >> acc_len);
}
v ++;
}
}
/*
* Flush remaining bits (if any).
*/
if (acc_len > 0) {
if (buf != NULL) {
if (v >= max_out_len) {
return 0;
}
buf[v] = (uint8_t)(acc << (8 - acc_len));
}
v ++;
}
return v;
}
/* see inner.h */
size_t
PQCLEAN_FALCON512_CLEAN_comp_decode(
int16_t *x, unsigned logn,
const void *in, size_t max_in_len) {
const uint8_t *buf;
size_t n, u, v;
uint32_t acc;
unsigned acc_len;
n = (size_t)1 << logn;
buf = in;
acc = 0;
acc_len = 0;
v = 0;
for (u = 0; u < n; u ++) {
unsigned b, s, m;
/*
* Get next eight bits: sign and low seven bits of the
* absolute value.
*/
if (v >= max_in_len) {
return 0;
}
acc = (acc << 8) | (uint32_t)buf[v ++];
b = acc >> acc_len;
s = b & 128;
m = b & 127;
/*
* Get next bits until a 1 is reached.
*/
for (;;) {
if (acc_len == 0) {
if (v >= max_in_len) {
return 0;
}
acc = (acc << 8) | (uint32_t)buf[v ++];
acc_len = 8;
}
acc_len --;
if (((acc >> acc_len) & 1) != 0) {
break;
}
m += 128;
if (m > 2047) {
return 0;
}
}
x[u] = (int16_t)(s ? -(int)m : (int)m);
}
return v;
}
/*
* Key elements and signatures are polynomials with small integer
* coefficients. Here are some statistics gathered over many
* generated key pairs (10000 or more for each degree):
*
* log(n) n max(f,g) std(f,g) max(F,G) std(F,G)
* 1 2 129 56.31 143 60.02
* 2 4 123 40.93 160 46.52
* 3 8 97 28.97 159 38.01
* 4 16 100 21.48 154 32.50
* 5 32 71 15.41 151 29.36
* 6 64 59 11.07 138 27.77
* 7 128 39 7.91 144 27.00
* 8 256 32 5.63 148 26.61
* 9 512 22 4.00 137 26.46
* 10 1024 15 2.84 146 26.41
*
* We want a compact storage format for private key, and, as part of
* key generation, we are allowed to reject some keys which would
* otherwise be fine (this does not induce any noticeable vulnerability
* as long as we reject only a small proportion of possible keys).
* Hence, we enforce at key generation time maximum values for the
* elements of f, g, F and G, so that their encoding can be expressed
* in fixed-width values. Limits have been chosen so that generated
* keys are almost always within bounds, thus not impacting neither
* security or performance.
*
* IMPORTANT: the code assumes that all coefficients of f, g, F and G
* ultimately fit in the -127..+127 range. Thus, none of the elements
* of max_fg_bits[] and max_FG_bits[] shall be greater than 8.
*/
const uint8_t PQCLEAN_FALCON512_CLEAN_max_fg_bits[] = {
0, /* unused */
8,
8,
8,
8,
8,
7,
7,
6,
6,
5
};
const uint8_t PQCLEAN_FALCON512_CLEAN_max_FG_bits[] = {
0, /* unused */
8,
8,
8,
8,
8,
8,
8,
8,
8,
8
};
/*
* When generating a new key pair, we can always reject keys which
* feature an abnormally large coefficient. This can also be done for
* signatures, albeit with some care: in case the signature process is
* used in a derandomized setup (explicitly seeded with the message and
* private key), we have to follow the specification faithfully, and the
* specification only enforces a limit on the L2 norm of the signature
* vector. The limit on the L2 norm implies that the absolute value of
* a coefficient of the signature cannot be more than the following:
*
* log(n) n max sig coeff (theoretical)
* 1 2 412
* 2 4 583
* 3 8 824
* 4 16 1166
* 5 32 1649
* 6 64 2332
* 7 128 3299
* 8 256 4665
* 9 512 6598
* 10 1024 9331
*
* However, the largest observed signature coefficients during our
* experiments was 1077 (in absolute value), hence we can assume that,
* with overwhelming probability, signature coefficients will fit
* in -2047..2047, i.e. 12 bits.
*/
const uint8_t PQCLEAN_FALCON512_CLEAN_max_sig_bits[] = {
0, /* unused */
10,
11,
11,
12,
12,
12,
12,
12,
12,
12
};

View File

@ -1,293 +0,0 @@
/*
* Support functions for signatures (hash-to-point, norm).
*
* ==========================(LICENSE BEGIN)============================
*
* Copyright (c) 2017-2019 Falcon Project
*
* 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.
*
* ===========================(LICENSE END)=============================
*
* @author Thomas Pornin <thomas.pornin@nccgroup.com>
*/
#include "inner.h"
/* see inner.h */
void
PQCLEAN_FALCON512_CLEAN_hash_to_point_vartime(
inner_shake256_context *sc,
uint16_t *x, unsigned logn) {
/*
* This is the straightforward per-the-spec implementation. It
* is not constant-time, thus it might reveal information on the
* plaintext (at least, enough to check the plaintext against a
* list of potential plaintexts) in a scenario where the
* attacker does not have access to the signature value or to
* the public key, but knows the nonce (without knowledge of the
* nonce, the hashed output cannot be matched against potential
* plaintexts).
*/
size_t n;
n = (size_t)1 << logn;
while (n > 0) {
uint8_t buf[2];
uint32_t w;
inner_shake256_extract(sc, (void *)buf, sizeof buf);
w = ((unsigned)buf[0] << 8) | (unsigned)buf[1];
if (w < 61445) {
while (w >= 12289) {
w -= 12289;
}
*x ++ = (uint16_t)w;
n --;
}
}
}
/* see inner.h */
void
PQCLEAN_FALCON512_CLEAN_hash_to_point_ct(
inner_shake256_context *sc,
uint16_t *x, unsigned logn, uint8_t *tmp) {
/*
* Each 16-bit sample is a value in 0..65535. The value is
* kept if it falls in 0..61444 (because 61445 = 5*12289)
* and rejected otherwise; thus, each sample has probability
* about 0.93758 of being selected.
*
* We want to oversample enough to be sure that we will
* have enough values with probability at least 1 - 2^(-256).
* Depending on degree N, this leads to the following
* required oversampling:
*
* logn n oversampling
* 1 2 65
* 2 4 67
* 3 8 71
* 4 16 77
* 5 32 86
* 6 64 100
* 7 128 122
* 8 256 154
* 9 512 205
* 10 1024 287
*
* If logn >= 7, then the provided temporary buffer is large
* enough. Otherwise, we use a stack buffer of 63 entries
* (i.e. 126 bytes) for the values that do not fit in tmp[].
*/
static const uint16_t overtab[] = {
0, /* unused */
65,
67,
71,
77,
86,
100,
122,
154,
205,
287
};
unsigned n, n2, u, m, p, over;
uint16_t *tt1, tt2[63];
/*
* We first generate m 16-bit value. Values 0..n-1 go to x[].
* Values n..2*n-1 go to tt1[]. Values 2*n and later go to tt2[].
* We also reduce modulo q the values; rejected values are set
* to 0xFFFF.
*/
n = 1U << logn;
n2 = n << 1;
over = overtab[logn];
m = n + over;
tt1 = (uint16_t *)tmp;
for (u = 0; u < m; u ++) {
uint8_t buf[2];
uint32_t w, wr;
inner_shake256_extract(sc, buf, sizeof buf);
w = ((uint32_t)buf[0] << 8) | (uint32_t)buf[1];
wr = w - ((uint32_t)24578 & (((w - 24578) >> 31) - 1));
wr = wr - ((uint32_t)24578 & (((wr - 24578) >> 31) - 1));
wr = wr - ((uint32_t)12289 & (((wr - 12289) >> 31) - 1));
wr |= ((w - 61445) >> 31) - 1;
if (u < n) {
x[u] = (uint16_t)wr;
} else if (u < n2) {
tt1[u - n] = (uint16_t)wr;
} else {
tt2[u - n2] = (uint16_t)wr;
}
}
/*
* Now we must "squeeze out" the invalid values. We do this in
* a logarithmic sequence of passes; each pass computes where a
* value should go, and moves it down by 'p' slots if necessary,
* where 'p' uses an increasing powers-of-two scale. It can be
* shown that in all cases where the loop decides that a value
* has to be moved down by p slots, the destination slot is
* "free" (i.e. contains an invalid value).
*/
for (p = 1; p <= over; p <<= 1) {
unsigned v;
/*
* In the loop below:
*
* - v contains the index of the final destination of
* the value; it is recomputed dynamically based on
* whether values are valid or not.
*
* - u is the index of the value we consider ("source");
* its address is s.
*
* - The loop may swap the value with the one at index
* u-p. The address of the swap destination is d.
*/
v = 0;
for (u = 0; u < m; u ++) {
uint16_t *s, *d;
unsigned j, sv, dv, mk;
if (u < n) {
s = &x[u];
} else if (u < n2) {
s = &tt1[u - n];
} else {
s = &tt2[u - n2];
}
sv = *s;
/*
* The value in sv should ultimately go to
* address v, i.e. jump back by u-v slots.
*/
j = u - v;
/*
* We increment v for the next iteration, but
* only if the source value is valid. The mask
* 'mk' is -1 if the value is valid, 0 otherwise,
* so we _subtract_ mk.
*/
mk = (sv >> 15) - 1U;
v -= mk;
/*
* In this loop we consider jumps by p slots; if
* u < p then there is nothing more to do.
*/
if (u < p) {
continue;
}
/*
* Destination for the swap: value at address u-p.
*/
if ((u - p) < n) {
d = &x[u - p];
} else if ((u - p) < n2) {
d = &tt1[(u - p) - n];
} else {
d = &tt2[(u - p) - n2];
}
dv = *d;
/*
* The swap should be performed only if the source
* is valid AND the jump j has its 'p' bit set.
*/
mk &= -(((j & p) + 0x1FF) >> 9);
*s = (uint16_t)(sv ^ (mk & (sv ^ dv)));
*d = (uint16_t)(dv ^ (mk & (sv ^ dv)));
}
}
}
/* see inner.h */
int
PQCLEAN_FALCON512_CLEAN_is_short(
const int16_t *s1, const int16_t *s2, unsigned logn) {
/*
* We use the l2-norm. Code below uses only 32-bit operations to
* compute the square of the norm with saturation to 2^32-1 if
* the value exceeds 2^31-1.
*/
size_t n, u;
uint32_t s, ng;
n = (size_t)1 << logn;
s = 0;
ng = 0;
for (u = 0; u < n; u ++) {
int32_t z;
z = s1[u];
s += (uint32_t)(z * z);
ng |= s;
z = s2[u];
s += (uint32_t)(z * z);
ng |= s;
}
s |= -(ng >> 31);
/*
* Acceptance bound on the l2-norm is:
* 1.2*1.55*sqrt(q)*sqrt(2*N)
* Value 7085 is floor((1.2^2)*(1.55^2)*2*1024).
*/
return s < (((uint32_t)7085 * (uint32_t)12289) >> (10 - logn));
}
/* see inner.h */
int
PQCLEAN_FALCON512_CLEAN_is_short_half(
uint32_t sqn, const int16_t *s2, unsigned logn) {
size_t n, u;
uint32_t ng;
n = (size_t)1 << logn;
ng = -(sqn >> 31);
for (u = 0; u < n; u ++) {
int32_t z;
z = s2[u];
sqn += (uint32_t)(z * z);
ng |= sqn;
}
sqn |= -(ng >> 31);
/*
* Acceptance bound on the l2-norm is:
* 1.2*1.55*sqrt(q)*sqrt(2*N)
* Value 7085 is floor((1.2^2)*(1.55^2)*2*1024).
*/
return sqn < (((uint32_t)7085 * (uint32_t)12289) >> (10 - logn));
}

Some files were not shown because too many files have changed in this diff Show More