mirror of
https://github.com/open-quantum-safe/liboqs.git
synced 2025-11-22 00:09:23 -05:00
Added HQC from PQClean. (#805)
This commit is contained in:
parent
aa7f1dfa3d
commit
adac989932
@ -81,6 +81,14 @@ cmake_dependent_option(OQS_ENABLE_KEM_classic_mceliece_6960119f "" ON "OQS_ENABL
|
||||
cmake_dependent_option(OQS_ENABLE_KEM_classic_mceliece_8192128 "" ON "OQS_ENABLE_KEM_CLASSIC_MCELIECE" OFF)
|
||||
cmake_dependent_option(OQS_ENABLE_KEM_classic_mceliece_8192128f "" ON "OQS_ENABLE_KEM_CLASSIC_MCELIECE" OFF)
|
||||
|
||||
option(OQS_ENABLE_KEM_HQC "" ON)
|
||||
cmake_dependent_option(OQS_ENABLE_KEM_hqc_128_1_cca2 "" ON "OQS_ENABLE_KEM_HQC" OFF)
|
||||
cmake_dependent_option(OQS_ENABLE_KEM_hqc_192_1_cca2 "" ON "OQS_ENABLE_KEM_HQC" OFF)
|
||||
cmake_dependent_option(OQS_ENABLE_KEM_hqc_192_2_cca2 "" ON "OQS_ENABLE_KEM_HQC" OFF)
|
||||
cmake_dependent_option(OQS_ENABLE_KEM_hqc_256_1_cca2 "" ON "OQS_ENABLE_KEM_HQC" OFF)
|
||||
cmake_dependent_option(OQS_ENABLE_KEM_hqc_256_2_cca2 "" ON "OQS_ENABLE_KEM_HQC" OFF)
|
||||
cmake_dependent_option(OQS_ENABLE_KEM_hqc_256_3_cca2 "" ON "OQS_ENABLE_KEM_HQC" OFF)
|
||||
|
||||
option(OQS_ENABLE_KEM_KYBER "" ON)
|
||||
cmake_dependent_option(OQS_ENABLE_KEM_kyber_512 "" ON "OQS_ENABLE_KEM_KYBER" OFF)
|
||||
if(ARCH STREQUAL "x86_64" AND CMAKE_SYSTEM_NAME MATCHES "Linux" AND OQS_USE_AVX2_INSTRUCTIONS AND OQS_USE_BMI2_INSTRUCTIONS)
|
||||
|
||||
@ -77,6 +77,9 @@ endif()
|
||||
if(OQS_ENABLE_KEM_CLASSIC_MCELIECE)
|
||||
set(PUBLIC_HEADERS ${PUBLIC_HEADERS} ${PROJECT_SOURCE_DIR}/src/kem/classic_mceliece/kem_classic_mceliece.h)
|
||||
endif()
|
||||
if(OQS_ENABLE_KEM_HQC)
|
||||
set(PUBLIC_HEADERS ${PUBLIC_HEADERS} ${PROJECT_SOURCE_DIR}/src/kem/hqc/kem_hqc.h)
|
||||
endif()
|
||||
if(OQS_ENABLE_KEM_KYBER)
|
||||
set(PUBLIC_HEADERS ${PUBLIC_HEADERS} ${PROJECT_SOURCE_DIR}/src/kem/kyber/kem_kyber.h)
|
||||
endif()
|
||||
|
||||
@ -41,6 +41,7 @@ Details on each supported algorithm can be found in the [docs/algorithms folder]
|
||||
- **BIKE**: BIKE1-L1-CPA, BIKE1-L3-CPA, BIKE1-L1-FO, BIKE1-L3-FO
|
||||
- **Classic McEliece**: Classic-McEliece-348864†, Classic-McEliece-348864f†, Classic-McEliece-460896†, Classic-McEliece-460896f†, Classic-McEliece-6688128†, Classic-McEliece-6688128f†, Classic-McEliece-6960119†, Classic-McEliece-6960119f†, Classic-McEliece-8192128†, Classic-McEliece-8192128f†
|
||||
- **FrodoKEM**: FrodoKEM-640-AES, FrodoKEM-640-SHAKE, FrodoKEM-976-AES, FrodoKEM-976-SHAKE, FrodoKEM-1344-AES, FrodoKEM-1344-SHAKE
|
||||
- **HQC**: HQC-128-1-CCA2, HQC-192-1-CCA2, HQC-192-2-CCA2, HQC-256-1-CCA2†, HQC-256-2-CCA2†, HQC-256-3-CCA2†
|
||||
- **Kyber**: Kyber512, Kyber768, Kyber1024, Kyber512-90s, Kyber768-90s, Kyber1024-90s
|
||||
- **NewHope**: NewHope-512-CCA, NewHope-1024-CCA
|
||||
- **NTRU**: NTRU-HPS-2048-509, NTRU-HPS-2048-677, NTRU-HPS-4096-821, NTRU-HRSS-701
|
||||
|
||||
@ -33,6 +33,8 @@ This release continues from the 0.3.0 release of liboqs.
|
||||
|
||||
### Key encapsulation mechanisms
|
||||
|
||||
- HQC: Added version 2019/08/24
|
||||
- NewHope: Update to version 1.1
|
||||
- SIKE: Update to version 3.3
|
||||
|
||||
### Digital signature schemes
|
||||
@ -47,4 +49,4 @@ This release continues from the 0.3.0 release of liboqs.
|
||||
Deprecations
|
||||
------------
|
||||
|
||||
As a result of NIST's announcement of Round 3 of the Post-Quantum Cryptography Standardization Project, the 0.4.x series will be the last release(s) of liboqs that contain algorithms from Round 2 that are not Round 3 finalists or alternate candidates. Those algorithms will be removed in the 0.5.0 release. The algorithms in question are: NewHope, ThreeBears, MQDSS, and qTesla. These algorithms are considered deprecated within liboqs and are no longer receiving updates.
|
||||
As a result of NIST's announcement of Round 3 of the Post-Quantum Cryptography Standardization Project, the 0.4.x series will be the last release(s) of liboqs that contain algorithms from Round 2 that are not Round 3 finalists or alternate candidates. Those algorithms will be removed in the 0.5.0 release. The algorithms in question are: NewHope, ThreeBears, MQDSS, and qTesla. These algorithms are considered deprecated within liboqs and will receive no updates after this release.
|
||||
|
||||
29
docs/algorithms/kem/hqc.md
Normal file
29
docs/algorithms/kem/hqc.md
Normal file
@ -0,0 +1,29 @@
|
||||
HQC
|
||||
===
|
||||
|
||||
- **Algorithm type**: key encapsulation mechanism
|
||||
- **Main cryptographic assumption**: Syndrome decoding of structure codes (Hamming Quasi-Cyclic)
|
||||
- **Scheme authors**: Carlos Aguilar Melchor, Nicolas Aragon, Slim Bettaieb, Loïc Bidoux, Olivier Blazy, Jean-Christophe Deneuville, Philippe Gaborit, Edoardo Persichetti, Gilles Zémor
|
||||
- **Authors' website**: http://pqc-hqc.org
|
||||
- **Version**: 2019/08/24
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
|
||||
- **Source of implementation**: http://pqc-hqc.org/doc/hqc-submission_2019-08-24.zip
|
||||
- **Implementation version**: https://github.com/PQClean/PQClean/commit/90630db2ebada4bacceb5331b0a1a9a356ba65b9
|
||||
- **License**: Public domain
|
||||
- **Constant-time**: No
|
||||
- **Optimizations**: Portable C
|
||||
|
||||
Parameter sets
|
||||
--------------
|
||||
|
||||
| Parameter set | Security model | Claimed NIST security level | Public key size (bytes) | Secret key size (bytes) | Ciphertext size (bytes) | Shared secret size (bytes) |
|
||||
|----------------|----------------|-----------------------------|-------------------------|-------------------------|-------------------------|----------------------------|
|
||||
| HQC-128-1-CCA2 | IND-CCA | 1 | 3125 | 3165 | 6234 | 64 |
|
||||
| HQC-192-1-CCA2 | IND-CCA | 3 | 5499 | 5539 | 10981 | 64 |
|
||||
| HQC-192-2-CCA2 | IND-CCA | 3 | 5884 | 5924 | 11749 | 64 |
|
||||
| HQC-256-1-CCA2 | IND-CCA | 5 | 7989 | 8029 | 15961 | 64 |
|
||||
| HQC-256-2-CCA2 | IND-CCA | 5 | 8503 | 8543 | 16985 | 64 |
|
||||
| HQC-256-3-CCA2 | IND-CCA | 5 | 8897 | 8937 | 17777 | 64 |
|
||||
@ -63,6 +63,34 @@ kems:
|
||||
pretty_name_full: Classic-McEliece-8192128f
|
||||
implementation: vec
|
||||
sources: ['aes256ctr.c', 'benes.c', 'bm.c', 'controlbits.c', 'decrypt.c', 'encrypt.c', 'fft.c', 'fft_tr.c', 'gf.c', 'operations.c', 'pk_gen.c', 'sk_gen.c', 'transpose.c', 'util.c', 'vec.c']
|
||||
-
|
||||
name: hqc
|
||||
default_implementation: leaktime
|
||||
schemes:
|
||||
-
|
||||
scheme: "128_1_cca2"
|
||||
pqclean_scheme: hqc-128-1-cca2
|
||||
pretty_name_full: HQC-128-1-CCA2
|
||||
-
|
||||
scheme: "192_1_cca2"
|
||||
pqclean_scheme: hqc-192-1-cca2
|
||||
pretty_name_full: HQC-192-1-CCA2
|
||||
-
|
||||
scheme: "192_2_cca2"
|
||||
pqclean_scheme: hqc-192-2-cca2
|
||||
pretty_name_full: HQC-192-2-CCA2
|
||||
-
|
||||
scheme: "256_1_cca2"
|
||||
pqclean_scheme: hqc-256-1-cca2
|
||||
pretty_name_full: HQC-256-1-CCA2
|
||||
-
|
||||
scheme: "256_2_cca2"
|
||||
pqclean_scheme: hqc-256-2-cca2
|
||||
pretty_name_full: HQC-256-2-CCA2
|
||||
-
|
||||
scheme: "256_3_cca2"
|
||||
pqclean_scheme: hqc-256-3-cca2
|
||||
pretty_name_full: HQC-256-3-CCA2
|
||||
-
|
||||
name: kyber
|
||||
default_implementation: clean
|
||||
|
||||
@ -27,6 +27,10 @@ if(OQS_ENABLE_KEM_CLASSIC_MCELIECE)
|
||||
add_subdirectory(kem/classic_mceliece)
|
||||
set(KEM_OBJS ${KEM_OBJS} ${CLASSIC_MCELIECE_OBJS})
|
||||
endif()
|
||||
if(OQS_ENABLE_KEM_HQC)
|
||||
add_subdirectory(kem/hqc)
|
||||
set(KEM_OBJS ${KEM_OBJS} ${HQC_OBJS})
|
||||
endif()
|
||||
if(OQS_ENABLE_KEM_KYBER)
|
||||
add_subdirectory(kem/kyber)
|
||||
set(KEM_OBJS ${KEM_OBJS} ${KYBER_OBJS})
|
||||
|
||||
@ -42,6 +42,7 @@ add_library(common OBJECT ${AES_IMPL}
|
||||
${SHA2_IMPL}
|
||||
${SHA3_IMPL}
|
||||
common.c
|
||||
pqclean_shims/nistseedexpander.c
|
||||
rand/rand.c
|
||||
rand/rand_nist.c)
|
||||
if(OQS_USE_OPENSSL)
|
||||
|
||||
102
src/common/pqclean_shims/nistseedexpander.c
Normal file
102
src/common/pqclean_shims/nistseedexpander.c
Normal file
@ -0,0 +1,102 @@
|
||||
//
|
||||
// rng.c
|
||||
//
|
||||
// Created by Bassham, Lawrence E (Fed) on 8/29/17.
|
||||
// Copyright © 2017 Bassham, Lawrence E (Fed). All rights reserved.
|
||||
// SPDX-License-Identifier: Unknown
|
||||
// Modified for PQClean by Sebastian Verschoor
|
||||
//
|
||||
|
||||
#include "nistseedexpander.h"
|
||||
#include "aes.h"
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
seedexpander_init()
|
||||
ctx - stores the current state of an instance of the seed expander
|
||||
seed - a 32 byte random value
|
||||
diversifier - an 8 byte diversifier
|
||||
maxlen - maximum number of bytes (less than 2**32) generated under this seed and diversifier
|
||||
*/
|
||||
int
|
||||
seedexpander_init(AES_XOF_struct *ctx,
|
||||
const uint8_t *seed,
|
||||
const uint8_t *diversifier,
|
||||
size_t maxlen) {
|
||||
ctx->length_remaining = maxlen;
|
||||
|
||||
memcpy(ctx->key, seed, 32);
|
||||
memcpy(ctx->ctr, diversifier, 8);
|
||||
|
||||
ctx->ctr[11] = (uint8_t) (maxlen % 256);
|
||||
maxlen >>= 8;
|
||||
ctx->ctr[10] = (uint8_t) (maxlen % 256);
|
||||
maxlen >>= 8;
|
||||
ctx->ctr[9] = (uint8_t) (maxlen % 256);
|
||||
maxlen >>= 8;
|
||||
ctx->ctr[8] = (uint8_t) (maxlen % 256);
|
||||
memset(ctx->ctr + 12, 0x00, 4);
|
||||
|
||||
ctx->buffer_pos = 16;
|
||||
memset(ctx->buffer, 0x00, 16);
|
||||
|
||||
return RNG_SUCCESS;
|
||||
}
|
||||
|
||||
static void AES256_ECB(uint8_t *key, uint8_t *ctr, uint8_t *buffer) {
|
||||
aes256ctx ctx;
|
||||
aes256_ecb_keyexp(&ctx, key);
|
||||
aes256_ecb(buffer, ctr, 1, &ctx);
|
||||
aes256_ctx_release(&ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
seedexpander()
|
||||
ctx - stores the current state of an instance of the seed expander
|
||||
x - returns the XOF data
|
||||
xlen - number of bytes to return
|
||||
*/
|
||||
int
|
||||
seedexpander(AES_XOF_struct *ctx, uint8_t *x, size_t xlen) {
|
||||
size_t offset;
|
||||
|
||||
if ( x == NULL ) {
|
||||
return RNG_BAD_OUTBUF;
|
||||
}
|
||||
if ( xlen >= ctx->length_remaining ) {
|
||||
return RNG_BAD_REQ_LEN;
|
||||
}
|
||||
|
||||
ctx->length_remaining -= xlen;
|
||||
|
||||
offset = 0;
|
||||
while ( xlen > 0 ) {
|
||||
if ( xlen <= (16 - ctx->buffer_pos) ) { // buffer has what we need
|
||||
memcpy(x + offset, ctx->buffer + ctx->buffer_pos, xlen);
|
||||
ctx->buffer_pos += xlen;
|
||||
|
||||
return RNG_SUCCESS;
|
||||
}
|
||||
|
||||
// take what's in the buffer
|
||||
memcpy(x + offset, ctx->buffer + ctx->buffer_pos, 16 - ctx->buffer_pos);
|
||||
xlen -= 16 - ctx->buffer_pos;
|
||||
offset += 16 - ctx->buffer_pos;
|
||||
|
||||
AES256_ECB(ctx->key, ctx->ctr, ctx->buffer);
|
||||
ctx->buffer_pos = 0;
|
||||
|
||||
//increment the counter
|
||||
for (size_t i = 15; i >= 12; i--) {
|
||||
if ( ctx->ctr[i] == 0xff ) {
|
||||
ctx->ctr[i] = 0x00;
|
||||
} else {
|
||||
ctx->ctr[i]++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return RNG_SUCCESS;
|
||||
}
|
||||
40
src/common/pqclean_shims/nistseedexpander.h
Normal file
40
src/common/pqclean_shims/nistseedexpander.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef NISTSEEDEXPANDER_H
|
||||
#define NISTSEEDEXPANDER_H
|
||||
|
||||
//
|
||||
// rng.h
|
||||
//
|
||||
// Created by Bassham, Lawrence E (Fed) on 8/29/17.
|
||||
// Copyright © 2017 Bassham, Lawrence E (Fed). All rights reserved.
|
||||
// SPDX-License-Identifier: Unknown
|
||||
// Modified for PQClean by Sebastian Verschoor
|
||||
//
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define NISTSEEDEXPANDER_SEED_LEN 32
|
||||
|
||||
#define RNG_SUCCESS ( 0)
|
||||
#define RNG_BAD_MAXLEN (-1)
|
||||
#define RNG_BAD_OUTBUF (-2)
|
||||
#define RNG_BAD_REQ_LEN (-3)
|
||||
|
||||
typedef struct {
|
||||
uint8_t buffer[16];
|
||||
size_t buffer_pos;
|
||||
size_t length_remaining;
|
||||
uint8_t key[NISTSEEDEXPANDER_SEED_LEN];
|
||||
uint8_t ctr[16];
|
||||
} AES_XOF_struct;
|
||||
|
||||
int
|
||||
seedexpander_init(AES_XOF_struct *ctx,
|
||||
const uint8_t *seed,
|
||||
const uint8_t *diversifier,
|
||||
size_t maxlen);
|
||||
|
||||
int
|
||||
seedexpander(AES_XOF_struct *ctx, uint8_t *x, size_t xlen);
|
||||
|
||||
#endif /* NISTSEEDEXPANDER_H */
|
||||
48
src/kem/hqc/CMakeLists.txt
Normal file
48
src/kem/hqc/CMakeLists.txt
Normal file
@ -0,0 +1,48 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# This file was generated by
|
||||
# scripts/copy_from_pqclean/copy_from_pqclean.py
|
||||
|
||||
if(OQS_ENABLE_KEM_hqc_128_1_cca2)
|
||||
add_library(hqc_128_1_cca2_leaktime OBJECT kem_hqc_128_1_cca2.c pqclean_hqc-128-1-cca2_leaktime/bch.c pqclean_hqc-128-1-cca2_leaktime/fft.c pqclean_hqc-128-1-cca2_leaktime/gf.c pqclean_hqc-128-1-cca2_leaktime/gf2x.c pqclean_hqc-128-1-cca2_leaktime/hqc.c pqclean_hqc-128-1-cca2_leaktime/kem.c pqclean_hqc-128-1-cca2_leaktime/parsing.c pqclean_hqc-128-1-cca2_leaktime/repetition.c pqclean_hqc-128-1-cca2_leaktime/tensor.c pqclean_hqc-128-1-cca2_leaktime/util.c pqclean_hqc-128-1-cca2_leaktime/vector.c)
|
||||
target_include_directories(hqc_128_1_cca2_leaktime PRIVATE ${CMAKE_CURRENT_LIST_DIR}/pqclean_hqc-128-1-cca2_leaktime)
|
||||
target_include_directories(hqc_128_1_cca2_leaktime PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims)
|
||||
set(_HQC_OBJS ${_HQC_OBJS} $<TARGET_OBJECTS:hqc_128_1_cca2_leaktime>)
|
||||
endif()
|
||||
|
||||
if(OQS_ENABLE_KEM_hqc_192_1_cca2)
|
||||
add_library(hqc_192_1_cca2_leaktime OBJECT kem_hqc_192_1_cca2.c pqclean_hqc-192-1-cca2_leaktime/bch.c pqclean_hqc-192-1-cca2_leaktime/fft.c pqclean_hqc-192-1-cca2_leaktime/gf.c pqclean_hqc-192-1-cca2_leaktime/gf2x.c pqclean_hqc-192-1-cca2_leaktime/hqc.c pqclean_hqc-192-1-cca2_leaktime/kem.c pqclean_hqc-192-1-cca2_leaktime/parsing.c pqclean_hqc-192-1-cca2_leaktime/repetition.c pqclean_hqc-192-1-cca2_leaktime/tensor.c pqclean_hqc-192-1-cca2_leaktime/util.c pqclean_hqc-192-1-cca2_leaktime/vector.c)
|
||||
target_include_directories(hqc_192_1_cca2_leaktime PRIVATE ${CMAKE_CURRENT_LIST_DIR}/pqclean_hqc-192-1-cca2_leaktime)
|
||||
target_include_directories(hqc_192_1_cca2_leaktime PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims)
|
||||
set(_HQC_OBJS ${_HQC_OBJS} $<TARGET_OBJECTS:hqc_192_1_cca2_leaktime>)
|
||||
endif()
|
||||
|
||||
if(OQS_ENABLE_KEM_hqc_192_2_cca2)
|
||||
add_library(hqc_192_2_cca2_leaktime OBJECT kem_hqc_192_2_cca2.c pqclean_hqc-192-2-cca2_leaktime/bch.c pqclean_hqc-192-2-cca2_leaktime/fft.c pqclean_hqc-192-2-cca2_leaktime/gf.c pqclean_hqc-192-2-cca2_leaktime/gf2x.c pqclean_hqc-192-2-cca2_leaktime/hqc.c pqclean_hqc-192-2-cca2_leaktime/kem.c pqclean_hqc-192-2-cca2_leaktime/parsing.c pqclean_hqc-192-2-cca2_leaktime/repetition.c pqclean_hqc-192-2-cca2_leaktime/tensor.c pqclean_hqc-192-2-cca2_leaktime/util.c pqclean_hqc-192-2-cca2_leaktime/vector.c)
|
||||
target_include_directories(hqc_192_2_cca2_leaktime PRIVATE ${CMAKE_CURRENT_LIST_DIR}/pqclean_hqc-192-2-cca2_leaktime)
|
||||
target_include_directories(hqc_192_2_cca2_leaktime PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims)
|
||||
set(_HQC_OBJS ${_HQC_OBJS} $<TARGET_OBJECTS:hqc_192_2_cca2_leaktime>)
|
||||
endif()
|
||||
|
||||
if(OQS_ENABLE_KEM_hqc_256_1_cca2)
|
||||
add_library(hqc_256_1_cca2_leaktime OBJECT kem_hqc_256_1_cca2.c pqclean_hqc-256-1-cca2_leaktime/bch.c pqclean_hqc-256-1-cca2_leaktime/fft.c pqclean_hqc-256-1-cca2_leaktime/gf.c pqclean_hqc-256-1-cca2_leaktime/gf2x.c pqclean_hqc-256-1-cca2_leaktime/hqc.c pqclean_hqc-256-1-cca2_leaktime/kem.c pqclean_hqc-256-1-cca2_leaktime/parsing.c pqclean_hqc-256-1-cca2_leaktime/repetition.c pqclean_hqc-256-1-cca2_leaktime/tensor.c pqclean_hqc-256-1-cca2_leaktime/util.c pqclean_hqc-256-1-cca2_leaktime/vector.c)
|
||||
target_include_directories(hqc_256_1_cca2_leaktime PRIVATE ${CMAKE_CURRENT_LIST_DIR}/pqclean_hqc-256-1-cca2_leaktime)
|
||||
target_include_directories(hqc_256_1_cca2_leaktime PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims)
|
||||
set(_HQC_OBJS ${_HQC_OBJS} $<TARGET_OBJECTS:hqc_256_1_cca2_leaktime>)
|
||||
endif()
|
||||
|
||||
if(OQS_ENABLE_KEM_hqc_256_2_cca2)
|
||||
add_library(hqc_256_2_cca2_leaktime OBJECT kem_hqc_256_2_cca2.c pqclean_hqc-256-2-cca2_leaktime/bch.c pqclean_hqc-256-2-cca2_leaktime/fft.c pqclean_hqc-256-2-cca2_leaktime/gf.c pqclean_hqc-256-2-cca2_leaktime/gf2x.c pqclean_hqc-256-2-cca2_leaktime/hqc.c pqclean_hqc-256-2-cca2_leaktime/kem.c pqclean_hqc-256-2-cca2_leaktime/parsing.c pqclean_hqc-256-2-cca2_leaktime/repetition.c pqclean_hqc-256-2-cca2_leaktime/tensor.c pqclean_hqc-256-2-cca2_leaktime/util.c pqclean_hqc-256-2-cca2_leaktime/vector.c)
|
||||
target_include_directories(hqc_256_2_cca2_leaktime PRIVATE ${CMAKE_CURRENT_LIST_DIR}/pqclean_hqc-256-2-cca2_leaktime)
|
||||
target_include_directories(hqc_256_2_cca2_leaktime PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims)
|
||||
set(_HQC_OBJS ${_HQC_OBJS} $<TARGET_OBJECTS:hqc_256_2_cca2_leaktime>)
|
||||
endif()
|
||||
|
||||
if(OQS_ENABLE_KEM_hqc_256_3_cca2)
|
||||
add_library(hqc_256_3_cca2_leaktime OBJECT kem_hqc_256_3_cca2.c pqclean_hqc-256-3-cca2_leaktime/bch.c pqclean_hqc-256-3-cca2_leaktime/fft.c pqclean_hqc-256-3-cca2_leaktime/gf.c pqclean_hqc-256-3-cca2_leaktime/gf2x.c pqclean_hqc-256-3-cca2_leaktime/hqc.c pqclean_hqc-256-3-cca2_leaktime/kem.c pqclean_hqc-256-3-cca2_leaktime/parsing.c pqclean_hqc-256-3-cca2_leaktime/repetition.c pqclean_hqc-256-3-cca2_leaktime/tensor.c pqclean_hqc-256-3-cca2_leaktime/util.c pqclean_hqc-256-3-cca2_leaktime/vector.c)
|
||||
target_include_directories(hqc_256_3_cca2_leaktime PRIVATE ${CMAKE_CURRENT_LIST_DIR}/pqclean_hqc-256-3-cca2_leaktime)
|
||||
target_include_directories(hqc_256_3_cca2_leaktime PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims)
|
||||
set(_HQC_OBJS ${_HQC_OBJS} $<TARGET_OBJECTS:hqc_256_3_cca2_leaktime>)
|
||||
endif()
|
||||
|
||||
set(HQC_OBJS ${_HQC_OBJS} PARENT_SCOPE)
|
||||
75
src/kem/hqc/kem_hqc.h
Normal file
75
src/kem/hqc/kem_hqc.h
Normal file
@ -0,0 +1,75 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef OQS_KEM_HQC_H
|
||||
#define OQS_KEM_HQC_H
|
||||
|
||||
#include <oqs/oqs.h>
|
||||
|
||||
#ifdef OQS_ENABLE_KEM_hqc_128_1_cca2
|
||||
#define OQS_KEM_hqc_128_1_cca2_length_public_key 3125
|
||||
#define OQS_KEM_hqc_128_1_cca2_length_secret_key 3165
|
||||
#define OQS_KEM_hqc_128_1_cca2_length_ciphertext 6234
|
||||
#define OQS_KEM_hqc_128_1_cca2_length_shared_secret 64
|
||||
OQS_KEM *OQS_KEM_hqc_128_1_cca2_new(void);
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_128_1_cca2_keypair(uint8_t *public_key, uint8_t *secret_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_128_1_cca2_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_128_1_cca2_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key);
|
||||
#endif
|
||||
|
||||
#ifdef OQS_ENABLE_KEM_hqc_192_1_cca2
|
||||
#define OQS_KEM_hqc_192_1_cca2_length_public_key 5499
|
||||
#define OQS_KEM_hqc_192_1_cca2_length_secret_key 5539
|
||||
#define OQS_KEM_hqc_192_1_cca2_length_ciphertext 10981
|
||||
#define OQS_KEM_hqc_192_1_cca2_length_shared_secret 64
|
||||
OQS_KEM *OQS_KEM_hqc_192_1_cca2_new(void);
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_192_1_cca2_keypair(uint8_t *public_key, uint8_t *secret_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_192_1_cca2_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_192_1_cca2_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key);
|
||||
#endif
|
||||
|
||||
#ifdef OQS_ENABLE_KEM_hqc_192_2_cca2
|
||||
#define OQS_KEM_hqc_192_2_cca2_length_public_key 5884
|
||||
#define OQS_KEM_hqc_192_2_cca2_length_secret_key 5924
|
||||
#define OQS_KEM_hqc_192_2_cca2_length_ciphertext 11749
|
||||
#define OQS_KEM_hqc_192_2_cca2_length_shared_secret 64
|
||||
OQS_KEM *OQS_KEM_hqc_192_2_cca2_new(void);
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_192_2_cca2_keypair(uint8_t *public_key, uint8_t *secret_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_192_2_cca2_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_192_2_cca2_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key);
|
||||
#endif
|
||||
|
||||
#ifdef OQS_ENABLE_KEM_hqc_256_1_cca2
|
||||
#define OQS_KEM_hqc_256_1_cca2_length_public_key 7989
|
||||
#define OQS_KEM_hqc_256_1_cca2_length_secret_key 8029
|
||||
#define OQS_KEM_hqc_256_1_cca2_length_ciphertext 15961
|
||||
#define OQS_KEM_hqc_256_1_cca2_length_shared_secret 64
|
||||
OQS_KEM *OQS_KEM_hqc_256_1_cca2_new(void);
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_256_1_cca2_keypair(uint8_t *public_key, uint8_t *secret_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_256_1_cca2_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_256_1_cca2_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key);
|
||||
#endif
|
||||
|
||||
#ifdef OQS_ENABLE_KEM_hqc_256_2_cca2
|
||||
#define OQS_KEM_hqc_256_2_cca2_length_public_key 8503
|
||||
#define OQS_KEM_hqc_256_2_cca2_length_secret_key 8543
|
||||
#define OQS_KEM_hqc_256_2_cca2_length_ciphertext 16985
|
||||
#define OQS_KEM_hqc_256_2_cca2_length_shared_secret 64
|
||||
OQS_KEM *OQS_KEM_hqc_256_2_cca2_new(void);
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_256_2_cca2_keypair(uint8_t *public_key, uint8_t *secret_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_256_2_cca2_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_256_2_cca2_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key);
|
||||
#endif
|
||||
|
||||
#ifdef OQS_ENABLE_KEM_hqc_256_3_cca2
|
||||
#define OQS_KEM_hqc_256_3_cca2_length_public_key 8897
|
||||
#define OQS_KEM_hqc_256_3_cca2_length_secret_key 8937
|
||||
#define OQS_KEM_hqc_256_3_cca2_length_ciphertext 17777
|
||||
#define OQS_KEM_hqc_256_3_cca2_length_shared_secret 64
|
||||
OQS_KEM *OQS_KEM_hqc_256_3_cca2_new(void);
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_256_3_cca2_keypair(uint8_t *public_key, uint8_t *secret_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_256_3_cca2_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key);
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_256_3_cca2_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
49
src/kem/hqc/kem_hqc_128_1_cca2.c
Normal file
49
src/kem/hqc/kem_hqc_128_1_cca2.c
Normal file
@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <oqs/kem_hqc.h>
|
||||
|
||||
#if defined(OQS_ENABLE_KEM_hqc_128_1_cca2)
|
||||
|
||||
OQS_KEM *OQS_KEM_hqc_128_1_cca2_new() {
|
||||
|
||||
OQS_KEM *kem = malloc(sizeof(OQS_KEM));
|
||||
if (kem == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
kem->method_name = OQS_KEM_alg_hqc_128_1_cca2;
|
||||
kem->alg_version = "https://pqc-hqc.org/doc/hqc-reference-implementation_2019-08-24.zip";
|
||||
|
||||
kem->claimed_nist_level = 1;
|
||||
kem->ind_cca = true;
|
||||
|
||||
kem->length_public_key = OQS_KEM_hqc_128_1_cca2_length_public_key;
|
||||
kem->length_secret_key = OQS_KEM_hqc_128_1_cca2_length_secret_key;
|
||||
kem->length_ciphertext = OQS_KEM_hqc_128_1_cca2_length_ciphertext;
|
||||
kem->length_shared_secret = OQS_KEM_hqc_128_1_cca2_length_shared_secret;
|
||||
|
||||
kem->keypair = OQS_KEM_hqc_128_1_cca2_keypair;
|
||||
kem->encaps = OQS_KEM_hqc_128_1_cca2_encaps;
|
||||
kem->decaps = OQS_KEM_hqc_128_1_cca2_decaps;
|
||||
|
||||
return kem;
|
||||
}
|
||||
|
||||
extern int PQCLEAN_HQC1281CCA2_LEAKTIME_crypto_kem_keypair(unsigned char *pk, unsigned char *sk);
|
||||
extern int PQCLEAN_HQC1281CCA2_LEAKTIME_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk);
|
||||
extern int PQCLEAN_HQC1281CCA2_LEAKTIME_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk);
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_128_1_cca2_keypair(uint8_t *public_key, uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_HQC1281CCA2_LEAKTIME_crypto_kem_keypair(public_key, secret_key);
|
||||
}
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_128_1_cca2_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key) {
|
||||
return (OQS_STATUS) PQCLEAN_HQC1281CCA2_LEAKTIME_crypto_kem_enc(ciphertext, shared_secret, public_key);
|
||||
}
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_128_1_cca2_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_HQC1281CCA2_LEAKTIME_crypto_kem_dec(shared_secret, ciphertext, secret_key);
|
||||
}
|
||||
|
||||
#endif
|
||||
49
src/kem/hqc/kem_hqc_192_1_cca2.c
Normal file
49
src/kem/hqc/kem_hqc_192_1_cca2.c
Normal file
@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <oqs/kem_hqc.h>
|
||||
|
||||
#if defined(OQS_ENABLE_KEM_hqc_192_1_cca2)
|
||||
|
||||
OQS_KEM *OQS_KEM_hqc_192_1_cca2_new() {
|
||||
|
||||
OQS_KEM *kem = malloc(sizeof(OQS_KEM));
|
||||
if (kem == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
kem->method_name = OQS_KEM_alg_hqc_192_1_cca2;
|
||||
kem->alg_version = "https://pqc-hqc.org/doc/hqc-reference-implementation_2019-08-24.zip";
|
||||
|
||||
kem->claimed_nist_level = 3;
|
||||
kem->ind_cca = true;
|
||||
|
||||
kem->length_public_key = OQS_KEM_hqc_192_1_cca2_length_public_key;
|
||||
kem->length_secret_key = OQS_KEM_hqc_192_1_cca2_length_secret_key;
|
||||
kem->length_ciphertext = OQS_KEM_hqc_192_1_cca2_length_ciphertext;
|
||||
kem->length_shared_secret = OQS_KEM_hqc_192_1_cca2_length_shared_secret;
|
||||
|
||||
kem->keypair = OQS_KEM_hqc_192_1_cca2_keypair;
|
||||
kem->encaps = OQS_KEM_hqc_192_1_cca2_encaps;
|
||||
kem->decaps = OQS_KEM_hqc_192_1_cca2_decaps;
|
||||
|
||||
return kem;
|
||||
}
|
||||
|
||||
extern int PQCLEAN_HQC1921CCA2_LEAKTIME_crypto_kem_keypair(unsigned char *pk, unsigned char *sk);
|
||||
extern int PQCLEAN_HQC1921CCA2_LEAKTIME_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk);
|
||||
extern int PQCLEAN_HQC1921CCA2_LEAKTIME_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk);
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_192_1_cca2_keypair(uint8_t *public_key, uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_HQC1921CCA2_LEAKTIME_crypto_kem_keypair(public_key, secret_key);
|
||||
}
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_192_1_cca2_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key) {
|
||||
return (OQS_STATUS) PQCLEAN_HQC1921CCA2_LEAKTIME_crypto_kem_enc(ciphertext, shared_secret, public_key);
|
||||
}
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_192_1_cca2_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_HQC1921CCA2_LEAKTIME_crypto_kem_dec(shared_secret, ciphertext, secret_key);
|
||||
}
|
||||
|
||||
#endif
|
||||
49
src/kem/hqc/kem_hqc_192_2_cca2.c
Normal file
49
src/kem/hqc/kem_hqc_192_2_cca2.c
Normal file
@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <oqs/kem_hqc.h>
|
||||
|
||||
#if defined(OQS_ENABLE_KEM_hqc_192_2_cca2)
|
||||
|
||||
OQS_KEM *OQS_KEM_hqc_192_2_cca2_new() {
|
||||
|
||||
OQS_KEM *kem = malloc(sizeof(OQS_KEM));
|
||||
if (kem == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
kem->method_name = OQS_KEM_alg_hqc_192_2_cca2;
|
||||
kem->alg_version = "https://pqc-hqc.org/doc/hqc-reference-implementation_2019-08-24.zip";
|
||||
|
||||
kem->claimed_nist_level = 3;
|
||||
kem->ind_cca = true;
|
||||
|
||||
kem->length_public_key = OQS_KEM_hqc_192_2_cca2_length_public_key;
|
||||
kem->length_secret_key = OQS_KEM_hqc_192_2_cca2_length_secret_key;
|
||||
kem->length_ciphertext = OQS_KEM_hqc_192_2_cca2_length_ciphertext;
|
||||
kem->length_shared_secret = OQS_KEM_hqc_192_2_cca2_length_shared_secret;
|
||||
|
||||
kem->keypair = OQS_KEM_hqc_192_2_cca2_keypair;
|
||||
kem->encaps = OQS_KEM_hqc_192_2_cca2_encaps;
|
||||
kem->decaps = OQS_KEM_hqc_192_2_cca2_decaps;
|
||||
|
||||
return kem;
|
||||
}
|
||||
|
||||
extern int PQCLEAN_HQC1922CCA2_LEAKTIME_crypto_kem_keypair(unsigned char *pk, unsigned char *sk);
|
||||
extern int PQCLEAN_HQC1922CCA2_LEAKTIME_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk);
|
||||
extern int PQCLEAN_HQC1922CCA2_LEAKTIME_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk);
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_192_2_cca2_keypair(uint8_t *public_key, uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_HQC1922CCA2_LEAKTIME_crypto_kem_keypair(public_key, secret_key);
|
||||
}
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_192_2_cca2_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key) {
|
||||
return (OQS_STATUS) PQCLEAN_HQC1922CCA2_LEAKTIME_crypto_kem_enc(ciphertext, shared_secret, public_key);
|
||||
}
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_192_2_cca2_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_HQC1922CCA2_LEAKTIME_crypto_kem_dec(shared_secret, ciphertext, secret_key);
|
||||
}
|
||||
|
||||
#endif
|
||||
49
src/kem/hqc/kem_hqc_256_1_cca2.c
Normal file
49
src/kem/hqc/kem_hqc_256_1_cca2.c
Normal file
@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <oqs/kem_hqc.h>
|
||||
|
||||
#if defined(OQS_ENABLE_KEM_hqc_256_1_cca2)
|
||||
|
||||
OQS_KEM *OQS_KEM_hqc_256_1_cca2_new() {
|
||||
|
||||
OQS_KEM *kem = malloc(sizeof(OQS_KEM));
|
||||
if (kem == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
kem->method_name = OQS_KEM_alg_hqc_256_1_cca2;
|
||||
kem->alg_version = "https://pqc-hqc.org/doc/hqc-reference-implementation_2019-08-24.zip";
|
||||
|
||||
kem->claimed_nist_level = 5;
|
||||
kem->ind_cca = true;
|
||||
|
||||
kem->length_public_key = OQS_KEM_hqc_256_1_cca2_length_public_key;
|
||||
kem->length_secret_key = OQS_KEM_hqc_256_1_cca2_length_secret_key;
|
||||
kem->length_ciphertext = OQS_KEM_hqc_256_1_cca2_length_ciphertext;
|
||||
kem->length_shared_secret = OQS_KEM_hqc_256_1_cca2_length_shared_secret;
|
||||
|
||||
kem->keypair = OQS_KEM_hqc_256_1_cca2_keypair;
|
||||
kem->encaps = OQS_KEM_hqc_256_1_cca2_encaps;
|
||||
kem->decaps = OQS_KEM_hqc_256_1_cca2_decaps;
|
||||
|
||||
return kem;
|
||||
}
|
||||
|
||||
extern int PQCLEAN_HQC2561CCA2_LEAKTIME_crypto_kem_keypair(unsigned char *pk, unsigned char *sk);
|
||||
extern int PQCLEAN_HQC2561CCA2_LEAKTIME_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk);
|
||||
extern int PQCLEAN_HQC2561CCA2_LEAKTIME_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk);
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_256_1_cca2_keypair(uint8_t *public_key, uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_HQC2561CCA2_LEAKTIME_crypto_kem_keypair(public_key, secret_key);
|
||||
}
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_256_1_cca2_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key) {
|
||||
return (OQS_STATUS) PQCLEAN_HQC2561CCA2_LEAKTIME_crypto_kem_enc(ciphertext, shared_secret, public_key);
|
||||
}
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_256_1_cca2_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_HQC2561CCA2_LEAKTIME_crypto_kem_dec(shared_secret, ciphertext, secret_key);
|
||||
}
|
||||
|
||||
#endif
|
||||
49
src/kem/hqc/kem_hqc_256_2_cca2.c
Normal file
49
src/kem/hqc/kem_hqc_256_2_cca2.c
Normal file
@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <oqs/kem_hqc.h>
|
||||
|
||||
#if defined(OQS_ENABLE_KEM_hqc_256_2_cca2)
|
||||
|
||||
OQS_KEM *OQS_KEM_hqc_256_2_cca2_new() {
|
||||
|
||||
OQS_KEM *kem = malloc(sizeof(OQS_KEM));
|
||||
if (kem == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
kem->method_name = OQS_KEM_alg_hqc_256_2_cca2;
|
||||
kem->alg_version = "https://pqc-hqc.org/doc/hqc-reference-implementation_2019-08-24.zip";
|
||||
|
||||
kem->claimed_nist_level = 5;
|
||||
kem->ind_cca = true;
|
||||
|
||||
kem->length_public_key = OQS_KEM_hqc_256_2_cca2_length_public_key;
|
||||
kem->length_secret_key = OQS_KEM_hqc_256_2_cca2_length_secret_key;
|
||||
kem->length_ciphertext = OQS_KEM_hqc_256_2_cca2_length_ciphertext;
|
||||
kem->length_shared_secret = OQS_KEM_hqc_256_2_cca2_length_shared_secret;
|
||||
|
||||
kem->keypair = OQS_KEM_hqc_256_2_cca2_keypair;
|
||||
kem->encaps = OQS_KEM_hqc_256_2_cca2_encaps;
|
||||
kem->decaps = OQS_KEM_hqc_256_2_cca2_decaps;
|
||||
|
||||
return kem;
|
||||
}
|
||||
|
||||
extern int PQCLEAN_HQC2562CCA2_LEAKTIME_crypto_kem_keypair(unsigned char *pk, unsigned char *sk);
|
||||
extern int PQCLEAN_HQC2562CCA2_LEAKTIME_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk);
|
||||
extern int PQCLEAN_HQC2562CCA2_LEAKTIME_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk);
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_256_2_cca2_keypair(uint8_t *public_key, uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_HQC2562CCA2_LEAKTIME_crypto_kem_keypair(public_key, secret_key);
|
||||
}
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_256_2_cca2_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key) {
|
||||
return (OQS_STATUS) PQCLEAN_HQC2562CCA2_LEAKTIME_crypto_kem_enc(ciphertext, shared_secret, public_key);
|
||||
}
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_256_2_cca2_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_HQC2562CCA2_LEAKTIME_crypto_kem_dec(shared_secret, ciphertext, secret_key);
|
||||
}
|
||||
|
||||
#endif
|
||||
49
src/kem/hqc/kem_hqc_256_3_cca2.c
Normal file
49
src/kem/hqc/kem_hqc_256_3_cca2.c
Normal file
@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <oqs/kem_hqc.h>
|
||||
|
||||
#if defined(OQS_ENABLE_KEM_hqc_256_3_cca2)
|
||||
|
||||
OQS_KEM *OQS_KEM_hqc_256_3_cca2_new() {
|
||||
|
||||
OQS_KEM *kem = malloc(sizeof(OQS_KEM));
|
||||
if (kem == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
kem->method_name = OQS_KEM_alg_hqc_256_3_cca2;
|
||||
kem->alg_version = "https://pqc-hqc.org/doc/hqc-reference-implementation_2019-08-24.zip";
|
||||
|
||||
kem->claimed_nist_level = 5;
|
||||
kem->ind_cca = true;
|
||||
|
||||
kem->length_public_key = OQS_KEM_hqc_256_3_cca2_length_public_key;
|
||||
kem->length_secret_key = OQS_KEM_hqc_256_3_cca2_length_secret_key;
|
||||
kem->length_ciphertext = OQS_KEM_hqc_256_3_cca2_length_ciphertext;
|
||||
kem->length_shared_secret = OQS_KEM_hqc_256_3_cca2_length_shared_secret;
|
||||
|
||||
kem->keypair = OQS_KEM_hqc_256_3_cca2_keypair;
|
||||
kem->encaps = OQS_KEM_hqc_256_3_cca2_encaps;
|
||||
kem->decaps = OQS_KEM_hqc_256_3_cca2_decaps;
|
||||
|
||||
return kem;
|
||||
}
|
||||
|
||||
extern int PQCLEAN_HQC2563CCA2_LEAKTIME_crypto_kem_keypair(unsigned char *pk, unsigned char *sk);
|
||||
extern int PQCLEAN_HQC2563CCA2_LEAKTIME_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk);
|
||||
extern int PQCLEAN_HQC2563CCA2_LEAKTIME_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk);
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_256_3_cca2_keypair(uint8_t *public_key, uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_HQC2563CCA2_LEAKTIME_crypto_kem_keypair(public_key, secret_key);
|
||||
}
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_256_3_cca2_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key) {
|
||||
return (OQS_STATUS) PQCLEAN_HQC2563CCA2_LEAKTIME_crypto_kem_enc(ciphertext, shared_secret, public_key);
|
||||
}
|
||||
|
||||
OQS_API OQS_STATUS OQS_KEM_hqc_256_3_cca2_decaps(uint8_t *shared_secret, const unsigned char *ciphertext, const uint8_t *secret_key) {
|
||||
return (OQS_STATUS) PQCLEAN_HQC2563CCA2_LEAKTIME_crypto_kem_dec(shared_secret, ciphertext, secret_key);
|
||||
}
|
||||
|
||||
#endif
|
||||
1
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/LICENSE
Normal file
1
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/LICENSE
Normal file
@ -0,0 +1 @@
|
||||
Public domain
|
||||
25
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/api.h
Normal file
25
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/api.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef PQCLEAN_HQC1281CCA2_LEAKTIME_API_H
|
||||
#define PQCLEAN_HQC1281CCA2_LEAKTIME_API_H
|
||||
|
||||
/**
|
||||
* \file api.h
|
||||
* \brief NIST KEM API used by the HQC_KEM IND-CCA2 scheme
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PQCLEAN_HQC1281CCA2_LEAKTIME_CRYPTO_ALGNAME "HQC_128_1_CCA2"
|
||||
|
||||
#define PQCLEAN_HQC1281CCA2_LEAKTIME_CRYPTO_SECRETKEYBYTES 3165
|
||||
#define PQCLEAN_HQC1281CCA2_LEAKTIME_CRYPTO_PUBLICKEYBYTES 3125
|
||||
#define PQCLEAN_HQC1281CCA2_LEAKTIME_CRYPTO_BYTES 64
|
||||
#define PQCLEAN_HQC1281CCA2_LEAKTIME_CRYPTO_CIPHERTEXTBYTES 6234
|
||||
|
||||
// As a technicality, the public key is appended to the secret key in order to respect the NIST API.
|
||||
// Without this constraint, CRYPTO_SECRETKEYBYTES would be defined as 32
|
||||
|
||||
int PQCLEAN_HQC1281CCA2_LEAKTIME_crypto_kem_keypair(uint8_t *pk, uint8_t *sk);
|
||||
int PQCLEAN_HQC1281CCA2_LEAKTIME_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
|
||||
int PQCLEAN_HQC1281CCA2_LEAKTIME_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
|
||||
|
||||
#endif
|
||||
295
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/bch.c
Normal file
295
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/bch.c
Normal file
@ -0,0 +1,295 @@
|
||||
/**
|
||||
* @file bch.c
|
||||
* Constant time implementation of BCH codes
|
||||
*/
|
||||
|
||||
#include "bch.h"
|
||||
#include "fft.h"
|
||||
#include "gf.h"
|
||||
#include "parameters.h"
|
||||
#include "vector.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
static void unpack_message(uint8_t *message_unpacked, const uint8_t *message);
|
||||
static void lfsr_encode(uint8_t *codeword, const uint8_t *message);
|
||||
static void pack_codeword(uint8_t *codeword, const uint8_t *codeword_unpacked);
|
||||
static size_t compute_elp(uint16_t *sigma, const uint16_t *syndromes);
|
||||
static void message_from_codeword(uint8_t *message, const uint8_t *codeword);
|
||||
static void compute_syndromes(uint16_t *syndromes, const uint8_t *vector);
|
||||
static void compute_roots(uint8_t *error, const uint16_t *sigma);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Unpacks the message message to the array message_unpacked where each byte stores a bit of the message
|
||||
*
|
||||
* @param[out] message_unpacked Array of VEC_K_SIZE_BYTES bytes receiving the unpacked message
|
||||
* @param[in] message Array of PARAM_K bytes storing the packed message
|
||||
*/
|
||||
static void unpack_message(uint8_t *message_unpacked, const uint8_t *message) {
|
||||
for (size_t i = 0; i < (VEC_K_SIZE_BYTES - (PARAM_K % 8 != 0)); ++i) {
|
||||
for (size_t j = 0; j < 8; ++j) {
|
||||
message_unpacked[j + 8 * i] = (message[i] >> j) & 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
for (int8_t j = 0; j < PARAM_K % 8; ++j) {
|
||||
message_unpacked[j + 8 * (VEC_K_SIZE_BYTES - 1)] = (message[VEC_K_SIZE_BYTES - 1] >> j) & 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encodes the message message to a codeword codeword using the generator polynomial bch_poly of the code
|
||||
*
|
||||
* @param[out] codeword Array of PARAM_N1 bytes receiving the codeword
|
||||
* @param[in] message Array of PARAM_K bytes storing the message to encode
|
||||
*/
|
||||
static void lfsr_encode(uint8_t *codeword, const uint8_t *message) {
|
||||
uint8_t gate_value = 0;
|
||||
uint8_t bch_poly[PARAM_G] = PARAM_BCH_POLY;
|
||||
|
||||
// Compute the Parity-check digits
|
||||
for (int16_t i = PARAM_K - 1; i >= 0; --i) {
|
||||
gate_value = message[i] ^ codeword[PARAM_N1 - PARAM_K - 1];
|
||||
|
||||
for (size_t j = PARAM_N1 - PARAM_K - 1; j; --j) {
|
||||
codeword[j] = codeword[j - 1] ^ (-gate_value & bch_poly[j]);
|
||||
}
|
||||
|
||||
codeword[0] = gate_value;
|
||||
}
|
||||
|
||||
// Add the message
|
||||
memcpy(codeword + PARAM_N1 - PARAM_K, message, PARAM_K);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Packs the codeword from an array codeword_unpacked where each byte stores a bit to a compact array codeword
|
||||
*
|
||||
* @param[out] codeword Array of VEC_N1_SIZE_BYTES bytes receiving the packed codeword
|
||||
* @param[in] codeword_unpacked Array of PARAM_N1 bytes storing the unpacked codeword
|
||||
*/
|
||||
static void pack_codeword(uint8_t *codeword, const uint8_t *codeword_unpacked) {
|
||||
for (size_t i = 0; i < (VEC_N1_SIZE_BYTES - (PARAM_N1 % 8 != 0)); ++i) {
|
||||
for (size_t j = 0; j < 8; ++j) {
|
||||
codeword[i] |= codeword_unpacked[j + 8 * i] << j;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < PARAM_N1 % 8; ++j) {
|
||||
codeword[VEC_N1_SIZE_BYTES - 1] |= codeword_unpacked[j + 8 * (VEC_N1_SIZE_BYTES - 1)] << j;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encodes a message message of PARAM_K bits to a BCH codeword codeword of PARAM_N1 bits
|
||||
*
|
||||
* Following @cite lin1983error (Chapter 4 - Cyclic Codes),
|
||||
* We perform a systematic encoding using a linear (PARAM_N1 - PARAM_K)-stage shift register
|
||||
* with feedback connections based on the generator polynomial bch_poly of the BCH code.
|
||||
*
|
||||
* @param[out] codeword Array of size VEC_N1_SIZE_BYTES receiving the encoded message
|
||||
* @param[in] message Array of size VEC_K_SIZE_BYTES storing the message
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_bch_code_encode(uint8_t *codeword, const uint8_t *message) {
|
||||
uint8_t message_unpacked[PARAM_K];
|
||||
uint8_t codeword_unpacked[PARAM_N1] = {0};
|
||||
|
||||
unpack_message(message_unpacked, message);
|
||||
lfsr_encode(codeword_unpacked, message_unpacked);
|
||||
pack_codeword(codeword, codeword_unpacked);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the error locator polynomial (ELP) sigma
|
||||
*
|
||||
* This is a constant time implementation of Berlekamp's simplified algorithm (see @cite joiner1995decoding). <br>
|
||||
* We use the letter p for rho which is initialized at -1/2. <br>
|
||||
* The array X_sigma_p represents the polynomial X^(2(mu-rho))*sigma_p(X). <br>
|
||||
* Instead of maintaining a list of sigmas, we update in place both sigma and X_sigma_p. <br>
|
||||
* sigma_copy serves as a temporary save of sigma in case X_sigma_p needs to be updated. <br>
|
||||
* We can properly correct only if the degree of sigma does not exceed PARAM_DELTA.
|
||||
* This means only the first PARAM_DELTA + 1 coefficients of sigma are of value
|
||||
* and we only need to save its first PARAM_DELTA - 1 coefficients.
|
||||
*
|
||||
* @returns the degree of the ELP sigma
|
||||
* @param[out] sigma Array of size (at least) PARAM_DELTA receiving the ELP
|
||||
* @param[in] syndromes Array of size (at least) 2*PARAM_DELTA storing the syndromes
|
||||
*/
|
||||
static size_t compute_elp(uint16_t *sigma, const uint16_t *syndromes) {
|
||||
sigma[0] = 1;
|
||||
size_t deg_sigma = 0;
|
||||
size_t deg_sigma_p = 0;
|
||||
uint16_t sigma_copy[PARAM_DELTA - 1] = {0};
|
||||
size_t deg_sigma_copy = 0;
|
||||
uint16_t X_sigma_p[PARAM_DELTA + 1] = {0, 1};
|
||||
int32_t pp = -1; // 2*rho
|
||||
uint16_t d_p = 1;
|
||||
uint16_t d = syndromes[0];
|
||||
|
||||
for (size_t mu = 0; mu < PARAM_DELTA; ++mu) {
|
||||
// Save sigma in case we need it to update X_sigma_p
|
||||
memcpy(sigma_copy, sigma, 2 * (PARAM_DELTA - 1));
|
||||
deg_sigma_copy = deg_sigma;
|
||||
|
||||
uint16_t dd = PQCLEAN_HQC1281CCA2_LEAKTIME_gf_mul(d, PQCLEAN_HQC1281CCA2_LEAKTIME_gf_inverse(d_p)); // 0 if(d == 0)
|
||||
for (size_t i = 1; (i <= 2 * mu + 1) && (i <= PARAM_DELTA); ++i) {
|
||||
sigma[i] ^= PQCLEAN_HQC1281CCA2_LEAKTIME_gf_mul(dd, X_sigma_p[i]);
|
||||
}
|
||||
|
||||
size_t deg_X = 2 * mu - pp; // 2*(mu-rho)
|
||||
size_t deg_X_sigma_p = deg_X + deg_sigma_p;
|
||||
|
||||
// mask1 = 0xffff if(d != 0) and 0 otherwise
|
||||
int16_t mask1 = -((uint16_t) - d >> 15);
|
||||
|
||||
// mask2 = 0xffff if(deg_X_sigma_p > deg_sigma) and 0 otherwise
|
||||
int16_t mask2 = -((uint16_t) (deg_sigma - deg_X_sigma_p) >> 15);
|
||||
|
||||
// mask12 = 0xffff if the deg_sigma increased and 0 otherwise
|
||||
int16_t mask12 = mask1 & mask2;
|
||||
deg_sigma = (mask12 & deg_X_sigma_p) ^ (~mask12 & deg_sigma);
|
||||
|
||||
if (mu == PARAM_DELTA - 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Update pp, d_p and X_sigma_p if needed
|
||||
pp = (mask12 & (2 * mu)) ^ (~mask12 & pp);
|
||||
d_p = (mask12 & d) ^ (~mask12 & d_p);
|
||||
for (size_t i = PARAM_DELTA - 1; i; --i) {
|
||||
X_sigma_p[i + 1] = (mask12 & sigma_copy[i - 1]) ^ (~mask12 & X_sigma_p[i - 1]);
|
||||
}
|
||||
X_sigma_p[1] = 0;
|
||||
X_sigma_p[0] = 0;
|
||||
deg_sigma_p = (mask12 & deg_sigma_copy) ^ (~mask12 & deg_sigma_p);
|
||||
|
||||
// Compute the next discrepancy
|
||||
d = syndromes[2 * mu + 2];
|
||||
for (size_t i = 1; (i <= 2 * mu + 1) && (i <= PARAM_DELTA); ++i) {
|
||||
d ^= PQCLEAN_HQC1281CCA2_LEAKTIME_gf_mul(sigma[i], syndromes[2 * mu + 2 - i]);
|
||||
}
|
||||
}
|
||||
|
||||
return deg_sigma;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieves the message message from the codeword codeword
|
||||
*
|
||||
* Since we performed a systematic encoding, the message is the last PARAM_K bits of the codeword.
|
||||
*
|
||||
* @param[out] message Array of size VEC_K_SIZE_BYTES receiving the message
|
||||
* @param[in] codeword Array of size VEC_N1_SIZE_BYTES storing the codeword
|
||||
*/
|
||||
static void message_from_codeword(uint8_t *message, const uint8_t *codeword) {
|
||||
int32_t val = PARAM_N1 - PARAM_K;
|
||||
|
||||
uint8_t mask1 = 0xff << val % 8;
|
||||
uint8_t mask2 = 0xff >> (8 - val % 8);
|
||||
size_t index = val / 8;
|
||||
|
||||
for (size_t i = 0; i < VEC_K_SIZE_BYTES - 1; ++i) {
|
||||
uint8_t message1 = (codeword[index] & mask1) >> val % 8;
|
||||
uint8_t message2 = (codeword[++index] & mask2) << (8 - val % 8);
|
||||
message[i] = message1 | message2;
|
||||
}
|
||||
|
||||
// Last byte (8-val % 8 is the number of bits given by message1)
|
||||
if ((PARAM_K % 8 == 0) || (8 - val % 8 < PARAM_K % 8)) {
|
||||
uint8_t message1 = (codeword[index] & mask1) >> val % 8;
|
||||
uint8_t message2 = (codeword[++index] & mask2) << (8 - val % 8);
|
||||
message[VEC_K_SIZE_BYTES - 1] = message1 | message2;
|
||||
} else {
|
||||
uint8_t message1 = (codeword[index] & mask1) >> val % 8;
|
||||
message[VEC_K_SIZE_BYTES - 1] = message1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the 2^PARAM_DELTA syndromes from the received vector vector
|
||||
*
|
||||
* Syndromes are the sum of powers of alpha weighted by vector's coefficients.
|
||||
* To do so, we use the additive FFT transpose, which takes as input a family w of GF(2^PARAM_M) elements
|
||||
* and outputs the weighted power sums of these w. <br>
|
||||
* Therefore, this requires twisting and applying a permutation before feeding vector to the fft transpose. <br>
|
||||
* For more details see Berstein, Chou and Schawbe's explanations:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*
|
||||
* @param[out] syndromes Array of size 2^(PARAM_FFT_T) receiving the 2*PARAM_DELTA syndromes
|
||||
* @param[in] vector Array of size VEC_N1_SIZE_BYTES storing the received word
|
||||
*/
|
||||
static void compute_syndromes(uint16_t *syndromes, const uint8_t *vector) {
|
||||
uint16_t w[1 << PARAM_M];
|
||||
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_fft_t_preprocess_bch_codeword(w, vector);
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_fft_t(syndromes, w, 2 * PARAM_DELTA);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the error polynomial error from the error locator polynomial sigma
|
||||
*
|
||||
* See function fft for more details.
|
||||
*
|
||||
* @param[out] err Array of VEC_N1_SIZE_BYTES elements receiving the error polynomial
|
||||
* @param[in] sigma Array of 2^PARAM_FFT elements storing the error locator polynomial
|
||||
*/
|
||||
static void compute_roots(uint8_t *error, const uint16_t *sigma) {
|
||||
uint16_t w[1 << PARAM_M] = {0}; // w will receive the evaluation of sigma in all field elements
|
||||
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_fft(w, sigma, PARAM_DELTA + 1);
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_fft_retrieve_bch_error_poly(error, w);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Decodes the received word
|
||||
*
|
||||
* This function relies on four steps:
|
||||
* <ol>
|
||||
* <li> The first step, done by additive FFT transpose, is the computation of the 2*PARAM_DELTA syndromes.
|
||||
* <li> The second step is the computation of the error-locator polynomial sigma.
|
||||
* <li> The third step, done by additive FFT, is finding the error-locator numbers by calculating the roots of the polynomial sigma and takings their inverses.
|
||||
* <li> The fourth step is the correction of the errors in the received polynomial.
|
||||
* </ol>
|
||||
* For a more complete picture on BCH decoding, see Shu. Lin and Daniel J. Costello in Error Control Coding: Fundamentals and Applications @cite lin1983error
|
||||
*
|
||||
* @param[out] message Array of size VEC_K_SIZE_BYTES receiving the decoded message
|
||||
* @param[in] vector Array of size VEC_N1_SIZE_BYTES storing the received word
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_bch_code_decode(uint8_t *message, uint8_t *vector) {
|
||||
uint16_t syndromes[1 << PARAM_FFT_T];
|
||||
uint16_t sigma[1 << PARAM_FFT] = {0};
|
||||
uint8_t error[(1 << PARAM_M) / 8] = {0};
|
||||
|
||||
// Calculate the 2*PARAM_DELTA syndromes
|
||||
compute_syndromes(syndromes, vector);
|
||||
|
||||
// Compute the error locator polynomial sigma
|
||||
// Sigma's degree is at most PARAM_DELTA but the FFT requires the extra room
|
||||
compute_elp(sigma, syndromes);
|
||||
|
||||
// Compute the error polynomial error
|
||||
compute_roots(error, sigma);
|
||||
|
||||
// Add the error polynomial to the received polynomial
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_add(vector, vector, error, VEC_N1_SIZE_BYTES);
|
||||
|
||||
// Retrieve the message from the decoded codeword
|
||||
message_from_codeword(message, vector);
|
||||
}
|
||||
16
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/bch.h
Normal file
16
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/bch.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef PQCLEAN_HQC1281CCA2_LEAKTIME_BCH_H
|
||||
#define PQCLEAN_HQC1281CCA2_LEAKTIME_BCH_H
|
||||
|
||||
/**
|
||||
* @file bch.h
|
||||
* Header file of bch.c
|
||||
*/
|
||||
|
||||
#include "parameters.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_bch_code_encode(uint8_t *codeword, const uint8_t *message);
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_bch_code_decode(uint8_t *message, uint8_t *vector);
|
||||
|
||||
#endif
|
||||
628
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/fft.c
Normal file
628
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/fft.c
Normal file
@ -0,0 +1,628 @@
|
||||
/**
|
||||
* @file fft.c
|
||||
* Implementation of the additive FFT and its transpose.
|
||||
* This implementation is based on the paper from Gao and Mateer: <br>
|
||||
* Shuhong Gao and Todd Mateer, Additive Fast Fourier Transforms over Finite Fields,
|
||||
* IEEE Transactions on Information Theory 56 (2010), 6265--6272.
|
||||
* http://www.math.clemson.edu/~sgao/papers/GM10.pdf <br>
|
||||
* and includes improvements proposed by Bernstein, Chou and Schwabe here:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*/
|
||||
|
||||
#include "fft.h"
|
||||
#include "gf.h"
|
||||
#include "parameters.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
static void compute_fft_betas(uint16_t *betas);
|
||||
static void compute_subset_sums(uint16_t *subset_sums, const uint16_t *set, size_t set_size);
|
||||
static void radix_t(uint16_t *f, const uint16_t *f0, const uint16_t *f1, uint32_t m_f);
|
||||
static void fft_t_rec(uint16_t *f, const uint16_t *w, size_t f_coeffs, uint8_t m, uint32_t m_f, const uint16_t *betas);
|
||||
static void radix(uint16_t *f0, uint16_t *f1, const uint16_t *f, uint32_t m_f);
|
||||
static void fft_rec(uint16_t *w, uint16_t *f, size_t f_coeffs, uint8_t m, uint32_t m_f, const uint16_t *betas);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the basis of betas (omitting 1) used in the additive FFT and its transpose
|
||||
*
|
||||
* @param[out] betas Array of size PARAM_M-1
|
||||
*/
|
||||
static void compute_fft_betas(uint16_t *betas) {
|
||||
for (size_t i = 0; i < PARAM_M - 1; ++i) {
|
||||
betas[i] = 1 << (PARAM_M - 1 - i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the subset sums of the given set
|
||||
*
|
||||
* The array subset_sums is such that its ith element is
|
||||
* the subset sum of the set elements given by the binary form of i.
|
||||
*
|
||||
* @param[out] subset_sums Array of size 2^set_size receiving the subset sums
|
||||
* @param[in] set Array of set_size elements
|
||||
* @param[in] set_size Size of the array set
|
||||
*/
|
||||
static void compute_subset_sums(uint16_t *subset_sums, const uint16_t *set, size_t set_size) {
|
||||
subset_sums[0] = 0;
|
||||
|
||||
for (size_t i = 0; i < set_size; ++i) {
|
||||
for (size_t j = 0; j < (((size_t)1) << i); ++j) {
|
||||
subset_sums[(((size_t)1) << i) + j] = set[i] ^ subset_sums[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Transpose of the linear radix conversion
|
||||
*
|
||||
* This is a direct transposition of the radix function
|
||||
* implemented following the process of transposing a linear function as exposed by Bernstein, Chou and Schwabe here:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*
|
||||
* @param[out] f Array of size a power of 2
|
||||
* @param[in] f0 Array half the size of f
|
||||
* @param[in] f1 Array half the size of f
|
||||
* @param[in] m_f 2^{m_f} is the smallest power of 2 greater or equal to the number of coefficients of f
|
||||
*/
|
||||
static void radix_t(uint16_t *f, const uint16_t *f0, const uint16_t *f1, uint32_t m_f) {
|
||||
switch (m_f) {
|
||||
case 4:
|
||||
f[0] = f0[0];
|
||||
f[1] = f1[0];
|
||||
f[2] = f0[1] ^ f1[0];
|
||||
f[3] = f[2] ^ f1[1];
|
||||
f[4] = f[2] ^ f0[2];
|
||||
f[5] = f[3] ^ f1[2];
|
||||
f[6] = f[4] ^ f0[3] ^ f1[2];
|
||||
f[7] = f[3] ^ f0[3] ^ f1[3];
|
||||
f[8] = f[4] ^ f0[4];
|
||||
f[9] = f[5] ^ f1[4];
|
||||
f[10] = f[6] ^ f0[5] ^ f1[4];
|
||||
f[11] = f[7] ^ f0[5] ^ f1[4] ^ f1[5];
|
||||
f[12] = f[8] ^ f0[5] ^ f0[6] ^ f1[4];
|
||||
f[13] = f[7] ^ f[9] ^ f[11] ^ f1[6];
|
||||
f[14] = f[6] ^ f0[6] ^ f0[7] ^ f1[6];
|
||||
f[15] = f[7] ^ f0[7] ^ f1[7];
|
||||
return;
|
||||
|
||||
case 3:
|
||||
f[0] = f0[0];
|
||||
f[1] = f1[0];
|
||||
f[2] = f0[1] ^ f1[0];
|
||||
f[3] = f[2] ^ f1[1];
|
||||
f[4] = f[2] ^ f0[2];
|
||||
f[5] = f[3] ^ f1[2];
|
||||
f[6] = f[4] ^ f0[3] ^ f1[2];
|
||||
f[7] = f[3] ^ f0[3] ^ f1[3];
|
||||
return;
|
||||
|
||||
case 2:
|
||||
f[0] = f0[0];
|
||||
f[1] = f1[0];
|
||||
f[2] = f0[1] ^ f1[0];
|
||||
f[3] = f[2] ^ f1[1];
|
||||
return;
|
||||
|
||||
case 1:
|
||||
f[0] = f0[0];
|
||||
f[1] = f1[0];
|
||||
return;
|
||||
|
||||
default:
|
||||
;
|
||||
|
||||
size_t n = ((size_t)1) << (m_f - 2);
|
||||
|
||||
uint16_t Q0[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t Q1[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t R0[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t R1[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
|
||||
uint16_t Q[1 << 2 * (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t R[1 << 2 * (PARAM_FFT_T - 2)] = {0};
|
||||
|
||||
memcpy(Q0, f0 + n, 2 * n);
|
||||
memcpy(Q1, f1 + n, 2 * n);
|
||||
memcpy(R0, f0, 2 * n);
|
||||
memcpy(R1, f1, 2 * n);
|
||||
|
||||
radix_t (Q, Q0, Q1, m_f - 1);
|
||||
radix_t (R, R0, R1, m_f - 1);
|
||||
|
||||
memcpy(f, R, 4 * n);
|
||||
memcpy(f + 2 * n, R + n, 2 * n);
|
||||
memcpy(f + 3 * n, Q + n, 2 * n);
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
f[2 * n + i] ^= Q[i];
|
||||
f[3 * n + i] ^= f[2 * n + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Recursively computes syndromes of family w
|
||||
*
|
||||
* This function is a subroutine of the function fft_t
|
||||
*
|
||||
* @param[out] f Array receiving the syndromes
|
||||
* @param[in] w Array storing the family
|
||||
* @param[in] f_coeffs Length of syndromes vector
|
||||
* @param[in] m 2^m is the smallest power of 2 greater or equal to the length of family w
|
||||
* @param[in] m_f 2^{m_f} is the smallest power of 2 greater or equal to the length of f
|
||||
* @param[in] betas FFT constants
|
||||
*/
|
||||
static void fft_t_rec(uint16_t *f, const uint16_t *w, size_t f_coeffs,
|
||||
uint8_t m, uint32_t m_f, const uint16_t *betas) {
|
||||
size_t k = ((size_t)1) << (m - 1);
|
||||
uint16_t gammas[PARAM_M - 2] = {0};
|
||||
uint16_t deltas[PARAM_M - 2] = {0};
|
||||
uint16_t gammas_sums[1 << (PARAM_M - 1)];
|
||||
uint16_t u[1 << (PARAM_M - 2)] = {0};
|
||||
uint16_t f0[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t f1[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t betas_sums[1 << (PARAM_M - 1)] = {0};
|
||||
|
||||
// Step 1
|
||||
if (m_f == 1) {
|
||||
for (size_t i = 0; i < (((size_t)1) << m); ++i) {
|
||||
f[0] ^= w[i];
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < m; ++j) {
|
||||
for (size_t ki = 0; ki < (((size_t)1) << j); ++ki) {
|
||||
size_t index = (((size_t)1) << j) + ki;
|
||||
betas_sums[index] = betas_sums[ki] ^ betas[j];
|
||||
f[1] ^= PQCLEAN_HQC1281CCA2_LEAKTIME_gf_mul(betas_sums[index], w[index]);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute gammas and deltas
|
||||
for (uint8_t i = 0; i < m - 1; ++i) {
|
||||
gammas[i] = PQCLEAN_HQC1281CCA2_LEAKTIME_gf_mul(betas[i], PQCLEAN_HQC1281CCA2_LEAKTIME_gf_inverse(betas[m - 1]));
|
||||
deltas[i] = PQCLEAN_HQC1281CCA2_LEAKTIME_gf_square(gammas[i]) ^ gammas[i];
|
||||
}
|
||||
|
||||
// Compute gammas subset sums
|
||||
compute_subset_sums(gammas_sums, gammas, m - 1);
|
||||
|
||||
/* Step 6: Compute u and v from w (aka w)
|
||||
* w[i] = u[i] + G[i].v[i]
|
||||
* w[k+i] = w[i] + v[i] = u[i] + (G[i]+1).v[i]
|
||||
* Transpose:
|
||||
* u[i] = w[i] + w[k+i]
|
||||
* v[i] = G[i].w[i] + (G[i]+1).w[k+i] = G[i].u[i] + w[k+i] */
|
||||
if (f_coeffs <= 3) { // 3-coefficient polynomial f case
|
||||
// Step 5: Compute f0 from u and f1 from v
|
||||
f1[1] = 0;
|
||||
u[0] = w[0] ^ w[k];
|
||||
f1[0] = w[k];
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
u[i] = w[i] ^ w[k + i];
|
||||
f1[0] ^= PQCLEAN_HQC1281CCA2_LEAKTIME_gf_mul(gammas_sums[i], u[i]) ^ w[k + i];
|
||||
}
|
||||
fft_t_rec(f0, u, (f_coeffs + 1) / 2, m - 1, m_f - 1, deltas);
|
||||
} else {
|
||||
uint16_t v[1 << (PARAM_M - 2)] = {0};
|
||||
|
||||
u[0] = w[0] ^ w[k];
|
||||
v[0] = w[k];
|
||||
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
u[i] = w[i] ^ w[k + i];
|
||||
v[i] = PQCLEAN_HQC1281CCA2_LEAKTIME_gf_mul(gammas_sums[i], u[i]) ^ w[k + i];
|
||||
}
|
||||
|
||||
// Step 5: Compute f0 from u and f1 from v
|
||||
fft_t_rec(f0, u, (f_coeffs + 1) / 2, m - 1, m_f - 1, deltas);
|
||||
fft_t_rec(f1, v, f_coeffs / 2, m - 1, m_f - 1, deltas);
|
||||
}
|
||||
|
||||
// Step 3: Compute g from g0 and g1
|
||||
radix_t(f, f0, f1, m_f);
|
||||
|
||||
// Step 2: compute f from g
|
||||
if (betas[m - 1] != 1) {
|
||||
uint16_t beta_m_pow = 1;
|
||||
for (size_t i = 1; i < (((size_t)1) << m_f); ++i) {
|
||||
beta_m_pow = PQCLEAN_HQC1281CCA2_LEAKTIME_gf_mul(beta_m_pow, betas[m - 1]);
|
||||
f[i] = PQCLEAN_HQC1281CCA2_LEAKTIME_gf_mul(beta_m_pow, f[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the syndromes f of the family w
|
||||
*
|
||||
* Since the syndromes linear map is the transpose of multipoint evaluation,
|
||||
* it uses exactly the same constants, either hardcoded or precomputed by compute_fft_lut(...). <br>
|
||||
* This follows directives from Bernstein, Chou and Schwabe given here:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*
|
||||
* @param[out] f Array of size 2*(PARAM_FFT_T) elements receiving the syndromes
|
||||
* @param[in] w Array of PARAM_GF_MUL_ORDER+1 elements
|
||||
* @param[in] f_coeffs Length of syndromes vector f
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_fft_t(uint16_t *f, const uint16_t *w, size_t f_coeffs) {
|
||||
// Transposed from Gao and Mateer algorithm
|
||||
uint16_t betas[PARAM_M - 1];
|
||||
uint16_t betas_sums[1 << (PARAM_M - 1)];
|
||||
size_t k = 1 << (PARAM_M - 1);
|
||||
uint16_t u[1 << (PARAM_M - 1)] = {0};
|
||||
uint16_t v[1 << (PARAM_M - 1)] = {0};
|
||||
uint16_t deltas[PARAM_M - 1];
|
||||
uint16_t f0[1 << (PARAM_FFT_T - 1)];
|
||||
uint16_t f1[1 << (PARAM_FFT_T - 1)];
|
||||
|
||||
compute_fft_betas(betas);
|
||||
compute_subset_sums(betas_sums, betas, PARAM_M - 1);
|
||||
|
||||
/* Step 6: Compute u and v from w (aka w)
|
||||
*
|
||||
* We had:
|
||||
* w[i] = u[i] + G[i].v[i]
|
||||
* w[k+i] = w[i] + v[i] = u[i] + (G[i]+1).v[i]
|
||||
* Transpose:
|
||||
* u[i] = w[i] + w[k+i]
|
||||
* v[i] = G[i].w[i] + (G[i]+1).w[k+i] = G[i].u[i] + w[k+i] */
|
||||
u[0] = w[0] ^ w[k];
|
||||
v[0] = w[k];
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
u[i] = w[i] ^ w[k + i];
|
||||
v[i] = PQCLEAN_HQC1281CCA2_LEAKTIME_gf_mul(betas_sums[i], u[i]) ^ w[k + i];
|
||||
}
|
||||
|
||||
// Compute deltas
|
||||
for (size_t i = 0; i < PARAM_M - 1; ++i) {
|
||||
deltas[i] = PQCLEAN_HQC1281CCA2_LEAKTIME_gf_square(betas[i]) ^ betas[i];
|
||||
}
|
||||
|
||||
// Step 5: Compute f0 from u and f1 from v
|
||||
fft_t_rec(f0, u, (f_coeffs + 1) / 2, PARAM_M - 1, PARAM_FFT_T - 1, deltas);
|
||||
fft_t_rec(f1, v, f_coeffs / 2, PARAM_M - 1, PARAM_FFT_T - 1, deltas);
|
||||
|
||||
// Step 3: Compute g from g0 and g1
|
||||
radix_t(f, f0, f1, PARAM_FFT_T);
|
||||
|
||||
// Step 2: beta_m = 1 so f = g
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the radix conversion of a polynomial f in GF(2^m)[x]
|
||||
*
|
||||
* Computes f0 and f1 such that f(x) = f0(x^2-x) + x.f1(x^2-x)
|
||||
* as proposed by Bernstein, Chou and Schwabe:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*
|
||||
* @param[out] f0 Array half the size of f
|
||||
* @param[out] f1 Array half the size of f
|
||||
* @param[in] f Array of size a power of 2
|
||||
* @param[in] m_f 2^{m_f} is the smallest power of 2 greater or equal to the number of coefficients of f
|
||||
*/
|
||||
static void radix(uint16_t *f0, uint16_t *f1, const uint16_t *f, uint32_t m_f) {
|
||||
switch (m_f) {
|
||||
case 4:
|
||||
f0[4] = f[8] ^ f[12];
|
||||
f0[6] = f[12] ^ f[14];
|
||||
f0[7] = f[14] ^ f[15];
|
||||
f1[5] = f[11] ^ f[13];
|
||||
f1[6] = f[13] ^ f[14];
|
||||
f1[7] = f[15];
|
||||
f0[5] = f[10] ^ f[12] ^ f1[5];
|
||||
f1[4] = f[9] ^ f[13] ^ f0[5];
|
||||
|
||||
f0[0] = f[0];
|
||||
f1[3] = f[7] ^ f[11] ^ f[15];
|
||||
f0[3] = f[6] ^ f[10] ^ f[14] ^ f1[3];
|
||||
f0[2] = f[4] ^ f0[4] ^ f0[3] ^ f1[3];
|
||||
f1[1] = f[3] ^ f[5] ^ f[9] ^ f[13] ^ f1[3];
|
||||
f1[2] = f[3] ^ f1[1] ^ f0[3];
|
||||
f0[1] = f[2] ^ f0[2] ^ f1[1];
|
||||
f1[0] = f[1] ^ f0[1];
|
||||
return;
|
||||
|
||||
case 3:
|
||||
f0[0] = f[0];
|
||||
f0[2] = f[4] ^ f[6];
|
||||
f0[3] = f[6] ^ f[7];
|
||||
f1[1] = f[3] ^ f[5] ^ f[7];
|
||||
f1[2] = f[5] ^ f[6];
|
||||
f1[3] = f[7];
|
||||
f0[1] = f[2] ^ f0[2] ^ f1[1];
|
||||
f1[0] = f[1] ^ f0[1];
|
||||
return;
|
||||
|
||||
case 2:
|
||||
f0[0] = f[0];
|
||||
f0[1] = f[2] ^ f[3];
|
||||
f1[0] = f[1] ^ f0[1];
|
||||
f1[1] = f[3];
|
||||
return;
|
||||
|
||||
case 1:
|
||||
f0[0] = f[0];
|
||||
f1[0] = f[1];
|
||||
return;
|
||||
|
||||
default:
|
||||
;
|
||||
size_t n = ((size_t)1) << (m_f - 2);
|
||||
|
||||
uint16_t Q[2 * (1 << (PARAM_FFT - 2))];
|
||||
uint16_t R[2 * (1 << (PARAM_FFT - 2))];
|
||||
|
||||
uint16_t Q0[1 << (PARAM_FFT - 2)];
|
||||
uint16_t Q1[1 << (PARAM_FFT - 2)];
|
||||
uint16_t R0[1 << (PARAM_FFT - 2)];
|
||||
uint16_t R1[1 << (PARAM_FFT - 2)];
|
||||
|
||||
memcpy(Q, f + 3 * n, 2 * n);
|
||||
memcpy(Q + n, f + 3 * n, 2 * n);
|
||||
memcpy(R, f, 4 * n);
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
Q[i] ^= f[2 * n + i];
|
||||
R[n + i] ^= Q[i];
|
||||
}
|
||||
|
||||
radix(Q0, Q1, Q, m_f - 1);
|
||||
radix(R0, R1, R, m_f - 1);
|
||||
|
||||
memcpy(f0, R0, 2 * n);
|
||||
memcpy(f0 + n, Q0, 2 * n);
|
||||
memcpy(f1, R1, 2 * n);
|
||||
memcpy(f1 + n, Q1, 2 * n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Evaluates f at all subset sums of a given set
|
||||
*
|
||||
* This function is a subroutine of the function fft.
|
||||
*
|
||||
* @param[out] w Array
|
||||
* @param[in] f Array
|
||||
* @param[in] f_coeffs Number of coefficients of f
|
||||
* @param[in] m Number of betas
|
||||
* @param[in] m_f Number of coefficients of f (one more than its degree)
|
||||
* @param[in] betas FFT constants
|
||||
*/
|
||||
static void fft_rec(uint16_t *w, uint16_t *f, size_t f_coeffs,
|
||||
uint8_t m, uint32_t m_f, const uint16_t *betas) {
|
||||
|
||||
uint16_t f0[1 << (PARAM_FFT - 2)] = {0};
|
||||
uint16_t f1[1 << (PARAM_FFT - 2)] = {0};
|
||||
uint16_t gammas[PARAM_M - 2] = {0};
|
||||
uint16_t deltas[PARAM_M - 2] = {0};
|
||||
size_t k = ((size_t)1) << (m - 1);
|
||||
uint16_t gammas_sums[1 << (PARAM_M - 2)] = {0};
|
||||
uint16_t u[1 << (PARAM_M - 2)] = {0};
|
||||
uint16_t v[1 << (PARAM_M - 2)] = {0};
|
||||
|
||||
// Step 1
|
||||
if (m_f == 1) {
|
||||
uint16_t tmp[PARAM_M - (PARAM_FFT - 1)];
|
||||
for (size_t i = 0; i < m; ++i) {
|
||||
tmp[i] = PQCLEAN_HQC1281CCA2_LEAKTIME_gf_mul(betas[i], f[1]);
|
||||
}
|
||||
|
||||
w[0] = f[0];
|
||||
for (size_t j = 0; j < m; ++j) {
|
||||
for (size_t ki = 0; ki < (((size_t)1) << j); ++ki) {
|
||||
w[(((size_t)1) << j) + ki] = w[ki] ^ tmp[j];
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2: compute g
|
||||
if (betas[m - 1] != 1) {
|
||||
uint16_t beta_m_pow = 1;
|
||||
for (size_t i = 1; i < (((size_t)1) << m_f); ++i) {
|
||||
beta_m_pow = PQCLEAN_HQC1281CCA2_LEAKTIME_gf_mul(beta_m_pow, betas[m - 1]);
|
||||
f[i] = PQCLEAN_HQC1281CCA2_LEAKTIME_gf_mul(beta_m_pow, f[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3
|
||||
radix(f0, f1, f, m_f);
|
||||
|
||||
// Step 4: compute gammas and deltas
|
||||
for (uint8_t i = 0; i < m - 1; ++i) {
|
||||
gammas[i] = PQCLEAN_HQC1281CCA2_LEAKTIME_gf_mul(betas[i], PQCLEAN_HQC1281CCA2_LEAKTIME_gf_inverse(betas[m - 1]));
|
||||
deltas[i] = PQCLEAN_HQC1281CCA2_LEAKTIME_gf_square(gammas[i]) ^ gammas[i];
|
||||
}
|
||||
|
||||
// Compute gammas sums
|
||||
compute_subset_sums(gammas_sums, gammas, m - 1);
|
||||
|
||||
// Step 5
|
||||
fft_rec(u, f0, (f_coeffs + 1) / 2, m - 1, m_f - 1, deltas);
|
||||
|
||||
if (f_coeffs <= 3) { // 3-coefficient polynomial f case: f1 is constant
|
||||
w[0] = u[0];
|
||||
w[k] = u[0] ^ f1[0];
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
w[i] = u[i] ^ PQCLEAN_HQC1281CCA2_LEAKTIME_gf_mul(gammas_sums[i], f1[0]);
|
||||
w[k + i] = w[i] ^ f1[0];
|
||||
}
|
||||
} else {
|
||||
fft_rec(v, f1, f_coeffs / 2, m - 1, m_f - 1, deltas);
|
||||
|
||||
// Step 6
|
||||
memcpy(w + k, v, 2 * k);
|
||||
w[0] = u[0];
|
||||
w[k] ^= u[0];
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
w[i] = u[i] ^ PQCLEAN_HQC1281CCA2_LEAKTIME_gf_mul(gammas_sums[i], v[i]);
|
||||
w[k + i] ^= w[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Evaluates f on all fields elements using an additive FFT algorithm
|
||||
*
|
||||
* f_coeffs is the number of coefficients of f (one less than its degree). <br>
|
||||
* The FFT proceeds recursively to evaluate f at all subset sums of a basis B. <br>
|
||||
* This implementation is based on the paper from Gao and Mateer: <br>
|
||||
* Shuhong Gao and Todd Mateer, Additive Fast Fourier Transforms over Finite Fields,
|
||||
* IEEE Transactions on Information Theory 56 (2010), 6265--6272.
|
||||
* http://www.math.clemson.edu/~sgao/papers/GM10.pdf <br>
|
||||
* and includes improvements proposed by Bernstein, Chou and Schwabe here:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf <br>
|
||||
* Constants betas, gammas and deltas involved in the algorithm are either hardcoded or precomputed
|
||||
* by the subroutine compute_fft_lut(...). <br>
|
||||
* Note that on this first call (as opposed to the recursive calls to fft_rec), gammas are equal to betas,
|
||||
* meaning the first gammas subset sums are actually the subset sums of betas (except 1). <br>
|
||||
* Also note that f is altered during computation (twisted at each level).
|
||||
*
|
||||
* @param[out] w Array
|
||||
* @param[in] f Array of 2^PARAM_FFT elements
|
||||
* @param[in] f_coeffs Number coefficients of f (i.e. deg(f)+1)
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_fft(uint16_t *w, const uint16_t *f, size_t f_coeffs) {
|
||||
uint16_t betas[PARAM_M - 1] = {0};
|
||||
uint16_t betas_sums[1 << (PARAM_M - 1)] = {0};
|
||||
uint16_t f0[1 << (PARAM_FFT - 1)] = {0};
|
||||
uint16_t f1[1 << (PARAM_FFT - 1)] = {0};
|
||||
uint16_t deltas[PARAM_M - 1];
|
||||
size_t k = 1 << (PARAM_M - 1);
|
||||
uint16_t u[1 << (PARAM_M - 1)] = {0};
|
||||
uint16_t v[1 << (PARAM_M - 1)] = {0};
|
||||
|
||||
// Follows Gao and Mateer algorithm
|
||||
compute_fft_betas(betas);
|
||||
|
||||
// Step 1: PARAM_FFT > 1, nothing to do
|
||||
|
||||
// Compute gammas sums
|
||||
compute_subset_sums(betas_sums, betas, PARAM_M - 1);
|
||||
|
||||
// Step 2: beta_m = 1, nothing to do
|
||||
|
||||
// Step 3
|
||||
radix(f0, f1, f, PARAM_FFT);
|
||||
|
||||
// Step 4: Compute deltas
|
||||
for (size_t i = 0; i < PARAM_M - 1; ++i) {
|
||||
deltas[i] = PQCLEAN_HQC1281CCA2_LEAKTIME_gf_square(betas[i]) ^ betas[i];
|
||||
}
|
||||
|
||||
// Step 5
|
||||
fft_rec(u, f0, (f_coeffs + 1) / 2, PARAM_M - 1, PARAM_FFT - 1, deltas);
|
||||
fft_rec(v, f1, f_coeffs / 2, PARAM_M - 1, PARAM_FFT - 1, deltas);
|
||||
|
||||
// Step 6, 7 and error polynomial computation
|
||||
memcpy(w + k, v, 2 * k);
|
||||
|
||||
// Check if 0 is root
|
||||
w[0] = u[0];
|
||||
|
||||
// Check if 1 is root
|
||||
w[k] ^= u[0];
|
||||
|
||||
// Find other roots
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
w[i] = u[i] ^ PQCLEAN_HQC1281CCA2_LEAKTIME_gf_mul(betas_sums[i], v[i]);
|
||||
w[k + i] ^= w[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Arranges the received word vector in a form w such that applying the additive FFT transpose to w yields the BCH syndromes of the received word vector.
|
||||
*
|
||||
* Since the received word vector gives coefficients of the primitive element alpha, we twist accordingly. <br>
|
||||
* Furthermore, the additive FFT transpose needs elements indexed by their decomposition on the chosen basis,
|
||||
* so we apply the adequate permutation.
|
||||
*
|
||||
* @param[out] w Array of size 2^PARAM_M
|
||||
* @param[in] vector Array of size VEC_N1_SIZE_BYTES
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_fft_t_preprocess_bch_codeword(uint16_t *w, const uint8_t *vector) {
|
||||
uint16_t r[1 << PARAM_M];
|
||||
uint16_t gammas[PARAM_M - 1];
|
||||
uint16_t gammas_sums[1 << (PARAM_M - 1)];
|
||||
size_t k = 1 << (PARAM_M - 1);
|
||||
|
||||
// Unpack the received word vector into array r
|
||||
size_t i;
|
||||
for (i = 0; i < VEC_N1_SIZE_BYTES - (PARAM_N1 % 8 != 0); ++i) {
|
||||
for (size_t j = 0; j < 8; ++j) {
|
||||
r[8 * i + j] = (vector[i] >> j) & 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Last byte
|
||||
for (size_t j = 0; j < PARAM_N1 % 8; ++j) {
|
||||
r[8 * i + j] = (vector[i] >> j) & 1;
|
||||
}
|
||||
|
||||
// Complete r with zeros
|
||||
memset(r + PARAM_N1, 0, 2 * ((1 << PARAM_M) - PARAM_N1));
|
||||
|
||||
compute_fft_betas(gammas);
|
||||
compute_subset_sums(gammas_sums, gammas, PARAM_M - 1);
|
||||
|
||||
// Twist and permute r adequately to obtain w
|
||||
w[0] = 0;
|
||||
w[k] = -r[0] & 1;
|
||||
for (i = 1; i < k; ++i) {
|
||||
w[i] = -r[PQCLEAN_HQC1281CCA2_LEAKTIME_gf_log(gammas_sums[i])] & gammas_sums[i];
|
||||
w[k + i] = -r[PQCLEAN_HQC1281CCA2_LEAKTIME_gf_log(gammas_sums[i] ^ 1)] & (gammas_sums[i] ^ 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieves the error polynomial error from the evaluations w of the ELP (Error Locator Polynomial) on all field elements.
|
||||
*
|
||||
* @param[out] error Array of size VEC_N1_SIZE_BYTES
|
||||
* @param[in] w Array of size 2^PARAM_M
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_fft_retrieve_bch_error_poly(uint8_t *error, const uint16_t *w) {
|
||||
uint16_t gammas[PARAM_M - 1];
|
||||
uint16_t gammas_sums[1 << (PARAM_M - 1)];
|
||||
size_t k = 1 << (PARAM_M - 1);
|
||||
size_t index = PARAM_GF_MUL_ORDER;
|
||||
|
||||
compute_fft_betas(gammas);
|
||||
compute_subset_sums(gammas_sums, gammas, PARAM_M - 1);
|
||||
|
||||
error[0] ^= 1 ^ ((uint16_t) - w[0] >> 15);
|
||||
uint8_t bit = 1 ^ ((uint16_t) - w[k] >> 15);
|
||||
error[index / 8] ^= bit << (index % 8);
|
||||
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
index = PARAM_GF_MUL_ORDER - PQCLEAN_HQC1281CCA2_LEAKTIME_gf_log(gammas_sums[i]);
|
||||
bit = 1 ^ ((uint16_t) - w[i] >> 15);
|
||||
error[index / 8] ^= bit << (index % 8);
|
||||
|
||||
index = PARAM_GF_MUL_ORDER - PQCLEAN_HQC1281CCA2_LEAKTIME_gf_log(gammas_sums[i] ^ 1);
|
||||
bit = 1 ^ ((uint16_t) - w[k + i] >> 15);
|
||||
error[index / 8] ^= bit << (index % 8);
|
||||
}
|
||||
}
|
||||
18
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/fft.h
Normal file
18
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/fft.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef PQCLEAN_HQC1281CCA2_LEAKTIME_FFT_H
|
||||
#define PQCLEAN_HQC1281CCA2_LEAKTIME_FFT_H
|
||||
|
||||
/**
|
||||
* @file fft.h
|
||||
* Header file of fft.c
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_fft_t(uint16_t *f, const uint16_t *w, size_t f_coeffs);
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_fft_t_preprocess_bch_codeword(uint16_t *w, const uint8_t *vector);
|
||||
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_fft(uint16_t *w, const uint16_t *f, size_t f_coeffs);
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_fft_retrieve_bch_error_poly(uint8_t *error, const uint16_t *w);
|
||||
|
||||
#endif
|
||||
99
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/gf.c
Normal file
99
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/gf.c
Normal file
File diff suppressed because one or more lines are too long
18
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/gf.h
Normal file
18
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/gf.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef PQCLEAN_HQC1281CCA2_LEAKTIME_GF_H
|
||||
#define PQCLEAN_HQC1281CCA2_LEAKTIME_GF_H
|
||||
|
||||
/**
|
||||
* @file gf.h
|
||||
* Header file of gf.c
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint16_t PQCLEAN_HQC1281CCA2_LEAKTIME_gf_log(uint16_t elt);
|
||||
uint16_t PQCLEAN_HQC1281CCA2_LEAKTIME_gf_mul(uint16_t a, uint16_t b);
|
||||
uint16_t PQCLEAN_HQC1281CCA2_LEAKTIME_gf_square(uint16_t a);
|
||||
uint16_t PQCLEAN_HQC1281CCA2_LEAKTIME_gf_inverse(uint16_t a);
|
||||
uint16_t PQCLEAN_HQC1281CCA2_LEAKTIME_gf_mod(uint16_t i);
|
||||
|
||||
#endif
|
||||
123
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/gf2x.c
Normal file
123
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/gf2x.c
Normal file
@ -0,0 +1,123 @@
|
||||
/**
|
||||
* \file gf2x.c
|
||||
* \brief Implementation of multiplication of two polynomials
|
||||
*/
|
||||
|
||||
#include "gf2x.h"
|
||||
#include "parameters.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define WORD_TYPE uint64_t
|
||||
#define WORD_TYPE_BITS (sizeof(WORD_TYPE) * 8)
|
||||
#define UTILS_VECTOR_ARRAY_SIZE CEIL_DIVIDE(PARAM_N, WORD_TYPE_BITS)
|
||||
|
||||
static int vect_mul_precompute_rows(WORD_TYPE *o, const WORD_TYPE *v);
|
||||
|
||||
|
||||
/**
|
||||
* @brief A subroutine used in the function sparse_dense_mul()
|
||||
*
|
||||
* @param[out] o Pointer to an array
|
||||
* @param[in] v Pointer to an array
|
||||
* @return 0 if precomputation is successful, -1 otherwise
|
||||
*/
|
||||
static int vect_mul_precompute_rows(WORD_TYPE *o, const WORD_TYPE *v) {
|
||||
int8_t var;
|
||||
for (size_t i = 0; i < PARAM_N; ++i) {
|
||||
var = 0;
|
||||
|
||||
// All the bits that we need are in the same block
|
||||
if (((i % WORD_TYPE_BITS) == 0) && (i != PARAM_N - (PARAM_N % WORD_TYPE_BITS))) {
|
||||
var = 1;
|
||||
}
|
||||
|
||||
// Cases where the bits are in before the last block, the last block and the first block
|
||||
if (i > PARAM_N - WORD_TYPE_BITS) {
|
||||
if (i >= PARAM_N - (PARAM_N % WORD_TYPE_BITS)) {
|
||||
var = 2;
|
||||
} else {
|
||||
var = 3;
|
||||
}
|
||||
}
|
||||
|
||||
switch (var) {
|
||||
case 0:
|
||||
// Take bits in the last block and the first one
|
||||
o[i] = 0;
|
||||
o[i] += v[i / WORD_TYPE_BITS] >> (i % WORD_TYPE_BITS);
|
||||
o[i] += v[(i / WORD_TYPE_BITS) + 1] << (WORD_TYPE_BITS - (i % WORD_TYPE_BITS));
|
||||
break;
|
||||
|
||||
case 1:
|
||||
o[i] = v[i / WORD_TYPE_BITS];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
o[i] = 0;
|
||||
o[i] += v[i / WORD_TYPE_BITS] >> (i % WORD_TYPE_BITS);
|
||||
o[i] += v[0] << ((PARAM_N - i) % WORD_TYPE_BITS);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
o[i] = 0;
|
||||
o[i] += v[i / WORD_TYPE_BITS] >> (i % WORD_TYPE_BITS);
|
||||
o[i] += v[(i / WORD_TYPE_BITS) + 1] << (WORD_TYPE_BITS - (i % WORD_TYPE_BITS));
|
||||
o[i] += v[0] << ((WORD_TYPE_BITS - i + (PARAM_N % WORD_TYPE_BITS)) % WORD_TYPE_BITS);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Multiplies two vectors
|
||||
*
|
||||
* This function multiplies two vectors: a sparse vector of Hamming weight equal to <b>weight</b> and a dense (random) vector.
|
||||
* The vector <b>a1</b> is the sparse vector and <b>a2</b> is the dense vector.
|
||||
* We notice that the idea is explained using vector of 32 bits elements instead of 64 (the algorithm works in booth cases).
|
||||
*
|
||||
* @param[out] o Pointer to a vector that is the result of the multiplication
|
||||
* @param[in] a1 Pointer to the sparse vector stored by position
|
||||
* @param[in] a2 Pointer to the dense vector
|
||||
* @param[in] weight Integer that is the weight of the sparse vector
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_vect_mul(uint8_t *o, const uint32_t *a1, const uint8_t *a2, uint16_t weight) {
|
||||
WORD_TYPE v1[UTILS_VECTOR_ARRAY_SIZE] = {0};
|
||||
WORD_TYPE res[UTILS_VECTOR_ARRAY_SIZE] = {0};
|
||||
WORD_TYPE precomputation_array [PARAM_N] = {0};
|
||||
WORD_TYPE row [UTILS_VECTOR_ARRAY_SIZE] = {0};
|
||||
uint32_t index;
|
||||
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_load8_arr(v1, UTILS_VECTOR_ARRAY_SIZE, a2, VEC_N_SIZE_BYTES);
|
||||
vect_mul_precompute_rows(precomputation_array, v1);
|
||||
|
||||
for (size_t i = 0; i < weight; ++i) {
|
||||
int32_t k = UTILS_VECTOR_ARRAY_SIZE;
|
||||
|
||||
for (size_t j = 0; j < UTILS_VECTOR_ARRAY_SIZE - 1; ++j) {
|
||||
index = WORD_TYPE_BITS * (uint32_t)j - a1[i];
|
||||
if (index > PARAM_N) {
|
||||
index += PARAM_N;
|
||||
}
|
||||
row[j] = precomputation_array[index];
|
||||
}
|
||||
|
||||
index = WORD_TYPE_BITS * (UTILS_VECTOR_ARRAY_SIZE - 1) - a1[i];
|
||||
row[UTILS_VECTOR_ARRAY_SIZE - 1] = precomputation_array[(index < PARAM_N ? index : index + PARAM_N)] & BITMASK(PARAM_N, WORD_TYPE_BITS);
|
||||
|
||||
while (k--) {
|
||||
res[k] ^= row[k];
|
||||
}
|
||||
}
|
||||
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_store8_arr(o, VEC_N_SIZE_BYTES, res, UTILS_VECTOR_ARRAY_SIZE);
|
||||
}
|
||||
13
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/gf2x.h
Normal file
13
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/gf2x.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef PQCLEAN_HQC1281CCA2_LEAKTIME_GF2X_H
|
||||
#define PQCLEAN_HQC1281CCA2_LEAKTIME_GF2X_H
|
||||
|
||||
/**
|
||||
* @file gf2x.h
|
||||
* @brief Header file for gf2x.c
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_vect_mul(uint8_t *o, const uint32_t *a1, const uint8_t *a2, uint16_t weight);
|
||||
|
||||
#endif
|
||||
135
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/hqc.c
Normal file
135
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/hqc.c
Normal file
@ -0,0 +1,135 @@
|
||||
/**
|
||||
* @file hqc.c
|
||||
* @brief Implementation of hqc.h
|
||||
*/
|
||||
|
||||
#include "gf2x.h"
|
||||
#include "hqc.h"
|
||||
#include "nistseedexpander.h"
|
||||
#include "parameters.h"
|
||||
#include "parsing.h"
|
||||
#include "randombytes.h"
|
||||
#include "tensor.h"
|
||||
#include "vector.h"
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Keygen of the HQC_PKE IND_CPA scheme
|
||||
*
|
||||
* The public key is composed of the syndrome <b>s</b> as well as the <b>seed</b> used to generate the vector <b>h</b>.
|
||||
*
|
||||
* The secret key is composed of the <b>seed</b> used to generate vectors <b>x</b> and <b>y</b>.
|
||||
* As a technicality, the public key is appended to the secret key in order to respect NIST API.
|
||||
*
|
||||
* @param[out] pk String containing the public key
|
||||
* @param[out] sk String containing the secret key
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_pke_keygen(uint8_t *pk, uint8_t *sk) {
|
||||
AES_XOF_struct sk_seedexpander;
|
||||
AES_XOF_struct pk_seedexpander;
|
||||
uint8_t sk_seed[SEED_BYTES] = {0};
|
||||
uint8_t pk_seed[SEED_BYTES] = {0};
|
||||
uint8_t x[VEC_N_SIZE_BYTES] = {0};
|
||||
uint32_t y[PARAM_OMEGA] = {0};
|
||||
uint8_t h[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t s[VEC_N_SIZE_BYTES] = {0};
|
||||
|
||||
// Create seed_expanders for public key and secret key
|
||||
randombytes(sk_seed, SEED_BYTES);
|
||||
seedexpander_init(&sk_seedexpander, sk_seed, sk_seed + 32, SEEDEXPANDER_MAX_LENGTH);
|
||||
|
||||
randombytes(pk_seed, SEED_BYTES);
|
||||
seedexpander_init(&pk_seedexpander, pk_seed, pk_seed + 32, SEEDEXPANDER_MAX_LENGTH);
|
||||
|
||||
// Compute secret key
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_set_random_fixed_weight(&sk_seedexpander, x, PARAM_OMEGA);
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_set_random_fixed_weight_by_coordinates(&sk_seedexpander, y, PARAM_OMEGA);
|
||||
|
||||
// Compute public key
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_set_random(&pk_seedexpander, h);
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_mul(s, y, h, PARAM_OMEGA);
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_add(s, x, s, VEC_N_SIZE_BYTES);
|
||||
|
||||
// Parse keys to string
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_public_key_to_string(pk, pk_seed, s);
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_secret_key_to_string(sk, sk_seed, pk);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encryption of the HQC_PKE IND_CPA scheme
|
||||
*
|
||||
* The cihertext is composed of vectors <b>u</b> and <b>v</b>.
|
||||
*
|
||||
* @param[out] u Vector u (first part of the ciphertext)
|
||||
* @param[out] v Vector v (second part of the ciphertext)
|
||||
* @param[in] m Vector representing the message to encrypt
|
||||
* @param[in] theta Seed used to derive randomness required for encryption
|
||||
* @param[in] pk String containing the public key
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_pke_encrypt(uint8_t *u, uint8_t *v, const uint8_t *m, const uint8_t *theta, const uint8_t *pk) {
|
||||
AES_XOF_struct seedexpander;
|
||||
uint8_t h[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t s[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t r1[VEC_N_SIZE_BYTES] = {0};
|
||||
uint32_t r2[PARAM_OMEGA_R] = {0};
|
||||
uint8_t e[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t tmp1[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t tmp2[VEC_N_SIZE_BYTES] = {0};
|
||||
|
||||
// Create seed_expander from theta
|
||||
seedexpander_init(&seedexpander, theta, theta + 32, SEEDEXPANDER_MAX_LENGTH);
|
||||
|
||||
// Retrieve h and s from public key
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_public_key_from_string(h, s, pk);
|
||||
|
||||
// Generate r1, r2 and e
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_set_random_fixed_weight(&seedexpander, r1, PARAM_OMEGA_R);
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_set_random_fixed_weight_by_coordinates(&seedexpander, r2, PARAM_OMEGA_R);
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_set_random_fixed_weight(&seedexpander, e, PARAM_OMEGA_E);
|
||||
|
||||
// Compute u = r1 + r2.h
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_mul(u, r2, h, PARAM_OMEGA_R);
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_add(u, r1, u, VEC_N_SIZE_BYTES);
|
||||
|
||||
// Compute v = m.G by encoding the message
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_tensor_code_encode(v, m);
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_resize(tmp1, PARAM_N, v, PARAM_N1N2);
|
||||
|
||||
// Compute v = m.G + s.r2 + e
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_mul(tmp2, r2, s, PARAM_OMEGA_R);
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_add(tmp2, e, tmp2, VEC_N_SIZE_BYTES);
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_add(tmp2, tmp1, tmp2, VEC_N_SIZE_BYTES);
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_resize(v, PARAM_N1N2, tmp2, PARAM_N);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Decryption of the HQC_PKE IND_CPA scheme
|
||||
*
|
||||
* @param[out] m Vector representing the decrypted message
|
||||
* @param[in] u Vector u (first part of the ciphertext)
|
||||
* @param[in] v Vector v (second part of the ciphertext)
|
||||
* @param[in] sk String containing the secret key
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_pke_decrypt(uint8_t *m, const uint8_t *u, const uint8_t *v, const uint8_t *sk) {
|
||||
uint8_t x[VEC_N_SIZE_BYTES] = {0};
|
||||
uint32_t y[PARAM_OMEGA] = {0};
|
||||
uint8_t pk[PUBLIC_KEY_BYTES] = {0};
|
||||
uint8_t tmp1[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t tmp2[VEC_N_SIZE_BYTES] = {0};
|
||||
|
||||
// Retrieve x, y, pk from secret key
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_secret_key_from_string(x, y, pk, sk);
|
||||
|
||||
// Compute v - u.y
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_resize(tmp1, PARAM_N, v, PARAM_N1N2);
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_mul(tmp2, y, u, PARAM_OMEGA);
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_add(tmp2, tmp1, tmp2, VEC_N_SIZE_BYTES);
|
||||
|
||||
// Compute m by decoding v - u.y
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_tensor_code_decode(m, tmp2);
|
||||
}
|
||||
15
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/hqc.h
Normal file
15
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/hqc.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef PQCLEAN_HQC1281CCA2_LEAKTIME_HQC_H
|
||||
#define PQCLEAN_HQC1281CCA2_LEAKTIME_HQC_H
|
||||
|
||||
/**
|
||||
* @file hqc.h
|
||||
* @brief Functions of the HQC_PKE IND_CPA scheme
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_pke_keygen(uint8_t *pk, uint8_t *sk);
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_pke_encrypt(uint8_t *u, uint8_t *v, const uint8_t *m, const uint8_t *theta, const uint8_t *pk);
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_pke_decrypt(uint8_t *m, const uint8_t *u, const uint8_t *v, const uint8_t *sk);
|
||||
|
||||
#endif
|
||||
154
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/kem.c
Normal file
154
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/kem.c
Normal file
@ -0,0 +1,154 @@
|
||||
/**
|
||||
* @file kem.c
|
||||
* @brief Implementation of api.h
|
||||
*/
|
||||
|
||||
#include "api.h"
|
||||
#include "hqc.h"
|
||||
#include "nistseedexpander.h"
|
||||
#include "parameters.h"
|
||||
#include "parsing.h"
|
||||
#include "sha2.h"
|
||||
#include "vector.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Keygen of the HQC_KEM IND_CAA2 scheme
|
||||
*
|
||||
* The public key is composed of the syndrome <b>s</b> as well as the seed used to generate the vector <b>h</b>.
|
||||
*
|
||||
* The secret key is composed of the seed used to generate vectors <b>x</b> and <b>y</b>.
|
||||
* As a technicality, the public key is appended to the secret key in order to respect NIST API.
|
||||
*
|
||||
* @param[out] pk String containing the public key
|
||||
* @param[out] sk String containing the secret key
|
||||
* @returns 0 if keygen is successful
|
||||
*/
|
||||
int PQCLEAN_HQC1281CCA2_LEAKTIME_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) {
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_pke_keygen(pk, sk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encapsulation of the HQC_KEM IND_CAA2 scheme
|
||||
*
|
||||
* @param[out] ct String containing the ciphertext
|
||||
* @param[out] ss String containing the shared secret
|
||||
* @param[in] pk String containing the public key
|
||||
* @returns 0 if encapsulation is successful
|
||||
*/
|
||||
int PQCLEAN_HQC1281CCA2_LEAKTIME_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
|
||||
AES_XOF_struct G_seedexpander;
|
||||
uint8_t seed_G[VEC_K_SIZE_BYTES];
|
||||
uint8_t diversifier_bytes[8] = {0};
|
||||
uint8_t m[VEC_K_SIZE_BYTES] = {0};
|
||||
uint8_t theta[SEED_BYTES] = {0};
|
||||
uint8_t u[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t v[VEC_N1N2_SIZE_BYTES] = {0};
|
||||
uint8_t d[SHA512_BYTES] = {0};
|
||||
uint8_t mc[VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES] = {0};
|
||||
|
||||
// Computing m
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_set_random_from_randombytes(m);
|
||||
|
||||
// Generating G function
|
||||
memcpy(seed_G, m, VEC_K_SIZE_BYTES);
|
||||
seedexpander_init(&G_seedexpander, seed_G, diversifier_bytes, SEEDEXPANDER_MAX_LENGTH);
|
||||
|
||||
// Computing theta
|
||||
seedexpander(&G_seedexpander, theta, SEED_BYTES);
|
||||
|
||||
// Encrypting m
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_pke_encrypt(u, v, m, theta, pk);
|
||||
|
||||
// Computing d
|
||||
sha512(d, m, VEC_K_SIZE_BYTES);
|
||||
|
||||
// Computing shared secret
|
||||
memcpy(mc, m, VEC_K_SIZE_BYTES);
|
||||
memcpy(mc + VEC_K_SIZE_BYTES, u, VEC_N_SIZE_BYTES);
|
||||
memcpy(mc + VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES, v, VEC_N1N2_SIZE_BYTES);
|
||||
sha512(ss, mc, VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES);
|
||||
|
||||
// Computing ciphertext
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_ciphertext_to_string(ct, u, v, d);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Decapsulation of the HQC_KEM IND_CAA2 scheme
|
||||
*
|
||||
* @param[out] ss String containing the shared secret
|
||||
* @param[in] ct String containing the cipĥertext
|
||||
* @param[in] sk String containing the secret key
|
||||
* @returns 0 if decapsulation is successful, -1 otherwise
|
||||
*/
|
||||
int PQCLEAN_HQC1281CCA2_LEAKTIME_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
|
||||
AES_XOF_struct G_seedexpander;
|
||||
uint8_t seed_G[VEC_K_SIZE_BYTES] = {0};
|
||||
uint8_t diversifier_bytes[8] = {0};
|
||||
uint8_t u[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t v[VEC_N1N2_SIZE_BYTES] = {0};
|
||||
uint8_t d[SHA512_BYTES] = {0};
|
||||
uint8_t pk[PUBLIC_KEY_BYTES] = {0};
|
||||
uint8_t m[VEC_K_SIZE_BYTES] = {0};
|
||||
uint8_t theta[SEED_BYTES] = {0};
|
||||
uint8_t u2[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t v2[VEC_N1N2_SIZE_BYTES] = {0};
|
||||
uint8_t d2[SHA512_BYTES] = {0};
|
||||
uint8_t mc[VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES] = {0};
|
||||
int8_t abort = 0;
|
||||
|
||||
// Retrieving u, v and d from ciphertext
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_ciphertext_from_string(u, v, d, ct);
|
||||
|
||||
// Retrieving pk from sk
|
||||
memcpy(pk, sk + SEED_BYTES, PUBLIC_KEY_BYTES);
|
||||
|
||||
// Decryting
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_pke_decrypt(m, u, v, sk);
|
||||
|
||||
// Generating G function
|
||||
memcpy(seed_G, m, VEC_K_SIZE_BYTES);
|
||||
seedexpander_init(&G_seedexpander, seed_G, diversifier_bytes, SEEDEXPANDER_MAX_LENGTH);
|
||||
|
||||
// Computing theta
|
||||
seedexpander(&G_seedexpander, theta, SEED_BYTES);
|
||||
|
||||
// Encrypting m'
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_pke_encrypt(u2, v2, m, theta, pk);
|
||||
|
||||
// Checking that c = c' and abort otherwise
|
||||
if (PQCLEAN_HQC1281CCA2_LEAKTIME_vect_compare(u, u2, VEC_N_SIZE_BYTES) != 0 ||
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_compare(v, v2, VEC_N1N2_SIZE_BYTES) != 0) {
|
||||
abort = 1;
|
||||
}
|
||||
|
||||
// Computing d'
|
||||
sha512(d2, m, VEC_K_SIZE_BYTES);
|
||||
|
||||
// Checking that d = d' and abort otherwise
|
||||
if (memcmp(d, d2, SHA512_BYTES) != 0) {
|
||||
abort = 1;
|
||||
}
|
||||
|
||||
if (abort == 1) {
|
||||
memset(ss, 0, SHARED_SECRET_BYTES);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Computing shared secret
|
||||
memcpy(mc, m, VEC_K_SIZE_BYTES);
|
||||
memcpy(mc + VEC_K_SIZE_BYTES, u, VEC_N_SIZE_BYTES);
|
||||
memcpy(mc + VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES, v, VEC_N1N2_SIZE_BYTES);
|
||||
sha512(ss, mc, VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES);
|
||||
|
||||
return 0;
|
||||
}
|
||||
112
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/parameters.h
Normal file
112
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/parameters.h
Normal file
@ -0,0 +1,112 @@
|
||||
#ifndef PQCLEAN_HQC1281CCA2_LEAKTIME_HQC_PARAMETERS_H
|
||||
#define PQCLEAN_HQC1281CCA2_LEAKTIME_HQC_PARAMETERS_H
|
||||
|
||||
/**
|
||||
* @file parameters.h
|
||||
* @brief Parameters of the HQC_KEM IND-CCA2 scheme
|
||||
*/
|
||||
|
||||
#include "api.h"
|
||||
|
||||
#define CEIL_DIVIDE(a, b) (((a)/(b)) + ((a) % (b) == 0 ? 0 : 1)) /*!< Divide a by b and ceil the result*/
|
||||
#define BITMASK(a, size) ((1ULL << ((a) % (size))) - 1) /*!< Create a mask*/
|
||||
|
||||
|
||||
/*
|
||||
#define PARAM_N Define the parameter n of the scheme
|
||||
#define PARAM_N1 Define the parameter n1 of the scheme (length of BCH code)
|
||||
#define PARAM_N2 Define the parameter n2 of the scheme (length of the repetition code)
|
||||
#define PARAM_N1N2 Define the parameter n1 * n2 of the scheme (length of the tensor code)
|
||||
#define PARAM_OMEGA Define the parameter omega of the scheme
|
||||
#define PARAM_OMEGA_E Define the parameter omega_e of the scheme
|
||||
#define PARAM_OMEGA_R Define the parameter omega_r of the scheme
|
||||
#define PARAM_SECURITY Define the security level corresponding to the chosen parameters
|
||||
#define PARAM_DFR_EXP Define the decryption failure rate corresponding to the chosen parameters
|
||||
|
||||
#define SECRET_KEY_BYTES Define the size of the secret key in bytes
|
||||
#define PUBLIC_KEY_BYTES Define the size of the public key in bytes
|
||||
#define SHARED_SECRET_BYTES Define the size of the shared secret in bytes
|
||||
#define CIPHERTEXT_BYTES Define the size of the ciphertext in bytes
|
||||
|
||||
#define UTILS_REJECTION_THRESHOLD Define the rejection threshold used to generate given weight vectors (see vector_set_random_fixed_weight function)
|
||||
#define VEC_N_ARRAY_SIZE_BYTES Define the size of the array used to store a PARAM_N sized vector in bytes
|
||||
#define VEC_N1_ARRAY_SIZE_BYTES Define the size of the array used to store a PARAM_N1 sized vector in bytes
|
||||
#define VEC_N1N2_ARRAY_SIZE_BYTES Define the size of the array used to store a PARAM_N1N2 sized vector in bytes
|
||||
#define VEC_K_ARRAY_SIZE_BYTES Define the size of the array used to store a PARAM_K sized vector in bytes
|
||||
|
||||
#define PARAM_T Define a threshold for decoding repetition code word (PARAM_T = (PARAM_N2 - 1) / 2)
|
||||
|
||||
#define PARAM_DELTA Define the parameter delta of the scheme (correcting capacity of the BCH code)
|
||||
#define PARAM_M Define a positive integer
|
||||
#define PARAM_GF_MUL_ORDER Define the size of the multiplicative group of GF(2^m), i.e 2^m -1
|
||||
#define PARAM_K Define the size of the information bits of the BCH code
|
||||
#define PARAM_G Define the size of the generator polynomial of BCH code
|
||||
#define PARAM_FFT The additive FFT takes a 2^PARAM_FFT polynomial as input
|
||||
We use the FFT to compute the roots of sigma, whose degree if PARAM_DELTA=60
|
||||
The smallest power of 2 greater than 60+1 is 64=2^6
|
||||
#define PARAM_FFT_T The additive FFT transpose computes a (2^PARAM_FFT_T)-sized syndrome vector
|
||||
We want to compute 2*PARAM_DELTA=120 syndromes
|
||||
The smallest power of 2 greater than 120 is 2^7
|
||||
#define PARAM_BCH_POLY Generator polynomial of the BCH code
|
||||
|
||||
#define SHA512_BYTES Define the size of SHA512 output in bytes
|
||||
#define SEED_BYTES Define the size of the seed in bytes
|
||||
#define SEEDEXPANDER_MAX_LENGTH Define the seed expander max length
|
||||
*/
|
||||
|
||||
|
||||
#define PARAM_N 24677
|
||||
#define PARAM_N1 796
|
||||
#define PARAM_N2 31
|
||||
#define PARAM_N1N2 24676
|
||||
#define PARAM_OMEGA 67
|
||||
#define PARAM_OMEGA_E 77
|
||||
#define PARAM_OMEGA_R 77
|
||||
#define PARAM_SECURITY 128
|
||||
#define PARAM_DFR_EXP 128
|
||||
|
||||
#define SECRET_KEY_BYTES PQCLEAN_HQC1281CCA2_LEAKTIME_CRYPTO_SECRETKEYBYTES
|
||||
#define PUBLIC_KEY_BYTES PQCLEAN_HQC1281CCA2_LEAKTIME_CRYPTO_PUBLICKEYBYTES
|
||||
#define SHARED_SECRET_BYTES PQCLEAN_HQC1281CCA2_LEAKTIME_CRYPTO_BYTES
|
||||
#define CIPHERTEXT_BYTES PQCLEAN_HQC1281CCA2_LEAKTIME_CRYPTO_CIPHERTEXTBYTES
|
||||
|
||||
#define UTILS_REJECTION_THRESHOLD 16755683
|
||||
#define VEC_K_SIZE_BYTES CEIL_DIVIDE(PARAM_K, 8)
|
||||
#define VEC_N_SIZE_BYTES CEIL_DIVIDE(PARAM_N, 8)
|
||||
#define VEC_N1_SIZE_BYTES CEIL_DIVIDE(PARAM_N1, 8)
|
||||
#define VEC_N1N2_SIZE_BYTES CEIL_DIVIDE(PARAM_N1N2, 8)
|
||||
|
||||
#define PARAM_T 15
|
||||
|
||||
#define PARAM_DELTA 60
|
||||
#define PARAM_M 10
|
||||
#define PARAM_GF_MUL_ORDER 1023
|
||||
#define PARAM_K 256
|
||||
#define PARAM_G 541
|
||||
#define PARAM_FFT 6
|
||||
#define PARAM_FFT_T 7
|
||||
#define PARAM_BCH_POLY { \
|
||||
1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,0, \
|
||||
1,0,0,1,0,1,1,0,1,0,0,1,1,1,0,0,1,1,1,0,0,0,1,0,1,0,1,0,1,1,0,0, \
|
||||
1,0,1,0,0,1,0,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,0,1,0,1,1,0,1,0, \
|
||||
0,1,0,1,1,1,0,0,0,1,1,1,1,0,0,0,1,0,1,1,1,1,0,1,0,0,1,1,1,1,0,1, \
|
||||
0,0,0,1,0,0,1,1,1,1,1,0,1,0,0,0,1,0,1,1,0,0,0,1,0,1,0,0,1,0,0,0, \
|
||||
1,1,0,1,0,1,0,1,1,0,1,1,0,0,1,1,1,0,0,1,0,1,0,0,1,0,0,1,1,0,1,0, \
|
||||
0,0,0,1,1,0,0,0,0,1,0,1,1,0,1,1,0,1,0,0,0,1,1,1,0,1,0,1,1,0,0,1, \
|
||||
1,0,1,1,0,0,0,1,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,1,0,0,1,0, \
|
||||
0,0,1,1,0,0,1,1,1,0,0,0,1,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,1,0,1,1, \
|
||||
1,1,1,1,0,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,0,0,1,0,1,1,1,0,1,0,1, \
|
||||
0,0,0,0,1,1,0,0,0,0,1,0,0,0,1,0,1,0,1,0,1,1,0,0,0,1,0,1,1,0,0,0, \
|
||||
1,0,0,1,0,0,1,1,0,0,1,0,1,0,0,1,1,1,1,0,0,1,1,0,0,1,1,0,1,0,1,1, \
|
||||
0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,0,1,1,1, \
|
||||
0,1,0,1,1,0,1,1,1,1,0,1,1,1,0,1,1,0,1,1,1,1,1,0,0,1,0,0,1,1,0,0, \
|
||||
0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,1,1,1,1,0,0,1,1,1,0,0,0,0,1,0,1,1, \
|
||||
1,1,0,0,1,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,1,0,1,0,0, \
|
||||
1,0,1,1,0,0,0,0,0,1,1,1,1,0,1,0,0,1,0,0,0,0,1,0,0,0,0,0,1 \
|
||||
};
|
||||
|
||||
#define SHA512_BYTES 64
|
||||
#define SEED_BYTES 40
|
||||
#define SEEDEXPANDER_MAX_LENGTH 4294967295
|
||||
|
||||
#endif
|
||||
126
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/parsing.c
Normal file
126
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/parsing.c
Normal file
@ -0,0 +1,126 @@
|
||||
/**
|
||||
* @file parsing.c
|
||||
* @brief Functions to parse secret key, public key and ciphertext of the HQC scheme
|
||||
*/
|
||||
|
||||
#include "nistseedexpander.h"
|
||||
#include "parameters.h"
|
||||
#include "parsing.h"
|
||||
#include "vector.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse a secret key into a string
|
||||
*
|
||||
* The secret key is composed of the seed used to generate vectors <b>x</b> and <b>y</b>.
|
||||
* As technicality, the public key is appended to the secret key in order to respect NIST API.
|
||||
*
|
||||
* @param[out] sk String containing the secret key
|
||||
* @param[in] sk_seed Seed used to generate the secret key
|
||||
* @param[in] pk String containing the public key
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_secret_key_to_string(uint8_t *sk, const uint8_t *sk_seed, const uint8_t *pk) {
|
||||
memcpy(sk, sk_seed, SEED_BYTES);
|
||||
memcpy(sk + SEED_BYTES, pk, PUBLIC_KEY_BYTES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse a secret key from a string
|
||||
*
|
||||
* The secret key is composed of the seed used to generate vectors <b>x</b> and <b>y</b>.
|
||||
* As technicality, the public key is appended to the secret key in order to respect NIST API.
|
||||
*
|
||||
* @param[out] x uint8_t representation of vector x
|
||||
* @param[out] y uint8_t representation of vector y
|
||||
* @param[out] pk String containing the public key
|
||||
* @param[in] sk String containing the secret key
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_secret_key_from_string(uint8_t *x, uint32_t *y, uint8_t *pk, const uint8_t *sk) {
|
||||
AES_XOF_struct sk_seedexpander;
|
||||
uint8_t sk_seed[SEED_BYTES] = {0};
|
||||
|
||||
memcpy(sk_seed, sk, SEED_BYTES);
|
||||
seedexpander_init(&sk_seedexpander, sk_seed, sk_seed + 32, SEEDEXPANDER_MAX_LENGTH);
|
||||
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_set_random_fixed_weight(&sk_seedexpander, x, PARAM_OMEGA);
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_set_random_fixed_weight_by_coordinates(&sk_seedexpander, y, PARAM_OMEGA);
|
||||
memcpy(pk, sk + SEED_BYTES, PUBLIC_KEY_BYTES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse a public key into a string
|
||||
*
|
||||
* The public key is composed of the syndrome <b>s</b> as well as the seed used to generate the vector <b>h</b>
|
||||
*
|
||||
* @param[out] pk String containing the public key
|
||||
* @param[in] pk_seed Seed used to generate the public key
|
||||
* @param[in] s uint8_t representation of vector s
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_public_key_to_string(uint8_t *pk, const uint8_t *pk_seed, const uint8_t *s) {
|
||||
memcpy(pk, pk_seed, SEED_BYTES);
|
||||
memcpy(pk + SEED_BYTES, s, VEC_N_SIZE_BYTES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse a public key from a string
|
||||
*
|
||||
* The public key is composed of the syndrome <b>s</b> as well as the seed used to generate the vector <b>h</b>
|
||||
*
|
||||
* @param[out] h uint8_t representation of vector h
|
||||
* @param[out] s uint8_t representation of vector s
|
||||
* @param[in] pk String containing the public key
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_public_key_from_string(uint8_t *h, uint8_t *s, const uint8_t *pk) {
|
||||
AES_XOF_struct pk_seedexpander;
|
||||
uint8_t pk_seed[SEED_BYTES] = {0};
|
||||
|
||||
memcpy(pk_seed, pk, SEED_BYTES);
|
||||
seedexpander_init(&pk_seedexpander, pk_seed, pk_seed + 32, SEEDEXPANDER_MAX_LENGTH);
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_set_random(&pk_seedexpander, h);
|
||||
|
||||
memcpy(s, pk + SEED_BYTES, VEC_N_SIZE_BYTES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse a ciphertext into a string
|
||||
*
|
||||
* The ciphertext is composed of vectors <b>u</b>, <b>v</b> and hash <b>d</b>.
|
||||
*
|
||||
* @param[out] ct String containing the ciphertext
|
||||
* @param[in] u uint8_t representation of vector u
|
||||
* @param[in] v uint8_t representation of vector v
|
||||
* @param[in] d String containing the hash d
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_ciphertext_to_string(uint8_t *ct, const uint8_t *u, const uint8_t *v, const uint8_t *d) {
|
||||
memcpy(ct, u, VEC_N_SIZE_BYTES);
|
||||
memcpy(ct + VEC_N_SIZE_BYTES, v, VEC_N1N2_SIZE_BYTES);
|
||||
memcpy(ct + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, d, SHA512_BYTES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse a ciphertext from a string
|
||||
*
|
||||
* The ciphertext is composed of vectors <b>u</b>, <b>v</b> and hash <b>d</b>.
|
||||
*
|
||||
* @param[out] u uint8_t representation of vector u
|
||||
* @param[out] v uint8_t representation of vector v
|
||||
* @param[out] d String containing the hash d
|
||||
* @param[in] ct String containing the ciphertext
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_ciphertext_from_string(uint8_t *u, uint8_t *v, uint8_t *d, const uint8_t *ct) {
|
||||
memcpy(u, ct, VEC_N_SIZE_BYTES);
|
||||
memcpy(v, ct + VEC_N_SIZE_BYTES, VEC_N1N2_SIZE_BYTES);
|
||||
memcpy(d, ct + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, SHA512_BYTES);
|
||||
}
|
||||
20
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/parsing.h
Normal file
20
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/parsing.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef PQCLEAN_HQC1281CCA2_LEAKTIME_PARSING_H
|
||||
#define PQCLEAN_HQC1281CCA2_LEAKTIME_PARSING_H
|
||||
|
||||
/**
|
||||
* @file parsing.h
|
||||
* @brief Header file for parsing.c
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_secret_key_to_string(uint8_t *sk, const uint8_t *sk_seed, const uint8_t *pk);
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_secret_key_from_string(uint8_t *x, uint32_t *y, uint8_t *pk, const uint8_t *sk);
|
||||
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_public_key_to_string(uint8_t *pk, const uint8_t *pk_seed, const uint8_t *s);
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_public_key_from_string(uint8_t *h, uint8_t *s, const uint8_t *pk);
|
||||
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_ciphertext_to_string(uint8_t *ct, const uint8_t *u, const uint8_t *v, const uint8_t *d);
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_ciphertext_from_string(uint8_t *u, uint8_t *v, uint8_t *d, const uint8_t *ct);
|
||||
|
||||
#endif
|
||||
100
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/repetition.c
Normal file
100
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/repetition.c
Normal file
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @file repetition.c
|
||||
* @brief Implementation of repetition codes
|
||||
*/
|
||||
|
||||
#include "parameters.h"
|
||||
#include "repetition.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static void array_to_rep_codeword(uint8_t *o, const uint8_t *v);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encoding each bit in the message m using the repetition code
|
||||
*
|
||||
* For reasons of clarity and comprehensibility, we do the encoding by storing the encoded bits in a String (each bit in an a uint8_t),
|
||||
* then we parse the obtained string to an compact array using the function array_to_rep_codeword().
|
||||
*
|
||||
* @param[out] em Pointer to an array that is the code word
|
||||
* @param[in] m Pointer to an array that is the message
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_repetition_code_encode(uint8_t *em, const uint8_t *m) {
|
||||
uint8_t tmp[PARAM_N1N2] = {0};
|
||||
uint8_t bit = 0;
|
||||
uint32_t index;
|
||||
|
||||
for (size_t i = 0; i < (VEC_N1_SIZE_BYTES - 1); ++i) {
|
||||
for (uint8_t j = 0; j < 8; ++j) {
|
||||
bit = (m[i] >> j) & 0x01;
|
||||
index = (8 * (uint32_t)i + j) * PARAM_N2;
|
||||
for (uint8_t k = 0; k < PARAM_N2; ++k) {
|
||||
tmp[index + k] = bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t j = 0; j < (PARAM_N1 % 8); ++j) {
|
||||
bit = (m[VEC_N1_SIZE_BYTES - 1] >> j) & 0x01;
|
||||
index = (8 * (VEC_N1_SIZE_BYTES - 1) + j) * PARAM_N2;
|
||||
for (uint8_t k = 0; k < PARAM_N2; ++k) {
|
||||
tmp[index + k] = bit;
|
||||
}
|
||||
}
|
||||
|
||||
array_to_rep_codeword(em, tmp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Decoding the code words to a message using the repetition code
|
||||
*
|
||||
* We use a majority decoding. In fact we have that PARAM_N2 = 2 * PARAM_T + 1, thus,
|
||||
* if the Hamming weight of the vector is greater than PARAM_T, the code word is decoded
|
||||
* to 1 and 0 otherwise.
|
||||
*
|
||||
* @param[out] m Pointer to an array that is the message
|
||||
* @param[in] em Pointer to an array that is the code word
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_repetition_code_decode(uint8_t *m, const uint8_t *em) {
|
||||
size_t t = 0; // m index
|
||||
uint8_t k = PARAM_N2; // block counter
|
||||
uint8_t ones = 0; // number of 1 in the current block
|
||||
|
||||
for (size_t i = 0; i < VEC_N1N2_SIZE_BYTES; ++i) {
|
||||
for (uint8_t j = 0; j < 8; ++j) {
|
||||
ones += (em[i] >> j) & 0x01;
|
||||
|
||||
if (--k) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m[t / 8] |= (ones > PARAM_T) << t % 8;
|
||||
++t;
|
||||
k = PARAM_N2;
|
||||
ones = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse an array to an compact array
|
||||
*
|
||||
* @param[out] o Pointer to an array
|
||||
* @param[in] v Pointer to an array
|
||||
*/
|
||||
static void array_to_rep_codeword(uint8_t *o, const uint8_t *v) {
|
||||
for (size_t i = 0; i < (VEC_N1N2_SIZE_BYTES - 1); ++i) {
|
||||
for (uint8_t j = 0; j < 8; ++j) {
|
||||
o[i] |= v[j + 8 * i] << j;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t j = 0; j < PARAM_N1N2 % 8; ++j) {
|
||||
o[VEC_N1N2_SIZE_BYTES - 1] |= (v[j + 8 * (VEC_N1N2_SIZE_BYTES - 1)]) << j;
|
||||
}
|
||||
}
|
||||
14
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/repetition.h
Normal file
14
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/repetition.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef PQCLEAN_HQC1281CCA2_LEAKTIME_REPETITION_H
|
||||
#define PQCLEAN_HQC1281CCA2_LEAKTIME_REPETITION_H
|
||||
|
||||
/**
|
||||
* @file repetition.h
|
||||
* @brief Header file for repetition.c
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_repetition_code_encode(uint8_t *em, const uint8_t *m);
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_repetition_code_decode(uint8_t *m, const uint8_t *em);
|
||||
|
||||
#endif
|
||||
42
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/tensor.c
Normal file
42
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/tensor.c
Normal file
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @file tensor.c
|
||||
* @brief Implementation of tensor code
|
||||
*/
|
||||
|
||||
#include "bch.h"
|
||||
#include "parameters.h"
|
||||
#include "repetition.h"
|
||||
#include "tensor.h"
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encoding the message m to a code word em using the tensor code
|
||||
*
|
||||
* First we encode the message using the BCH code, then with the repetition code to obtain
|
||||
* a tensor code word.
|
||||
*
|
||||
* @param[out] em Pointer to an array that is the tensor code word
|
||||
* @param[in] m Pointer to an array that is the message
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_tensor_code_encode(uint8_t *em, const uint8_t *m) {
|
||||
uint8_t tmp[VEC_N1_SIZE_BYTES] = {0};
|
||||
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_bch_code_encode(tmp, m);
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_repetition_code_encode(em, tmp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Decoding the code word em to a message m using the tensor code
|
||||
*
|
||||
* @param[out] m Pointer to an array that is the message
|
||||
* @param[in] em Pointer to an array that is the code word
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_tensor_code_decode(uint8_t *m, const uint8_t *em) {
|
||||
uint8_t tmp[VEC_N1_SIZE_BYTES] = {0};
|
||||
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_repetition_code_decode(tmp, em);
|
||||
PQCLEAN_HQC1281CCA2_LEAKTIME_bch_code_decode(m, tmp);
|
||||
}
|
||||
14
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/tensor.h
Normal file
14
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/tensor.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef PQCLEAN_HQC1281CCA2_LEAKTIME_TENSOR_H
|
||||
#define PQCLEAN_HQC1281CCA2_LEAKTIME_TENSOR_H
|
||||
|
||||
/**
|
||||
* @file tensor.h
|
||||
* @brief Header file for tensor.c
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_tensor_code_encode(uint8_t *em, const uint8_t *m);
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_tensor_code_decode(uint8_t *m, const uint8_t *em);
|
||||
|
||||
#endif
|
||||
69
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/util.c
Normal file
69
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/util.c
Normal file
@ -0,0 +1,69 @@
|
||||
#include "util.h"
|
||||
#include "stddef.h"
|
||||
|
||||
#include "assert.h"
|
||||
|
||||
/* These functions should help with endianness-safe conversions
|
||||
*
|
||||
* load8 and store8 are copied from the McEliece implementations,
|
||||
* which are in the public domain.
|
||||
*/
|
||||
|
||||
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_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_HQC1281CCA2_LEAKTIME_load8(const unsigned char *in) {
|
||||
uint64_t ret = in[7];
|
||||
|
||||
for (int8_t i = 6; i >= 0; i--) {
|
||||
ret <<= 8;
|
||||
ret |= in[i];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_load8_arr(uint64_t *out64, size_t outlen, const uint8_t *in8, size_t inlen) {
|
||||
size_t index_in = 0;
|
||||
size_t index_out = 0;
|
||||
|
||||
// first copy by 8 bytes
|
||||
if (inlen >= 8 && outlen >= 1) {
|
||||
while (index_out < outlen && index_in + 8 <= inlen) {
|
||||
out64[index_out] = PQCLEAN_HQC1281CCA2_LEAKTIME_load8(in8 + index_in);
|
||||
|
||||
index_in += 8;
|
||||
index_out += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// we now need to do the last 7 bytes if necessary
|
||||
if (index_in >= inlen || index_out >= outlen) {
|
||||
return;
|
||||
}
|
||||
out64[index_out] = in8[inlen - 1];
|
||||
for (int8_t i = (int8_t)(inlen - index_in) - 2; i >= 0; i--) {
|
||||
out64[index_out] <<= 8;
|
||||
out64[index_out] |= in8[index_in + i];
|
||||
}
|
||||
}
|
||||
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_store8_arr(uint8_t *out8, size_t outlen, const uint64_t *in64, size_t inlen) {
|
||||
for (size_t index_out = 0, index_in = 0; index_out < outlen && index_in < inlen;) {
|
||||
out8[index_out] = (in64[index_in] >> ((index_out % 8) * 8)) & 0xFF;
|
||||
index_out++;
|
||||
if (index_out % 8 == 0) {
|
||||
index_in++;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/util.h
Normal file
9
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/util.h
Normal file
@ -0,0 +1,9 @@
|
||||
/* These functions should help with endianness-safe conversions */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_store8(unsigned char *out, uint64_t in);
|
||||
uint64_t PQCLEAN_HQC1281CCA2_LEAKTIME_load8(const unsigned char *in);
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_load8_arr(uint64_t *out64, size_t outlen, const uint8_t *in8, size_t inlen);
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_store8_arr(uint8_t *out8, size_t outlen, const uint64_t *in64, size_t inlen);
|
||||
224
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/vector.c
Normal file
224
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/vector.c
Normal file
@ -0,0 +1,224 @@
|
||||
/**
|
||||
* @file vector.c
|
||||
* @brief Implementation of vectors sampling and some utilities for the HQC scheme
|
||||
*/
|
||||
|
||||
#include "nistseedexpander.h"
|
||||
#include "parameters.h"
|
||||
#include "randombytes.h"
|
||||
#include "vector.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Generates a vector of a given Hamming weight
|
||||
*
|
||||
* This function generates uniformly at random a binary vector of a Hamming weight equal to the parameter <b>weight</b>. The vector
|
||||
* is stored by position.
|
||||
* To generate the vector we have to sample uniformly at random values in the interval [0, PARAM_N -1]. Suppose the PARAM_N is equal to \f$ 70853 \f$, to select a position \f$ r\f$ the function works as follow:
|
||||
* 1. It makes a call to the seedexpander function to obtain a random number \f$ x\f$ in \f$ [0, 2^{24}[ \f$.
|
||||
* 2. Let \f$ t = \lfloor {2^{24} \over 70853} \rfloor \times 70853\f$
|
||||
* 3. If \f$ x \geq t\f$, go to 1
|
||||
* 4. It return \f$ r = x \mod 70853\f$
|
||||
*
|
||||
* The parameter \f$ t \f$ is precomputed and it's denoted by UTILS_REJECTION_THRESHOLD (see the file parameters.h).
|
||||
*
|
||||
* @param[in] v Pointer to an array
|
||||
* @param[in] weight Integer that is the Hamming weight
|
||||
* @param[in] ctx Pointer to the context of the seed expander
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_vect_set_random_fixed_weight_by_coordinates(AES_XOF_struct *ctx, uint32_t *v, uint16_t weight) {
|
||||
size_t random_bytes_size = 3 * weight;
|
||||
uint8_t rand_bytes[3 * PARAM_OMEGA_R] = {0}; // weight is expected to be <= PARAM_OMEGA_R
|
||||
uint32_t random_data = 0;
|
||||
uint8_t exist = 0;
|
||||
size_t j = 0;
|
||||
|
||||
seedexpander(ctx, rand_bytes, random_bytes_size);
|
||||
|
||||
for (uint32_t i = 0; i < weight; ++i) {
|
||||
exist = 0;
|
||||
do {
|
||||
if (j == random_bytes_size) {
|
||||
seedexpander(ctx, rand_bytes, random_bytes_size);
|
||||
j = 0;
|
||||
}
|
||||
|
||||
random_data = ((uint32_t) rand_bytes[j++]) << 16;
|
||||
random_data |= ((uint32_t) rand_bytes[j++]) << 8;
|
||||
random_data |= rand_bytes[j++];
|
||||
|
||||
} while (random_data >= UTILS_REJECTION_THRESHOLD);
|
||||
|
||||
random_data = random_data % PARAM_N;
|
||||
|
||||
for (uint32_t k = 0; k < i; k++) {
|
||||
if (v[k] == random_data) {
|
||||
exist = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (exist == 1) {
|
||||
i--;
|
||||
} else {
|
||||
v[i] = random_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Generates a vector of a given Hamming weight
|
||||
*
|
||||
* This function generates uniformly at random a binary vector of a Hamming weight equal to the parameter <b>weight</b>.
|
||||
* To generate the vector we have to sample uniformly at random values in the interval [0, PARAM_N -1]. Suppose the PARAM_N is equal to \f$ 70853 \f$, to select a position \f$ r\f$ the function works as follow:
|
||||
* 1. It makes a call to the seedexpander function to obtain a random number \f$ x\f$ in \f$ [0, 2^{24}[ \f$.
|
||||
* 2. Let \f$ t = \lfloor {2^{24} \over 70853} \rfloor \times 70853\f$
|
||||
* 3. If \f$ x \geq t\f$, go to 1
|
||||
* 4. It return \f$ r = x \mod 70853\f$
|
||||
*
|
||||
* The parameter \f$ t \f$ is precomputed and it's denoted by UTILS_REJECTION_THRESHOLD (see the file parameters.h).
|
||||
*
|
||||
* @param[in] v Pointer to an array
|
||||
* @param[in] weight Integer that is the Hamming weight
|
||||
* @param[in] ctx Pointer to the context of the seed expander
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_vect_set_random_fixed_weight(AES_XOF_struct *ctx, uint8_t *v, uint16_t weight) {
|
||||
|
||||
size_t random_bytes_size = 3 * weight;
|
||||
uint8_t rand_bytes[3 * PARAM_OMEGA_R] = {0}; // weight is expected to be <= PARAM_OMEGA_R
|
||||
uint32_t random_data = 0;
|
||||
uint32_t tmp[PARAM_OMEGA_R] = {0};
|
||||
uint8_t exist = 0;
|
||||
size_t j = 0;
|
||||
|
||||
seedexpander(ctx, rand_bytes, random_bytes_size);
|
||||
|
||||
for (uint32_t i = 0; i < weight; ++i) {
|
||||
exist = 0;
|
||||
do {
|
||||
if (j == random_bytes_size) {
|
||||
seedexpander(ctx, rand_bytes, random_bytes_size);
|
||||
j = 0;
|
||||
}
|
||||
|
||||
random_data = ((uint32_t) rand_bytes[j++]) << 16;
|
||||
random_data |= ((uint32_t) rand_bytes[j++]) << 8;
|
||||
random_data |= rand_bytes[j++];
|
||||
|
||||
} while (random_data >= UTILS_REJECTION_THRESHOLD);
|
||||
|
||||
random_data = random_data % PARAM_N;
|
||||
|
||||
for (uint32_t k = 0; k < i; k++) {
|
||||
if (tmp[k] == random_data) {
|
||||
exist = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (exist == 1) {
|
||||
i--;
|
||||
} else {
|
||||
tmp[i] = random_data;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < weight; ++i) {
|
||||
int32_t index = tmp[i] / 8;
|
||||
int32_t pos = tmp[i] % 8;
|
||||
v[index] |= 1 << pos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Generates a random vector of dimension <b>PARAM_N</b>
|
||||
*
|
||||
* This function generates a random binary vector of dimension <b>PARAM_N</b>. It generates a random
|
||||
* array of bytes using the seedexpander function, and drop the extra bits using a mask.
|
||||
*
|
||||
* @param[in] v Pointer to an array
|
||||
* @param[in] ctx Pointer to the context of the seed expander
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_vect_set_random(AES_XOF_struct *ctx, uint8_t *v) {
|
||||
uint8_t rand_bytes[VEC_N_SIZE_BYTES] = {0};
|
||||
|
||||
seedexpander(ctx, rand_bytes, VEC_N_SIZE_BYTES);
|
||||
|
||||
memcpy(v, rand_bytes, VEC_N_SIZE_BYTES);
|
||||
v[VEC_N_SIZE_BYTES - 1] &= BITMASK(PARAM_N, 8);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Generates a random vector
|
||||
*
|
||||
* This function generates a random binary vector. It uses the the randombytes function.
|
||||
*
|
||||
* @param[in] v Pointer to an array
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_vect_set_random_from_randombytes(uint8_t *v) {
|
||||
uint8_t rand_bytes [VEC_K_SIZE_BYTES] = {0};
|
||||
|
||||
randombytes(rand_bytes, VEC_K_SIZE_BYTES);
|
||||
memcpy(v, rand_bytes, VEC_K_SIZE_BYTES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Adds two vectors
|
||||
*
|
||||
* @param[out] o Pointer to an array that is the result
|
||||
* @param[in] v1 Pointer to an array that is the first vector
|
||||
* @param[in] v2 Pointer to an array that is the second vector
|
||||
* @param[in] size Integer that is the size of the vectors
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_vect_add(uint8_t *o, const uint8_t *v1, const uint8_t *v2, uint32_t size) {
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
o[i] = v1[i] ^ v2[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Compares two vectors
|
||||
*
|
||||
* @param[in] v1 Pointer to an array that is first vector
|
||||
* @param[in] v2 Pointer to an array that is second vector
|
||||
* @param[in] size Integer that is the size of the vectors
|
||||
* @returns 0 if the vectors are equals and a negative/psotive value otherwise
|
||||
*/
|
||||
int PQCLEAN_HQC1281CCA2_LEAKTIME_vect_compare(const uint8_t *v1, const uint8_t *v2, uint32_t size) {
|
||||
return memcmp(v1, v2, size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Resize a vector so that it contains <b>size_o</b> bits
|
||||
*
|
||||
* @param[out] o Pointer to the output vector
|
||||
* @param[in] size_o Integer that is the size of the output vector in bits
|
||||
* @param[in] v Pointer to the input vector
|
||||
* @param[in] size_v Integer that is the size of the input vector in bits
|
||||
*/
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_vect_resize(uint8_t *o, uint32_t size_o, const uint8_t *v, uint32_t size_v) {
|
||||
if (size_o < size_v) {
|
||||
uint8_t mask = 0x7F;
|
||||
int8_t val = 8 - (size_o % 8);
|
||||
|
||||
memcpy(o, v, VEC_N1N2_SIZE_BYTES);
|
||||
|
||||
for (int8_t i = 0; i < val; ++i) {
|
||||
o[VEC_N1N2_SIZE_BYTES - 1] &= (mask >> i);
|
||||
}
|
||||
} else {
|
||||
memcpy(o, v, CEIL_DIVIDE(size_v, 8));
|
||||
}
|
||||
}
|
||||
22
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/vector.h
Normal file
22
src/kem/hqc/pqclean_hqc-128-1-cca2_leaktime/vector.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef PQCLEAN_HQC1281CCA2_LEAKTIME_VECTOR_H
|
||||
#define PQCLEAN_HQC1281CCA2_LEAKTIME_VECTOR_H
|
||||
|
||||
/**
|
||||
* @file vector.h
|
||||
* @brief Header file for vector.c
|
||||
*/
|
||||
|
||||
#include "nistseedexpander.h"
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_vect_set_random_fixed_weight_by_coordinates(AES_XOF_struct *ctx, uint32_t *v, uint16_t weight);
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_vect_set_random_fixed_weight(AES_XOF_struct *ctx, uint8_t *v, uint16_t weight);
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_vect_set_random(AES_XOF_struct *ctx, uint8_t *v);
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_vect_set_random_from_randombytes(uint8_t *v);
|
||||
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_vect_add(uint8_t *o, const uint8_t *v1, const uint8_t *v2, uint32_t size);
|
||||
int PQCLEAN_HQC1281CCA2_LEAKTIME_vect_compare(const uint8_t *v1, const uint8_t *v2, uint32_t size);
|
||||
|
||||
void PQCLEAN_HQC1281CCA2_LEAKTIME_vect_resize(uint8_t *o, uint32_t size_o, const uint8_t *v, uint32_t size_v);
|
||||
|
||||
#endif
|
||||
1
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/LICENSE
Normal file
1
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/LICENSE
Normal file
@ -0,0 +1 @@
|
||||
Public domain
|
||||
25
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/api.h
Normal file
25
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/api.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef PQCLEAN_HQC1921CCA2_LEAKTIME_API_H
|
||||
#define PQCLEAN_HQC1921CCA2_LEAKTIME_API_H
|
||||
|
||||
/**
|
||||
* \file api.h
|
||||
* \brief NIST KEM API used by the HQC_KEM IND-CCA2 scheme
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PQCLEAN_HQC1921CCA2_LEAKTIME_CRYPTO_ALGNAME "HQC_192_1_CCA2"
|
||||
|
||||
#define PQCLEAN_HQC1921CCA2_LEAKTIME_CRYPTO_SECRETKEYBYTES 5539
|
||||
#define PQCLEAN_HQC1921CCA2_LEAKTIME_CRYPTO_PUBLICKEYBYTES 5499
|
||||
#define PQCLEAN_HQC1921CCA2_LEAKTIME_CRYPTO_BYTES 64
|
||||
#define PQCLEAN_HQC1921CCA2_LEAKTIME_CRYPTO_CIPHERTEXTBYTES 10981
|
||||
|
||||
// As a technicality, the public key is appended to the secret key in order to respect the NIST API.
|
||||
// Without this constraint, CRYPTO_SECRETKEYBYTES would be defined as 32
|
||||
|
||||
int PQCLEAN_HQC1921CCA2_LEAKTIME_crypto_kem_keypair(uint8_t *pk, uint8_t *sk);
|
||||
int PQCLEAN_HQC1921CCA2_LEAKTIME_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
|
||||
int PQCLEAN_HQC1921CCA2_LEAKTIME_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
|
||||
|
||||
#endif
|
||||
295
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/bch.c
Normal file
295
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/bch.c
Normal file
@ -0,0 +1,295 @@
|
||||
/**
|
||||
* @file bch.c
|
||||
* Constant time implementation of BCH codes
|
||||
*/
|
||||
|
||||
#include "bch.h"
|
||||
#include "fft.h"
|
||||
#include "gf.h"
|
||||
#include "parameters.h"
|
||||
#include "vector.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
static void unpack_message(uint8_t *message_unpacked, const uint8_t *message);
|
||||
static void lfsr_encode(uint8_t *codeword, const uint8_t *message);
|
||||
static void pack_codeword(uint8_t *codeword, const uint8_t *codeword_unpacked);
|
||||
static size_t compute_elp(uint16_t *sigma, const uint16_t *syndromes);
|
||||
static void message_from_codeword(uint8_t *message, const uint8_t *codeword);
|
||||
static void compute_syndromes(uint16_t *syndromes, const uint8_t *vector);
|
||||
static void compute_roots(uint8_t *error, const uint16_t *sigma);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Unpacks the message message to the array message_unpacked where each byte stores a bit of the message
|
||||
*
|
||||
* @param[out] message_unpacked Array of VEC_K_SIZE_BYTES bytes receiving the unpacked message
|
||||
* @param[in] message Array of PARAM_K bytes storing the packed message
|
||||
*/
|
||||
static void unpack_message(uint8_t *message_unpacked, const uint8_t *message) {
|
||||
for (size_t i = 0; i < (VEC_K_SIZE_BYTES - (PARAM_K % 8 != 0)); ++i) {
|
||||
for (size_t j = 0; j < 8; ++j) {
|
||||
message_unpacked[j + 8 * i] = (message[i] >> j) & 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
for (int8_t j = 0; j < PARAM_K % 8; ++j) {
|
||||
message_unpacked[j + 8 * (VEC_K_SIZE_BYTES - 1)] = (message[VEC_K_SIZE_BYTES - 1] >> j) & 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encodes the message message to a codeword codeword using the generator polynomial bch_poly of the code
|
||||
*
|
||||
* @param[out] codeword Array of PARAM_N1 bytes receiving the codeword
|
||||
* @param[in] message Array of PARAM_K bytes storing the message to encode
|
||||
*/
|
||||
static void lfsr_encode(uint8_t *codeword, const uint8_t *message) {
|
||||
uint8_t gate_value = 0;
|
||||
uint8_t bch_poly[PARAM_G] = PARAM_BCH_POLY;
|
||||
|
||||
// Compute the Parity-check digits
|
||||
for (int16_t i = PARAM_K - 1; i >= 0; --i) {
|
||||
gate_value = message[i] ^ codeword[PARAM_N1 - PARAM_K - 1];
|
||||
|
||||
for (size_t j = PARAM_N1 - PARAM_K - 1; j; --j) {
|
||||
codeword[j] = codeword[j - 1] ^ (-gate_value & bch_poly[j]);
|
||||
}
|
||||
|
||||
codeword[0] = gate_value;
|
||||
}
|
||||
|
||||
// Add the message
|
||||
memcpy(codeword + PARAM_N1 - PARAM_K, message, PARAM_K);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Packs the codeword from an array codeword_unpacked where each byte stores a bit to a compact array codeword
|
||||
*
|
||||
* @param[out] codeword Array of VEC_N1_SIZE_BYTES bytes receiving the packed codeword
|
||||
* @param[in] codeword_unpacked Array of PARAM_N1 bytes storing the unpacked codeword
|
||||
*/
|
||||
static void pack_codeword(uint8_t *codeword, const uint8_t *codeword_unpacked) {
|
||||
for (size_t i = 0; i < (VEC_N1_SIZE_BYTES - (PARAM_N1 % 8 != 0)); ++i) {
|
||||
for (size_t j = 0; j < 8; ++j) {
|
||||
codeword[i] |= codeword_unpacked[j + 8 * i] << j;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < PARAM_N1 % 8; ++j) {
|
||||
codeword[VEC_N1_SIZE_BYTES - 1] |= codeword_unpacked[j + 8 * (VEC_N1_SIZE_BYTES - 1)] << j;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encodes a message message of PARAM_K bits to a BCH codeword codeword of PARAM_N1 bits
|
||||
*
|
||||
* Following @cite lin1983error (Chapter 4 - Cyclic Codes),
|
||||
* We perform a systematic encoding using a linear (PARAM_N1 - PARAM_K)-stage shift register
|
||||
* with feedback connections based on the generator polynomial bch_poly of the BCH code.
|
||||
*
|
||||
* @param[out] codeword Array of size VEC_N1_SIZE_BYTES receiving the encoded message
|
||||
* @param[in] message Array of size VEC_K_SIZE_BYTES storing the message
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_bch_code_encode(uint8_t *codeword, const uint8_t *message) {
|
||||
uint8_t message_unpacked[PARAM_K];
|
||||
uint8_t codeword_unpacked[PARAM_N1] = {0};
|
||||
|
||||
unpack_message(message_unpacked, message);
|
||||
lfsr_encode(codeword_unpacked, message_unpacked);
|
||||
pack_codeword(codeword, codeword_unpacked);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the error locator polynomial (ELP) sigma
|
||||
*
|
||||
* This is a constant time implementation of Berlekamp's simplified algorithm (see @cite joiner1995decoding). <br>
|
||||
* We use the letter p for rho which is initialized at -1/2. <br>
|
||||
* The array X_sigma_p represents the polynomial X^(2(mu-rho))*sigma_p(X). <br>
|
||||
* Instead of maintaining a list of sigmas, we update in place both sigma and X_sigma_p. <br>
|
||||
* sigma_copy serves as a temporary save of sigma in case X_sigma_p needs to be updated. <br>
|
||||
* We can properly correct only if the degree of sigma does not exceed PARAM_DELTA.
|
||||
* This means only the first PARAM_DELTA + 1 coefficients of sigma are of value
|
||||
* and we only need to save its first PARAM_DELTA - 1 coefficients.
|
||||
*
|
||||
* @returns the degree of the ELP sigma
|
||||
* @param[out] sigma Array of size (at least) PARAM_DELTA receiving the ELP
|
||||
* @param[in] syndromes Array of size (at least) 2*PARAM_DELTA storing the syndromes
|
||||
*/
|
||||
static size_t compute_elp(uint16_t *sigma, const uint16_t *syndromes) {
|
||||
sigma[0] = 1;
|
||||
size_t deg_sigma = 0;
|
||||
size_t deg_sigma_p = 0;
|
||||
uint16_t sigma_copy[PARAM_DELTA - 1] = {0};
|
||||
size_t deg_sigma_copy = 0;
|
||||
uint16_t X_sigma_p[PARAM_DELTA + 1] = {0, 1};
|
||||
int32_t pp = -1; // 2*rho
|
||||
uint16_t d_p = 1;
|
||||
uint16_t d = syndromes[0];
|
||||
|
||||
for (size_t mu = 0; mu < PARAM_DELTA; ++mu) {
|
||||
// Save sigma in case we need it to update X_sigma_p
|
||||
memcpy(sigma_copy, sigma, 2 * (PARAM_DELTA - 1));
|
||||
deg_sigma_copy = deg_sigma;
|
||||
|
||||
uint16_t dd = PQCLEAN_HQC1921CCA2_LEAKTIME_gf_mul(d, PQCLEAN_HQC1921CCA2_LEAKTIME_gf_inverse(d_p)); // 0 if(d == 0)
|
||||
for (size_t i = 1; (i <= 2 * mu + 1) && (i <= PARAM_DELTA); ++i) {
|
||||
sigma[i] ^= PQCLEAN_HQC1921CCA2_LEAKTIME_gf_mul(dd, X_sigma_p[i]);
|
||||
}
|
||||
|
||||
size_t deg_X = 2 * mu - pp; // 2*(mu-rho)
|
||||
size_t deg_X_sigma_p = deg_X + deg_sigma_p;
|
||||
|
||||
// mask1 = 0xffff if(d != 0) and 0 otherwise
|
||||
int16_t mask1 = -((uint16_t) - d >> 15);
|
||||
|
||||
// mask2 = 0xffff if(deg_X_sigma_p > deg_sigma) and 0 otherwise
|
||||
int16_t mask2 = -((uint16_t) (deg_sigma - deg_X_sigma_p) >> 15);
|
||||
|
||||
// mask12 = 0xffff if the deg_sigma increased and 0 otherwise
|
||||
int16_t mask12 = mask1 & mask2;
|
||||
deg_sigma = (mask12 & deg_X_sigma_p) ^ (~mask12 & deg_sigma);
|
||||
|
||||
if (mu == PARAM_DELTA - 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Update pp, d_p and X_sigma_p if needed
|
||||
pp = (mask12 & (2 * mu)) ^ (~mask12 & pp);
|
||||
d_p = (mask12 & d) ^ (~mask12 & d_p);
|
||||
for (size_t i = PARAM_DELTA - 1; i; --i) {
|
||||
X_sigma_p[i + 1] = (mask12 & sigma_copy[i - 1]) ^ (~mask12 & X_sigma_p[i - 1]);
|
||||
}
|
||||
X_sigma_p[1] = 0;
|
||||
X_sigma_p[0] = 0;
|
||||
deg_sigma_p = (mask12 & deg_sigma_copy) ^ (~mask12 & deg_sigma_p);
|
||||
|
||||
// Compute the next discrepancy
|
||||
d = syndromes[2 * mu + 2];
|
||||
for (size_t i = 1; (i <= 2 * mu + 1) && (i <= PARAM_DELTA); ++i) {
|
||||
d ^= PQCLEAN_HQC1921CCA2_LEAKTIME_gf_mul(sigma[i], syndromes[2 * mu + 2 - i]);
|
||||
}
|
||||
}
|
||||
|
||||
return deg_sigma;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieves the message message from the codeword codeword
|
||||
*
|
||||
* Since we performed a systematic encoding, the message is the last PARAM_K bits of the codeword.
|
||||
*
|
||||
* @param[out] message Array of size VEC_K_SIZE_BYTES receiving the message
|
||||
* @param[in] codeword Array of size VEC_N1_SIZE_BYTES storing the codeword
|
||||
*/
|
||||
static void message_from_codeword(uint8_t *message, const uint8_t *codeword) {
|
||||
int32_t val = PARAM_N1 - PARAM_K;
|
||||
|
||||
uint8_t mask1 = 0xff << val % 8;
|
||||
uint8_t mask2 = 0xff >> (8 - val % 8);
|
||||
size_t index = val / 8;
|
||||
|
||||
for (size_t i = 0; i < VEC_K_SIZE_BYTES - 1; ++i) {
|
||||
uint8_t message1 = (codeword[index] & mask1) >> val % 8;
|
||||
uint8_t message2 = (codeword[++index] & mask2) << (8 - val % 8);
|
||||
message[i] = message1 | message2;
|
||||
}
|
||||
|
||||
// Last byte (8-val % 8 is the number of bits given by message1)
|
||||
if ((PARAM_K % 8 == 0) || (8 - val % 8 < PARAM_K % 8)) {
|
||||
uint8_t message1 = (codeword[index] & mask1) >> val % 8;
|
||||
uint8_t message2 = (codeword[++index] & mask2) << (8 - val % 8);
|
||||
message[VEC_K_SIZE_BYTES - 1] = message1 | message2;
|
||||
} else {
|
||||
uint8_t message1 = (codeword[index] & mask1) >> val % 8;
|
||||
message[VEC_K_SIZE_BYTES - 1] = message1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the 2^PARAM_DELTA syndromes from the received vector vector
|
||||
*
|
||||
* Syndromes are the sum of powers of alpha weighted by vector's coefficients.
|
||||
* To do so, we use the additive FFT transpose, which takes as input a family w of GF(2^PARAM_M) elements
|
||||
* and outputs the weighted power sums of these w. <br>
|
||||
* Therefore, this requires twisting and applying a permutation before feeding vector to the fft transpose. <br>
|
||||
* For more details see Berstein, Chou and Schawbe's explanations:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*
|
||||
* @param[out] syndromes Array of size 2^(PARAM_FFT_T) receiving the 2*PARAM_DELTA syndromes
|
||||
* @param[in] vector Array of size VEC_N1_SIZE_BYTES storing the received word
|
||||
*/
|
||||
static void compute_syndromes(uint16_t *syndromes, const uint8_t *vector) {
|
||||
uint16_t w[1 << PARAM_M];
|
||||
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_fft_t_preprocess_bch_codeword(w, vector);
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_fft_t(syndromes, w, 2 * PARAM_DELTA);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the error polynomial error from the error locator polynomial sigma
|
||||
*
|
||||
* See function fft for more details.
|
||||
*
|
||||
* @param[out] err Array of VEC_N1_SIZE_BYTES elements receiving the error polynomial
|
||||
* @param[in] sigma Array of 2^PARAM_FFT elements storing the error locator polynomial
|
||||
*/
|
||||
static void compute_roots(uint8_t *error, const uint16_t *sigma) {
|
||||
uint16_t w[1 << PARAM_M] = {0}; // w will receive the evaluation of sigma in all field elements
|
||||
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_fft(w, sigma, PARAM_DELTA + 1);
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_fft_retrieve_bch_error_poly(error, w);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Decodes the received word
|
||||
*
|
||||
* This function relies on four steps:
|
||||
* <ol>
|
||||
* <li> The first step, done by additive FFT transpose, is the computation of the 2*PARAM_DELTA syndromes.
|
||||
* <li> The second step is the computation of the error-locator polynomial sigma.
|
||||
* <li> The third step, done by additive FFT, is finding the error-locator numbers by calculating the roots of the polynomial sigma and takings their inverses.
|
||||
* <li> The fourth step is the correction of the errors in the received polynomial.
|
||||
* </ol>
|
||||
* For a more complete picture on BCH decoding, see Shu. Lin and Daniel J. Costello in Error Control Coding: Fundamentals and Applications @cite lin1983error
|
||||
*
|
||||
* @param[out] message Array of size VEC_K_SIZE_BYTES receiving the decoded message
|
||||
* @param[in] vector Array of size VEC_N1_SIZE_BYTES storing the received word
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_bch_code_decode(uint8_t *message, uint8_t *vector) {
|
||||
uint16_t syndromes[1 << PARAM_FFT_T];
|
||||
uint16_t sigma[1 << PARAM_FFT] = {0};
|
||||
uint8_t error[(1 << PARAM_M) / 8] = {0};
|
||||
|
||||
// Calculate the 2*PARAM_DELTA syndromes
|
||||
compute_syndromes(syndromes, vector);
|
||||
|
||||
// Compute the error locator polynomial sigma
|
||||
// Sigma's degree is at most PARAM_DELTA but the FFT requires the extra room
|
||||
compute_elp(sigma, syndromes);
|
||||
|
||||
// Compute the error polynomial error
|
||||
compute_roots(error, sigma);
|
||||
|
||||
// Add the error polynomial to the received polynomial
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_add(vector, vector, error, VEC_N1_SIZE_BYTES);
|
||||
|
||||
// Retrieve the message from the decoded codeword
|
||||
message_from_codeword(message, vector);
|
||||
}
|
||||
16
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/bch.h
Normal file
16
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/bch.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef PQCLEAN_HQC1921CCA2_LEAKTIME_BCH_H
|
||||
#define PQCLEAN_HQC1921CCA2_LEAKTIME_BCH_H
|
||||
|
||||
/**
|
||||
* @file bch.h
|
||||
* Header file of bch.c
|
||||
*/
|
||||
|
||||
#include "parameters.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_bch_code_encode(uint8_t *codeword, const uint8_t *message);
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_bch_code_decode(uint8_t *message, uint8_t *vector);
|
||||
|
||||
#endif
|
||||
628
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/fft.c
Normal file
628
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/fft.c
Normal file
@ -0,0 +1,628 @@
|
||||
/**
|
||||
* @file fft.c
|
||||
* Implementation of the additive FFT and its transpose.
|
||||
* This implementation is based on the paper from Gao and Mateer: <br>
|
||||
* Shuhong Gao and Todd Mateer, Additive Fast Fourier Transforms over Finite Fields,
|
||||
* IEEE Transactions on Information Theory 56 (2010), 6265--6272.
|
||||
* http://www.math.clemson.edu/~sgao/papers/GM10.pdf <br>
|
||||
* and includes improvements proposed by Bernstein, Chou and Schwabe here:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*/
|
||||
|
||||
#include "fft.h"
|
||||
#include "gf.h"
|
||||
#include "parameters.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
static void compute_fft_betas(uint16_t *betas);
|
||||
static void compute_subset_sums(uint16_t *subset_sums, const uint16_t *set, size_t set_size);
|
||||
static void radix_t(uint16_t *f, const uint16_t *f0, const uint16_t *f1, uint32_t m_f);
|
||||
static void fft_t_rec(uint16_t *f, const uint16_t *w, size_t f_coeffs, uint8_t m, uint32_t m_f, const uint16_t *betas);
|
||||
static void radix(uint16_t *f0, uint16_t *f1, const uint16_t *f, uint32_t m_f);
|
||||
static void fft_rec(uint16_t *w, uint16_t *f, size_t f_coeffs, uint8_t m, uint32_t m_f, const uint16_t *betas);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the basis of betas (omitting 1) used in the additive FFT and its transpose
|
||||
*
|
||||
* @param[out] betas Array of size PARAM_M-1
|
||||
*/
|
||||
static void compute_fft_betas(uint16_t *betas) {
|
||||
for (size_t i = 0; i < PARAM_M - 1; ++i) {
|
||||
betas[i] = 1 << (PARAM_M - 1 - i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the subset sums of the given set
|
||||
*
|
||||
* The array subset_sums is such that its ith element is
|
||||
* the subset sum of the set elements given by the binary form of i.
|
||||
*
|
||||
* @param[out] subset_sums Array of size 2^set_size receiving the subset sums
|
||||
* @param[in] set Array of set_size elements
|
||||
* @param[in] set_size Size of the array set
|
||||
*/
|
||||
static void compute_subset_sums(uint16_t *subset_sums, const uint16_t *set, size_t set_size) {
|
||||
subset_sums[0] = 0;
|
||||
|
||||
for (size_t i = 0; i < set_size; ++i) {
|
||||
for (size_t j = 0; j < (((size_t)1) << i); ++j) {
|
||||
subset_sums[(((size_t)1) << i) + j] = set[i] ^ subset_sums[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Transpose of the linear radix conversion
|
||||
*
|
||||
* This is a direct transposition of the radix function
|
||||
* implemented following the process of transposing a linear function as exposed by Bernstein, Chou and Schwabe here:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*
|
||||
* @param[out] f Array of size a power of 2
|
||||
* @param[in] f0 Array half the size of f
|
||||
* @param[in] f1 Array half the size of f
|
||||
* @param[in] m_f 2^{m_f} is the smallest power of 2 greater or equal to the number of coefficients of f
|
||||
*/
|
||||
static void radix_t(uint16_t *f, const uint16_t *f0, const uint16_t *f1, uint32_t m_f) {
|
||||
switch (m_f) {
|
||||
case 4:
|
||||
f[0] = f0[0];
|
||||
f[1] = f1[0];
|
||||
f[2] = f0[1] ^ f1[0];
|
||||
f[3] = f[2] ^ f1[1];
|
||||
f[4] = f[2] ^ f0[2];
|
||||
f[5] = f[3] ^ f1[2];
|
||||
f[6] = f[4] ^ f0[3] ^ f1[2];
|
||||
f[7] = f[3] ^ f0[3] ^ f1[3];
|
||||
f[8] = f[4] ^ f0[4];
|
||||
f[9] = f[5] ^ f1[4];
|
||||
f[10] = f[6] ^ f0[5] ^ f1[4];
|
||||
f[11] = f[7] ^ f0[5] ^ f1[4] ^ f1[5];
|
||||
f[12] = f[8] ^ f0[5] ^ f0[6] ^ f1[4];
|
||||
f[13] = f[7] ^ f[9] ^ f[11] ^ f1[6];
|
||||
f[14] = f[6] ^ f0[6] ^ f0[7] ^ f1[6];
|
||||
f[15] = f[7] ^ f0[7] ^ f1[7];
|
||||
return;
|
||||
|
||||
case 3:
|
||||
f[0] = f0[0];
|
||||
f[1] = f1[0];
|
||||
f[2] = f0[1] ^ f1[0];
|
||||
f[3] = f[2] ^ f1[1];
|
||||
f[4] = f[2] ^ f0[2];
|
||||
f[5] = f[3] ^ f1[2];
|
||||
f[6] = f[4] ^ f0[3] ^ f1[2];
|
||||
f[7] = f[3] ^ f0[3] ^ f1[3];
|
||||
return;
|
||||
|
||||
case 2:
|
||||
f[0] = f0[0];
|
||||
f[1] = f1[0];
|
||||
f[2] = f0[1] ^ f1[0];
|
||||
f[3] = f[2] ^ f1[1];
|
||||
return;
|
||||
|
||||
case 1:
|
||||
f[0] = f0[0];
|
||||
f[1] = f1[0];
|
||||
return;
|
||||
|
||||
default:
|
||||
;
|
||||
|
||||
size_t n = ((size_t)1) << (m_f - 2);
|
||||
|
||||
uint16_t Q0[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t Q1[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t R0[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t R1[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
|
||||
uint16_t Q[1 << 2 * (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t R[1 << 2 * (PARAM_FFT_T - 2)] = {0};
|
||||
|
||||
memcpy(Q0, f0 + n, 2 * n);
|
||||
memcpy(Q1, f1 + n, 2 * n);
|
||||
memcpy(R0, f0, 2 * n);
|
||||
memcpy(R1, f1, 2 * n);
|
||||
|
||||
radix_t (Q, Q0, Q1, m_f - 1);
|
||||
radix_t (R, R0, R1, m_f - 1);
|
||||
|
||||
memcpy(f, R, 4 * n);
|
||||
memcpy(f + 2 * n, R + n, 2 * n);
|
||||
memcpy(f + 3 * n, Q + n, 2 * n);
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
f[2 * n + i] ^= Q[i];
|
||||
f[3 * n + i] ^= f[2 * n + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Recursively computes syndromes of family w
|
||||
*
|
||||
* This function is a subroutine of the function fft_t
|
||||
*
|
||||
* @param[out] f Array receiving the syndromes
|
||||
* @param[in] w Array storing the family
|
||||
* @param[in] f_coeffs Length of syndromes vector
|
||||
* @param[in] m 2^m is the smallest power of 2 greater or equal to the length of family w
|
||||
* @param[in] m_f 2^{m_f} is the smallest power of 2 greater or equal to the length of f
|
||||
* @param[in] betas FFT constants
|
||||
*/
|
||||
static void fft_t_rec(uint16_t *f, const uint16_t *w, size_t f_coeffs,
|
||||
uint8_t m, uint32_t m_f, const uint16_t *betas) {
|
||||
size_t k = ((size_t)1) << (m - 1);
|
||||
uint16_t gammas[PARAM_M - 2] = {0};
|
||||
uint16_t deltas[PARAM_M - 2] = {0};
|
||||
uint16_t gammas_sums[1 << (PARAM_M - 1)];
|
||||
uint16_t u[1 << (PARAM_M - 2)] = {0};
|
||||
uint16_t f0[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t f1[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t betas_sums[1 << (PARAM_M - 1)] = {0};
|
||||
|
||||
// Step 1
|
||||
if (m_f == 1) {
|
||||
for (size_t i = 0; i < (((size_t)1) << m); ++i) {
|
||||
f[0] ^= w[i];
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < m; ++j) {
|
||||
for (size_t ki = 0; ki < (((size_t)1) << j); ++ki) {
|
||||
size_t index = (((size_t)1) << j) + ki;
|
||||
betas_sums[index] = betas_sums[ki] ^ betas[j];
|
||||
f[1] ^= PQCLEAN_HQC1921CCA2_LEAKTIME_gf_mul(betas_sums[index], w[index]);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute gammas and deltas
|
||||
for (uint8_t i = 0; i < m - 1; ++i) {
|
||||
gammas[i] = PQCLEAN_HQC1921CCA2_LEAKTIME_gf_mul(betas[i], PQCLEAN_HQC1921CCA2_LEAKTIME_gf_inverse(betas[m - 1]));
|
||||
deltas[i] = PQCLEAN_HQC1921CCA2_LEAKTIME_gf_square(gammas[i]) ^ gammas[i];
|
||||
}
|
||||
|
||||
// Compute gammas subset sums
|
||||
compute_subset_sums(gammas_sums, gammas, m - 1);
|
||||
|
||||
/* Step 6: Compute u and v from w (aka w)
|
||||
* w[i] = u[i] + G[i].v[i]
|
||||
* w[k+i] = w[i] + v[i] = u[i] + (G[i]+1).v[i]
|
||||
* Transpose:
|
||||
* u[i] = w[i] + w[k+i]
|
||||
* v[i] = G[i].w[i] + (G[i]+1).w[k+i] = G[i].u[i] + w[k+i] */
|
||||
if (f_coeffs <= 3) { // 3-coefficient polynomial f case
|
||||
// Step 5: Compute f0 from u and f1 from v
|
||||
f1[1] = 0;
|
||||
u[0] = w[0] ^ w[k];
|
||||
f1[0] = w[k];
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
u[i] = w[i] ^ w[k + i];
|
||||
f1[0] ^= PQCLEAN_HQC1921CCA2_LEAKTIME_gf_mul(gammas_sums[i], u[i]) ^ w[k + i];
|
||||
}
|
||||
fft_t_rec(f0, u, (f_coeffs + 1) / 2, m - 1, m_f - 1, deltas);
|
||||
} else {
|
||||
uint16_t v[1 << (PARAM_M - 2)] = {0};
|
||||
|
||||
u[0] = w[0] ^ w[k];
|
||||
v[0] = w[k];
|
||||
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
u[i] = w[i] ^ w[k + i];
|
||||
v[i] = PQCLEAN_HQC1921CCA2_LEAKTIME_gf_mul(gammas_sums[i], u[i]) ^ w[k + i];
|
||||
}
|
||||
|
||||
// Step 5: Compute f0 from u and f1 from v
|
||||
fft_t_rec(f0, u, (f_coeffs + 1) / 2, m - 1, m_f - 1, deltas);
|
||||
fft_t_rec(f1, v, f_coeffs / 2, m - 1, m_f - 1, deltas);
|
||||
}
|
||||
|
||||
// Step 3: Compute g from g0 and g1
|
||||
radix_t(f, f0, f1, m_f);
|
||||
|
||||
// Step 2: compute f from g
|
||||
if (betas[m - 1] != 1) {
|
||||
uint16_t beta_m_pow = 1;
|
||||
for (size_t i = 1; i < (((size_t)1) << m_f); ++i) {
|
||||
beta_m_pow = PQCLEAN_HQC1921CCA2_LEAKTIME_gf_mul(beta_m_pow, betas[m - 1]);
|
||||
f[i] = PQCLEAN_HQC1921CCA2_LEAKTIME_gf_mul(beta_m_pow, f[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the syndromes f of the family w
|
||||
*
|
||||
* Since the syndromes linear map is the transpose of multipoint evaluation,
|
||||
* it uses exactly the same constants, either hardcoded or precomputed by compute_fft_lut(...). <br>
|
||||
* This follows directives from Bernstein, Chou and Schwabe given here:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*
|
||||
* @param[out] f Array of size 2*(PARAM_FFT_T) elements receiving the syndromes
|
||||
* @param[in] w Array of PARAM_GF_MUL_ORDER+1 elements
|
||||
* @param[in] f_coeffs Length of syndromes vector f
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_fft_t(uint16_t *f, const uint16_t *w, size_t f_coeffs) {
|
||||
// Transposed from Gao and Mateer algorithm
|
||||
uint16_t betas[PARAM_M - 1];
|
||||
uint16_t betas_sums[1 << (PARAM_M - 1)];
|
||||
size_t k = 1 << (PARAM_M - 1);
|
||||
uint16_t u[1 << (PARAM_M - 1)] = {0};
|
||||
uint16_t v[1 << (PARAM_M - 1)] = {0};
|
||||
uint16_t deltas[PARAM_M - 1];
|
||||
uint16_t f0[1 << (PARAM_FFT_T - 1)];
|
||||
uint16_t f1[1 << (PARAM_FFT_T - 1)];
|
||||
|
||||
compute_fft_betas(betas);
|
||||
compute_subset_sums(betas_sums, betas, PARAM_M - 1);
|
||||
|
||||
/* Step 6: Compute u and v from w (aka w)
|
||||
*
|
||||
* We had:
|
||||
* w[i] = u[i] + G[i].v[i]
|
||||
* w[k+i] = w[i] + v[i] = u[i] + (G[i]+1).v[i]
|
||||
* Transpose:
|
||||
* u[i] = w[i] + w[k+i]
|
||||
* v[i] = G[i].w[i] + (G[i]+1).w[k+i] = G[i].u[i] + w[k+i] */
|
||||
u[0] = w[0] ^ w[k];
|
||||
v[0] = w[k];
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
u[i] = w[i] ^ w[k + i];
|
||||
v[i] = PQCLEAN_HQC1921CCA2_LEAKTIME_gf_mul(betas_sums[i], u[i]) ^ w[k + i];
|
||||
}
|
||||
|
||||
// Compute deltas
|
||||
for (size_t i = 0; i < PARAM_M - 1; ++i) {
|
||||
deltas[i] = PQCLEAN_HQC1921CCA2_LEAKTIME_gf_square(betas[i]) ^ betas[i];
|
||||
}
|
||||
|
||||
// Step 5: Compute f0 from u and f1 from v
|
||||
fft_t_rec(f0, u, (f_coeffs + 1) / 2, PARAM_M - 1, PARAM_FFT_T - 1, deltas);
|
||||
fft_t_rec(f1, v, f_coeffs / 2, PARAM_M - 1, PARAM_FFT_T - 1, deltas);
|
||||
|
||||
// Step 3: Compute g from g0 and g1
|
||||
radix_t(f, f0, f1, PARAM_FFT_T);
|
||||
|
||||
// Step 2: beta_m = 1 so f = g
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the radix conversion of a polynomial f in GF(2^m)[x]
|
||||
*
|
||||
* Computes f0 and f1 such that f(x) = f0(x^2-x) + x.f1(x^2-x)
|
||||
* as proposed by Bernstein, Chou and Schwabe:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*
|
||||
* @param[out] f0 Array half the size of f
|
||||
* @param[out] f1 Array half the size of f
|
||||
* @param[in] f Array of size a power of 2
|
||||
* @param[in] m_f 2^{m_f} is the smallest power of 2 greater or equal to the number of coefficients of f
|
||||
*/
|
||||
static void radix(uint16_t *f0, uint16_t *f1, const uint16_t *f, uint32_t m_f) {
|
||||
switch (m_f) {
|
||||
case 4:
|
||||
f0[4] = f[8] ^ f[12];
|
||||
f0[6] = f[12] ^ f[14];
|
||||
f0[7] = f[14] ^ f[15];
|
||||
f1[5] = f[11] ^ f[13];
|
||||
f1[6] = f[13] ^ f[14];
|
||||
f1[7] = f[15];
|
||||
f0[5] = f[10] ^ f[12] ^ f1[5];
|
||||
f1[4] = f[9] ^ f[13] ^ f0[5];
|
||||
|
||||
f0[0] = f[0];
|
||||
f1[3] = f[7] ^ f[11] ^ f[15];
|
||||
f0[3] = f[6] ^ f[10] ^ f[14] ^ f1[3];
|
||||
f0[2] = f[4] ^ f0[4] ^ f0[3] ^ f1[3];
|
||||
f1[1] = f[3] ^ f[5] ^ f[9] ^ f[13] ^ f1[3];
|
||||
f1[2] = f[3] ^ f1[1] ^ f0[3];
|
||||
f0[1] = f[2] ^ f0[2] ^ f1[1];
|
||||
f1[0] = f[1] ^ f0[1];
|
||||
return;
|
||||
|
||||
case 3:
|
||||
f0[0] = f[0];
|
||||
f0[2] = f[4] ^ f[6];
|
||||
f0[3] = f[6] ^ f[7];
|
||||
f1[1] = f[3] ^ f[5] ^ f[7];
|
||||
f1[2] = f[5] ^ f[6];
|
||||
f1[3] = f[7];
|
||||
f0[1] = f[2] ^ f0[2] ^ f1[1];
|
||||
f1[0] = f[1] ^ f0[1];
|
||||
return;
|
||||
|
||||
case 2:
|
||||
f0[0] = f[0];
|
||||
f0[1] = f[2] ^ f[3];
|
||||
f1[0] = f[1] ^ f0[1];
|
||||
f1[1] = f[3];
|
||||
return;
|
||||
|
||||
case 1:
|
||||
f0[0] = f[0];
|
||||
f1[0] = f[1];
|
||||
return;
|
||||
|
||||
default:
|
||||
;
|
||||
size_t n = ((size_t)1) << (m_f - 2);
|
||||
|
||||
uint16_t Q[2 * (1 << (PARAM_FFT - 2))];
|
||||
uint16_t R[2 * (1 << (PARAM_FFT - 2))];
|
||||
|
||||
uint16_t Q0[1 << (PARAM_FFT - 2)];
|
||||
uint16_t Q1[1 << (PARAM_FFT - 2)];
|
||||
uint16_t R0[1 << (PARAM_FFT - 2)];
|
||||
uint16_t R1[1 << (PARAM_FFT - 2)];
|
||||
|
||||
memcpy(Q, f + 3 * n, 2 * n);
|
||||
memcpy(Q + n, f + 3 * n, 2 * n);
|
||||
memcpy(R, f, 4 * n);
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
Q[i] ^= f[2 * n + i];
|
||||
R[n + i] ^= Q[i];
|
||||
}
|
||||
|
||||
radix(Q0, Q1, Q, m_f - 1);
|
||||
radix(R0, R1, R, m_f - 1);
|
||||
|
||||
memcpy(f0, R0, 2 * n);
|
||||
memcpy(f0 + n, Q0, 2 * n);
|
||||
memcpy(f1, R1, 2 * n);
|
||||
memcpy(f1 + n, Q1, 2 * n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Evaluates f at all subset sums of a given set
|
||||
*
|
||||
* This function is a subroutine of the function fft.
|
||||
*
|
||||
* @param[out] w Array
|
||||
* @param[in] f Array
|
||||
* @param[in] f_coeffs Number of coefficients of f
|
||||
* @param[in] m Number of betas
|
||||
* @param[in] m_f Number of coefficients of f (one more than its degree)
|
||||
* @param[in] betas FFT constants
|
||||
*/
|
||||
static void fft_rec(uint16_t *w, uint16_t *f, size_t f_coeffs,
|
||||
uint8_t m, uint32_t m_f, const uint16_t *betas) {
|
||||
|
||||
uint16_t f0[1 << (PARAM_FFT - 2)] = {0};
|
||||
uint16_t f1[1 << (PARAM_FFT - 2)] = {0};
|
||||
uint16_t gammas[PARAM_M - 2] = {0};
|
||||
uint16_t deltas[PARAM_M - 2] = {0};
|
||||
size_t k = ((size_t)1) << (m - 1);
|
||||
uint16_t gammas_sums[1 << (PARAM_M - 2)] = {0};
|
||||
uint16_t u[1 << (PARAM_M - 2)] = {0};
|
||||
uint16_t v[1 << (PARAM_M - 2)] = {0};
|
||||
|
||||
// Step 1
|
||||
if (m_f == 1) {
|
||||
uint16_t tmp[PARAM_M - (PARAM_FFT - 1)];
|
||||
for (size_t i = 0; i < m; ++i) {
|
||||
tmp[i] = PQCLEAN_HQC1921CCA2_LEAKTIME_gf_mul(betas[i], f[1]);
|
||||
}
|
||||
|
||||
w[0] = f[0];
|
||||
for (size_t j = 0; j < m; ++j) {
|
||||
for (size_t ki = 0; ki < (((size_t)1) << j); ++ki) {
|
||||
w[(((size_t)1) << j) + ki] = w[ki] ^ tmp[j];
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2: compute g
|
||||
if (betas[m - 1] != 1) {
|
||||
uint16_t beta_m_pow = 1;
|
||||
for (size_t i = 1; i < (((size_t)1) << m_f); ++i) {
|
||||
beta_m_pow = PQCLEAN_HQC1921CCA2_LEAKTIME_gf_mul(beta_m_pow, betas[m - 1]);
|
||||
f[i] = PQCLEAN_HQC1921CCA2_LEAKTIME_gf_mul(beta_m_pow, f[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3
|
||||
radix(f0, f1, f, m_f);
|
||||
|
||||
// Step 4: compute gammas and deltas
|
||||
for (uint8_t i = 0; i < m - 1; ++i) {
|
||||
gammas[i] = PQCLEAN_HQC1921CCA2_LEAKTIME_gf_mul(betas[i], PQCLEAN_HQC1921CCA2_LEAKTIME_gf_inverse(betas[m - 1]));
|
||||
deltas[i] = PQCLEAN_HQC1921CCA2_LEAKTIME_gf_square(gammas[i]) ^ gammas[i];
|
||||
}
|
||||
|
||||
// Compute gammas sums
|
||||
compute_subset_sums(gammas_sums, gammas, m - 1);
|
||||
|
||||
// Step 5
|
||||
fft_rec(u, f0, (f_coeffs + 1) / 2, m - 1, m_f - 1, deltas);
|
||||
|
||||
if (f_coeffs <= 3) { // 3-coefficient polynomial f case: f1 is constant
|
||||
w[0] = u[0];
|
||||
w[k] = u[0] ^ f1[0];
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
w[i] = u[i] ^ PQCLEAN_HQC1921CCA2_LEAKTIME_gf_mul(gammas_sums[i], f1[0]);
|
||||
w[k + i] = w[i] ^ f1[0];
|
||||
}
|
||||
} else {
|
||||
fft_rec(v, f1, f_coeffs / 2, m - 1, m_f - 1, deltas);
|
||||
|
||||
// Step 6
|
||||
memcpy(w + k, v, 2 * k);
|
||||
w[0] = u[0];
|
||||
w[k] ^= u[0];
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
w[i] = u[i] ^ PQCLEAN_HQC1921CCA2_LEAKTIME_gf_mul(gammas_sums[i], v[i]);
|
||||
w[k + i] ^= w[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Evaluates f on all fields elements using an additive FFT algorithm
|
||||
*
|
||||
* f_coeffs is the number of coefficients of f (one less than its degree). <br>
|
||||
* The FFT proceeds recursively to evaluate f at all subset sums of a basis B. <br>
|
||||
* This implementation is based on the paper from Gao and Mateer: <br>
|
||||
* Shuhong Gao and Todd Mateer, Additive Fast Fourier Transforms over Finite Fields,
|
||||
* IEEE Transactions on Information Theory 56 (2010), 6265--6272.
|
||||
* http://www.math.clemson.edu/~sgao/papers/GM10.pdf <br>
|
||||
* and includes improvements proposed by Bernstein, Chou and Schwabe here:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf <br>
|
||||
* Constants betas, gammas and deltas involved in the algorithm are either hardcoded or precomputed
|
||||
* by the subroutine compute_fft_lut(...). <br>
|
||||
* Note that on this first call (as opposed to the recursive calls to fft_rec), gammas are equal to betas,
|
||||
* meaning the first gammas subset sums are actually the subset sums of betas (except 1). <br>
|
||||
* Also note that f is altered during computation (twisted at each level).
|
||||
*
|
||||
* @param[out] w Array
|
||||
* @param[in] f Array of 2^PARAM_FFT elements
|
||||
* @param[in] f_coeffs Number coefficients of f (i.e. deg(f)+1)
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_fft(uint16_t *w, const uint16_t *f, size_t f_coeffs) {
|
||||
uint16_t betas[PARAM_M - 1] = {0};
|
||||
uint16_t betas_sums[1 << (PARAM_M - 1)] = {0};
|
||||
uint16_t f0[1 << (PARAM_FFT - 1)] = {0};
|
||||
uint16_t f1[1 << (PARAM_FFT - 1)] = {0};
|
||||
uint16_t deltas[PARAM_M - 1];
|
||||
size_t k = 1 << (PARAM_M - 1);
|
||||
uint16_t u[1 << (PARAM_M - 1)] = {0};
|
||||
uint16_t v[1 << (PARAM_M - 1)] = {0};
|
||||
|
||||
// Follows Gao and Mateer algorithm
|
||||
compute_fft_betas(betas);
|
||||
|
||||
// Step 1: PARAM_FFT > 1, nothing to do
|
||||
|
||||
// Compute gammas sums
|
||||
compute_subset_sums(betas_sums, betas, PARAM_M - 1);
|
||||
|
||||
// Step 2: beta_m = 1, nothing to do
|
||||
|
||||
// Step 3
|
||||
radix(f0, f1, f, PARAM_FFT);
|
||||
|
||||
// Step 4: Compute deltas
|
||||
for (size_t i = 0; i < PARAM_M - 1; ++i) {
|
||||
deltas[i] = PQCLEAN_HQC1921CCA2_LEAKTIME_gf_square(betas[i]) ^ betas[i];
|
||||
}
|
||||
|
||||
// Step 5
|
||||
fft_rec(u, f0, (f_coeffs + 1) / 2, PARAM_M - 1, PARAM_FFT - 1, deltas);
|
||||
fft_rec(v, f1, f_coeffs / 2, PARAM_M - 1, PARAM_FFT - 1, deltas);
|
||||
|
||||
// Step 6, 7 and error polynomial computation
|
||||
memcpy(w + k, v, 2 * k);
|
||||
|
||||
// Check if 0 is root
|
||||
w[0] = u[0];
|
||||
|
||||
// Check if 1 is root
|
||||
w[k] ^= u[0];
|
||||
|
||||
// Find other roots
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
w[i] = u[i] ^ PQCLEAN_HQC1921CCA2_LEAKTIME_gf_mul(betas_sums[i], v[i]);
|
||||
w[k + i] ^= w[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Arranges the received word vector in a form w such that applying the additive FFT transpose to w yields the BCH syndromes of the received word vector.
|
||||
*
|
||||
* Since the received word vector gives coefficients of the primitive element alpha, we twist accordingly. <br>
|
||||
* Furthermore, the additive FFT transpose needs elements indexed by their decomposition on the chosen basis,
|
||||
* so we apply the adequate permutation.
|
||||
*
|
||||
* @param[out] w Array of size 2^PARAM_M
|
||||
* @param[in] vector Array of size VEC_N1_SIZE_BYTES
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_fft_t_preprocess_bch_codeword(uint16_t *w, const uint8_t *vector) {
|
||||
uint16_t r[1 << PARAM_M];
|
||||
uint16_t gammas[PARAM_M - 1];
|
||||
uint16_t gammas_sums[1 << (PARAM_M - 1)];
|
||||
size_t k = 1 << (PARAM_M - 1);
|
||||
|
||||
// Unpack the received word vector into array r
|
||||
size_t i;
|
||||
for (i = 0; i < VEC_N1_SIZE_BYTES - (PARAM_N1 % 8 != 0); ++i) {
|
||||
for (size_t j = 0; j < 8; ++j) {
|
||||
r[8 * i + j] = (vector[i] >> j) & 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Last byte
|
||||
for (size_t j = 0; j < PARAM_N1 % 8; ++j) {
|
||||
r[8 * i + j] = (vector[i] >> j) & 1;
|
||||
}
|
||||
|
||||
// Complete r with zeros
|
||||
memset(r + PARAM_N1, 0, 2 * ((1 << PARAM_M) - PARAM_N1));
|
||||
|
||||
compute_fft_betas(gammas);
|
||||
compute_subset_sums(gammas_sums, gammas, PARAM_M - 1);
|
||||
|
||||
// Twist and permute r adequately to obtain w
|
||||
w[0] = 0;
|
||||
w[k] = -r[0] & 1;
|
||||
for (i = 1; i < k; ++i) {
|
||||
w[i] = -r[PQCLEAN_HQC1921CCA2_LEAKTIME_gf_log(gammas_sums[i])] & gammas_sums[i];
|
||||
w[k + i] = -r[PQCLEAN_HQC1921CCA2_LEAKTIME_gf_log(gammas_sums[i] ^ 1)] & (gammas_sums[i] ^ 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieves the error polynomial error from the evaluations w of the ELP (Error Locator Polynomial) on all field elements.
|
||||
*
|
||||
* @param[out] error Array of size VEC_N1_SIZE_BYTES
|
||||
* @param[in] w Array of size 2^PARAM_M
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_fft_retrieve_bch_error_poly(uint8_t *error, const uint16_t *w) {
|
||||
uint16_t gammas[PARAM_M - 1];
|
||||
uint16_t gammas_sums[1 << (PARAM_M - 1)];
|
||||
size_t k = 1 << (PARAM_M - 1);
|
||||
size_t index = PARAM_GF_MUL_ORDER;
|
||||
|
||||
compute_fft_betas(gammas);
|
||||
compute_subset_sums(gammas_sums, gammas, PARAM_M - 1);
|
||||
|
||||
error[0] ^= 1 ^ ((uint16_t) - w[0] >> 15);
|
||||
uint8_t bit = 1 ^ ((uint16_t) - w[k] >> 15);
|
||||
error[index / 8] ^= bit << (index % 8);
|
||||
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
index = PARAM_GF_MUL_ORDER - PQCLEAN_HQC1921CCA2_LEAKTIME_gf_log(gammas_sums[i]);
|
||||
bit = 1 ^ ((uint16_t) - w[i] >> 15);
|
||||
error[index / 8] ^= bit << (index % 8);
|
||||
|
||||
index = PARAM_GF_MUL_ORDER - PQCLEAN_HQC1921CCA2_LEAKTIME_gf_log(gammas_sums[i] ^ 1);
|
||||
bit = 1 ^ ((uint16_t) - w[k + i] >> 15);
|
||||
error[index / 8] ^= bit << (index % 8);
|
||||
}
|
||||
}
|
||||
18
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/fft.h
Normal file
18
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/fft.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef PQCLEAN_HQC1921CCA2_LEAKTIME_FFT_H
|
||||
#define PQCLEAN_HQC1921CCA2_LEAKTIME_FFT_H
|
||||
|
||||
/**
|
||||
* @file fft.h
|
||||
* Header file of fft.c
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_fft_t(uint16_t *f, const uint16_t *w, size_t f_coeffs);
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_fft_t_preprocess_bch_codeword(uint16_t *w, const uint8_t *vector);
|
||||
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_fft(uint16_t *w, const uint16_t *f, size_t f_coeffs);
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_fft_retrieve_bch_error_poly(uint8_t *error, const uint16_t *w);
|
||||
|
||||
#endif
|
||||
99
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/gf.c
Normal file
99
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/gf.c
Normal file
File diff suppressed because one or more lines are too long
18
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/gf.h
Normal file
18
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/gf.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef PQCLEAN_HQC1921CCA2_LEAKTIME_GF_H
|
||||
#define PQCLEAN_HQC1921CCA2_LEAKTIME_GF_H
|
||||
|
||||
/**
|
||||
* @file gf.h
|
||||
* Header file of gf.c
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint16_t PQCLEAN_HQC1921CCA2_LEAKTIME_gf_log(uint16_t elt);
|
||||
uint16_t PQCLEAN_HQC1921CCA2_LEAKTIME_gf_mul(uint16_t a, uint16_t b);
|
||||
uint16_t PQCLEAN_HQC1921CCA2_LEAKTIME_gf_square(uint16_t a);
|
||||
uint16_t PQCLEAN_HQC1921CCA2_LEAKTIME_gf_inverse(uint16_t a);
|
||||
uint16_t PQCLEAN_HQC1921CCA2_LEAKTIME_gf_mod(uint16_t i);
|
||||
|
||||
#endif
|
||||
123
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/gf2x.c
Normal file
123
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/gf2x.c
Normal file
@ -0,0 +1,123 @@
|
||||
/**
|
||||
* \file gf2x.c
|
||||
* \brief Implementation of multiplication of two polynomials
|
||||
*/
|
||||
|
||||
#include "gf2x.h"
|
||||
#include "parameters.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define WORD_TYPE uint64_t
|
||||
#define WORD_TYPE_BITS (sizeof(WORD_TYPE) * 8)
|
||||
#define UTILS_VECTOR_ARRAY_SIZE CEIL_DIVIDE(PARAM_N, WORD_TYPE_BITS)
|
||||
|
||||
static int vect_mul_precompute_rows(WORD_TYPE *o, const WORD_TYPE *v);
|
||||
|
||||
|
||||
/**
|
||||
* @brief A subroutine used in the function sparse_dense_mul()
|
||||
*
|
||||
* @param[out] o Pointer to an array
|
||||
* @param[in] v Pointer to an array
|
||||
* @return 0 if precomputation is successful, -1 otherwise
|
||||
*/
|
||||
static int vect_mul_precompute_rows(WORD_TYPE *o, const WORD_TYPE *v) {
|
||||
int8_t var;
|
||||
for (size_t i = 0; i < PARAM_N; ++i) {
|
||||
var = 0;
|
||||
|
||||
// All the bits that we need are in the same block
|
||||
if (((i % WORD_TYPE_BITS) == 0) && (i != PARAM_N - (PARAM_N % WORD_TYPE_BITS))) {
|
||||
var = 1;
|
||||
}
|
||||
|
||||
// Cases where the bits are in before the last block, the last block and the first block
|
||||
if (i > PARAM_N - WORD_TYPE_BITS) {
|
||||
if (i >= PARAM_N - (PARAM_N % WORD_TYPE_BITS)) {
|
||||
var = 2;
|
||||
} else {
|
||||
var = 3;
|
||||
}
|
||||
}
|
||||
|
||||
switch (var) {
|
||||
case 0:
|
||||
// Take bits in the last block and the first one
|
||||
o[i] = 0;
|
||||
o[i] += v[i / WORD_TYPE_BITS] >> (i % WORD_TYPE_BITS);
|
||||
o[i] += v[(i / WORD_TYPE_BITS) + 1] << (WORD_TYPE_BITS - (i % WORD_TYPE_BITS));
|
||||
break;
|
||||
|
||||
case 1:
|
||||
o[i] = v[i / WORD_TYPE_BITS];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
o[i] = 0;
|
||||
o[i] += v[i / WORD_TYPE_BITS] >> (i % WORD_TYPE_BITS);
|
||||
o[i] += v[0] << ((PARAM_N - i) % WORD_TYPE_BITS);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
o[i] = 0;
|
||||
o[i] += v[i / WORD_TYPE_BITS] >> (i % WORD_TYPE_BITS);
|
||||
o[i] += v[(i / WORD_TYPE_BITS) + 1] << (WORD_TYPE_BITS - (i % WORD_TYPE_BITS));
|
||||
o[i] += v[0] << ((WORD_TYPE_BITS - i + (PARAM_N % WORD_TYPE_BITS)) % WORD_TYPE_BITS);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Multiplies two vectors
|
||||
*
|
||||
* This function multiplies two vectors: a sparse vector of Hamming weight equal to <b>weight</b> and a dense (random) vector.
|
||||
* The vector <b>a1</b> is the sparse vector and <b>a2</b> is the dense vector.
|
||||
* We notice that the idea is explained using vector of 32 bits elements instead of 64 (the algorithm works in booth cases).
|
||||
*
|
||||
* @param[out] o Pointer to a vector that is the result of the multiplication
|
||||
* @param[in] a1 Pointer to the sparse vector stored by position
|
||||
* @param[in] a2 Pointer to the dense vector
|
||||
* @param[in] weight Integer that is the weight of the sparse vector
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_vect_mul(uint8_t *o, const uint32_t *a1, const uint8_t *a2, uint16_t weight) {
|
||||
WORD_TYPE v1[UTILS_VECTOR_ARRAY_SIZE] = {0};
|
||||
WORD_TYPE res[UTILS_VECTOR_ARRAY_SIZE] = {0};
|
||||
WORD_TYPE precomputation_array [PARAM_N] = {0};
|
||||
WORD_TYPE row [UTILS_VECTOR_ARRAY_SIZE] = {0};
|
||||
uint32_t index;
|
||||
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_load8_arr(v1, UTILS_VECTOR_ARRAY_SIZE, a2, VEC_N_SIZE_BYTES);
|
||||
vect_mul_precompute_rows(precomputation_array, v1);
|
||||
|
||||
for (size_t i = 0; i < weight; ++i) {
|
||||
int32_t k = UTILS_VECTOR_ARRAY_SIZE;
|
||||
|
||||
for (size_t j = 0; j < UTILS_VECTOR_ARRAY_SIZE - 1; ++j) {
|
||||
index = WORD_TYPE_BITS * (uint32_t)j - a1[i];
|
||||
if (index > PARAM_N) {
|
||||
index += PARAM_N;
|
||||
}
|
||||
row[j] = precomputation_array[index];
|
||||
}
|
||||
|
||||
index = WORD_TYPE_BITS * (UTILS_VECTOR_ARRAY_SIZE - 1) - a1[i];
|
||||
row[UTILS_VECTOR_ARRAY_SIZE - 1] = precomputation_array[(index < PARAM_N ? index : index + PARAM_N)] & BITMASK(PARAM_N, WORD_TYPE_BITS);
|
||||
|
||||
while (k--) {
|
||||
res[k] ^= row[k];
|
||||
}
|
||||
}
|
||||
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_store8_arr(o, VEC_N_SIZE_BYTES, res, UTILS_VECTOR_ARRAY_SIZE);
|
||||
}
|
||||
13
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/gf2x.h
Normal file
13
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/gf2x.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef PQCLEAN_HQC1921CCA2_LEAKTIME_GF2X_H
|
||||
#define PQCLEAN_HQC1921CCA2_LEAKTIME_GF2X_H
|
||||
|
||||
/**
|
||||
* @file gf2x.h
|
||||
* @brief Header file for gf2x.c
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_vect_mul(uint8_t *o, const uint32_t *a1, const uint8_t *a2, uint16_t weight);
|
||||
|
||||
#endif
|
||||
135
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/hqc.c
Normal file
135
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/hqc.c
Normal file
@ -0,0 +1,135 @@
|
||||
/**
|
||||
* @file hqc.c
|
||||
* @brief Implementation of hqc.h
|
||||
*/
|
||||
|
||||
#include "gf2x.h"
|
||||
#include "hqc.h"
|
||||
#include "nistseedexpander.h"
|
||||
#include "parameters.h"
|
||||
#include "parsing.h"
|
||||
#include "randombytes.h"
|
||||
#include "tensor.h"
|
||||
#include "vector.h"
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Keygen of the HQC_PKE IND_CPA scheme
|
||||
*
|
||||
* The public key is composed of the syndrome <b>s</b> as well as the <b>seed</b> used to generate the vector <b>h</b>.
|
||||
*
|
||||
* The secret key is composed of the <b>seed</b> used to generate vectors <b>x</b> and <b>y</b>.
|
||||
* As a technicality, the public key is appended to the secret key in order to respect NIST API.
|
||||
*
|
||||
* @param[out] pk String containing the public key
|
||||
* @param[out] sk String containing the secret key
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_pke_keygen(uint8_t *pk, uint8_t *sk) {
|
||||
AES_XOF_struct sk_seedexpander;
|
||||
AES_XOF_struct pk_seedexpander;
|
||||
uint8_t sk_seed[SEED_BYTES] = {0};
|
||||
uint8_t pk_seed[SEED_BYTES] = {0};
|
||||
uint8_t x[VEC_N_SIZE_BYTES] = {0};
|
||||
uint32_t y[PARAM_OMEGA] = {0};
|
||||
uint8_t h[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t s[VEC_N_SIZE_BYTES] = {0};
|
||||
|
||||
// Create seed_expanders for public key and secret key
|
||||
randombytes(sk_seed, SEED_BYTES);
|
||||
seedexpander_init(&sk_seedexpander, sk_seed, sk_seed + 32, SEEDEXPANDER_MAX_LENGTH);
|
||||
|
||||
randombytes(pk_seed, SEED_BYTES);
|
||||
seedexpander_init(&pk_seedexpander, pk_seed, pk_seed + 32, SEEDEXPANDER_MAX_LENGTH);
|
||||
|
||||
// Compute secret key
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_set_random_fixed_weight(&sk_seedexpander, x, PARAM_OMEGA);
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_set_random_fixed_weight_by_coordinates(&sk_seedexpander, y, PARAM_OMEGA);
|
||||
|
||||
// Compute public key
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_set_random(&pk_seedexpander, h);
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_mul(s, y, h, PARAM_OMEGA);
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_add(s, x, s, VEC_N_SIZE_BYTES);
|
||||
|
||||
// Parse keys to string
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_public_key_to_string(pk, pk_seed, s);
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_secret_key_to_string(sk, sk_seed, pk);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encryption of the HQC_PKE IND_CPA scheme
|
||||
*
|
||||
* The cihertext is composed of vectors <b>u</b> and <b>v</b>.
|
||||
*
|
||||
* @param[out] u Vector u (first part of the ciphertext)
|
||||
* @param[out] v Vector v (second part of the ciphertext)
|
||||
* @param[in] m Vector representing the message to encrypt
|
||||
* @param[in] theta Seed used to derive randomness required for encryption
|
||||
* @param[in] pk String containing the public key
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_pke_encrypt(uint8_t *u, uint8_t *v, const uint8_t *m, const uint8_t *theta, const uint8_t *pk) {
|
||||
AES_XOF_struct seedexpander;
|
||||
uint8_t h[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t s[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t r1[VEC_N_SIZE_BYTES] = {0};
|
||||
uint32_t r2[PARAM_OMEGA_R] = {0};
|
||||
uint8_t e[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t tmp1[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t tmp2[VEC_N_SIZE_BYTES] = {0};
|
||||
|
||||
// Create seed_expander from theta
|
||||
seedexpander_init(&seedexpander, theta, theta + 32, SEEDEXPANDER_MAX_LENGTH);
|
||||
|
||||
// Retrieve h and s from public key
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_public_key_from_string(h, s, pk);
|
||||
|
||||
// Generate r1, r2 and e
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_set_random_fixed_weight(&seedexpander, r1, PARAM_OMEGA_R);
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_set_random_fixed_weight_by_coordinates(&seedexpander, r2, PARAM_OMEGA_R);
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_set_random_fixed_weight(&seedexpander, e, PARAM_OMEGA_E);
|
||||
|
||||
// Compute u = r1 + r2.h
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_mul(u, r2, h, PARAM_OMEGA_R);
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_add(u, r1, u, VEC_N_SIZE_BYTES);
|
||||
|
||||
// Compute v = m.G by encoding the message
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_tensor_code_encode(v, m);
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_resize(tmp1, PARAM_N, v, PARAM_N1N2);
|
||||
|
||||
// Compute v = m.G + s.r2 + e
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_mul(tmp2, r2, s, PARAM_OMEGA_R);
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_add(tmp2, e, tmp2, VEC_N_SIZE_BYTES);
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_add(tmp2, tmp1, tmp2, VEC_N_SIZE_BYTES);
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_resize(v, PARAM_N1N2, tmp2, PARAM_N);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Decryption of the HQC_PKE IND_CPA scheme
|
||||
*
|
||||
* @param[out] m Vector representing the decrypted message
|
||||
* @param[in] u Vector u (first part of the ciphertext)
|
||||
* @param[in] v Vector v (second part of the ciphertext)
|
||||
* @param[in] sk String containing the secret key
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_pke_decrypt(uint8_t *m, const uint8_t *u, const uint8_t *v, const uint8_t *sk) {
|
||||
uint8_t x[VEC_N_SIZE_BYTES] = {0};
|
||||
uint32_t y[PARAM_OMEGA] = {0};
|
||||
uint8_t pk[PUBLIC_KEY_BYTES] = {0};
|
||||
uint8_t tmp1[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t tmp2[VEC_N_SIZE_BYTES] = {0};
|
||||
|
||||
// Retrieve x, y, pk from secret key
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_secret_key_from_string(x, y, pk, sk);
|
||||
|
||||
// Compute v - u.y
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_resize(tmp1, PARAM_N, v, PARAM_N1N2);
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_mul(tmp2, y, u, PARAM_OMEGA);
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_add(tmp2, tmp1, tmp2, VEC_N_SIZE_BYTES);
|
||||
|
||||
// Compute m by decoding v - u.y
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_tensor_code_decode(m, tmp2);
|
||||
}
|
||||
15
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/hqc.h
Normal file
15
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/hqc.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef PQCLEAN_HQC1921CCA2_LEAKTIME_HQC_H
|
||||
#define PQCLEAN_HQC1921CCA2_LEAKTIME_HQC_H
|
||||
|
||||
/**
|
||||
* @file hqc.h
|
||||
* @brief Functions of the HQC_PKE IND_CPA scheme
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_pke_keygen(uint8_t *pk, uint8_t *sk);
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_pke_encrypt(uint8_t *u, uint8_t *v, const uint8_t *m, const uint8_t *theta, const uint8_t *pk);
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_pke_decrypt(uint8_t *m, const uint8_t *u, const uint8_t *v, const uint8_t *sk);
|
||||
|
||||
#endif
|
||||
154
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/kem.c
Normal file
154
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/kem.c
Normal file
@ -0,0 +1,154 @@
|
||||
/**
|
||||
* @file kem.c
|
||||
* @brief Implementation of api.h
|
||||
*/
|
||||
|
||||
#include "api.h"
|
||||
#include "hqc.h"
|
||||
#include "nistseedexpander.h"
|
||||
#include "parameters.h"
|
||||
#include "parsing.h"
|
||||
#include "sha2.h"
|
||||
#include "vector.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Keygen of the HQC_KEM IND_CAA2 scheme
|
||||
*
|
||||
* The public key is composed of the syndrome <b>s</b> as well as the seed used to generate the vector <b>h</b>.
|
||||
*
|
||||
* The secret key is composed of the seed used to generate vectors <b>x</b> and <b>y</b>.
|
||||
* As a technicality, the public key is appended to the secret key in order to respect NIST API.
|
||||
*
|
||||
* @param[out] pk String containing the public key
|
||||
* @param[out] sk String containing the secret key
|
||||
* @returns 0 if keygen is successful
|
||||
*/
|
||||
int PQCLEAN_HQC1921CCA2_LEAKTIME_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) {
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_pke_keygen(pk, sk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encapsulation of the HQC_KEM IND_CAA2 scheme
|
||||
*
|
||||
* @param[out] ct String containing the ciphertext
|
||||
* @param[out] ss String containing the shared secret
|
||||
* @param[in] pk String containing the public key
|
||||
* @returns 0 if encapsulation is successful
|
||||
*/
|
||||
int PQCLEAN_HQC1921CCA2_LEAKTIME_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
|
||||
AES_XOF_struct G_seedexpander;
|
||||
uint8_t seed_G[VEC_K_SIZE_BYTES];
|
||||
uint8_t diversifier_bytes[8] = {0};
|
||||
uint8_t m[VEC_K_SIZE_BYTES] = {0};
|
||||
uint8_t theta[SEED_BYTES] = {0};
|
||||
uint8_t u[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t v[VEC_N1N2_SIZE_BYTES] = {0};
|
||||
uint8_t d[SHA512_BYTES] = {0};
|
||||
uint8_t mc[VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES] = {0};
|
||||
|
||||
// Computing m
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_set_random_from_randombytes(m);
|
||||
|
||||
// Generating G function
|
||||
memcpy(seed_G, m, VEC_K_SIZE_BYTES);
|
||||
seedexpander_init(&G_seedexpander, seed_G, diversifier_bytes, SEEDEXPANDER_MAX_LENGTH);
|
||||
|
||||
// Computing theta
|
||||
seedexpander(&G_seedexpander, theta, SEED_BYTES);
|
||||
|
||||
// Encrypting m
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_pke_encrypt(u, v, m, theta, pk);
|
||||
|
||||
// Computing d
|
||||
sha512(d, m, VEC_K_SIZE_BYTES);
|
||||
|
||||
// Computing shared secret
|
||||
memcpy(mc, m, VEC_K_SIZE_BYTES);
|
||||
memcpy(mc + VEC_K_SIZE_BYTES, u, VEC_N_SIZE_BYTES);
|
||||
memcpy(mc + VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES, v, VEC_N1N2_SIZE_BYTES);
|
||||
sha512(ss, mc, VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES);
|
||||
|
||||
// Computing ciphertext
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_ciphertext_to_string(ct, u, v, d);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Decapsulation of the HQC_KEM IND_CAA2 scheme
|
||||
*
|
||||
* @param[out] ss String containing the shared secret
|
||||
* @param[in] ct String containing the cipĥertext
|
||||
* @param[in] sk String containing the secret key
|
||||
* @returns 0 if decapsulation is successful, -1 otherwise
|
||||
*/
|
||||
int PQCLEAN_HQC1921CCA2_LEAKTIME_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
|
||||
AES_XOF_struct G_seedexpander;
|
||||
uint8_t seed_G[VEC_K_SIZE_BYTES] = {0};
|
||||
uint8_t diversifier_bytes[8] = {0};
|
||||
uint8_t u[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t v[VEC_N1N2_SIZE_BYTES] = {0};
|
||||
uint8_t d[SHA512_BYTES] = {0};
|
||||
uint8_t pk[PUBLIC_KEY_BYTES] = {0};
|
||||
uint8_t m[VEC_K_SIZE_BYTES] = {0};
|
||||
uint8_t theta[SEED_BYTES] = {0};
|
||||
uint8_t u2[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t v2[VEC_N1N2_SIZE_BYTES] = {0};
|
||||
uint8_t d2[SHA512_BYTES] = {0};
|
||||
uint8_t mc[VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES] = {0};
|
||||
int8_t abort = 0;
|
||||
|
||||
// Retrieving u, v and d from ciphertext
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_ciphertext_from_string(u, v, d, ct);
|
||||
|
||||
// Retrieving pk from sk
|
||||
memcpy(pk, sk + SEED_BYTES, PUBLIC_KEY_BYTES);
|
||||
|
||||
// Decryting
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_pke_decrypt(m, u, v, sk);
|
||||
|
||||
// Generating G function
|
||||
memcpy(seed_G, m, VEC_K_SIZE_BYTES);
|
||||
seedexpander_init(&G_seedexpander, seed_G, diversifier_bytes, SEEDEXPANDER_MAX_LENGTH);
|
||||
|
||||
// Computing theta
|
||||
seedexpander(&G_seedexpander, theta, SEED_BYTES);
|
||||
|
||||
// Encrypting m'
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_pke_encrypt(u2, v2, m, theta, pk);
|
||||
|
||||
// Checking that c = c' and abort otherwise
|
||||
if (PQCLEAN_HQC1921CCA2_LEAKTIME_vect_compare(u, u2, VEC_N_SIZE_BYTES) != 0 ||
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_compare(v, v2, VEC_N1N2_SIZE_BYTES) != 0) {
|
||||
abort = 1;
|
||||
}
|
||||
|
||||
// Computing d'
|
||||
sha512(d2, m, VEC_K_SIZE_BYTES);
|
||||
|
||||
// Checking that d = d' and abort otherwise
|
||||
if (memcmp(d, d2, SHA512_BYTES) != 0) {
|
||||
abort = 1;
|
||||
}
|
||||
|
||||
if (abort == 1) {
|
||||
memset(ss, 0, SHARED_SECRET_BYTES);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Computing shared secret
|
||||
memcpy(mc, m, VEC_K_SIZE_BYTES);
|
||||
memcpy(mc + VEC_K_SIZE_BYTES, u, VEC_N_SIZE_BYTES);
|
||||
memcpy(mc + VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES, v, VEC_N1N2_SIZE_BYTES);
|
||||
sha512(ss, mc, VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES);
|
||||
|
||||
return 0;
|
||||
}
|
||||
109
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/parameters.h
Normal file
109
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/parameters.h
Normal file
@ -0,0 +1,109 @@
|
||||
#ifndef PQCLEAN_HQC1921CCA2_LEAKTIME_HQC_PARAMETERS_H
|
||||
#define PQCLEAN_HQC1921CCA2_LEAKTIME_HQC_PARAMETERS_H
|
||||
|
||||
/**
|
||||
* @file parameters.h
|
||||
* @brief Parameters of the HQC_KEM IND-CCA2 scheme
|
||||
*/
|
||||
|
||||
#include "api.h"
|
||||
|
||||
#define CEIL_DIVIDE(a, b) (((a)/(b)) + ((a) % (b) == 0 ? 0 : 1)) /*!< Divide a by b and ceil the result*/
|
||||
#define BITMASK(a, size) ((1ULL << ((a) % (size))) - 1) /*!< Create a mask*/
|
||||
|
||||
|
||||
/*
|
||||
#define PARAM_N Define the parameter n of the scheme
|
||||
#define PARAM_N1 Define the parameter n1 of the scheme (length of BCH code)
|
||||
#define PARAM_N2 Define the parameter n2 of the scheme (length of the repetition code)
|
||||
#define PARAM_N1N2 Define the parameter n1 * n2 of the scheme (length of the tensor code)
|
||||
#define PARAM_OMEGA Define the parameter omega of the scheme
|
||||
#define PARAM_OMEGA_E Define the parameter omega_e of the scheme
|
||||
#define PARAM_OMEGA_R Define the parameter omega_r of the scheme
|
||||
#define PARAM_SECURITY Define the security level corresponding to the chosen parameters
|
||||
#define PARAM_DFR_EXP Define the decryption failure rate corresponding to the chosen parameters
|
||||
|
||||
#define SECRET_KEY_BYTES Define the size of the secret key in bytes
|
||||
#define PUBLIC_KEY_BYTES Define the size of the public key in bytes
|
||||
#define SHARED_SECRET_BYTES Define the size of the shared secret in bytes
|
||||
#define CIPHERTEXT_BYTES Define the size of the ciphertext in bytes
|
||||
|
||||
#define UTILS_REJECTION_THRESHOLD Define the rejection threshold used to generate given weight vectors (see vector_set_random_fixed_weight function)
|
||||
#define VEC_N_ARRAY_SIZE_BYTES Define the size of the array used to store a PARAM_N sized vector in bytes
|
||||
#define VEC_N1_ARRAY_SIZE_BYTES Define the size of the array used to store a PARAM_N1 sized vector in bytes
|
||||
#define VEC_N1N2_ARRAY_SIZE_BYTES Define the size of the array used to store a PARAM_N1N2 sized vector in bytes
|
||||
#define VEC_K_ARRAY_SIZE_BYTES Define the size of the array used to store a PARAM_K sized vector in bytes
|
||||
|
||||
#define PARAM_T Define a threshold for decoding repetition code word (PARAM_T = (PARAM_N2 - 1) / 2)
|
||||
|
||||
#define PARAM_DELTA Define the parameter delta of the scheme (correcting capacity of the BCH code)
|
||||
#define PARAM_M Define a positive integer
|
||||
#define PARAM_GF_MUL_ORDER Define the size of the multiplicative group of GF(2^m), i.e 2^m -1
|
||||
#define PARAM_K Define the size of the information bits of the BCH code
|
||||
#define PARAM_G Define the size of the generator polynomial of BCH code
|
||||
#define PARAM_FFT The additive FFT takes a 2^PARAM_FFT polynomial as input
|
||||
We use the FFT to compute the roots of sigma, whose degree if PARAM_DELTA=60
|
||||
The smallest power of 2 greater than 60+1 is 64=2^6
|
||||
#define PARAM_FFT_T The additive FFT transpose computes a (2^PARAM_FFT_T)-sized syndrome vector
|
||||
We want to compute 2*PARAM_DELTA=120 syndromes
|
||||
The smallest power of 2 greater than 120 is 2^7
|
||||
#define PARAM_BCH_POLY Generator polynomial of the BCH code
|
||||
|
||||
#define SHA512_BYTES Define the size of SHA512 output in bytes
|
||||
#define SEED_BYTES Define the size of the seed in bytes
|
||||
#define SEEDEXPANDER_MAX_LENGTH Define the seed expander max length
|
||||
*/
|
||||
|
||||
|
||||
#define PARAM_N 43669
|
||||
#define PARAM_N1 766
|
||||
#define PARAM_N2 57
|
||||
#define PARAM_N1N2 43662
|
||||
#define PARAM_OMEGA 101
|
||||
#define PARAM_OMEGA_E 117
|
||||
#define PARAM_OMEGA_R 117
|
||||
#define PARAM_SECURITY 192
|
||||
#define PARAM_DFR_EXP 128
|
||||
|
||||
#define SECRET_KEY_BYTES PQCLEAN_HQC1921CCA2_LEAKTIME_CRYPTO_SECRETKEYBYTES
|
||||
#define PUBLIC_KEY_BYTES PQCLEAN_HQC1921CCA2_LEAKTIME_CRYPTO_PUBLICKEYBYTES
|
||||
#define SHARED_SECRET_BYTES PQCLEAN_HQC1921CCA2_LEAKTIME_CRYPTO_BYTES
|
||||
#define CIPHERTEXT_BYTES PQCLEAN_HQC1921CCA2_LEAKTIME_CRYPTO_CIPHERTEXTBYTES
|
||||
|
||||
#define UTILS_REJECTION_THRESHOLD 16768896
|
||||
#define VEC_K_SIZE_BYTES CEIL_DIVIDE(PARAM_K, 8)
|
||||
#define VEC_N_SIZE_BYTES CEIL_DIVIDE(PARAM_N, 8)
|
||||
#define VEC_N1_SIZE_BYTES CEIL_DIVIDE(PARAM_N1, 8)
|
||||
#define VEC_N1N2_SIZE_BYTES CEIL_DIVIDE(PARAM_N1N2, 8)
|
||||
|
||||
#define PARAM_T 28
|
||||
|
||||
#define PARAM_DELTA 57
|
||||
#define PARAM_M 10
|
||||
#define PARAM_GF_MUL_ORDER 1023
|
||||
#define PARAM_K 256
|
||||
#define PARAM_G 511
|
||||
#define PARAM_FFT 6
|
||||
#define PARAM_FFT_T 7
|
||||
#define PARAM_BCH_POLY { \
|
||||
1,1,0,0,0,0,1,0,0,1,1,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,1,1,1,1,0,0,1,1,0,1,1, \
|
||||
1,1,0,1,1,1,1,0,1,0,0,0,1,0,0,1,1,1,0,1,1,0,1,0,1,1,1,0,1,0,1,0,0,1,0,0,0, \
|
||||
0,1,1,1,1,0,1,1,1,1,1,0,0,0,0,1,0,0,1,0,0,1,1,1,0,0,0,1,1,0,0,1,0,1,0,0,0, \
|
||||
1,0,0,0,0,1,0,0,0,1,0,1,1,0,0,0,0,1,1,0,0,1,1,0,1,0,1,0,1,0,1,1,1,1,0,1,0, \
|
||||
0,1,1,0,1,0,1,1,0,0,1,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,0,0,1,1,0,1,1,1,1,0, \
|
||||
1,1,1,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,1,0,0,1,1,0,1,0,0,0,0,1,0, \
|
||||
0,1,0,0,1,0,1,0,0,1,1,0,1,0,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,0,0,0,1,0,1, \
|
||||
1,1,1,1,1,0,1,0,1,0,1,1,0,0,0,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,0,1,1,1,1,0, \
|
||||
1,0,0,0,1,0,0,1,1,0,1,1,0,0,1,0,1,1,0,1,0,1,0,1,1,0,0,0,0,0,1,1,1,1,1,1,1, \
|
||||
1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,0,1,0,0,1,1,1,1,1,0,1,0,1, \
|
||||
0,0,0,0,1,0,1,1,1,1,0,1,0,0,0,0,0,1,0,0,1,0,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1, \
|
||||
1,0,1,0,0,1,0,0,1,1,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,1,1,0,0,0,1,1, \
|
||||
0,1,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,1,1,1,1,0,0,0,1,0,0,1,1,0,1,1,0,0,1,0,1, \
|
||||
1,0,1,1,1,0,0,0,0,1,1,0,1,1,1,0,1,0,0,0,0,1,0,0,0,1,0,0,1,1 \
|
||||
};
|
||||
|
||||
#define SHA512_BYTES 64
|
||||
#define SEED_BYTES 40
|
||||
#define SEEDEXPANDER_MAX_LENGTH 4294967295
|
||||
|
||||
#endif
|
||||
126
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/parsing.c
Normal file
126
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/parsing.c
Normal file
@ -0,0 +1,126 @@
|
||||
/**
|
||||
* @file parsing.c
|
||||
* @brief Functions to parse secret key, public key and ciphertext of the HQC scheme
|
||||
*/
|
||||
|
||||
#include "nistseedexpander.h"
|
||||
#include "parameters.h"
|
||||
#include "parsing.h"
|
||||
#include "vector.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse a secret key into a string
|
||||
*
|
||||
* The secret key is composed of the seed used to generate vectors <b>x</b> and <b>y</b>.
|
||||
* As technicality, the public key is appended to the secret key in order to respect NIST API.
|
||||
*
|
||||
* @param[out] sk String containing the secret key
|
||||
* @param[in] sk_seed Seed used to generate the secret key
|
||||
* @param[in] pk String containing the public key
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_secret_key_to_string(uint8_t *sk, const uint8_t *sk_seed, const uint8_t *pk) {
|
||||
memcpy(sk, sk_seed, SEED_BYTES);
|
||||
memcpy(sk + SEED_BYTES, pk, PUBLIC_KEY_BYTES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse a secret key from a string
|
||||
*
|
||||
* The secret key is composed of the seed used to generate vectors <b>x</b> and <b>y</b>.
|
||||
* As technicality, the public key is appended to the secret key in order to respect NIST API.
|
||||
*
|
||||
* @param[out] x uint8_t representation of vector x
|
||||
* @param[out] y uint8_t representation of vector y
|
||||
* @param[out] pk String containing the public key
|
||||
* @param[in] sk String containing the secret key
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_secret_key_from_string(uint8_t *x, uint32_t *y, uint8_t *pk, const uint8_t *sk) {
|
||||
AES_XOF_struct sk_seedexpander;
|
||||
uint8_t sk_seed[SEED_BYTES] = {0};
|
||||
|
||||
memcpy(sk_seed, sk, SEED_BYTES);
|
||||
seedexpander_init(&sk_seedexpander, sk_seed, sk_seed + 32, SEEDEXPANDER_MAX_LENGTH);
|
||||
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_set_random_fixed_weight(&sk_seedexpander, x, PARAM_OMEGA);
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_set_random_fixed_weight_by_coordinates(&sk_seedexpander, y, PARAM_OMEGA);
|
||||
memcpy(pk, sk + SEED_BYTES, PUBLIC_KEY_BYTES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse a public key into a string
|
||||
*
|
||||
* The public key is composed of the syndrome <b>s</b> as well as the seed used to generate the vector <b>h</b>
|
||||
*
|
||||
* @param[out] pk String containing the public key
|
||||
* @param[in] pk_seed Seed used to generate the public key
|
||||
* @param[in] s uint8_t representation of vector s
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_public_key_to_string(uint8_t *pk, const uint8_t *pk_seed, const uint8_t *s) {
|
||||
memcpy(pk, pk_seed, SEED_BYTES);
|
||||
memcpy(pk + SEED_BYTES, s, VEC_N_SIZE_BYTES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse a public key from a string
|
||||
*
|
||||
* The public key is composed of the syndrome <b>s</b> as well as the seed used to generate the vector <b>h</b>
|
||||
*
|
||||
* @param[out] h uint8_t representation of vector h
|
||||
* @param[out] s uint8_t representation of vector s
|
||||
* @param[in] pk String containing the public key
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_public_key_from_string(uint8_t *h, uint8_t *s, const uint8_t *pk) {
|
||||
AES_XOF_struct pk_seedexpander;
|
||||
uint8_t pk_seed[SEED_BYTES] = {0};
|
||||
|
||||
memcpy(pk_seed, pk, SEED_BYTES);
|
||||
seedexpander_init(&pk_seedexpander, pk_seed, pk_seed + 32, SEEDEXPANDER_MAX_LENGTH);
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_vect_set_random(&pk_seedexpander, h);
|
||||
|
||||
memcpy(s, pk + SEED_BYTES, VEC_N_SIZE_BYTES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse a ciphertext into a string
|
||||
*
|
||||
* The ciphertext is composed of vectors <b>u</b>, <b>v</b> and hash <b>d</b>.
|
||||
*
|
||||
* @param[out] ct String containing the ciphertext
|
||||
* @param[in] u uint8_t representation of vector u
|
||||
* @param[in] v uint8_t representation of vector v
|
||||
* @param[in] d String containing the hash d
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_ciphertext_to_string(uint8_t *ct, const uint8_t *u, const uint8_t *v, const uint8_t *d) {
|
||||
memcpy(ct, u, VEC_N_SIZE_BYTES);
|
||||
memcpy(ct + VEC_N_SIZE_BYTES, v, VEC_N1N2_SIZE_BYTES);
|
||||
memcpy(ct + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, d, SHA512_BYTES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse a ciphertext from a string
|
||||
*
|
||||
* The ciphertext is composed of vectors <b>u</b>, <b>v</b> and hash <b>d</b>.
|
||||
*
|
||||
* @param[out] u uint8_t representation of vector u
|
||||
* @param[out] v uint8_t representation of vector v
|
||||
* @param[out] d String containing the hash d
|
||||
* @param[in] ct String containing the ciphertext
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_ciphertext_from_string(uint8_t *u, uint8_t *v, uint8_t *d, const uint8_t *ct) {
|
||||
memcpy(u, ct, VEC_N_SIZE_BYTES);
|
||||
memcpy(v, ct + VEC_N_SIZE_BYTES, VEC_N1N2_SIZE_BYTES);
|
||||
memcpy(d, ct + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, SHA512_BYTES);
|
||||
}
|
||||
20
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/parsing.h
Normal file
20
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/parsing.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef PQCLEAN_HQC1921CCA2_LEAKTIME_PARSING_H
|
||||
#define PQCLEAN_HQC1921CCA2_LEAKTIME_PARSING_H
|
||||
|
||||
/**
|
||||
* @file parsing.h
|
||||
* @brief Header file for parsing.c
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_secret_key_to_string(uint8_t *sk, const uint8_t *sk_seed, const uint8_t *pk);
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_secret_key_from_string(uint8_t *x, uint32_t *y, uint8_t *pk, const uint8_t *sk);
|
||||
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_public_key_to_string(uint8_t *pk, const uint8_t *pk_seed, const uint8_t *s);
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_public_key_from_string(uint8_t *h, uint8_t *s, const uint8_t *pk);
|
||||
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_ciphertext_to_string(uint8_t *ct, const uint8_t *u, const uint8_t *v, const uint8_t *d);
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_hqc_ciphertext_from_string(uint8_t *u, uint8_t *v, uint8_t *d, const uint8_t *ct);
|
||||
|
||||
#endif
|
||||
100
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/repetition.c
Normal file
100
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/repetition.c
Normal file
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @file repetition.c
|
||||
* @brief Implementation of repetition codes
|
||||
*/
|
||||
|
||||
#include "parameters.h"
|
||||
#include "repetition.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static void array_to_rep_codeword(uint8_t *o, const uint8_t *v);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encoding each bit in the message m using the repetition code
|
||||
*
|
||||
* For reasons of clarity and comprehensibility, we do the encoding by storing the encoded bits in a String (each bit in an a uint8_t),
|
||||
* then we parse the obtained string to an compact array using the function array_to_rep_codeword().
|
||||
*
|
||||
* @param[out] em Pointer to an array that is the code word
|
||||
* @param[in] m Pointer to an array that is the message
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_repetition_code_encode(uint8_t *em, const uint8_t *m) {
|
||||
uint8_t tmp[PARAM_N1N2] = {0};
|
||||
uint8_t bit = 0;
|
||||
uint32_t index;
|
||||
|
||||
for (size_t i = 0; i < (VEC_N1_SIZE_BYTES - 1); ++i) {
|
||||
for (uint8_t j = 0; j < 8; ++j) {
|
||||
bit = (m[i] >> j) & 0x01;
|
||||
index = (8 * (uint32_t)i + j) * PARAM_N2;
|
||||
for (uint8_t k = 0; k < PARAM_N2; ++k) {
|
||||
tmp[index + k] = bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t j = 0; j < (PARAM_N1 % 8); ++j) {
|
||||
bit = (m[VEC_N1_SIZE_BYTES - 1] >> j) & 0x01;
|
||||
index = (8 * (VEC_N1_SIZE_BYTES - 1) + j) * PARAM_N2;
|
||||
for (uint8_t k = 0; k < PARAM_N2; ++k) {
|
||||
tmp[index + k] = bit;
|
||||
}
|
||||
}
|
||||
|
||||
array_to_rep_codeword(em, tmp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Decoding the code words to a message using the repetition code
|
||||
*
|
||||
* We use a majority decoding. In fact we have that PARAM_N2 = 2 * PARAM_T + 1, thus,
|
||||
* if the Hamming weight of the vector is greater than PARAM_T, the code word is decoded
|
||||
* to 1 and 0 otherwise.
|
||||
*
|
||||
* @param[out] m Pointer to an array that is the message
|
||||
* @param[in] em Pointer to an array that is the code word
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_repetition_code_decode(uint8_t *m, const uint8_t *em) {
|
||||
size_t t = 0; // m index
|
||||
uint8_t k = PARAM_N2; // block counter
|
||||
uint8_t ones = 0; // number of 1 in the current block
|
||||
|
||||
for (size_t i = 0; i < VEC_N1N2_SIZE_BYTES; ++i) {
|
||||
for (uint8_t j = 0; j < 8; ++j) {
|
||||
ones += (em[i] >> j) & 0x01;
|
||||
|
||||
if (--k) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m[t / 8] |= (ones > PARAM_T) << t % 8;
|
||||
++t;
|
||||
k = PARAM_N2;
|
||||
ones = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse an array to an compact array
|
||||
*
|
||||
* @param[out] o Pointer to an array
|
||||
* @param[in] v Pointer to an array
|
||||
*/
|
||||
static void array_to_rep_codeword(uint8_t *o, const uint8_t *v) {
|
||||
for (size_t i = 0; i < (VEC_N1N2_SIZE_BYTES - 1); ++i) {
|
||||
for (uint8_t j = 0; j < 8; ++j) {
|
||||
o[i] |= v[j + 8 * i] << j;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t j = 0; j < PARAM_N1N2 % 8; ++j) {
|
||||
o[VEC_N1N2_SIZE_BYTES - 1] |= (v[j + 8 * (VEC_N1N2_SIZE_BYTES - 1)]) << j;
|
||||
}
|
||||
}
|
||||
14
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/repetition.h
Normal file
14
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/repetition.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef PQCLEAN_HQC1921CCA2_LEAKTIME_REPETITION_H
|
||||
#define PQCLEAN_HQC1921CCA2_LEAKTIME_REPETITION_H
|
||||
|
||||
/**
|
||||
* @file repetition.h
|
||||
* @brief Header file for repetition.c
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_repetition_code_encode(uint8_t *em, const uint8_t *m);
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_repetition_code_decode(uint8_t *m, const uint8_t *em);
|
||||
|
||||
#endif
|
||||
42
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/tensor.c
Normal file
42
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/tensor.c
Normal file
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @file tensor.c
|
||||
* @brief Implementation of tensor code
|
||||
*/
|
||||
|
||||
#include "bch.h"
|
||||
#include "parameters.h"
|
||||
#include "repetition.h"
|
||||
#include "tensor.h"
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encoding the message m to a code word em using the tensor code
|
||||
*
|
||||
* First we encode the message using the BCH code, then with the repetition code to obtain
|
||||
* a tensor code word.
|
||||
*
|
||||
* @param[out] em Pointer to an array that is the tensor code word
|
||||
* @param[in] m Pointer to an array that is the message
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_tensor_code_encode(uint8_t *em, const uint8_t *m) {
|
||||
uint8_t tmp[VEC_N1_SIZE_BYTES] = {0};
|
||||
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_bch_code_encode(tmp, m);
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_repetition_code_encode(em, tmp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Decoding the code word em to a message m using the tensor code
|
||||
*
|
||||
* @param[out] m Pointer to an array that is the message
|
||||
* @param[in] em Pointer to an array that is the code word
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_tensor_code_decode(uint8_t *m, const uint8_t *em) {
|
||||
uint8_t tmp[VEC_N1_SIZE_BYTES] = {0};
|
||||
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_repetition_code_decode(tmp, em);
|
||||
PQCLEAN_HQC1921CCA2_LEAKTIME_bch_code_decode(m, tmp);
|
||||
}
|
||||
14
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/tensor.h
Normal file
14
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/tensor.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef PQCLEAN_HQC1921CCA2_LEAKTIME_TENSOR_H
|
||||
#define PQCLEAN_HQC1921CCA2_LEAKTIME_TENSOR_H
|
||||
|
||||
/**
|
||||
* @file tensor.h
|
||||
* @brief Header file for tensor.c
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_tensor_code_encode(uint8_t *em, const uint8_t *m);
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_tensor_code_decode(uint8_t *m, const uint8_t *em);
|
||||
|
||||
#endif
|
||||
69
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/util.c
Normal file
69
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/util.c
Normal file
@ -0,0 +1,69 @@
|
||||
#include "util.h"
|
||||
#include "stddef.h"
|
||||
|
||||
#include "assert.h"
|
||||
|
||||
/* These functions should help with endianness-safe conversions
|
||||
*
|
||||
* load8 and store8 are copied from the McEliece implementations,
|
||||
* which are in the public domain.
|
||||
*/
|
||||
|
||||
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_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_HQC1921CCA2_LEAKTIME_load8(const unsigned char *in) {
|
||||
uint64_t ret = in[7];
|
||||
|
||||
for (int8_t i = 6; i >= 0; i--) {
|
||||
ret <<= 8;
|
||||
ret |= in[i];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_load8_arr(uint64_t *out64, size_t outlen, const uint8_t *in8, size_t inlen) {
|
||||
size_t index_in = 0;
|
||||
size_t index_out = 0;
|
||||
|
||||
// first copy by 8 bytes
|
||||
if (inlen >= 8 && outlen >= 1) {
|
||||
while (index_out < outlen && index_in + 8 <= inlen) {
|
||||
out64[index_out] = PQCLEAN_HQC1921CCA2_LEAKTIME_load8(in8 + index_in);
|
||||
|
||||
index_in += 8;
|
||||
index_out += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// we now need to do the last 7 bytes if necessary
|
||||
if (index_in >= inlen || index_out >= outlen) {
|
||||
return;
|
||||
}
|
||||
out64[index_out] = in8[inlen - 1];
|
||||
for (int8_t i = (int8_t)(inlen - index_in) - 2; i >= 0; i--) {
|
||||
out64[index_out] <<= 8;
|
||||
out64[index_out] |= in8[index_in + i];
|
||||
}
|
||||
}
|
||||
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_store8_arr(uint8_t *out8, size_t outlen, const uint64_t *in64, size_t inlen) {
|
||||
for (size_t index_out = 0, index_in = 0; index_out < outlen && index_in < inlen;) {
|
||||
out8[index_out] = (in64[index_in] >> ((index_out % 8) * 8)) & 0xFF;
|
||||
index_out++;
|
||||
if (index_out % 8 == 0) {
|
||||
index_in++;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/util.h
Normal file
9
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/util.h
Normal file
@ -0,0 +1,9 @@
|
||||
/* These functions should help with endianness-safe conversions */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_store8(unsigned char *out, uint64_t in);
|
||||
uint64_t PQCLEAN_HQC1921CCA2_LEAKTIME_load8(const unsigned char *in);
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_load8_arr(uint64_t *out64, size_t outlen, const uint8_t *in8, size_t inlen);
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_store8_arr(uint8_t *out8, size_t outlen, const uint64_t *in64, size_t inlen);
|
||||
224
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/vector.c
Normal file
224
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/vector.c
Normal file
@ -0,0 +1,224 @@
|
||||
/**
|
||||
* @file vector.c
|
||||
* @brief Implementation of vectors sampling and some utilities for the HQC scheme
|
||||
*/
|
||||
|
||||
#include "nistseedexpander.h"
|
||||
#include "parameters.h"
|
||||
#include "randombytes.h"
|
||||
#include "vector.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Generates a vector of a given Hamming weight
|
||||
*
|
||||
* This function generates uniformly at random a binary vector of a Hamming weight equal to the parameter <b>weight</b>. The vector
|
||||
* is stored by position.
|
||||
* To generate the vector we have to sample uniformly at random values in the interval [0, PARAM_N -1]. Suppose the PARAM_N is equal to \f$ 70853 \f$, to select a position \f$ r\f$ the function works as follow:
|
||||
* 1. It makes a call to the seedexpander function to obtain a random number \f$ x\f$ in \f$ [0, 2^{24}[ \f$.
|
||||
* 2. Let \f$ t = \lfloor {2^{24} \over 70853} \rfloor \times 70853\f$
|
||||
* 3. If \f$ x \geq t\f$, go to 1
|
||||
* 4. It return \f$ r = x \mod 70853\f$
|
||||
*
|
||||
* The parameter \f$ t \f$ is precomputed and it's denoted by UTILS_REJECTION_THRESHOLD (see the file parameters.h).
|
||||
*
|
||||
* @param[in] v Pointer to an array
|
||||
* @param[in] weight Integer that is the Hamming weight
|
||||
* @param[in] ctx Pointer to the context of the seed expander
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_vect_set_random_fixed_weight_by_coordinates(AES_XOF_struct *ctx, uint32_t *v, uint16_t weight) {
|
||||
size_t random_bytes_size = 3 * weight;
|
||||
uint8_t rand_bytes[3 * PARAM_OMEGA_R] = {0}; // weight is expected to be <= PARAM_OMEGA_R
|
||||
uint32_t random_data = 0;
|
||||
uint8_t exist = 0;
|
||||
size_t j = 0;
|
||||
|
||||
seedexpander(ctx, rand_bytes, random_bytes_size);
|
||||
|
||||
for (uint32_t i = 0; i < weight; ++i) {
|
||||
exist = 0;
|
||||
do {
|
||||
if (j == random_bytes_size) {
|
||||
seedexpander(ctx, rand_bytes, random_bytes_size);
|
||||
j = 0;
|
||||
}
|
||||
|
||||
random_data = ((uint32_t) rand_bytes[j++]) << 16;
|
||||
random_data |= ((uint32_t) rand_bytes[j++]) << 8;
|
||||
random_data |= rand_bytes[j++];
|
||||
|
||||
} while (random_data >= UTILS_REJECTION_THRESHOLD);
|
||||
|
||||
random_data = random_data % PARAM_N;
|
||||
|
||||
for (uint32_t k = 0; k < i; k++) {
|
||||
if (v[k] == random_data) {
|
||||
exist = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (exist == 1) {
|
||||
i--;
|
||||
} else {
|
||||
v[i] = random_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Generates a vector of a given Hamming weight
|
||||
*
|
||||
* This function generates uniformly at random a binary vector of a Hamming weight equal to the parameter <b>weight</b>.
|
||||
* To generate the vector we have to sample uniformly at random values in the interval [0, PARAM_N -1]. Suppose the PARAM_N is equal to \f$ 70853 \f$, to select a position \f$ r\f$ the function works as follow:
|
||||
* 1. It makes a call to the seedexpander function to obtain a random number \f$ x\f$ in \f$ [0, 2^{24}[ \f$.
|
||||
* 2. Let \f$ t = \lfloor {2^{24} \over 70853} \rfloor \times 70853\f$
|
||||
* 3. If \f$ x \geq t\f$, go to 1
|
||||
* 4. It return \f$ r = x \mod 70853\f$
|
||||
*
|
||||
* The parameter \f$ t \f$ is precomputed and it's denoted by UTILS_REJECTION_THRESHOLD (see the file parameters.h).
|
||||
*
|
||||
* @param[in] v Pointer to an array
|
||||
* @param[in] weight Integer that is the Hamming weight
|
||||
* @param[in] ctx Pointer to the context of the seed expander
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_vect_set_random_fixed_weight(AES_XOF_struct *ctx, uint8_t *v, uint16_t weight) {
|
||||
|
||||
size_t random_bytes_size = 3 * weight;
|
||||
uint8_t rand_bytes[3 * PARAM_OMEGA_R] = {0}; // weight is expected to be <= PARAM_OMEGA_R
|
||||
uint32_t random_data = 0;
|
||||
uint32_t tmp[PARAM_OMEGA_R] = {0};
|
||||
uint8_t exist = 0;
|
||||
size_t j = 0;
|
||||
|
||||
seedexpander(ctx, rand_bytes, random_bytes_size);
|
||||
|
||||
for (uint32_t i = 0; i < weight; ++i) {
|
||||
exist = 0;
|
||||
do {
|
||||
if (j == random_bytes_size) {
|
||||
seedexpander(ctx, rand_bytes, random_bytes_size);
|
||||
j = 0;
|
||||
}
|
||||
|
||||
random_data = ((uint32_t) rand_bytes[j++]) << 16;
|
||||
random_data |= ((uint32_t) rand_bytes[j++]) << 8;
|
||||
random_data |= rand_bytes[j++];
|
||||
|
||||
} while (random_data >= UTILS_REJECTION_THRESHOLD);
|
||||
|
||||
random_data = random_data % PARAM_N;
|
||||
|
||||
for (uint32_t k = 0; k < i; k++) {
|
||||
if (tmp[k] == random_data) {
|
||||
exist = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (exist == 1) {
|
||||
i--;
|
||||
} else {
|
||||
tmp[i] = random_data;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < weight; ++i) {
|
||||
int32_t index = tmp[i] / 8;
|
||||
int32_t pos = tmp[i] % 8;
|
||||
v[index] |= 1 << pos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Generates a random vector of dimension <b>PARAM_N</b>
|
||||
*
|
||||
* This function generates a random binary vector of dimension <b>PARAM_N</b>. It generates a random
|
||||
* array of bytes using the seedexpander function, and drop the extra bits using a mask.
|
||||
*
|
||||
* @param[in] v Pointer to an array
|
||||
* @param[in] ctx Pointer to the context of the seed expander
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_vect_set_random(AES_XOF_struct *ctx, uint8_t *v) {
|
||||
uint8_t rand_bytes[VEC_N_SIZE_BYTES] = {0};
|
||||
|
||||
seedexpander(ctx, rand_bytes, VEC_N_SIZE_BYTES);
|
||||
|
||||
memcpy(v, rand_bytes, VEC_N_SIZE_BYTES);
|
||||
v[VEC_N_SIZE_BYTES - 1] &= BITMASK(PARAM_N, 8);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Generates a random vector
|
||||
*
|
||||
* This function generates a random binary vector. It uses the the randombytes function.
|
||||
*
|
||||
* @param[in] v Pointer to an array
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_vect_set_random_from_randombytes(uint8_t *v) {
|
||||
uint8_t rand_bytes [VEC_K_SIZE_BYTES] = {0};
|
||||
|
||||
randombytes(rand_bytes, VEC_K_SIZE_BYTES);
|
||||
memcpy(v, rand_bytes, VEC_K_SIZE_BYTES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Adds two vectors
|
||||
*
|
||||
* @param[out] o Pointer to an array that is the result
|
||||
* @param[in] v1 Pointer to an array that is the first vector
|
||||
* @param[in] v2 Pointer to an array that is the second vector
|
||||
* @param[in] size Integer that is the size of the vectors
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_vect_add(uint8_t *o, const uint8_t *v1, const uint8_t *v2, uint32_t size) {
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
o[i] = v1[i] ^ v2[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Compares two vectors
|
||||
*
|
||||
* @param[in] v1 Pointer to an array that is first vector
|
||||
* @param[in] v2 Pointer to an array that is second vector
|
||||
* @param[in] size Integer that is the size of the vectors
|
||||
* @returns 0 if the vectors are equals and a negative/psotive value otherwise
|
||||
*/
|
||||
int PQCLEAN_HQC1921CCA2_LEAKTIME_vect_compare(const uint8_t *v1, const uint8_t *v2, uint32_t size) {
|
||||
return memcmp(v1, v2, size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Resize a vector so that it contains <b>size_o</b> bits
|
||||
*
|
||||
* @param[out] o Pointer to the output vector
|
||||
* @param[in] size_o Integer that is the size of the output vector in bits
|
||||
* @param[in] v Pointer to the input vector
|
||||
* @param[in] size_v Integer that is the size of the input vector in bits
|
||||
*/
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_vect_resize(uint8_t *o, uint32_t size_o, const uint8_t *v, uint32_t size_v) {
|
||||
if (size_o < size_v) {
|
||||
uint8_t mask = 0x7F;
|
||||
int8_t val = 8 - (size_o % 8);
|
||||
|
||||
memcpy(o, v, VEC_N1N2_SIZE_BYTES);
|
||||
|
||||
for (int8_t i = 0; i < val; ++i) {
|
||||
o[VEC_N1N2_SIZE_BYTES - 1] &= (mask >> i);
|
||||
}
|
||||
} else {
|
||||
memcpy(o, v, CEIL_DIVIDE(size_v, 8));
|
||||
}
|
||||
}
|
||||
22
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/vector.h
Normal file
22
src/kem/hqc/pqclean_hqc-192-1-cca2_leaktime/vector.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef PQCLEAN_HQC1921CCA2_LEAKTIME_VECTOR_H
|
||||
#define PQCLEAN_HQC1921CCA2_LEAKTIME_VECTOR_H
|
||||
|
||||
/**
|
||||
* @file vector.h
|
||||
* @brief Header file for vector.c
|
||||
*/
|
||||
|
||||
#include "nistseedexpander.h"
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_vect_set_random_fixed_weight_by_coordinates(AES_XOF_struct *ctx, uint32_t *v, uint16_t weight);
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_vect_set_random_fixed_weight(AES_XOF_struct *ctx, uint8_t *v, uint16_t weight);
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_vect_set_random(AES_XOF_struct *ctx, uint8_t *v);
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_vect_set_random_from_randombytes(uint8_t *v);
|
||||
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_vect_add(uint8_t *o, const uint8_t *v1, const uint8_t *v2, uint32_t size);
|
||||
int PQCLEAN_HQC1921CCA2_LEAKTIME_vect_compare(const uint8_t *v1, const uint8_t *v2, uint32_t size);
|
||||
|
||||
void PQCLEAN_HQC1921CCA2_LEAKTIME_vect_resize(uint8_t *o, uint32_t size_o, const uint8_t *v, uint32_t size_v);
|
||||
|
||||
#endif
|
||||
1
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/LICENSE
Normal file
1
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/LICENSE
Normal file
@ -0,0 +1 @@
|
||||
Public domain
|
||||
25
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/api.h
Normal file
25
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/api.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef PQCLEAN_HQC1922CCA2_LEAKTIME_API_H
|
||||
#define PQCLEAN_HQC1922CCA2_LEAKTIME_API_H
|
||||
|
||||
/**
|
||||
* \file api.h
|
||||
* \brief NIST KEM API used by the HQC_KEM IND-CCA2 scheme
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PQCLEAN_HQC1922CCA2_LEAKTIME_CRYPTO_ALGNAME "HQC_192_2_CCA2"
|
||||
|
||||
#define PQCLEAN_HQC1922CCA2_LEAKTIME_CRYPTO_SECRETKEYBYTES 5924
|
||||
#define PQCLEAN_HQC1922CCA2_LEAKTIME_CRYPTO_PUBLICKEYBYTES 5884
|
||||
#define PQCLEAN_HQC1922CCA2_LEAKTIME_CRYPTO_BYTES 64
|
||||
#define PQCLEAN_HQC1922CCA2_LEAKTIME_CRYPTO_CIPHERTEXTBYTES 11749
|
||||
|
||||
// As a technicality, the public key is appended to the secret key in order to respect the NIST API.
|
||||
// Without this constraint, CRYPTO_SECRETKEYBYTES would be defined as 32
|
||||
|
||||
int PQCLEAN_HQC1922CCA2_LEAKTIME_crypto_kem_keypair(uint8_t *pk, uint8_t *sk);
|
||||
int PQCLEAN_HQC1922CCA2_LEAKTIME_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
|
||||
int PQCLEAN_HQC1922CCA2_LEAKTIME_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
|
||||
|
||||
#endif
|
||||
295
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/bch.c
Normal file
295
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/bch.c
Normal file
@ -0,0 +1,295 @@
|
||||
/**
|
||||
* @file bch.c
|
||||
* Constant time implementation of BCH codes
|
||||
*/
|
||||
|
||||
#include "bch.h"
|
||||
#include "fft.h"
|
||||
#include "gf.h"
|
||||
#include "parameters.h"
|
||||
#include "vector.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
static void unpack_message(uint8_t *message_unpacked, const uint8_t *message);
|
||||
static void lfsr_encode(uint8_t *codeword, const uint8_t *message);
|
||||
static void pack_codeword(uint8_t *codeword, const uint8_t *codeword_unpacked);
|
||||
static size_t compute_elp(uint16_t *sigma, const uint16_t *syndromes);
|
||||
static void message_from_codeword(uint8_t *message, const uint8_t *codeword);
|
||||
static void compute_syndromes(uint16_t *syndromes, const uint8_t *vector);
|
||||
static void compute_roots(uint8_t *error, const uint16_t *sigma);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Unpacks the message message to the array message_unpacked where each byte stores a bit of the message
|
||||
*
|
||||
* @param[out] message_unpacked Array of VEC_K_SIZE_BYTES bytes receiving the unpacked message
|
||||
* @param[in] message Array of PARAM_K bytes storing the packed message
|
||||
*/
|
||||
static void unpack_message(uint8_t *message_unpacked, const uint8_t *message) {
|
||||
for (size_t i = 0; i < (VEC_K_SIZE_BYTES - (PARAM_K % 8 != 0)); ++i) {
|
||||
for (size_t j = 0; j < 8; ++j) {
|
||||
message_unpacked[j + 8 * i] = (message[i] >> j) & 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
for (int8_t j = 0; j < PARAM_K % 8; ++j) {
|
||||
message_unpacked[j + 8 * (VEC_K_SIZE_BYTES - 1)] = (message[VEC_K_SIZE_BYTES - 1] >> j) & 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encodes the message message to a codeword codeword using the generator polynomial bch_poly of the code
|
||||
*
|
||||
* @param[out] codeword Array of PARAM_N1 bytes receiving the codeword
|
||||
* @param[in] message Array of PARAM_K bytes storing the message to encode
|
||||
*/
|
||||
static void lfsr_encode(uint8_t *codeword, const uint8_t *message) {
|
||||
uint8_t gate_value = 0;
|
||||
uint8_t bch_poly[PARAM_G] = PARAM_BCH_POLY;
|
||||
|
||||
// Compute the Parity-check digits
|
||||
for (int16_t i = PARAM_K - 1; i >= 0; --i) {
|
||||
gate_value = message[i] ^ codeword[PARAM_N1 - PARAM_K - 1];
|
||||
|
||||
for (size_t j = PARAM_N1 - PARAM_K - 1; j; --j) {
|
||||
codeword[j] = codeword[j - 1] ^ (-gate_value & bch_poly[j]);
|
||||
}
|
||||
|
||||
codeword[0] = gate_value;
|
||||
}
|
||||
|
||||
// Add the message
|
||||
memcpy(codeword + PARAM_N1 - PARAM_K, message, PARAM_K);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Packs the codeword from an array codeword_unpacked where each byte stores a bit to a compact array codeword
|
||||
*
|
||||
* @param[out] codeword Array of VEC_N1_SIZE_BYTES bytes receiving the packed codeword
|
||||
* @param[in] codeword_unpacked Array of PARAM_N1 bytes storing the unpacked codeword
|
||||
*/
|
||||
static void pack_codeword(uint8_t *codeword, const uint8_t *codeword_unpacked) {
|
||||
for (size_t i = 0; i < (VEC_N1_SIZE_BYTES - (PARAM_N1 % 8 != 0)); ++i) {
|
||||
for (size_t j = 0; j < 8; ++j) {
|
||||
codeword[i] |= codeword_unpacked[j + 8 * i] << j;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < PARAM_N1 % 8; ++j) {
|
||||
codeword[VEC_N1_SIZE_BYTES - 1] |= codeword_unpacked[j + 8 * (VEC_N1_SIZE_BYTES - 1)] << j;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encodes a message message of PARAM_K bits to a BCH codeword codeword of PARAM_N1 bits
|
||||
*
|
||||
* Following @cite lin1983error (Chapter 4 - Cyclic Codes),
|
||||
* We perform a systematic encoding using a linear (PARAM_N1 - PARAM_K)-stage shift register
|
||||
* with feedback connections based on the generator polynomial bch_poly of the BCH code.
|
||||
*
|
||||
* @param[out] codeword Array of size VEC_N1_SIZE_BYTES receiving the encoded message
|
||||
* @param[in] message Array of size VEC_K_SIZE_BYTES storing the message
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_bch_code_encode(uint8_t *codeword, const uint8_t *message) {
|
||||
uint8_t message_unpacked[PARAM_K];
|
||||
uint8_t codeword_unpacked[PARAM_N1] = {0};
|
||||
|
||||
unpack_message(message_unpacked, message);
|
||||
lfsr_encode(codeword_unpacked, message_unpacked);
|
||||
pack_codeword(codeword, codeword_unpacked);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the error locator polynomial (ELP) sigma
|
||||
*
|
||||
* This is a constant time implementation of Berlekamp's simplified algorithm (see @cite joiner1995decoding). <br>
|
||||
* We use the letter p for rho which is initialized at -1/2. <br>
|
||||
* The array X_sigma_p represents the polynomial X^(2(mu-rho))*sigma_p(X). <br>
|
||||
* Instead of maintaining a list of sigmas, we update in place both sigma and X_sigma_p. <br>
|
||||
* sigma_copy serves as a temporary save of sigma in case X_sigma_p needs to be updated. <br>
|
||||
* We can properly correct only if the degree of sigma does not exceed PARAM_DELTA.
|
||||
* This means only the first PARAM_DELTA + 1 coefficients of sigma are of value
|
||||
* and we only need to save its first PARAM_DELTA - 1 coefficients.
|
||||
*
|
||||
* @returns the degree of the ELP sigma
|
||||
* @param[out] sigma Array of size (at least) PARAM_DELTA receiving the ELP
|
||||
* @param[in] syndromes Array of size (at least) 2*PARAM_DELTA storing the syndromes
|
||||
*/
|
||||
static size_t compute_elp(uint16_t *sigma, const uint16_t *syndromes) {
|
||||
sigma[0] = 1;
|
||||
size_t deg_sigma = 0;
|
||||
size_t deg_sigma_p = 0;
|
||||
uint16_t sigma_copy[PARAM_DELTA - 1] = {0};
|
||||
size_t deg_sigma_copy = 0;
|
||||
uint16_t X_sigma_p[PARAM_DELTA + 1] = {0, 1};
|
||||
int32_t pp = -1; // 2*rho
|
||||
uint16_t d_p = 1;
|
||||
uint16_t d = syndromes[0];
|
||||
|
||||
for (size_t mu = 0; mu < PARAM_DELTA; ++mu) {
|
||||
// Save sigma in case we need it to update X_sigma_p
|
||||
memcpy(sigma_copy, sigma, 2 * (PARAM_DELTA - 1));
|
||||
deg_sigma_copy = deg_sigma;
|
||||
|
||||
uint16_t dd = PQCLEAN_HQC1922CCA2_LEAKTIME_gf_mul(d, PQCLEAN_HQC1922CCA2_LEAKTIME_gf_inverse(d_p)); // 0 if(d == 0)
|
||||
for (size_t i = 1; (i <= 2 * mu + 1) && (i <= PARAM_DELTA); ++i) {
|
||||
sigma[i] ^= PQCLEAN_HQC1922CCA2_LEAKTIME_gf_mul(dd, X_sigma_p[i]);
|
||||
}
|
||||
|
||||
size_t deg_X = 2 * mu - pp; // 2*(mu-rho)
|
||||
size_t deg_X_sigma_p = deg_X + deg_sigma_p;
|
||||
|
||||
// mask1 = 0xffff if(d != 0) and 0 otherwise
|
||||
int16_t mask1 = -((uint16_t) - d >> 15);
|
||||
|
||||
// mask2 = 0xffff if(deg_X_sigma_p > deg_sigma) and 0 otherwise
|
||||
int16_t mask2 = -((uint16_t) (deg_sigma - deg_X_sigma_p) >> 15);
|
||||
|
||||
// mask12 = 0xffff if the deg_sigma increased and 0 otherwise
|
||||
int16_t mask12 = mask1 & mask2;
|
||||
deg_sigma = (mask12 & deg_X_sigma_p) ^ (~mask12 & deg_sigma);
|
||||
|
||||
if (mu == PARAM_DELTA - 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Update pp, d_p and X_sigma_p if needed
|
||||
pp = (mask12 & (2 * mu)) ^ (~mask12 & pp);
|
||||
d_p = (mask12 & d) ^ (~mask12 & d_p);
|
||||
for (size_t i = PARAM_DELTA - 1; i; --i) {
|
||||
X_sigma_p[i + 1] = (mask12 & sigma_copy[i - 1]) ^ (~mask12 & X_sigma_p[i - 1]);
|
||||
}
|
||||
X_sigma_p[1] = 0;
|
||||
X_sigma_p[0] = 0;
|
||||
deg_sigma_p = (mask12 & deg_sigma_copy) ^ (~mask12 & deg_sigma_p);
|
||||
|
||||
// Compute the next discrepancy
|
||||
d = syndromes[2 * mu + 2];
|
||||
for (size_t i = 1; (i <= 2 * mu + 1) && (i <= PARAM_DELTA); ++i) {
|
||||
d ^= PQCLEAN_HQC1922CCA2_LEAKTIME_gf_mul(sigma[i], syndromes[2 * mu + 2 - i]);
|
||||
}
|
||||
}
|
||||
|
||||
return deg_sigma;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieves the message message from the codeword codeword
|
||||
*
|
||||
* Since we performed a systematic encoding, the message is the last PARAM_K bits of the codeword.
|
||||
*
|
||||
* @param[out] message Array of size VEC_K_SIZE_BYTES receiving the message
|
||||
* @param[in] codeword Array of size VEC_N1_SIZE_BYTES storing the codeword
|
||||
*/
|
||||
static void message_from_codeword(uint8_t *message, const uint8_t *codeword) {
|
||||
int32_t val = PARAM_N1 - PARAM_K;
|
||||
|
||||
uint8_t mask1 = 0xff << val % 8;
|
||||
uint8_t mask2 = 0xff >> (8 - val % 8);
|
||||
size_t index = val / 8;
|
||||
|
||||
for (size_t i = 0; i < VEC_K_SIZE_BYTES - 1; ++i) {
|
||||
uint8_t message1 = (codeword[index] & mask1) >> val % 8;
|
||||
uint8_t message2 = (codeword[++index] & mask2) << (8 - val % 8);
|
||||
message[i] = message1 | message2;
|
||||
}
|
||||
|
||||
// Last byte (8-val % 8 is the number of bits given by message1)
|
||||
if ((PARAM_K % 8 == 0) || (8 - val % 8 < PARAM_K % 8)) {
|
||||
uint8_t message1 = (codeword[index] & mask1) >> val % 8;
|
||||
uint8_t message2 = (codeword[++index] & mask2) << (8 - val % 8);
|
||||
message[VEC_K_SIZE_BYTES - 1] = message1 | message2;
|
||||
} else {
|
||||
uint8_t message1 = (codeword[index] & mask1) >> val % 8;
|
||||
message[VEC_K_SIZE_BYTES - 1] = message1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the 2^PARAM_DELTA syndromes from the received vector vector
|
||||
*
|
||||
* Syndromes are the sum of powers of alpha weighted by vector's coefficients.
|
||||
* To do so, we use the additive FFT transpose, which takes as input a family w of GF(2^PARAM_M) elements
|
||||
* and outputs the weighted power sums of these w. <br>
|
||||
* Therefore, this requires twisting and applying a permutation before feeding vector to the fft transpose. <br>
|
||||
* For more details see Berstein, Chou and Schawbe's explanations:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*
|
||||
* @param[out] syndromes Array of size 2^(PARAM_FFT_T) receiving the 2*PARAM_DELTA syndromes
|
||||
* @param[in] vector Array of size VEC_N1_SIZE_BYTES storing the received word
|
||||
*/
|
||||
static void compute_syndromes(uint16_t *syndromes, const uint8_t *vector) {
|
||||
uint16_t w[1 << PARAM_M];
|
||||
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_fft_t_preprocess_bch_codeword(w, vector);
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_fft_t(syndromes, w, 2 * PARAM_DELTA);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the error polynomial error from the error locator polynomial sigma
|
||||
*
|
||||
* See function fft for more details.
|
||||
*
|
||||
* @param[out] err Array of VEC_N1_SIZE_BYTES elements receiving the error polynomial
|
||||
* @param[in] sigma Array of 2^PARAM_FFT elements storing the error locator polynomial
|
||||
*/
|
||||
static void compute_roots(uint8_t *error, const uint16_t *sigma) {
|
||||
uint16_t w[1 << PARAM_M] = {0}; // w will receive the evaluation of sigma in all field elements
|
||||
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_fft(w, sigma, PARAM_DELTA + 1);
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_fft_retrieve_bch_error_poly(error, w);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Decodes the received word
|
||||
*
|
||||
* This function relies on four steps:
|
||||
* <ol>
|
||||
* <li> The first step, done by additive FFT transpose, is the computation of the 2*PARAM_DELTA syndromes.
|
||||
* <li> The second step is the computation of the error-locator polynomial sigma.
|
||||
* <li> The third step, done by additive FFT, is finding the error-locator numbers by calculating the roots of the polynomial sigma and takings their inverses.
|
||||
* <li> The fourth step is the correction of the errors in the received polynomial.
|
||||
* </ol>
|
||||
* For a more complete picture on BCH decoding, see Shu. Lin and Daniel J. Costello in Error Control Coding: Fundamentals and Applications @cite lin1983error
|
||||
*
|
||||
* @param[out] message Array of size VEC_K_SIZE_BYTES receiving the decoded message
|
||||
* @param[in] vector Array of size VEC_N1_SIZE_BYTES storing the received word
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_bch_code_decode(uint8_t *message, uint8_t *vector) {
|
||||
uint16_t syndromes[1 << PARAM_FFT_T];
|
||||
uint16_t sigma[1 << PARAM_FFT] = {0};
|
||||
uint8_t error[(1 << PARAM_M) / 8] = {0};
|
||||
|
||||
// Calculate the 2*PARAM_DELTA syndromes
|
||||
compute_syndromes(syndromes, vector);
|
||||
|
||||
// Compute the error locator polynomial sigma
|
||||
// Sigma's degree is at most PARAM_DELTA but the FFT requires the extra room
|
||||
compute_elp(sigma, syndromes);
|
||||
|
||||
// Compute the error polynomial error
|
||||
compute_roots(error, sigma);
|
||||
|
||||
// Add the error polynomial to the received polynomial
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_add(vector, vector, error, VEC_N1_SIZE_BYTES);
|
||||
|
||||
// Retrieve the message from the decoded codeword
|
||||
message_from_codeword(message, vector);
|
||||
}
|
||||
16
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/bch.h
Normal file
16
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/bch.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef PQCLEAN_HQC1922CCA2_LEAKTIME_BCH_H
|
||||
#define PQCLEAN_HQC1922CCA2_LEAKTIME_BCH_H
|
||||
|
||||
/**
|
||||
* @file bch.h
|
||||
* Header file of bch.c
|
||||
*/
|
||||
|
||||
#include "parameters.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_bch_code_encode(uint8_t *codeword, const uint8_t *message);
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_bch_code_decode(uint8_t *message, uint8_t *vector);
|
||||
|
||||
#endif
|
||||
628
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/fft.c
Normal file
628
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/fft.c
Normal file
@ -0,0 +1,628 @@
|
||||
/**
|
||||
* @file fft.c
|
||||
* Implementation of the additive FFT and its transpose.
|
||||
* This implementation is based on the paper from Gao and Mateer: <br>
|
||||
* Shuhong Gao and Todd Mateer, Additive Fast Fourier Transforms over Finite Fields,
|
||||
* IEEE Transactions on Information Theory 56 (2010), 6265--6272.
|
||||
* http://www.math.clemson.edu/~sgao/papers/GM10.pdf <br>
|
||||
* and includes improvements proposed by Bernstein, Chou and Schwabe here:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*/
|
||||
|
||||
#include "fft.h"
|
||||
#include "gf.h"
|
||||
#include "parameters.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
static void compute_fft_betas(uint16_t *betas);
|
||||
static void compute_subset_sums(uint16_t *subset_sums, const uint16_t *set, size_t set_size);
|
||||
static void radix_t(uint16_t *f, const uint16_t *f0, const uint16_t *f1, uint32_t m_f);
|
||||
static void fft_t_rec(uint16_t *f, const uint16_t *w, size_t f_coeffs, uint8_t m, uint32_t m_f, const uint16_t *betas);
|
||||
static void radix(uint16_t *f0, uint16_t *f1, const uint16_t *f, uint32_t m_f);
|
||||
static void fft_rec(uint16_t *w, uint16_t *f, size_t f_coeffs, uint8_t m, uint32_t m_f, const uint16_t *betas);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the basis of betas (omitting 1) used in the additive FFT and its transpose
|
||||
*
|
||||
* @param[out] betas Array of size PARAM_M-1
|
||||
*/
|
||||
static void compute_fft_betas(uint16_t *betas) {
|
||||
for (size_t i = 0; i < PARAM_M - 1; ++i) {
|
||||
betas[i] = 1 << (PARAM_M - 1 - i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the subset sums of the given set
|
||||
*
|
||||
* The array subset_sums is such that its ith element is
|
||||
* the subset sum of the set elements given by the binary form of i.
|
||||
*
|
||||
* @param[out] subset_sums Array of size 2^set_size receiving the subset sums
|
||||
* @param[in] set Array of set_size elements
|
||||
* @param[in] set_size Size of the array set
|
||||
*/
|
||||
static void compute_subset_sums(uint16_t *subset_sums, const uint16_t *set, size_t set_size) {
|
||||
subset_sums[0] = 0;
|
||||
|
||||
for (size_t i = 0; i < set_size; ++i) {
|
||||
for (size_t j = 0; j < (((size_t)1) << i); ++j) {
|
||||
subset_sums[(((size_t)1) << i) + j] = set[i] ^ subset_sums[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Transpose of the linear radix conversion
|
||||
*
|
||||
* This is a direct transposition of the radix function
|
||||
* implemented following the process of transposing a linear function as exposed by Bernstein, Chou and Schwabe here:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*
|
||||
* @param[out] f Array of size a power of 2
|
||||
* @param[in] f0 Array half the size of f
|
||||
* @param[in] f1 Array half the size of f
|
||||
* @param[in] m_f 2^{m_f} is the smallest power of 2 greater or equal to the number of coefficients of f
|
||||
*/
|
||||
static void radix_t(uint16_t *f, const uint16_t *f0, const uint16_t *f1, uint32_t m_f) {
|
||||
switch (m_f) {
|
||||
case 4:
|
||||
f[0] = f0[0];
|
||||
f[1] = f1[0];
|
||||
f[2] = f0[1] ^ f1[0];
|
||||
f[3] = f[2] ^ f1[1];
|
||||
f[4] = f[2] ^ f0[2];
|
||||
f[5] = f[3] ^ f1[2];
|
||||
f[6] = f[4] ^ f0[3] ^ f1[2];
|
||||
f[7] = f[3] ^ f0[3] ^ f1[3];
|
||||
f[8] = f[4] ^ f0[4];
|
||||
f[9] = f[5] ^ f1[4];
|
||||
f[10] = f[6] ^ f0[5] ^ f1[4];
|
||||
f[11] = f[7] ^ f0[5] ^ f1[4] ^ f1[5];
|
||||
f[12] = f[8] ^ f0[5] ^ f0[6] ^ f1[4];
|
||||
f[13] = f[7] ^ f[9] ^ f[11] ^ f1[6];
|
||||
f[14] = f[6] ^ f0[6] ^ f0[7] ^ f1[6];
|
||||
f[15] = f[7] ^ f0[7] ^ f1[7];
|
||||
return;
|
||||
|
||||
case 3:
|
||||
f[0] = f0[0];
|
||||
f[1] = f1[0];
|
||||
f[2] = f0[1] ^ f1[0];
|
||||
f[3] = f[2] ^ f1[1];
|
||||
f[4] = f[2] ^ f0[2];
|
||||
f[5] = f[3] ^ f1[2];
|
||||
f[6] = f[4] ^ f0[3] ^ f1[2];
|
||||
f[7] = f[3] ^ f0[3] ^ f1[3];
|
||||
return;
|
||||
|
||||
case 2:
|
||||
f[0] = f0[0];
|
||||
f[1] = f1[0];
|
||||
f[2] = f0[1] ^ f1[0];
|
||||
f[3] = f[2] ^ f1[1];
|
||||
return;
|
||||
|
||||
case 1:
|
||||
f[0] = f0[0];
|
||||
f[1] = f1[0];
|
||||
return;
|
||||
|
||||
default:
|
||||
;
|
||||
|
||||
size_t n = ((size_t)1) << (m_f - 2);
|
||||
|
||||
uint16_t Q0[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t Q1[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t R0[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t R1[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
|
||||
uint16_t Q[1 << 2 * (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t R[1 << 2 * (PARAM_FFT_T - 2)] = {0};
|
||||
|
||||
memcpy(Q0, f0 + n, 2 * n);
|
||||
memcpy(Q1, f1 + n, 2 * n);
|
||||
memcpy(R0, f0, 2 * n);
|
||||
memcpy(R1, f1, 2 * n);
|
||||
|
||||
radix_t (Q, Q0, Q1, m_f - 1);
|
||||
radix_t (R, R0, R1, m_f - 1);
|
||||
|
||||
memcpy(f, R, 4 * n);
|
||||
memcpy(f + 2 * n, R + n, 2 * n);
|
||||
memcpy(f + 3 * n, Q + n, 2 * n);
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
f[2 * n + i] ^= Q[i];
|
||||
f[3 * n + i] ^= f[2 * n + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Recursively computes syndromes of family w
|
||||
*
|
||||
* This function is a subroutine of the function fft_t
|
||||
*
|
||||
* @param[out] f Array receiving the syndromes
|
||||
* @param[in] w Array storing the family
|
||||
* @param[in] f_coeffs Length of syndromes vector
|
||||
* @param[in] m 2^m is the smallest power of 2 greater or equal to the length of family w
|
||||
* @param[in] m_f 2^{m_f} is the smallest power of 2 greater or equal to the length of f
|
||||
* @param[in] betas FFT constants
|
||||
*/
|
||||
static void fft_t_rec(uint16_t *f, const uint16_t *w, size_t f_coeffs,
|
||||
uint8_t m, uint32_t m_f, const uint16_t *betas) {
|
||||
size_t k = ((size_t)1) << (m - 1);
|
||||
uint16_t gammas[PARAM_M - 2] = {0};
|
||||
uint16_t deltas[PARAM_M - 2] = {0};
|
||||
uint16_t gammas_sums[1 << (PARAM_M - 1)];
|
||||
uint16_t u[1 << (PARAM_M - 2)] = {0};
|
||||
uint16_t f0[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t f1[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t betas_sums[1 << (PARAM_M - 1)] = {0};
|
||||
|
||||
// Step 1
|
||||
if (m_f == 1) {
|
||||
for (size_t i = 0; i < (((size_t)1) << m); ++i) {
|
||||
f[0] ^= w[i];
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < m; ++j) {
|
||||
for (size_t ki = 0; ki < (((size_t)1) << j); ++ki) {
|
||||
size_t index = (((size_t)1) << j) + ki;
|
||||
betas_sums[index] = betas_sums[ki] ^ betas[j];
|
||||
f[1] ^= PQCLEAN_HQC1922CCA2_LEAKTIME_gf_mul(betas_sums[index], w[index]);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute gammas and deltas
|
||||
for (uint8_t i = 0; i < m - 1; ++i) {
|
||||
gammas[i] = PQCLEAN_HQC1922CCA2_LEAKTIME_gf_mul(betas[i], PQCLEAN_HQC1922CCA2_LEAKTIME_gf_inverse(betas[m - 1]));
|
||||
deltas[i] = PQCLEAN_HQC1922CCA2_LEAKTIME_gf_square(gammas[i]) ^ gammas[i];
|
||||
}
|
||||
|
||||
// Compute gammas subset sums
|
||||
compute_subset_sums(gammas_sums, gammas, m - 1);
|
||||
|
||||
/* Step 6: Compute u and v from w (aka w)
|
||||
* w[i] = u[i] + G[i].v[i]
|
||||
* w[k+i] = w[i] + v[i] = u[i] + (G[i]+1).v[i]
|
||||
* Transpose:
|
||||
* u[i] = w[i] + w[k+i]
|
||||
* v[i] = G[i].w[i] + (G[i]+1).w[k+i] = G[i].u[i] + w[k+i] */
|
||||
if (f_coeffs <= 3) { // 3-coefficient polynomial f case
|
||||
// Step 5: Compute f0 from u and f1 from v
|
||||
f1[1] = 0;
|
||||
u[0] = w[0] ^ w[k];
|
||||
f1[0] = w[k];
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
u[i] = w[i] ^ w[k + i];
|
||||
f1[0] ^= PQCLEAN_HQC1922CCA2_LEAKTIME_gf_mul(gammas_sums[i], u[i]) ^ w[k + i];
|
||||
}
|
||||
fft_t_rec(f0, u, (f_coeffs + 1) / 2, m - 1, m_f - 1, deltas);
|
||||
} else {
|
||||
uint16_t v[1 << (PARAM_M - 2)] = {0};
|
||||
|
||||
u[0] = w[0] ^ w[k];
|
||||
v[0] = w[k];
|
||||
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
u[i] = w[i] ^ w[k + i];
|
||||
v[i] = PQCLEAN_HQC1922CCA2_LEAKTIME_gf_mul(gammas_sums[i], u[i]) ^ w[k + i];
|
||||
}
|
||||
|
||||
// Step 5: Compute f0 from u and f1 from v
|
||||
fft_t_rec(f0, u, (f_coeffs + 1) / 2, m - 1, m_f - 1, deltas);
|
||||
fft_t_rec(f1, v, f_coeffs / 2, m - 1, m_f - 1, deltas);
|
||||
}
|
||||
|
||||
// Step 3: Compute g from g0 and g1
|
||||
radix_t(f, f0, f1, m_f);
|
||||
|
||||
// Step 2: compute f from g
|
||||
if (betas[m - 1] != 1) {
|
||||
uint16_t beta_m_pow = 1;
|
||||
for (size_t i = 1; i < (((size_t)1) << m_f); ++i) {
|
||||
beta_m_pow = PQCLEAN_HQC1922CCA2_LEAKTIME_gf_mul(beta_m_pow, betas[m - 1]);
|
||||
f[i] = PQCLEAN_HQC1922CCA2_LEAKTIME_gf_mul(beta_m_pow, f[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the syndromes f of the family w
|
||||
*
|
||||
* Since the syndromes linear map is the transpose of multipoint evaluation,
|
||||
* it uses exactly the same constants, either hardcoded or precomputed by compute_fft_lut(...). <br>
|
||||
* This follows directives from Bernstein, Chou and Schwabe given here:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*
|
||||
* @param[out] f Array of size 2*(PARAM_FFT_T) elements receiving the syndromes
|
||||
* @param[in] w Array of PARAM_GF_MUL_ORDER+1 elements
|
||||
* @param[in] f_coeffs Length of syndromes vector f
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_fft_t(uint16_t *f, const uint16_t *w, size_t f_coeffs) {
|
||||
// Transposed from Gao and Mateer algorithm
|
||||
uint16_t betas[PARAM_M - 1];
|
||||
uint16_t betas_sums[1 << (PARAM_M - 1)];
|
||||
size_t k = 1 << (PARAM_M - 1);
|
||||
uint16_t u[1 << (PARAM_M - 1)] = {0};
|
||||
uint16_t v[1 << (PARAM_M - 1)] = {0};
|
||||
uint16_t deltas[PARAM_M - 1];
|
||||
uint16_t f0[1 << (PARAM_FFT_T - 1)];
|
||||
uint16_t f1[1 << (PARAM_FFT_T - 1)];
|
||||
|
||||
compute_fft_betas(betas);
|
||||
compute_subset_sums(betas_sums, betas, PARAM_M - 1);
|
||||
|
||||
/* Step 6: Compute u and v from w (aka w)
|
||||
*
|
||||
* We had:
|
||||
* w[i] = u[i] + G[i].v[i]
|
||||
* w[k+i] = w[i] + v[i] = u[i] + (G[i]+1).v[i]
|
||||
* Transpose:
|
||||
* u[i] = w[i] + w[k+i]
|
||||
* v[i] = G[i].w[i] + (G[i]+1).w[k+i] = G[i].u[i] + w[k+i] */
|
||||
u[0] = w[0] ^ w[k];
|
||||
v[0] = w[k];
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
u[i] = w[i] ^ w[k + i];
|
||||
v[i] = PQCLEAN_HQC1922CCA2_LEAKTIME_gf_mul(betas_sums[i], u[i]) ^ w[k + i];
|
||||
}
|
||||
|
||||
// Compute deltas
|
||||
for (size_t i = 0; i < PARAM_M - 1; ++i) {
|
||||
deltas[i] = PQCLEAN_HQC1922CCA2_LEAKTIME_gf_square(betas[i]) ^ betas[i];
|
||||
}
|
||||
|
||||
// Step 5: Compute f0 from u and f1 from v
|
||||
fft_t_rec(f0, u, (f_coeffs + 1) / 2, PARAM_M - 1, PARAM_FFT_T - 1, deltas);
|
||||
fft_t_rec(f1, v, f_coeffs / 2, PARAM_M - 1, PARAM_FFT_T - 1, deltas);
|
||||
|
||||
// Step 3: Compute g from g0 and g1
|
||||
radix_t(f, f0, f1, PARAM_FFT_T);
|
||||
|
||||
// Step 2: beta_m = 1 so f = g
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the radix conversion of a polynomial f in GF(2^m)[x]
|
||||
*
|
||||
* Computes f0 and f1 such that f(x) = f0(x^2-x) + x.f1(x^2-x)
|
||||
* as proposed by Bernstein, Chou and Schwabe:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*
|
||||
* @param[out] f0 Array half the size of f
|
||||
* @param[out] f1 Array half the size of f
|
||||
* @param[in] f Array of size a power of 2
|
||||
* @param[in] m_f 2^{m_f} is the smallest power of 2 greater or equal to the number of coefficients of f
|
||||
*/
|
||||
static void radix(uint16_t *f0, uint16_t *f1, const uint16_t *f, uint32_t m_f) {
|
||||
switch (m_f) {
|
||||
case 4:
|
||||
f0[4] = f[8] ^ f[12];
|
||||
f0[6] = f[12] ^ f[14];
|
||||
f0[7] = f[14] ^ f[15];
|
||||
f1[5] = f[11] ^ f[13];
|
||||
f1[6] = f[13] ^ f[14];
|
||||
f1[7] = f[15];
|
||||
f0[5] = f[10] ^ f[12] ^ f1[5];
|
||||
f1[4] = f[9] ^ f[13] ^ f0[5];
|
||||
|
||||
f0[0] = f[0];
|
||||
f1[3] = f[7] ^ f[11] ^ f[15];
|
||||
f0[3] = f[6] ^ f[10] ^ f[14] ^ f1[3];
|
||||
f0[2] = f[4] ^ f0[4] ^ f0[3] ^ f1[3];
|
||||
f1[1] = f[3] ^ f[5] ^ f[9] ^ f[13] ^ f1[3];
|
||||
f1[2] = f[3] ^ f1[1] ^ f0[3];
|
||||
f0[1] = f[2] ^ f0[2] ^ f1[1];
|
||||
f1[0] = f[1] ^ f0[1];
|
||||
return;
|
||||
|
||||
case 3:
|
||||
f0[0] = f[0];
|
||||
f0[2] = f[4] ^ f[6];
|
||||
f0[3] = f[6] ^ f[7];
|
||||
f1[1] = f[3] ^ f[5] ^ f[7];
|
||||
f1[2] = f[5] ^ f[6];
|
||||
f1[3] = f[7];
|
||||
f0[1] = f[2] ^ f0[2] ^ f1[1];
|
||||
f1[0] = f[1] ^ f0[1];
|
||||
return;
|
||||
|
||||
case 2:
|
||||
f0[0] = f[0];
|
||||
f0[1] = f[2] ^ f[3];
|
||||
f1[0] = f[1] ^ f0[1];
|
||||
f1[1] = f[3];
|
||||
return;
|
||||
|
||||
case 1:
|
||||
f0[0] = f[0];
|
||||
f1[0] = f[1];
|
||||
return;
|
||||
|
||||
default:
|
||||
;
|
||||
size_t n = ((size_t)1) << (m_f - 2);
|
||||
|
||||
uint16_t Q[2 * (1 << (PARAM_FFT - 2))];
|
||||
uint16_t R[2 * (1 << (PARAM_FFT - 2))];
|
||||
|
||||
uint16_t Q0[1 << (PARAM_FFT - 2)];
|
||||
uint16_t Q1[1 << (PARAM_FFT - 2)];
|
||||
uint16_t R0[1 << (PARAM_FFT - 2)];
|
||||
uint16_t R1[1 << (PARAM_FFT - 2)];
|
||||
|
||||
memcpy(Q, f + 3 * n, 2 * n);
|
||||
memcpy(Q + n, f + 3 * n, 2 * n);
|
||||
memcpy(R, f, 4 * n);
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
Q[i] ^= f[2 * n + i];
|
||||
R[n + i] ^= Q[i];
|
||||
}
|
||||
|
||||
radix(Q0, Q1, Q, m_f - 1);
|
||||
radix(R0, R1, R, m_f - 1);
|
||||
|
||||
memcpy(f0, R0, 2 * n);
|
||||
memcpy(f0 + n, Q0, 2 * n);
|
||||
memcpy(f1, R1, 2 * n);
|
||||
memcpy(f1 + n, Q1, 2 * n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Evaluates f at all subset sums of a given set
|
||||
*
|
||||
* This function is a subroutine of the function fft.
|
||||
*
|
||||
* @param[out] w Array
|
||||
* @param[in] f Array
|
||||
* @param[in] f_coeffs Number of coefficients of f
|
||||
* @param[in] m Number of betas
|
||||
* @param[in] m_f Number of coefficients of f (one more than its degree)
|
||||
* @param[in] betas FFT constants
|
||||
*/
|
||||
static void fft_rec(uint16_t *w, uint16_t *f, size_t f_coeffs,
|
||||
uint8_t m, uint32_t m_f, const uint16_t *betas) {
|
||||
|
||||
uint16_t f0[1 << (PARAM_FFT - 2)] = {0};
|
||||
uint16_t f1[1 << (PARAM_FFT - 2)] = {0};
|
||||
uint16_t gammas[PARAM_M - 2] = {0};
|
||||
uint16_t deltas[PARAM_M - 2] = {0};
|
||||
size_t k = ((size_t)1) << (m - 1);
|
||||
uint16_t gammas_sums[1 << (PARAM_M - 2)] = {0};
|
||||
uint16_t u[1 << (PARAM_M - 2)] = {0};
|
||||
uint16_t v[1 << (PARAM_M - 2)] = {0};
|
||||
|
||||
// Step 1
|
||||
if (m_f == 1) {
|
||||
uint16_t tmp[PARAM_M - (PARAM_FFT - 1)];
|
||||
for (size_t i = 0; i < m; ++i) {
|
||||
tmp[i] = PQCLEAN_HQC1922CCA2_LEAKTIME_gf_mul(betas[i], f[1]);
|
||||
}
|
||||
|
||||
w[0] = f[0];
|
||||
for (size_t j = 0; j < m; ++j) {
|
||||
for (size_t ki = 0; ki < (((size_t)1) << j); ++ki) {
|
||||
w[(((size_t)1) << j) + ki] = w[ki] ^ tmp[j];
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2: compute g
|
||||
if (betas[m - 1] != 1) {
|
||||
uint16_t beta_m_pow = 1;
|
||||
for (size_t i = 1; i < (((size_t)1) << m_f); ++i) {
|
||||
beta_m_pow = PQCLEAN_HQC1922CCA2_LEAKTIME_gf_mul(beta_m_pow, betas[m - 1]);
|
||||
f[i] = PQCLEAN_HQC1922CCA2_LEAKTIME_gf_mul(beta_m_pow, f[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3
|
||||
radix(f0, f1, f, m_f);
|
||||
|
||||
// Step 4: compute gammas and deltas
|
||||
for (uint8_t i = 0; i < m - 1; ++i) {
|
||||
gammas[i] = PQCLEAN_HQC1922CCA2_LEAKTIME_gf_mul(betas[i], PQCLEAN_HQC1922CCA2_LEAKTIME_gf_inverse(betas[m - 1]));
|
||||
deltas[i] = PQCLEAN_HQC1922CCA2_LEAKTIME_gf_square(gammas[i]) ^ gammas[i];
|
||||
}
|
||||
|
||||
// Compute gammas sums
|
||||
compute_subset_sums(gammas_sums, gammas, m - 1);
|
||||
|
||||
// Step 5
|
||||
fft_rec(u, f0, (f_coeffs + 1) / 2, m - 1, m_f - 1, deltas);
|
||||
|
||||
if (f_coeffs <= 3) { // 3-coefficient polynomial f case: f1 is constant
|
||||
w[0] = u[0];
|
||||
w[k] = u[0] ^ f1[0];
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
w[i] = u[i] ^ PQCLEAN_HQC1922CCA2_LEAKTIME_gf_mul(gammas_sums[i], f1[0]);
|
||||
w[k + i] = w[i] ^ f1[0];
|
||||
}
|
||||
} else {
|
||||
fft_rec(v, f1, f_coeffs / 2, m - 1, m_f - 1, deltas);
|
||||
|
||||
// Step 6
|
||||
memcpy(w + k, v, 2 * k);
|
||||
w[0] = u[0];
|
||||
w[k] ^= u[0];
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
w[i] = u[i] ^ PQCLEAN_HQC1922CCA2_LEAKTIME_gf_mul(gammas_sums[i], v[i]);
|
||||
w[k + i] ^= w[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Evaluates f on all fields elements using an additive FFT algorithm
|
||||
*
|
||||
* f_coeffs is the number of coefficients of f (one less than its degree). <br>
|
||||
* The FFT proceeds recursively to evaluate f at all subset sums of a basis B. <br>
|
||||
* This implementation is based on the paper from Gao and Mateer: <br>
|
||||
* Shuhong Gao and Todd Mateer, Additive Fast Fourier Transforms over Finite Fields,
|
||||
* IEEE Transactions on Information Theory 56 (2010), 6265--6272.
|
||||
* http://www.math.clemson.edu/~sgao/papers/GM10.pdf <br>
|
||||
* and includes improvements proposed by Bernstein, Chou and Schwabe here:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf <br>
|
||||
* Constants betas, gammas and deltas involved in the algorithm are either hardcoded or precomputed
|
||||
* by the subroutine compute_fft_lut(...). <br>
|
||||
* Note that on this first call (as opposed to the recursive calls to fft_rec), gammas are equal to betas,
|
||||
* meaning the first gammas subset sums are actually the subset sums of betas (except 1). <br>
|
||||
* Also note that f is altered during computation (twisted at each level).
|
||||
*
|
||||
* @param[out] w Array
|
||||
* @param[in] f Array of 2^PARAM_FFT elements
|
||||
* @param[in] f_coeffs Number coefficients of f (i.e. deg(f)+1)
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_fft(uint16_t *w, const uint16_t *f, size_t f_coeffs) {
|
||||
uint16_t betas[PARAM_M - 1] = {0};
|
||||
uint16_t betas_sums[1 << (PARAM_M - 1)] = {0};
|
||||
uint16_t f0[1 << (PARAM_FFT - 1)] = {0};
|
||||
uint16_t f1[1 << (PARAM_FFT - 1)] = {0};
|
||||
uint16_t deltas[PARAM_M - 1];
|
||||
size_t k = 1 << (PARAM_M - 1);
|
||||
uint16_t u[1 << (PARAM_M - 1)] = {0};
|
||||
uint16_t v[1 << (PARAM_M - 1)] = {0};
|
||||
|
||||
// Follows Gao and Mateer algorithm
|
||||
compute_fft_betas(betas);
|
||||
|
||||
// Step 1: PARAM_FFT > 1, nothing to do
|
||||
|
||||
// Compute gammas sums
|
||||
compute_subset_sums(betas_sums, betas, PARAM_M - 1);
|
||||
|
||||
// Step 2: beta_m = 1, nothing to do
|
||||
|
||||
// Step 3
|
||||
radix(f0, f1, f, PARAM_FFT);
|
||||
|
||||
// Step 4: Compute deltas
|
||||
for (size_t i = 0; i < PARAM_M - 1; ++i) {
|
||||
deltas[i] = PQCLEAN_HQC1922CCA2_LEAKTIME_gf_square(betas[i]) ^ betas[i];
|
||||
}
|
||||
|
||||
// Step 5
|
||||
fft_rec(u, f0, (f_coeffs + 1) / 2, PARAM_M - 1, PARAM_FFT - 1, deltas);
|
||||
fft_rec(v, f1, f_coeffs / 2, PARAM_M - 1, PARAM_FFT - 1, deltas);
|
||||
|
||||
// Step 6, 7 and error polynomial computation
|
||||
memcpy(w + k, v, 2 * k);
|
||||
|
||||
// Check if 0 is root
|
||||
w[0] = u[0];
|
||||
|
||||
// Check if 1 is root
|
||||
w[k] ^= u[0];
|
||||
|
||||
// Find other roots
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
w[i] = u[i] ^ PQCLEAN_HQC1922CCA2_LEAKTIME_gf_mul(betas_sums[i], v[i]);
|
||||
w[k + i] ^= w[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Arranges the received word vector in a form w such that applying the additive FFT transpose to w yields the BCH syndromes of the received word vector.
|
||||
*
|
||||
* Since the received word vector gives coefficients of the primitive element alpha, we twist accordingly. <br>
|
||||
* Furthermore, the additive FFT transpose needs elements indexed by their decomposition on the chosen basis,
|
||||
* so we apply the adequate permutation.
|
||||
*
|
||||
* @param[out] w Array of size 2^PARAM_M
|
||||
* @param[in] vector Array of size VEC_N1_SIZE_BYTES
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_fft_t_preprocess_bch_codeword(uint16_t *w, const uint8_t *vector) {
|
||||
uint16_t r[1 << PARAM_M];
|
||||
uint16_t gammas[PARAM_M - 1];
|
||||
uint16_t gammas_sums[1 << (PARAM_M - 1)];
|
||||
size_t k = 1 << (PARAM_M - 1);
|
||||
|
||||
// Unpack the received word vector into array r
|
||||
size_t i;
|
||||
for (i = 0; i < VEC_N1_SIZE_BYTES - (PARAM_N1 % 8 != 0); ++i) {
|
||||
for (size_t j = 0; j < 8; ++j) {
|
||||
r[8 * i + j] = (vector[i] >> j) & 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Last byte
|
||||
for (size_t j = 0; j < PARAM_N1 % 8; ++j) {
|
||||
r[8 * i + j] = (vector[i] >> j) & 1;
|
||||
}
|
||||
|
||||
// Complete r with zeros
|
||||
memset(r + PARAM_N1, 0, 2 * ((1 << PARAM_M) - PARAM_N1));
|
||||
|
||||
compute_fft_betas(gammas);
|
||||
compute_subset_sums(gammas_sums, gammas, PARAM_M - 1);
|
||||
|
||||
// Twist and permute r adequately to obtain w
|
||||
w[0] = 0;
|
||||
w[k] = -r[0] & 1;
|
||||
for (i = 1; i < k; ++i) {
|
||||
w[i] = -r[PQCLEAN_HQC1922CCA2_LEAKTIME_gf_log(gammas_sums[i])] & gammas_sums[i];
|
||||
w[k + i] = -r[PQCLEAN_HQC1922CCA2_LEAKTIME_gf_log(gammas_sums[i] ^ 1)] & (gammas_sums[i] ^ 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieves the error polynomial error from the evaluations w of the ELP (Error Locator Polynomial) on all field elements.
|
||||
*
|
||||
* @param[out] error Array of size VEC_N1_SIZE_BYTES
|
||||
* @param[in] w Array of size 2^PARAM_M
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_fft_retrieve_bch_error_poly(uint8_t *error, const uint16_t *w) {
|
||||
uint16_t gammas[PARAM_M - 1];
|
||||
uint16_t gammas_sums[1 << (PARAM_M - 1)];
|
||||
size_t k = 1 << (PARAM_M - 1);
|
||||
size_t index = PARAM_GF_MUL_ORDER;
|
||||
|
||||
compute_fft_betas(gammas);
|
||||
compute_subset_sums(gammas_sums, gammas, PARAM_M - 1);
|
||||
|
||||
error[0] ^= 1 ^ ((uint16_t) - w[0] >> 15);
|
||||
uint8_t bit = 1 ^ ((uint16_t) - w[k] >> 15);
|
||||
error[index / 8] ^= bit << (index % 8);
|
||||
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
index = PARAM_GF_MUL_ORDER - PQCLEAN_HQC1922CCA2_LEAKTIME_gf_log(gammas_sums[i]);
|
||||
bit = 1 ^ ((uint16_t) - w[i] >> 15);
|
||||
error[index / 8] ^= bit << (index % 8);
|
||||
|
||||
index = PARAM_GF_MUL_ORDER - PQCLEAN_HQC1922CCA2_LEAKTIME_gf_log(gammas_sums[i] ^ 1);
|
||||
bit = 1 ^ ((uint16_t) - w[k + i] >> 15);
|
||||
error[index / 8] ^= bit << (index % 8);
|
||||
}
|
||||
}
|
||||
18
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/fft.h
Normal file
18
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/fft.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef PQCLEAN_HQC1922CCA2_LEAKTIME_FFT_H
|
||||
#define PQCLEAN_HQC1922CCA2_LEAKTIME_FFT_H
|
||||
|
||||
/**
|
||||
* @file fft.h
|
||||
* Header file of fft.c
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_fft_t(uint16_t *f, const uint16_t *w, size_t f_coeffs);
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_fft_t_preprocess_bch_codeword(uint16_t *w, const uint8_t *vector);
|
||||
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_fft(uint16_t *w, const uint16_t *f, size_t f_coeffs);
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_fft_retrieve_bch_error_poly(uint8_t *error, const uint16_t *w);
|
||||
|
||||
#endif
|
||||
99
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/gf.c
Normal file
99
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/gf.c
Normal file
File diff suppressed because one or more lines are too long
18
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/gf.h
Normal file
18
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/gf.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef PQCLEAN_HQC1922CCA2_LEAKTIME_GF_H
|
||||
#define PQCLEAN_HQC1922CCA2_LEAKTIME_GF_H
|
||||
|
||||
/**
|
||||
* @file gf.h
|
||||
* Header file of gf.c
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint16_t PQCLEAN_HQC1922CCA2_LEAKTIME_gf_log(uint16_t elt);
|
||||
uint16_t PQCLEAN_HQC1922CCA2_LEAKTIME_gf_mul(uint16_t a, uint16_t b);
|
||||
uint16_t PQCLEAN_HQC1922CCA2_LEAKTIME_gf_square(uint16_t a);
|
||||
uint16_t PQCLEAN_HQC1922CCA2_LEAKTIME_gf_inverse(uint16_t a);
|
||||
uint16_t PQCLEAN_HQC1922CCA2_LEAKTIME_gf_mod(uint16_t i);
|
||||
|
||||
#endif
|
||||
123
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/gf2x.c
Normal file
123
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/gf2x.c
Normal file
@ -0,0 +1,123 @@
|
||||
/**
|
||||
* \file gf2x.c
|
||||
* \brief Implementation of multiplication of two polynomials
|
||||
*/
|
||||
|
||||
#include "gf2x.h"
|
||||
#include "parameters.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define WORD_TYPE uint64_t
|
||||
#define WORD_TYPE_BITS (sizeof(WORD_TYPE) * 8)
|
||||
#define UTILS_VECTOR_ARRAY_SIZE CEIL_DIVIDE(PARAM_N, WORD_TYPE_BITS)
|
||||
|
||||
static int vect_mul_precompute_rows(WORD_TYPE *o, const WORD_TYPE *v);
|
||||
|
||||
|
||||
/**
|
||||
* @brief A subroutine used in the function sparse_dense_mul()
|
||||
*
|
||||
* @param[out] o Pointer to an array
|
||||
* @param[in] v Pointer to an array
|
||||
* @return 0 if precomputation is successful, -1 otherwise
|
||||
*/
|
||||
static int vect_mul_precompute_rows(WORD_TYPE *o, const WORD_TYPE *v) {
|
||||
int8_t var;
|
||||
for (size_t i = 0; i < PARAM_N; ++i) {
|
||||
var = 0;
|
||||
|
||||
// All the bits that we need are in the same block
|
||||
if (((i % WORD_TYPE_BITS) == 0) && (i != PARAM_N - (PARAM_N % WORD_TYPE_BITS))) {
|
||||
var = 1;
|
||||
}
|
||||
|
||||
// Cases where the bits are in before the last block, the last block and the first block
|
||||
if (i > PARAM_N - WORD_TYPE_BITS) {
|
||||
if (i >= PARAM_N - (PARAM_N % WORD_TYPE_BITS)) {
|
||||
var = 2;
|
||||
} else {
|
||||
var = 3;
|
||||
}
|
||||
}
|
||||
|
||||
switch (var) {
|
||||
case 0:
|
||||
// Take bits in the last block and the first one
|
||||
o[i] = 0;
|
||||
o[i] += v[i / WORD_TYPE_BITS] >> (i % WORD_TYPE_BITS);
|
||||
o[i] += v[(i / WORD_TYPE_BITS) + 1] << (WORD_TYPE_BITS - (i % WORD_TYPE_BITS));
|
||||
break;
|
||||
|
||||
case 1:
|
||||
o[i] = v[i / WORD_TYPE_BITS];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
o[i] = 0;
|
||||
o[i] += v[i / WORD_TYPE_BITS] >> (i % WORD_TYPE_BITS);
|
||||
o[i] += v[0] << ((PARAM_N - i) % WORD_TYPE_BITS);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
o[i] = 0;
|
||||
o[i] += v[i / WORD_TYPE_BITS] >> (i % WORD_TYPE_BITS);
|
||||
o[i] += v[(i / WORD_TYPE_BITS) + 1] << (WORD_TYPE_BITS - (i % WORD_TYPE_BITS));
|
||||
o[i] += v[0] << ((WORD_TYPE_BITS - i + (PARAM_N % WORD_TYPE_BITS)) % WORD_TYPE_BITS);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Multiplies two vectors
|
||||
*
|
||||
* This function multiplies two vectors: a sparse vector of Hamming weight equal to <b>weight</b> and a dense (random) vector.
|
||||
* The vector <b>a1</b> is the sparse vector and <b>a2</b> is the dense vector.
|
||||
* We notice that the idea is explained using vector of 32 bits elements instead of 64 (the algorithm works in booth cases).
|
||||
*
|
||||
* @param[out] o Pointer to a vector that is the result of the multiplication
|
||||
* @param[in] a1 Pointer to the sparse vector stored by position
|
||||
* @param[in] a2 Pointer to the dense vector
|
||||
* @param[in] weight Integer that is the weight of the sparse vector
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_vect_mul(uint8_t *o, const uint32_t *a1, const uint8_t *a2, uint16_t weight) {
|
||||
WORD_TYPE v1[UTILS_VECTOR_ARRAY_SIZE] = {0};
|
||||
WORD_TYPE res[UTILS_VECTOR_ARRAY_SIZE] = {0};
|
||||
WORD_TYPE precomputation_array [PARAM_N] = {0};
|
||||
WORD_TYPE row [UTILS_VECTOR_ARRAY_SIZE] = {0};
|
||||
uint32_t index;
|
||||
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_load8_arr(v1, UTILS_VECTOR_ARRAY_SIZE, a2, VEC_N_SIZE_BYTES);
|
||||
vect_mul_precompute_rows(precomputation_array, v1);
|
||||
|
||||
for (size_t i = 0; i < weight; ++i) {
|
||||
int32_t k = UTILS_VECTOR_ARRAY_SIZE;
|
||||
|
||||
for (size_t j = 0; j < UTILS_VECTOR_ARRAY_SIZE - 1; ++j) {
|
||||
index = WORD_TYPE_BITS * (uint32_t)j - a1[i];
|
||||
if (index > PARAM_N) {
|
||||
index += PARAM_N;
|
||||
}
|
||||
row[j] = precomputation_array[index];
|
||||
}
|
||||
|
||||
index = WORD_TYPE_BITS * (UTILS_VECTOR_ARRAY_SIZE - 1) - a1[i];
|
||||
row[UTILS_VECTOR_ARRAY_SIZE - 1] = precomputation_array[(index < PARAM_N ? index : index + PARAM_N)] & BITMASK(PARAM_N, WORD_TYPE_BITS);
|
||||
|
||||
while (k--) {
|
||||
res[k] ^= row[k];
|
||||
}
|
||||
}
|
||||
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_store8_arr(o, VEC_N_SIZE_BYTES, res, UTILS_VECTOR_ARRAY_SIZE);
|
||||
}
|
||||
13
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/gf2x.h
Normal file
13
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/gf2x.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef PQCLEAN_HQC1922CCA2_LEAKTIME_GF2X_H
|
||||
#define PQCLEAN_HQC1922CCA2_LEAKTIME_GF2X_H
|
||||
|
||||
/**
|
||||
* @file gf2x.h
|
||||
* @brief Header file for gf2x.c
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_vect_mul(uint8_t *o, const uint32_t *a1, const uint8_t *a2, uint16_t weight);
|
||||
|
||||
#endif
|
||||
135
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/hqc.c
Normal file
135
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/hqc.c
Normal file
@ -0,0 +1,135 @@
|
||||
/**
|
||||
* @file hqc.c
|
||||
* @brief Implementation of hqc.h
|
||||
*/
|
||||
|
||||
#include "gf2x.h"
|
||||
#include "hqc.h"
|
||||
#include "nistseedexpander.h"
|
||||
#include "parameters.h"
|
||||
#include "parsing.h"
|
||||
#include "randombytes.h"
|
||||
#include "tensor.h"
|
||||
#include "vector.h"
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Keygen of the HQC_PKE IND_CPA scheme
|
||||
*
|
||||
* The public key is composed of the syndrome <b>s</b> as well as the <b>seed</b> used to generate the vector <b>h</b>.
|
||||
*
|
||||
* The secret key is composed of the <b>seed</b> used to generate vectors <b>x</b> and <b>y</b>.
|
||||
* As a technicality, the public key is appended to the secret key in order to respect NIST API.
|
||||
*
|
||||
* @param[out] pk String containing the public key
|
||||
* @param[out] sk String containing the secret key
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_pke_keygen(uint8_t *pk, uint8_t *sk) {
|
||||
AES_XOF_struct sk_seedexpander;
|
||||
AES_XOF_struct pk_seedexpander;
|
||||
uint8_t sk_seed[SEED_BYTES] = {0};
|
||||
uint8_t pk_seed[SEED_BYTES] = {0};
|
||||
uint8_t x[VEC_N_SIZE_BYTES] = {0};
|
||||
uint32_t y[PARAM_OMEGA] = {0};
|
||||
uint8_t h[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t s[VEC_N_SIZE_BYTES] = {0};
|
||||
|
||||
// Create seed_expanders for public key and secret key
|
||||
randombytes(sk_seed, SEED_BYTES);
|
||||
seedexpander_init(&sk_seedexpander, sk_seed, sk_seed + 32, SEEDEXPANDER_MAX_LENGTH);
|
||||
|
||||
randombytes(pk_seed, SEED_BYTES);
|
||||
seedexpander_init(&pk_seedexpander, pk_seed, pk_seed + 32, SEEDEXPANDER_MAX_LENGTH);
|
||||
|
||||
// Compute secret key
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_set_random_fixed_weight(&sk_seedexpander, x, PARAM_OMEGA);
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_set_random_fixed_weight_by_coordinates(&sk_seedexpander, y, PARAM_OMEGA);
|
||||
|
||||
// Compute public key
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_set_random(&pk_seedexpander, h);
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_mul(s, y, h, PARAM_OMEGA);
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_add(s, x, s, VEC_N_SIZE_BYTES);
|
||||
|
||||
// Parse keys to string
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_public_key_to_string(pk, pk_seed, s);
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_secret_key_to_string(sk, sk_seed, pk);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encryption of the HQC_PKE IND_CPA scheme
|
||||
*
|
||||
* The cihertext is composed of vectors <b>u</b> and <b>v</b>.
|
||||
*
|
||||
* @param[out] u Vector u (first part of the ciphertext)
|
||||
* @param[out] v Vector v (second part of the ciphertext)
|
||||
* @param[in] m Vector representing the message to encrypt
|
||||
* @param[in] theta Seed used to derive randomness required for encryption
|
||||
* @param[in] pk String containing the public key
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_pke_encrypt(uint8_t *u, uint8_t *v, const uint8_t *m, const uint8_t *theta, const uint8_t *pk) {
|
||||
AES_XOF_struct seedexpander;
|
||||
uint8_t h[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t s[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t r1[VEC_N_SIZE_BYTES] = {0};
|
||||
uint32_t r2[PARAM_OMEGA_R] = {0};
|
||||
uint8_t e[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t tmp1[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t tmp2[VEC_N_SIZE_BYTES] = {0};
|
||||
|
||||
// Create seed_expander from theta
|
||||
seedexpander_init(&seedexpander, theta, theta + 32, SEEDEXPANDER_MAX_LENGTH);
|
||||
|
||||
// Retrieve h and s from public key
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_public_key_from_string(h, s, pk);
|
||||
|
||||
// Generate r1, r2 and e
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_set_random_fixed_weight(&seedexpander, r1, PARAM_OMEGA_R);
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_set_random_fixed_weight_by_coordinates(&seedexpander, r2, PARAM_OMEGA_R);
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_set_random_fixed_weight(&seedexpander, e, PARAM_OMEGA_E);
|
||||
|
||||
// Compute u = r1 + r2.h
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_mul(u, r2, h, PARAM_OMEGA_R);
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_add(u, r1, u, VEC_N_SIZE_BYTES);
|
||||
|
||||
// Compute v = m.G by encoding the message
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_tensor_code_encode(v, m);
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_resize(tmp1, PARAM_N, v, PARAM_N1N2);
|
||||
|
||||
// Compute v = m.G + s.r2 + e
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_mul(tmp2, r2, s, PARAM_OMEGA_R);
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_add(tmp2, e, tmp2, VEC_N_SIZE_BYTES);
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_add(tmp2, tmp1, tmp2, VEC_N_SIZE_BYTES);
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_resize(v, PARAM_N1N2, tmp2, PARAM_N);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Decryption of the HQC_PKE IND_CPA scheme
|
||||
*
|
||||
* @param[out] m Vector representing the decrypted message
|
||||
* @param[in] u Vector u (first part of the ciphertext)
|
||||
* @param[in] v Vector v (second part of the ciphertext)
|
||||
* @param[in] sk String containing the secret key
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_pke_decrypt(uint8_t *m, const uint8_t *u, const uint8_t *v, const uint8_t *sk) {
|
||||
uint8_t x[VEC_N_SIZE_BYTES] = {0};
|
||||
uint32_t y[PARAM_OMEGA] = {0};
|
||||
uint8_t pk[PUBLIC_KEY_BYTES] = {0};
|
||||
uint8_t tmp1[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t tmp2[VEC_N_SIZE_BYTES] = {0};
|
||||
|
||||
// Retrieve x, y, pk from secret key
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_secret_key_from_string(x, y, pk, sk);
|
||||
|
||||
// Compute v - u.y
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_resize(tmp1, PARAM_N, v, PARAM_N1N2);
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_mul(tmp2, y, u, PARAM_OMEGA);
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_add(tmp2, tmp1, tmp2, VEC_N_SIZE_BYTES);
|
||||
|
||||
// Compute m by decoding v - u.y
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_tensor_code_decode(m, tmp2);
|
||||
}
|
||||
15
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/hqc.h
Normal file
15
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/hqc.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef PQCLEAN_HQC1922CCA2_LEAKTIME_HQC_H
|
||||
#define PQCLEAN_HQC1922CCA2_LEAKTIME_HQC_H
|
||||
|
||||
/**
|
||||
* @file hqc.h
|
||||
* @brief Functions of the HQC_PKE IND_CPA scheme
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_pke_keygen(uint8_t *pk, uint8_t *sk);
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_pke_encrypt(uint8_t *u, uint8_t *v, const uint8_t *m, const uint8_t *theta, const uint8_t *pk);
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_pke_decrypt(uint8_t *m, const uint8_t *u, const uint8_t *v, const uint8_t *sk);
|
||||
|
||||
#endif
|
||||
154
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/kem.c
Normal file
154
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/kem.c
Normal file
@ -0,0 +1,154 @@
|
||||
/**
|
||||
* @file kem.c
|
||||
* @brief Implementation of api.h
|
||||
*/
|
||||
|
||||
#include "api.h"
|
||||
#include "hqc.h"
|
||||
#include "nistseedexpander.h"
|
||||
#include "parameters.h"
|
||||
#include "parsing.h"
|
||||
#include "sha2.h"
|
||||
#include "vector.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Keygen of the HQC_KEM IND_CAA2 scheme
|
||||
*
|
||||
* The public key is composed of the syndrome <b>s</b> as well as the seed used to generate the vector <b>h</b>.
|
||||
*
|
||||
* The secret key is composed of the seed used to generate vectors <b>x</b> and <b>y</b>.
|
||||
* As a technicality, the public key is appended to the secret key in order to respect NIST API.
|
||||
*
|
||||
* @param[out] pk String containing the public key
|
||||
* @param[out] sk String containing the secret key
|
||||
* @returns 0 if keygen is successful
|
||||
*/
|
||||
int PQCLEAN_HQC1922CCA2_LEAKTIME_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) {
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_pke_keygen(pk, sk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encapsulation of the HQC_KEM IND_CAA2 scheme
|
||||
*
|
||||
* @param[out] ct String containing the ciphertext
|
||||
* @param[out] ss String containing the shared secret
|
||||
* @param[in] pk String containing the public key
|
||||
* @returns 0 if encapsulation is successful
|
||||
*/
|
||||
int PQCLEAN_HQC1922CCA2_LEAKTIME_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
|
||||
AES_XOF_struct G_seedexpander;
|
||||
uint8_t seed_G[VEC_K_SIZE_BYTES];
|
||||
uint8_t diversifier_bytes[8] = {0};
|
||||
uint8_t m[VEC_K_SIZE_BYTES] = {0};
|
||||
uint8_t theta[SEED_BYTES] = {0};
|
||||
uint8_t u[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t v[VEC_N1N2_SIZE_BYTES] = {0};
|
||||
uint8_t d[SHA512_BYTES] = {0};
|
||||
uint8_t mc[VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES] = {0};
|
||||
|
||||
// Computing m
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_set_random_from_randombytes(m);
|
||||
|
||||
// Generating G function
|
||||
memcpy(seed_G, m, VEC_K_SIZE_BYTES);
|
||||
seedexpander_init(&G_seedexpander, seed_G, diversifier_bytes, SEEDEXPANDER_MAX_LENGTH);
|
||||
|
||||
// Computing theta
|
||||
seedexpander(&G_seedexpander, theta, SEED_BYTES);
|
||||
|
||||
// Encrypting m
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_pke_encrypt(u, v, m, theta, pk);
|
||||
|
||||
// Computing d
|
||||
sha512(d, m, VEC_K_SIZE_BYTES);
|
||||
|
||||
// Computing shared secret
|
||||
memcpy(mc, m, VEC_K_SIZE_BYTES);
|
||||
memcpy(mc + VEC_K_SIZE_BYTES, u, VEC_N_SIZE_BYTES);
|
||||
memcpy(mc + VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES, v, VEC_N1N2_SIZE_BYTES);
|
||||
sha512(ss, mc, VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES);
|
||||
|
||||
// Computing ciphertext
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_ciphertext_to_string(ct, u, v, d);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Decapsulation of the HQC_KEM IND_CAA2 scheme
|
||||
*
|
||||
* @param[out] ss String containing the shared secret
|
||||
* @param[in] ct String containing the cipĥertext
|
||||
* @param[in] sk String containing the secret key
|
||||
* @returns 0 if decapsulation is successful, -1 otherwise
|
||||
*/
|
||||
int PQCLEAN_HQC1922CCA2_LEAKTIME_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
|
||||
AES_XOF_struct G_seedexpander;
|
||||
uint8_t seed_G[VEC_K_SIZE_BYTES] = {0};
|
||||
uint8_t diversifier_bytes[8] = {0};
|
||||
uint8_t u[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t v[VEC_N1N2_SIZE_BYTES] = {0};
|
||||
uint8_t d[SHA512_BYTES] = {0};
|
||||
uint8_t pk[PUBLIC_KEY_BYTES] = {0};
|
||||
uint8_t m[VEC_K_SIZE_BYTES] = {0};
|
||||
uint8_t theta[SEED_BYTES] = {0};
|
||||
uint8_t u2[VEC_N_SIZE_BYTES] = {0};
|
||||
uint8_t v2[VEC_N1N2_SIZE_BYTES] = {0};
|
||||
uint8_t d2[SHA512_BYTES] = {0};
|
||||
uint8_t mc[VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES] = {0};
|
||||
int8_t abort = 0;
|
||||
|
||||
// Retrieving u, v and d from ciphertext
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_ciphertext_from_string(u, v, d, ct);
|
||||
|
||||
// Retrieving pk from sk
|
||||
memcpy(pk, sk + SEED_BYTES, PUBLIC_KEY_BYTES);
|
||||
|
||||
// Decryting
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_pke_decrypt(m, u, v, sk);
|
||||
|
||||
// Generating G function
|
||||
memcpy(seed_G, m, VEC_K_SIZE_BYTES);
|
||||
seedexpander_init(&G_seedexpander, seed_G, diversifier_bytes, SEEDEXPANDER_MAX_LENGTH);
|
||||
|
||||
// Computing theta
|
||||
seedexpander(&G_seedexpander, theta, SEED_BYTES);
|
||||
|
||||
// Encrypting m'
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_pke_encrypt(u2, v2, m, theta, pk);
|
||||
|
||||
// Checking that c = c' and abort otherwise
|
||||
if (PQCLEAN_HQC1922CCA2_LEAKTIME_vect_compare(u, u2, VEC_N_SIZE_BYTES) != 0 ||
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_compare(v, v2, VEC_N1N2_SIZE_BYTES) != 0) {
|
||||
abort = 1;
|
||||
}
|
||||
|
||||
// Computing d'
|
||||
sha512(d2, m, VEC_K_SIZE_BYTES);
|
||||
|
||||
// Checking that d = d' and abort otherwise
|
||||
if (memcmp(d, d2, SHA512_BYTES) != 0) {
|
||||
abort = 1;
|
||||
}
|
||||
|
||||
if (abort == 1) {
|
||||
memset(ss, 0, SHARED_SECRET_BYTES);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Computing shared secret
|
||||
memcpy(mc, m, VEC_K_SIZE_BYTES);
|
||||
memcpy(mc + VEC_K_SIZE_BYTES, u, VEC_N_SIZE_BYTES);
|
||||
memcpy(mc + VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES, v, VEC_N1N2_SIZE_BYTES);
|
||||
sha512(ss, mc, VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES);
|
||||
|
||||
return 0;
|
||||
}
|
||||
109
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/parameters.h
Normal file
109
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/parameters.h
Normal file
@ -0,0 +1,109 @@
|
||||
#ifndef PQCLEAN_HQC1922CCA2_LEAKTIME_HQC_PARAMETERS_H
|
||||
#define PQCLEAN_HQC1922CCA2_LEAKTIME_HQC_PARAMETERS_H
|
||||
|
||||
/**
|
||||
* @file parameters.h
|
||||
* @brief Parameters of the HQC_KEM IND-CCA2 scheme
|
||||
*/
|
||||
|
||||
#include "api.h"
|
||||
|
||||
#define CEIL_DIVIDE(a, b) (((a)/(b)) + ((a) % (b) == 0 ? 0 : 1)) /*!< Divide a by b and ceil the result*/
|
||||
#define BITMASK(a, size) ((1ULL << ((a) % (size))) - 1) /*!< Create a mask*/
|
||||
|
||||
|
||||
/*
|
||||
#define PARAM_N Define the parameter n of the scheme
|
||||
#define PARAM_N1 Define the parameter n1 of the scheme (length of BCH code)
|
||||
#define PARAM_N2 Define the parameter n2 of the scheme (length of the repetition code)
|
||||
#define PARAM_N1N2 Define the parameter n1 * n2 of the scheme (length of the tensor code)
|
||||
#define PARAM_OMEGA Define the parameter omega of the scheme
|
||||
#define PARAM_OMEGA_E Define the parameter omega_e of the scheme
|
||||
#define PARAM_OMEGA_R Define the parameter omega_r of the scheme
|
||||
#define PARAM_SECURITY Define the security level corresponding to the chosen parameters
|
||||
#define PARAM_DFR_EXP Define the decryption failure rate corresponding to the chosen parameters
|
||||
|
||||
#define SECRET_KEY_BYTES Define the size of the secret key in bytes
|
||||
#define PUBLIC_KEY_BYTES Define the size of the public key in bytes
|
||||
#define SHARED_SECRET_BYTES Define the size of the shared secret in bytes
|
||||
#define CIPHERTEXT_BYTES Define the size of the ciphertext in bytes
|
||||
|
||||
#define UTILS_REJECTION_THRESHOLD Define the rejection threshold used to generate given weight vectors (see vector_set_random_fixed_weight function)
|
||||
#define VEC_N_ARRAY_SIZE_BYTES Define the size of the array used to store a PARAM_N sized vector in bytes
|
||||
#define VEC_N1_ARRAY_SIZE_BYTES Define the size of the array used to store a PARAM_N1 sized vector in bytes
|
||||
#define VEC_N1N2_ARRAY_SIZE_BYTES Define the size of the array used to store a PARAM_N1N2 sized vector in bytes
|
||||
#define VEC_K_ARRAY_SIZE_BYTES Define the size of the array used to store a PARAM_K sized vector in bytes
|
||||
|
||||
#define PARAM_T Define a threshold for decoding repetition code word (PARAM_T = (PARAM_N2 - 1) / 2)
|
||||
|
||||
#define PARAM_DELTA Define the parameter delta of the scheme (correcting capacity of the BCH code)
|
||||
#define PARAM_M Define a positive integer
|
||||
#define PARAM_GF_MUL_ORDER Define the size of the multiplicative group of GF(2^m), i.e 2^m -1
|
||||
#define PARAM_K Define the size of the information bits of the BCH code
|
||||
#define PARAM_G Define the size of the generator polynomial of BCH code
|
||||
#define PARAM_FFT The additive FFT takes a 2^PARAM_FFT polynomial as input
|
||||
We use the FFT to compute the roots of sigma, whose degree if PARAM_DELTA=60
|
||||
The smallest power of 2 greater than 60+1 is 64=2^6
|
||||
#define PARAM_FFT_T The additive FFT transpose computes a (2^PARAM_FFT_T)-sized syndrome vector
|
||||
We want to compute 2*PARAM_DELTA=120 syndromes
|
||||
The smallest power of 2 greater than 120 is 2^7
|
||||
#define PARAM_BCH_POLY Generator polynomial of the BCH code
|
||||
|
||||
#define SHA512_BYTES Define the size of SHA512 output in bytes
|
||||
#define SEED_BYTES Define the size of the seed in bytes
|
||||
#define SEEDEXPANDER_MAX_LENGTH Define the seed expander max length
|
||||
*/
|
||||
|
||||
|
||||
#define PARAM_N 46747
|
||||
#define PARAM_N1 766
|
||||
#define PARAM_N2 61
|
||||
#define PARAM_N1N2 46726
|
||||
#define PARAM_OMEGA 101
|
||||
#define PARAM_OMEGA_E 117
|
||||
#define PARAM_OMEGA_R 117
|
||||
#define PARAM_SECURITY 192
|
||||
#define PARAM_DFR_EXP 192
|
||||
|
||||
#define SECRET_KEY_BYTES PQCLEAN_HQC1922CCA2_LEAKTIME_CRYPTO_SECRETKEYBYTES
|
||||
#define PUBLIC_KEY_BYTES PQCLEAN_HQC1922CCA2_LEAKTIME_CRYPTO_PUBLICKEYBYTES
|
||||
#define SHARED_SECRET_BYTES PQCLEAN_HQC1922CCA2_LEAKTIME_CRYPTO_BYTES
|
||||
#define CIPHERTEXT_BYTES PQCLEAN_HQC1922CCA2_LEAKTIME_CRYPTO_CIPHERTEXTBYTES
|
||||
|
||||
#define UTILS_REJECTION_THRESHOLD 16735426
|
||||
#define VEC_K_SIZE_BYTES CEIL_DIVIDE(PARAM_K, 8)
|
||||
#define VEC_N_SIZE_BYTES CEIL_DIVIDE(PARAM_N, 8)
|
||||
#define VEC_N1_SIZE_BYTES CEIL_DIVIDE(PARAM_N1, 8)
|
||||
#define VEC_N1N2_SIZE_BYTES CEIL_DIVIDE(PARAM_N1N2, 8)
|
||||
|
||||
#define PARAM_T 30
|
||||
|
||||
#define PARAM_DELTA 57
|
||||
#define PARAM_M 10
|
||||
#define PARAM_GF_MUL_ORDER 1023
|
||||
#define PARAM_K 256
|
||||
#define PARAM_G 511
|
||||
#define PARAM_FFT 6
|
||||
#define PARAM_FFT_T 7
|
||||
#define PARAM_BCH_POLY { \
|
||||
1,1,0,0,0,0,1,0,0,1,1,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,1,1,1,1,0,0,1,1,0,1,1, \
|
||||
1,1,0,1,1,1,1,0,1,0,0,0,1,0,0,1,1,1,0,1,1,0,1,0,1,1,1,0,1,0,1,0,0,1,0,0,0, \
|
||||
0,1,1,1,1,0,1,1,1,1,1,0,0,0,0,1,0,0,1,0,0,1,1,1,0,0,0,1,1,0,0,1,0,1,0,0,0, \
|
||||
1,0,0,0,0,1,0,0,0,1,0,1,1,0,0,0,0,1,1,0,0,1,1,0,1,0,1,0,1,0,1,1,1,1,0,1,0, \
|
||||
0,1,1,0,1,0,1,1,0,0,1,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,0,0,1,1,0,1,1,1,1,0, \
|
||||
1,1,1,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,1,0,0,1,1,0,1,0,0,0,0,1,0, \
|
||||
0,1,0,0,1,0,1,0,0,1,1,0,1,0,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,0,0,0,1,0,1, \
|
||||
1,1,1,1,1,0,1,0,1,0,1,1,0,0,0,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,0,1,1,1,1,0, \
|
||||
1,0,0,0,1,0,0,1,1,0,1,1,0,0,1,0,1,1,0,1,0,1,0,1,1,0,0,0,0,0,1,1,1,1,1,1,1, \
|
||||
1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,0,1,0,0,1,1,1,1,1,0,1,0,1, \
|
||||
0,0,0,0,1,0,1,1,1,1,0,1,0,0,0,0,0,1,0,0,1,0,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1, \
|
||||
1,0,1,0,0,1,0,0,1,1,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,1,1,0,0,0,1,1, \
|
||||
0,1,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,1,1,1,1,0,0,0,1,0,0,1,1,0,1,1,0,0,1,0,1, \
|
||||
1,0,1,1,1,0,0,0,0,1,1,0,1,1,1,0,1,0,0,0,0,1,0,0,0,1,0,0,1,1 \
|
||||
};
|
||||
|
||||
#define SHA512_BYTES 64
|
||||
#define SEED_BYTES 40
|
||||
#define SEEDEXPANDER_MAX_LENGTH 4294967295
|
||||
|
||||
#endif
|
||||
126
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/parsing.c
Normal file
126
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/parsing.c
Normal file
@ -0,0 +1,126 @@
|
||||
/**
|
||||
* @file parsing.c
|
||||
* @brief Functions to parse secret key, public key and ciphertext of the HQC scheme
|
||||
*/
|
||||
|
||||
#include "nistseedexpander.h"
|
||||
#include "parameters.h"
|
||||
#include "parsing.h"
|
||||
#include "vector.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse a secret key into a string
|
||||
*
|
||||
* The secret key is composed of the seed used to generate vectors <b>x</b> and <b>y</b>.
|
||||
* As technicality, the public key is appended to the secret key in order to respect NIST API.
|
||||
*
|
||||
* @param[out] sk String containing the secret key
|
||||
* @param[in] sk_seed Seed used to generate the secret key
|
||||
* @param[in] pk String containing the public key
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_secret_key_to_string(uint8_t *sk, const uint8_t *sk_seed, const uint8_t *pk) {
|
||||
memcpy(sk, sk_seed, SEED_BYTES);
|
||||
memcpy(sk + SEED_BYTES, pk, PUBLIC_KEY_BYTES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse a secret key from a string
|
||||
*
|
||||
* The secret key is composed of the seed used to generate vectors <b>x</b> and <b>y</b>.
|
||||
* As technicality, the public key is appended to the secret key in order to respect NIST API.
|
||||
*
|
||||
* @param[out] x uint8_t representation of vector x
|
||||
* @param[out] y uint8_t representation of vector y
|
||||
* @param[out] pk String containing the public key
|
||||
* @param[in] sk String containing the secret key
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_secret_key_from_string(uint8_t *x, uint32_t *y, uint8_t *pk, const uint8_t *sk) {
|
||||
AES_XOF_struct sk_seedexpander;
|
||||
uint8_t sk_seed[SEED_BYTES] = {0};
|
||||
|
||||
memcpy(sk_seed, sk, SEED_BYTES);
|
||||
seedexpander_init(&sk_seedexpander, sk_seed, sk_seed + 32, SEEDEXPANDER_MAX_LENGTH);
|
||||
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_set_random_fixed_weight(&sk_seedexpander, x, PARAM_OMEGA);
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_set_random_fixed_weight_by_coordinates(&sk_seedexpander, y, PARAM_OMEGA);
|
||||
memcpy(pk, sk + SEED_BYTES, PUBLIC_KEY_BYTES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse a public key into a string
|
||||
*
|
||||
* The public key is composed of the syndrome <b>s</b> as well as the seed used to generate the vector <b>h</b>
|
||||
*
|
||||
* @param[out] pk String containing the public key
|
||||
* @param[in] pk_seed Seed used to generate the public key
|
||||
* @param[in] s uint8_t representation of vector s
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_public_key_to_string(uint8_t *pk, const uint8_t *pk_seed, const uint8_t *s) {
|
||||
memcpy(pk, pk_seed, SEED_BYTES);
|
||||
memcpy(pk + SEED_BYTES, s, VEC_N_SIZE_BYTES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse a public key from a string
|
||||
*
|
||||
* The public key is composed of the syndrome <b>s</b> as well as the seed used to generate the vector <b>h</b>
|
||||
*
|
||||
* @param[out] h uint8_t representation of vector h
|
||||
* @param[out] s uint8_t representation of vector s
|
||||
* @param[in] pk String containing the public key
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_public_key_from_string(uint8_t *h, uint8_t *s, const uint8_t *pk) {
|
||||
AES_XOF_struct pk_seedexpander;
|
||||
uint8_t pk_seed[SEED_BYTES] = {0};
|
||||
|
||||
memcpy(pk_seed, pk, SEED_BYTES);
|
||||
seedexpander_init(&pk_seedexpander, pk_seed, pk_seed + 32, SEEDEXPANDER_MAX_LENGTH);
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_vect_set_random(&pk_seedexpander, h);
|
||||
|
||||
memcpy(s, pk + SEED_BYTES, VEC_N_SIZE_BYTES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse a ciphertext into a string
|
||||
*
|
||||
* The ciphertext is composed of vectors <b>u</b>, <b>v</b> and hash <b>d</b>.
|
||||
*
|
||||
* @param[out] ct String containing the ciphertext
|
||||
* @param[in] u uint8_t representation of vector u
|
||||
* @param[in] v uint8_t representation of vector v
|
||||
* @param[in] d String containing the hash d
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_ciphertext_to_string(uint8_t *ct, const uint8_t *u, const uint8_t *v, const uint8_t *d) {
|
||||
memcpy(ct, u, VEC_N_SIZE_BYTES);
|
||||
memcpy(ct + VEC_N_SIZE_BYTES, v, VEC_N1N2_SIZE_BYTES);
|
||||
memcpy(ct + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, d, SHA512_BYTES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse a ciphertext from a string
|
||||
*
|
||||
* The ciphertext is composed of vectors <b>u</b>, <b>v</b> and hash <b>d</b>.
|
||||
*
|
||||
* @param[out] u uint8_t representation of vector u
|
||||
* @param[out] v uint8_t representation of vector v
|
||||
* @param[out] d String containing the hash d
|
||||
* @param[in] ct String containing the ciphertext
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_ciphertext_from_string(uint8_t *u, uint8_t *v, uint8_t *d, const uint8_t *ct) {
|
||||
memcpy(u, ct, VEC_N_SIZE_BYTES);
|
||||
memcpy(v, ct + VEC_N_SIZE_BYTES, VEC_N1N2_SIZE_BYTES);
|
||||
memcpy(d, ct + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, SHA512_BYTES);
|
||||
}
|
||||
20
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/parsing.h
Normal file
20
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/parsing.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef PQCLEAN_HQC1922CCA2_LEAKTIME_PARSING_H
|
||||
#define PQCLEAN_HQC1922CCA2_LEAKTIME_PARSING_H
|
||||
|
||||
/**
|
||||
* @file parsing.h
|
||||
* @brief Header file for parsing.c
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_secret_key_to_string(uint8_t *sk, const uint8_t *sk_seed, const uint8_t *pk);
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_secret_key_from_string(uint8_t *x, uint32_t *y, uint8_t *pk, const uint8_t *sk);
|
||||
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_public_key_to_string(uint8_t *pk, const uint8_t *pk_seed, const uint8_t *s);
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_public_key_from_string(uint8_t *h, uint8_t *s, const uint8_t *pk);
|
||||
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_ciphertext_to_string(uint8_t *ct, const uint8_t *u, const uint8_t *v, const uint8_t *d);
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_hqc_ciphertext_from_string(uint8_t *u, uint8_t *v, uint8_t *d, const uint8_t *ct);
|
||||
|
||||
#endif
|
||||
100
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/repetition.c
Normal file
100
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/repetition.c
Normal file
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @file repetition.c
|
||||
* @brief Implementation of repetition codes
|
||||
*/
|
||||
|
||||
#include "parameters.h"
|
||||
#include "repetition.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static void array_to_rep_codeword(uint8_t *o, const uint8_t *v);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encoding each bit in the message m using the repetition code
|
||||
*
|
||||
* For reasons of clarity and comprehensibility, we do the encoding by storing the encoded bits in a String (each bit in an a uint8_t),
|
||||
* then we parse the obtained string to an compact array using the function array_to_rep_codeword().
|
||||
*
|
||||
* @param[out] em Pointer to an array that is the code word
|
||||
* @param[in] m Pointer to an array that is the message
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_repetition_code_encode(uint8_t *em, const uint8_t *m) {
|
||||
uint8_t tmp[PARAM_N1N2] = {0};
|
||||
uint8_t bit = 0;
|
||||
uint32_t index;
|
||||
|
||||
for (size_t i = 0; i < (VEC_N1_SIZE_BYTES - 1); ++i) {
|
||||
for (uint8_t j = 0; j < 8; ++j) {
|
||||
bit = (m[i] >> j) & 0x01;
|
||||
index = (8 * (uint32_t)i + j) * PARAM_N2;
|
||||
for (uint8_t k = 0; k < PARAM_N2; ++k) {
|
||||
tmp[index + k] = bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t j = 0; j < (PARAM_N1 % 8); ++j) {
|
||||
bit = (m[VEC_N1_SIZE_BYTES - 1] >> j) & 0x01;
|
||||
index = (8 * (VEC_N1_SIZE_BYTES - 1) + j) * PARAM_N2;
|
||||
for (uint8_t k = 0; k < PARAM_N2; ++k) {
|
||||
tmp[index + k] = bit;
|
||||
}
|
||||
}
|
||||
|
||||
array_to_rep_codeword(em, tmp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Decoding the code words to a message using the repetition code
|
||||
*
|
||||
* We use a majority decoding. In fact we have that PARAM_N2 = 2 * PARAM_T + 1, thus,
|
||||
* if the Hamming weight of the vector is greater than PARAM_T, the code word is decoded
|
||||
* to 1 and 0 otherwise.
|
||||
*
|
||||
* @param[out] m Pointer to an array that is the message
|
||||
* @param[in] em Pointer to an array that is the code word
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_repetition_code_decode(uint8_t *m, const uint8_t *em) {
|
||||
size_t t = 0; // m index
|
||||
uint8_t k = PARAM_N2; // block counter
|
||||
uint8_t ones = 0; // number of 1 in the current block
|
||||
|
||||
for (size_t i = 0; i < VEC_N1N2_SIZE_BYTES; ++i) {
|
||||
for (uint8_t j = 0; j < 8; ++j) {
|
||||
ones += (em[i] >> j) & 0x01;
|
||||
|
||||
if (--k) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m[t / 8] |= (ones > PARAM_T) << t % 8;
|
||||
++t;
|
||||
k = PARAM_N2;
|
||||
ones = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse an array to an compact array
|
||||
*
|
||||
* @param[out] o Pointer to an array
|
||||
* @param[in] v Pointer to an array
|
||||
*/
|
||||
static void array_to_rep_codeword(uint8_t *o, const uint8_t *v) {
|
||||
for (size_t i = 0; i < (VEC_N1N2_SIZE_BYTES - 1); ++i) {
|
||||
for (uint8_t j = 0; j < 8; ++j) {
|
||||
o[i] |= v[j + 8 * i] << j;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t j = 0; j < PARAM_N1N2 % 8; ++j) {
|
||||
o[VEC_N1N2_SIZE_BYTES - 1] |= (v[j + 8 * (VEC_N1N2_SIZE_BYTES - 1)]) << j;
|
||||
}
|
||||
}
|
||||
14
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/repetition.h
Normal file
14
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/repetition.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef PQCLEAN_HQC1922CCA2_LEAKTIME_REPETITION_H
|
||||
#define PQCLEAN_HQC1922CCA2_LEAKTIME_REPETITION_H
|
||||
|
||||
/**
|
||||
* @file repetition.h
|
||||
* @brief Header file for repetition.c
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_repetition_code_encode(uint8_t *em, const uint8_t *m);
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_repetition_code_decode(uint8_t *m, const uint8_t *em);
|
||||
|
||||
#endif
|
||||
42
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/tensor.c
Normal file
42
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/tensor.c
Normal file
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @file tensor.c
|
||||
* @brief Implementation of tensor code
|
||||
*/
|
||||
|
||||
#include "bch.h"
|
||||
#include "parameters.h"
|
||||
#include "repetition.h"
|
||||
#include "tensor.h"
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encoding the message m to a code word em using the tensor code
|
||||
*
|
||||
* First we encode the message using the BCH code, then with the repetition code to obtain
|
||||
* a tensor code word.
|
||||
*
|
||||
* @param[out] em Pointer to an array that is the tensor code word
|
||||
* @param[in] m Pointer to an array that is the message
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_tensor_code_encode(uint8_t *em, const uint8_t *m) {
|
||||
uint8_t tmp[VEC_N1_SIZE_BYTES] = {0};
|
||||
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_bch_code_encode(tmp, m);
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_repetition_code_encode(em, tmp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Decoding the code word em to a message m using the tensor code
|
||||
*
|
||||
* @param[out] m Pointer to an array that is the message
|
||||
* @param[in] em Pointer to an array that is the code word
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_tensor_code_decode(uint8_t *m, const uint8_t *em) {
|
||||
uint8_t tmp[VEC_N1_SIZE_BYTES] = {0};
|
||||
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_repetition_code_decode(tmp, em);
|
||||
PQCLEAN_HQC1922CCA2_LEAKTIME_bch_code_decode(m, tmp);
|
||||
}
|
||||
14
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/tensor.h
Normal file
14
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/tensor.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef PQCLEAN_HQC1922CCA2_LEAKTIME_TENSOR_H
|
||||
#define PQCLEAN_HQC1922CCA2_LEAKTIME_TENSOR_H
|
||||
|
||||
/**
|
||||
* @file tensor.h
|
||||
* @brief Header file for tensor.c
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_tensor_code_encode(uint8_t *em, const uint8_t *m);
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_tensor_code_decode(uint8_t *m, const uint8_t *em);
|
||||
|
||||
#endif
|
||||
69
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/util.c
Normal file
69
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/util.c
Normal file
@ -0,0 +1,69 @@
|
||||
#include "util.h"
|
||||
#include "stddef.h"
|
||||
|
||||
#include "assert.h"
|
||||
|
||||
/* These functions should help with endianness-safe conversions
|
||||
*
|
||||
* load8 and store8 are copied from the McEliece implementations,
|
||||
* which are in the public domain.
|
||||
*/
|
||||
|
||||
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_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_HQC1922CCA2_LEAKTIME_load8(const unsigned char *in) {
|
||||
uint64_t ret = in[7];
|
||||
|
||||
for (int8_t i = 6; i >= 0; i--) {
|
||||
ret <<= 8;
|
||||
ret |= in[i];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_load8_arr(uint64_t *out64, size_t outlen, const uint8_t *in8, size_t inlen) {
|
||||
size_t index_in = 0;
|
||||
size_t index_out = 0;
|
||||
|
||||
// first copy by 8 bytes
|
||||
if (inlen >= 8 && outlen >= 1) {
|
||||
while (index_out < outlen && index_in + 8 <= inlen) {
|
||||
out64[index_out] = PQCLEAN_HQC1922CCA2_LEAKTIME_load8(in8 + index_in);
|
||||
|
||||
index_in += 8;
|
||||
index_out += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// we now need to do the last 7 bytes if necessary
|
||||
if (index_in >= inlen || index_out >= outlen) {
|
||||
return;
|
||||
}
|
||||
out64[index_out] = in8[inlen - 1];
|
||||
for (int8_t i = (int8_t)(inlen - index_in) - 2; i >= 0; i--) {
|
||||
out64[index_out] <<= 8;
|
||||
out64[index_out] |= in8[index_in + i];
|
||||
}
|
||||
}
|
||||
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_store8_arr(uint8_t *out8, size_t outlen, const uint64_t *in64, size_t inlen) {
|
||||
for (size_t index_out = 0, index_in = 0; index_out < outlen && index_in < inlen;) {
|
||||
out8[index_out] = (in64[index_in] >> ((index_out % 8) * 8)) & 0xFF;
|
||||
index_out++;
|
||||
if (index_out % 8 == 0) {
|
||||
index_in++;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/util.h
Normal file
9
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/util.h
Normal file
@ -0,0 +1,9 @@
|
||||
/* These functions should help with endianness-safe conversions */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_store8(unsigned char *out, uint64_t in);
|
||||
uint64_t PQCLEAN_HQC1922CCA2_LEAKTIME_load8(const unsigned char *in);
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_load8_arr(uint64_t *out64, size_t outlen, const uint8_t *in8, size_t inlen);
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_store8_arr(uint8_t *out8, size_t outlen, const uint64_t *in64, size_t inlen);
|
||||
224
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/vector.c
Normal file
224
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/vector.c
Normal file
@ -0,0 +1,224 @@
|
||||
/**
|
||||
* @file vector.c
|
||||
* @brief Implementation of vectors sampling and some utilities for the HQC scheme
|
||||
*/
|
||||
|
||||
#include "nistseedexpander.h"
|
||||
#include "parameters.h"
|
||||
#include "randombytes.h"
|
||||
#include "vector.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Generates a vector of a given Hamming weight
|
||||
*
|
||||
* This function generates uniformly at random a binary vector of a Hamming weight equal to the parameter <b>weight</b>. The vector
|
||||
* is stored by position.
|
||||
* To generate the vector we have to sample uniformly at random values in the interval [0, PARAM_N -1]. Suppose the PARAM_N is equal to \f$ 70853 \f$, to select a position \f$ r\f$ the function works as follow:
|
||||
* 1. It makes a call to the seedexpander function to obtain a random number \f$ x\f$ in \f$ [0, 2^{24}[ \f$.
|
||||
* 2. Let \f$ t = \lfloor {2^{24} \over 70853} \rfloor \times 70853\f$
|
||||
* 3. If \f$ x \geq t\f$, go to 1
|
||||
* 4. It return \f$ r = x \mod 70853\f$
|
||||
*
|
||||
* The parameter \f$ t \f$ is precomputed and it's denoted by UTILS_REJECTION_THRESHOLD (see the file parameters.h).
|
||||
*
|
||||
* @param[in] v Pointer to an array
|
||||
* @param[in] weight Integer that is the Hamming weight
|
||||
* @param[in] ctx Pointer to the context of the seed expander
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_vect_set_random_fixed_weight_by_coordinates(AES_XOF_struct *ctx, uint32_t *v, uint16_t weight) {
|
||||
size_t random_bytes_size = 3 * weight;
|
||||
uint8_t rand_bytes[3 * PARAM_OMEGA_R] = {0}; // weight is expected to be <= PARAM_OMEGA_R
|
||||
uint32_t random_data = 0;
|
||||
uint8_t exist = 0;
|
||||
size_t j = 0;
|
||||
|
||||
seedexpander(ctx, rand_bytes, random_bytes_size);
|
||||
|
||||
for (uint32_t i = 0; i < weight; ++i) {
|
||||
exist = 0;
|
||||
do {
|
||||
if (j == random_bytes_size) {
|
||||
seedexpander(ctx, rand_bytes, random_bytes_size);
|
||||
j = 0;
|
||||
}
|
||||
|
||||
random_data = ((uint32_t) rand_bytes[j++]) << 16;
|
||||
random_data |= ((uint32_t) rand_bytes[j++]) << 8;
|
||||
random_data |= rand_bytes[j++];
|
||||
|
||||
} while (random_data >= UTILS_REJECTION_THRESHOLD);
|
||||
|
||||
random_data = random_data % PARAM_N;
|
||||
|
||||
for (uint32_t k = 0; k < i; k++) {
|
||||
if (v[k] == random_data) {
|
||||
exist = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (exist == 1) {
|
||||
i--;
|
||||
} else {
|
||||
v[i] = random_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Generates a vector of a given Hamming weight
|
||||
*
|
||||
* This function generates uniformly at random a binary vector of a Hamming weight equal to the parameter <b>weight</b>.
|
||||
* To generate the vector we have to sample uniformly at random values in the interval [0, PARAM_N -1]. Suppose the PARAM_N is equal to \f$ 70853 \f$, to select a position \f$ r\f$ the function works as follow:
|
||||
* 1. It makes a call to the seedexpander function to obtain a random number \f$ x\f$ in \f$ [0, 2^{24}[ \f$.
|
||||
* 2. Let \f$ t = \lfloor {2^{24} \over 70853} \rfloor \times 70853\f$
|
||||
* 3. If \f$ x \geq t\f$, go to 1
|
||||
* 4. It return \f$ r = x \mod 70853\f$
|
||||
*
|
||||
* The parameter \f$ t \f$ is precomputed and it's denoted by UTILS_REJECTION_THRESHOLD (see the file parameters.h).
|
||||
*
|
||||
* @param[in] v Pointer to an array
|
||||
* @param[in] weight Integer that is the Hamming weight
|
||||
* @param[in] ctx Pointer to the context of the seed expander
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_vect_set_random_fixed_weight(AES_XOF_struct *ctx, uint8_t *v, uint16_t weight) {
|
||||
|
||||
size_t random_bytes_size = 3 * weight;
|
||||
uint8_t rand_bytes[3 * PARAM_OMEGA_R] = {0}; // weight is expected to be <= PARAM_OMEGA_R
|
||||
uint32_t random_data = 0;
|
||||
uint32_t tmp[PARAM_OMEGA_R] = {0};
|
||||
uint8_t exist = 0;
|
||||
size_t j = 0;
|
||||
|
||||
seedexpander(ctx, rand_bytes, random_bytes_size);
|
||||
|
||||
for (uint32_t i = 0; i < weight; ++i) {
|
||||
exist = 0;
|
||||
do {
|
||||
if (j == random_bytes_size) {
|
||||
seedexpander(ctx, rand_bytes, random_bytes_size);
|
||||
j = 0;
|
||||
}
|
||||
|
||||
random_data = ((uint32_t) rand_bytes[j++]) << 16;
|
||||
random_data |= ((uint32_t) rand_bytes[j++]) << 8;
|
||||
random_data |= rand_bytes[j++];
|
||||
|
||||
} while (random_data >= UTILS_REJECTION_THRESHOLD);
|
||||
|
||||
random_data = random_data % PARAM_N;
|
||||
|
||||
for (uint32_t k = 0; k < i; k++) {
|
||||
if (tmp[k] == random_data) {
|
||||
exist = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (exist == 1) {
|
||||
i--;
|
||||
} else {
|
||||
tmp[i] = random_data;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < weight; ++i) {
|
||||
int32_t index = tmp[i] / 8;
|
||||
int32_t pos = tmp[i] % 8;
|
||||
v[index] |= 1 << pos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Generates a random vector of dimension <b>PARAM_N</b>
|
||||
*
|
||||
* This function generates a random binary vector of dimension <b>PARAM_N</b>. It generates a random
|
||||
* array of bytes using the seedexpander function, and drop the extra bits using a mask.
|
||||
*
|
||||
* @param[in] v Pointer to an array
|
||||
* @param[in] ctx Pointer to the context of the seed expander
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_vect_set_random(AES_XOF_struct *ctx, uint8_t *v) {
|
||||
uint8_t rand_bytes[VEC_N_SIZE_BYTES] = {0};
|
||||
|
||||
seedexpander(ctx, rand_bytes, VEC_N_SIZE_BYTES);
|
||||
|
||||
memcpy(v, rand_bytes, VEC_N_SIZE_BYTES);
|
||||
v[VEC_N_SIZE_BYTES - 1] &= BITMASK(PARAM_N, 8);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Generates a random vector
|
||||
*
|
||||
* This function generates a random binary vector. It uses the the randombytes function.
|
||||
*
|
||||
* @param[in] v Pointer to an array
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_vect_set_random_from_randombytes(uint8_t *v) {
|
||||
uint8_t rand_bytes [VEC_K_SIZE_BYTES] = {0};
|
||||
|
||||
randombytes(rand_bytes, VEC_K_SIZE_BYTES);
|
||||
memcpy(v, rand_bytes, VEC_K_SIZE_BYTES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Adds two vectors
|
||||
*
|
||||
* @param[out] o Pointer to an array that is the result
|
||||
* @param[in] v1 Pointer to an array that is the first vector
|
||||
* @param[in] v2 Pointer to an array that is the second vector
|
||||
* @param[in] size Integer that is the size of the vectors
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_vect_add(uint8_t *o, const uint8_t *v1, const uint8_t *v2, uint32_t size) {
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
o[i] = v1[i] ^ v2[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Compares two vectors
|
||||
*
|
||||
* @param[in] v1 Pointer to an array that is first vector
|
||||
* @param[in] v2 Pointer to an array that is second vector
|
||||
* @param[in] size Integer that is the size of the vectors
|
||||
* @returns 0 if the vectors are equals and a negative/psotive value otherwise
|
||||
*/
|
||||
int PQCLEAN_HQC1922CCA2_LEAKTIME_vect_compare(const uint8_t *v1, const uint8_t *v2, uint32_t size) {
|
||||
return memcmp(v1, v2, size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Resize a vector so that it contains <b>size_o</b> bits
|
||||
*
|
||||
* @param[out] o Pointer to the output vector
|
||||
* @param[in] size_o Integer that is the size of the output vector in bits
|
||||
* @param[in] v Pointer to the input vector
|
||||
* @param[in] size_v Integer that is the size of the input vector in bits
|
||||
*/
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_vect_resize(uint8_t *o, uint32_t size_o, const uint8_t *v, uint32_t size_v) {
|
||||
if (size_o < size_v) {
|
||||
uint8_t mask = 0x7F;
|
||||
int8_t val = 8 - (size_o % 8);
|
||||
|
||||
memcpy(o, v, VEC_N1N2_SIZE_BYTES);
|
||||
|
||||
for (int8_t i = 0; i < val; ++i) {
|
||||
o[VEC_N1N2_SIZE_BYTES - 1] &= (mask >> i);
|
||||
}
|
||||
} else {
|
||||
memcpy(o, v, CEIL_DIVIDE(size_v, 8));
|
||||
}
|
||||
}
|
||||
22
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/vector.h
Normal file
22
src/kem/hqc/pqclean_hqc-192-2-cca2_leaktime/vector.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef PQCLEAN_HQC1922CCA2_LEAKTIME_VECTOR_H
|
||||
#define PQCLEAN_HQC1922CCA2_LEAKTIME_VECTOR_H
|
||||
|
||||
/**
|
||||
* @file vector.h
|
||||
* @brief Header file for vector.c
|
||||
*/
|
||||
|
||||
#include "nistseedexpander.h"
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_vect_set_random_fixed_weight_by_coordinates(AES_XOF_struct *ctx, uint32_t *v, uint16_t weight);
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_vect_set_random_fixed_weight(AES_XOF_struct *ctx, uint8_t *v, uint16_t weight);
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_vect_set_random(AES_XOF_struct *ctx, uint8_t *v);
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_vect_set_random_from_randombytes(uint8_t *v);
|
||||
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_vect_add(uint8_t *o, const uint8_t *v1, const uint8_t *v2, uint32_t size);
|
||||
int PQCLEAN_HQC1922CCA2_LEAKTIME_vect_compare(const uint8_t *v1, const uint8_t *v2, uint32_t size);
|
||||
|
||||
void PQCLEAN_HQC1922CCA2_LEAKTIME_vect_resize(uint8_t *o, uint32_t size_o, const uint8_t *v, uint32_t size_v);
|
||||
|
||||
#endif
|
||||
1
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/LICENSE
Normal file
1
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/LICENSE
Normal file
@ -0,0 +1 @@
|
||||
Public domain
|
||||
25
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/api.h
Normal file
25
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/api.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef PQCLEAN_HQC2561CCA2_LEAKTIME_API_H
|
||||
#define PQCLEAN_HQC2561CCA2_LEAKTIME_API_H
|
||||
|
||||
/**
|
||||
* \file api.h
|
||||
* \brief NIST KEM API used by the HQC_KEM IND-CCA2 scheme
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PQCLEAN_HQC2561CCA2_LEAKTIME_CRYPTO_ALGNAME "HQC_256_1_CCA2"
|
||||
|
||||
#define PQCLEAN_HQC2561CCA2_LEAKTIME_CRYPTO_SECRETKEYBYTES 8029
|
||||
#define PQCLEAN_HQC2561CCA2_LEAKTIME_CRYPTO_PUBLICKEYBYTES 7989
|
||||
#define PQCLEAN_HQC2561CCA2_LEAKTIME_CRYPTO_BYTES 64
|
||||
#define PQCLEAN_HQC2561CCA2_LEAKTIME_CRYPTO_CIPHERTEXTBYTES 15961
|
||||
|
||||
// As a technicality, the public key is appended to the secret key in order to respect the NIST API.
|
||||
// Without this constraint, CRYPTO_SECRETKEYBYTES would be defined as 32
|
||||
|
||||
int PQCLEAN_HQC2561CCA2_LEAKTIME_crypto_kem_keypair(uint8_t *pk, uint8_t *sk);
|
||||
int PQCLEAN_HQC2561CCA2_LEAKTIME_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
|
||||
int PQCLEAN_HQC2561CCA2_LEAKTIME_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
|
||||
|
||||
#endif
|
||||
295
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/bch.c
Normal file
295
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/bch.c
Normal file
@ -0,0 +1,295 @@
|
||||
/**
|
||||
* @file bch.c
|
||||
* Constant time implementation of BCH codes
|
||||
*/
|
||||
|
||||
#include "bch.h"
|
||||
#include "fft.h"
|
||||
#include "gf.h"
|
||||
#include "parameters.h"
|
||||
#include "vector.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
static void unpack_message(uint8_t *message_unpacked, const uint8_t *message);
|
||||
static void lfsr_encode(uint8_t *codeword, const uint8_t *message);
|
||||
static void pack_codeword(uint8_t *codeword, const uint8_t *codeword_unpacked);
|
||||
static size_t compute_elp(uint16_t *sigma, const uint16_t *syndromes);
|
||||
static void message_from_codeword(uint8_t *message, const uint8_t *codeword);
|
||||
static void compute_syndromes(uint16_t *syndromes, const uint8_t *vector);
|
||||
static void compute_roots(uint8_t *error, const uint16_t *sigma);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Unpacks the message message to the array message_unpacked where each byte stores a bit of the message
|
||||
*
|
||||
* @param[out] message_unpacked Array of VEC_K_SIZE_BYTES bytes receiving the unpacked message
|
||||
* @param[in] message Array of PARAM_K bytes storing the packed message
|
||||
*/
|
||||
static void unpack_message(uint8_t *message_unpacked, const uint8_t *message) {
|
||||
for (size_t i = 0; i < (VEC_K_SIZE_BYTES - (PARAM_K % 8 != 0)); ++i) {
|
||||
for (size_t j = 0; j < 8; ++j) {
|
||||
message_unpacked[j + 8 * i] = (message[i] >> j) & 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
for (int8_t j = 0; j < PARAM_K % 8; ++j) {
|
||||
message_unpacked[j + 8 * (VEC_K_SIZE_BYTES - 1)] = (message[VEC_K_SIZE_BYTES - 1] >> j) & 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encodes the message message to a codeword codeword using the generator polynomial bch_poly of the code
|
||||
*
|
||||
* @param[out] codeword Array of PARAM_N1 bytes receiving the codeword
|
||||
* @param[in] message Array of PARAM_K bytes storing the message to encode
|
||||
*/
|
||||
static void lfsr_encode(uint8_t *codeword, const uint8_t *message) {
|
||||
uint8_t gate_value = 0;
|
||||
uint8_t bch_poly[PARAM_G] = PARAM_BCH_POLY;
|
||||
|
||||
// Compute the Parity-check digits
|
||||
for (int16_t i = PARAM_K - 1; i >= 0; --i) {
|
||||
gate_value = message[i] ^ codeword[PARAM_N1 - PARAM_K - 1];
|
||||
|
||||
for (size_t j = PARAM_N1 - PARAM_K - 1; j; --j) {
|
||||
codeword[j] = codeword[j - 1] ^ (-gate_value & bch_poly[j]);
|
||||
}
|
||||
|
||||
codeword[0] = gate_value;
|
||||
}
|
||||
|
||||
// Add the message
|
||||
memcpy(codeword + PARAM_N1 - PARAM_K, message, PARAM_K);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Packs the codeword from an array codeword_unpacked where each byte stores a bit to a compact array codeword
|
||||
*
|
||||
* @param[out] codeword Array of VEC_N1_SIZE_BYTES bytes receiving the packed codeword
|
||||
* @param[in] codeword_unpacked Array of PARAM_N1 bytes storing the unpacked codeword
|
||||
*/
|
||||
static void pack_codeword(uint8_t *codeword, const uint8_t *codeword_unpacked) {
|
||||
for (size_t i = 0; i < (VEC_N1_SIZE_BYTES - (PARAM_N1 % 8 != 0)); ++i) {
|
||||
for (size_t j = 0; j < 8; ++j) {
|
||||
codeword[i] |= codeword_unpacked[j + 8 * i] << j;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < PARAM_N1 % 8; ++j) {
|
||||
codeword[VEC_N1_SIZE_BYTES - 1] |= codeword_unpacked[j + 8 * (VEC_N1_SIZE_BYTES - 1)] << j;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encodes a message message of PARAM_K bits to a BCH codeword codeword of PARAM_N1 bits
|
||||
*
|
||||
* Following @cite lin1983error (Chapter 4 - Cyclic Codes),
|
||||
* We perform a systematic encoding using a linear (PARAM_N1 - PARAM_K)-stage shift register
|
||||
* with feedback connections based on the generator polynomial bch_poly of the BCH code.
|
||||
*
|
||||
* @param[out] codeword Array of size VEC_N1_SIZE_BYTES receiving the encoded message
|
||||
* @param[in] message Array of size VEC_K_SIZE_BYTES storing the message
|
||||
*/
|
||||
void PQCLEAN_HQC2561CCA2_LEAKTIME_bch_code_encode(uint8_t *codeword, const uint8_t *message) {
|
||||
uint8_t message_unpacked[PARAM_K];
|
||||
uint8_t codeword_unpacked[PARAM_N1] = {0};
|
||||
|
||||
unpack_message(message_unpacked, message);
|
||||
lfsr_encode(codeword_unpacked, message_unpacked);
|
||||
pack_codeword(codeword, codeword_unpacked);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the error locator polynomial (ELP) sigma
|
||||
*
|
||||
* This is a constant time implementation of Berlekamp's simplified algorithm (see @cite joiner1995decoding). <br>
|
||||
* We use the letter p for rho which is initialized at -1/2. <br>
|
||||
* The array X_sigma_p represents the polynomial X^(2(mu-rho))*sigma_p(X). <br>
|
||||
* Instead of maintaining a list of sigmas, we update in place both sigma and X_sigma_p. <br>
|
||||
* sigma_copy serves as a temporary save of sigma in case X_sigma_p needs to be updated. <br>
|
||||
* We can properly correct only if the degree of sigma does not exceed PARAM_DELTA.
|
||||
* This means only the first PARAM_DELTA + 1 coefficients of sigma are of value
|
||||
* and we only need to save its first PARAM_DELTA - 1 coefficients.
|
||||
*
|
||||
* @returns the degree of the ELP sigma
|
||||
* @param[out] sigma Array of size (at least) PARAM_DELTA receiving the ELP
|
||||
* @param[in] syndromes Array of size (at least) 2*PARAM_DELTA storing the syndromes
|
||||
*/
|
||||
static size_t compute_elp(uint16_t *sigma, const uint16_t *syndromes) {
|
||||
sigma[0] = 1;
|
||||
size_t deg_sigma = 0;
|
||||
size_t deg_sigma_p = 0;
|
||||
uint16_t sigma_copy[PARAM_DELTA - 1] = {0};
|
||||
size_t deg_sigma_copy = 0;
|
||||
uint16_t X_sigma_p[PARAM_DELTA + 1] = {0, 1};
|
||||
int32_t pp = -1; // 2*rho
|
||||
uint16_t d_p = 1;
|
||||
uint16_t d = syndromes[0];
|
||||
|
||||
for (size_t mu = 0; mu < PARAM_DELTA; ++mu) {
|
||||
// Save sigma in case we need it to update X_sigma_p
|
||||
memcpy(sigma_copy, sigma, 2 * (PARAM_DELTA - 1));
|
||||
deg_sigma_copy = deg_sigma;
|
||||
|
||||
uint16_t dd = PQCLEAN_HQC2561CCA2_LEAKTIME_gf_mul(d, PQCLEAN_HQC2561CCA2_LEAKTIME_gf_inverse(d_p)); // 0 if(d == 0)
|
||||
for (size_t i = 1; (i <= 2 * mu + 1) && (i <= PARAM_DELTA); ++i) {
|
||||
sigma[i] ^= PQCLEAN_HQC2561CCA2_LEAKTIME_gf_mul(dd, X_sigma_p[i]);
|
||||
}
|
||||
|
||||
size_t deg_X = 2 * mu - pp; // 2*(mu-rho)
|
||||
size_t deg_X_sigma_p = deg_X + deg_sigma_p;
|
||||
|
||||
// mask1 = 0xffff if(d != 0) and 0 otherwise
|
||||
int16_t mask1 = -((uint16_t) - d >> 15);
|
||||
|
||||
// mask2 = 0xffff if(deg_X_sigma_p > deg_sigma) and 0 otherwise
|
||||
int16_t mask2 = -((uint16_t) (deg_sigma - deg_X_sigma_p) >> 15);
|
||||
|
||||
// mask12 = 0xffff if the deg_sigma increased and 0 otherwise
|
||||
int16_t mask12 = mask1 & mask2;
|
||||
deg_sigma = (mask12 & deg_X_sigma_p) ^ (~mask12 & deg_sigma);
|
||||
|
||||
if (mu == PARAM_DELTA - 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Update pp, d_p and X_sigma_p if needed
|
||||
pp = (mask12 & (2 * mu)) ^ (~mask12 & pp);
|
||||
d_p = (mask12 & d) ^ (~mask12 & d_p);
|
||||
for (size_t i = PARAM_DELTA - 1; i; --i) {
|
||||
X_sigma_p[i + 1] = (mask12 & sigma_copy[i - 1]) ^ (~mask12 & X_sigma_p[i - 1]);
|
||||
}
|
||||
X_sigma_p[1] = 0;
|
||||
X_sigma_p[0] = 0;
|
||||
deg_sigma_p = (mask12 & deg_sigma_copy) ^ (~mask12 & deg_sigma_p);
|
||||
|
||||
// Compute the next discrepancy
|
||||
d = syndromes[2 * mu + 2];
|
||||
for (size_t i = 1; (i <= 2 * mu + 1) && (i <= PARAM_DELTA); ++i) {
|
||||
d ^= PQCLEAN_HQC2561CCA2_LEAKTIME_gf_mul(sigma[i], syndromes[2 * mu + 2 - i]);
|
||||
}
|
||||
}
|
||||
|
||||
return deg_sigma;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieves the message message from the codeword codeword
|
||||
*
|
||||
* Since we performed a systematic encoding, the message is the last PARAM_K bits of the codeword.
|
||||
*
|
||||
* @param[out] message Array of size VEC_K_SIZE_BYTES receiving the message
|
||||
* @param[in] codeword Array of size VEC_N1_SIZE_BYTES storing the codeword
|
||||
*/
|
||||
static void message_from_codeword(uint8_t *message, const uint8_t *codeword) {
|
||||
int32_t val = PARAM_N1 - PARAM_K;
|
||||
|
||||
uint8_t mask1 = 0xff << val % 8;
|
||||
uint8_t mask2 = 0xff >> (8 - val % 8);
|
||||
size_t index = val / 8;
|
||||
|
||||
for (size_t i = 0; i < VEC_K_SIZE_BYTES - 1; ++i) {
|
||||
uint8_t message1 = (codeword[index] & mask1) >> val % 8;
|
||||
uint8_t message2 = (codeword[++index] & mask2) << (8 - val % 8);
|
||||
message[i] = message1 | message2;
|
||||
}
|
||||
|
||||
// Last byte (8-val % 8 is the number of bits given by message1)
|
||||
if ((PARAM_K % 8 == 0) || (8 - val % 8 < PARAM_K % 8)) {
|
||||
uint8_t message1 = (codeword[index] & mask1) >> val % 8;
|
||||
uint8_t message2 = (codeword[++index] & mask2) << (8 - val % 8);
|
||||
message[VEC_K_SIZE_BYTES - 1] = message1 | message2;
|
||||
} else {
|
||||
uint8_t message1 = (codeword[index] & mask1) >> val % 8;
|
||||
message[VEC_K_SIZE_BYTES - 1] = message1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the 2^PARAM_DELTA syndromes from the received vector vector
|
||||
*
|
||||
* Syndromes are the sum of powers of alpha weighted by vector's coefficients.
|
||||
* To do so, we use the additive FFT transpose, which takes as input a family w of GF(2^PARAM_M) elements
|
||||
* and outputs the weighted power sums of these w. <br>
|
||||
* Therefore, this requires twisting and applying a permutation before feeding vector to the fft transpose. <br>
|
||||
* For more details see Berstein, Chou and Schawbe's explanations:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*
|
||||
* @param[out] syndromes Array of size 2^(PARAM_FFT_T) receiving the 2*PARAM_DELTA syndromes
|
||||
* @param[in] vector Array of size VEC_N1_SIZE_BYTES storing the received word
|
||||
*/
|
||||
static void compute_syndromes(uint16_t *syndromes, const uint8_t *vector) {
|
||||
uint16_t w[1 << PARAM_M];
|
||||
|
||||
PQCLEAN_HQC2561CCA2_LEAKTIME_fft_t_preprocess_bch_codeword(w, vector);
|
||||
PQCLEAN_HQC2561CCA2_LEAKTIME_fft_t(syndromes, w, 2 * PARAM_DELTA);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the error polynomial error from the error locator polynomial sigma
|
||||
*
|
||||
* See function fft for more details.
|
||||
*
|
||||
* @param[out] err Array of VEC_N1_SIZE_BYTES elements receiving the error polynomial
|
||||
* @param[in] sigma Array of 2^PARAM_FFT elements storing the error locator polynomial
|
||||
*/
|
||||
static void compute_roots(uint8_t *error, const uint16_t *sigma) {
|
||||
uint16_t w[1 << PARAM_M] = {0}; // w will receive the evaluation of sigma in all field elements
|
||||
|
||||
PQCLEAN_HQC2561CCA2_LEAKTIME_fft(w, sigma, PARAM_DELTA + 1);
|
||||
PQCLEAN_HQC2561CCA2_LEAKTIME_fft_retrieve_bch_error_poly(error, w);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Decodes the received word
|
||||
*
|
||||
* This function relies on four steps:
|
||||
* <ol>
|
||||
* <li> The first step, done by additive FFT transpose, is the computation of the 2*PARAM_DELTA syndromes.
|
||||
* <li> The second step is the computation of the error-locator polynomial sigma.
|
||||
* <li> The third step, done by additive FFT, is finding the error-locator numbers by calculating the roots of the polynomial sigma and takings their inverses.
|
||||
* <li> The fourth step is the correction of the errors in the received polynomial.
|
||||
* </ol>
|
||||
* For a more complete picture on BCH decoding, see Shu. Lin and Daniel J. Costello in Error Control Coding: Fundamentals and Applications @cite lin1983error
|
||||
*
|
||||
* @param[out] message Array of size VEC_K_SIZE_BYTES receiving the decoded message
|
||||
* @param[in] vector Array of size VEC_N1_SIZE_BYTES storing the received word
|
||||
*/
|
||||
void PQCLEAN_HQC2561CCA2_LEAKTIME_bch_code_decode(uint8_t *message, uint8_t *vector) {
|
||||
uint16_t syndromes[1 << PARAM_FFT_T];
|
||||
uint16_t sigma[1 << PARAM_FFT] = {0};
|
||||
uint8_t error[(1 << PARAM_M) / 8] = {0};
|
||||
|
||||
// Calculate the 2*PARAM_DELTA syndromes
|
||||
compute_syndromes(syndromes, vector);
|
||||
|
||||
// Compute the error locator polynomial sigma
|
||||
// Sigma's degree is at most PARAM_DELTA but the FFT requires the extra room
|
||||
compute_elp(sigma, syndromes);
|
||||
|
||||
// Compute the error polynomial error
|
||||
compute_roots(error, sigma);
|
||||
|
||||
// Add the error polynomial to the received polynomial
|
||||
PQCLEAN_HQC2561CCA2_LEAKTIME_vect_add(vector, vector, error, VEC_N1_SIZE_BYTES);
|
||||
|
||||
// Retrieve the message from the decoded codeword
|
||||
message_from_codeword(message, vector);
|
||||
}
|
||||
16
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/bch.h
Normal file
16
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/bch.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef PQCLEAN_HQC2561CCA2_LEAKTIME_BCH_H
|
||||
#define PQCLEAN_HQC2561CCA2_LEAKTIME_BCH_H
|
||||
|
||||
/**
|
||||
* @file bch.h
|
||||
* Header file of bch.c
|
||||
*/
|
||||
|
||||
#include "parameters.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC2561CCA2_LEAKTIME_bch_code_encode(uint8_t *codeword, const uint8_t *message);
|
||||
void PQCLEAN_HQC2561CCA2_LEAKTIME_bch_code_decode(uint8_t *message, uint8_t *vector);
|
||||
|
||||
#endif
|
||||
628
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/fft.c
Normal file
628
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/fft.c
Normal file
@ -0,0 +1,628 @@
|
||||
/**
|
||||
* @file fft.c
|
||||
* Implementation of the additive FFT and its transpose.
|
||||
* This implementation is based on the paper from Gao and Mateer: <br>
|
||||
* Shuhong Gao and Todd Mateer, Additive Fast Fourier Transforms over Finite Fields,
|
||||
* IEEE Transactions on Information Theory 56 (2010), 6265--6272.
|
||||
* http://www.math.clemson.edu/~sgao/papers/GM10.pdf <br>
|
||||
* and includes improvements proposed by Bernstein, Chou and Schwabe here:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*/
|
||||
|
||||
#include "fft.h"
|
||||
#include "gf.h"
|
||||
#include "parameters.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
static void compute_fft_betas(uint16_t *betas);
|
||||
static void compute_subset_sums(uint16_t *subset_sums, const uint16_t *set, size_t set_size);
|
||||
static void radix_t(uint16_t *f, const uint16_t *f0, const uint16_t *f1, uint32_t m_f);
|
||||
static void fft_t_rec(uint16_t *f, const uint16_t *w, size_t f_coeffs, uint8_t m, uint32_t m_f, const uint16_t *betas);
|
||||
static void radix(uint16_t *f0, uint16_t *f1, const uint16_t *f, uint32_t m_f);
|
||||
static void fft_rec(uint16_t *w, uint16_t *f, size_t f_coeffs, uint8_t m, uint32_t m_f, const uint16_t *betas);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the basis of betas (omitting 1) used in the additive FFT and its transpose
|
||||
*
|
||||
* @param[out] betas Array of size PARAM_M-1
|
||||
*/
|
||||
static void compute_fft_betas(uint16_t *betas) {
|
||||
for (size_t i = 0; i < PARAM_M - 1; ++i) {
|
||||
betas[i] = 1 << (PARAM_M - 1 - i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the subset sums of the given set
|
||||
*
|
||||
* The array subset_sums is such that its ith element is
|
||||
* the subset sum of the set elements given by the binary form of i.
|
||||
*
|
||||
* @param[out] subset_sums Array of size 2^set_size receiving the subset sums
|
||||
* @param[in] set Array of set_size elements
|
||||
* @param[in] set_size Size of the array set
|
||||
*/
|
||||
static void compute_subset_sums(uint16_t *subset_sums, const uint16_t *set, size_t set_size) {
|
||||
subset_sums[0] = 0;
|
||||
|
||||
for (size_t i = 0; i < set_size; ++i) {
|
||||
for (size_t j = 0; j < (((size_t)1) << i); ++j) {
|
||||
subset_sums[(((size_t)1) << i) + j] = set[i] ^ subset_sums[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Transpose of the linear radix conversion
|
||||
*
|
||||
* This is a direct transposition of the radix function
|
||||
* implemented following the process of transposing a linear function as exposed by Bernstein, Chou and Schwabe here:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*
|
||||
* @param[out] f Array of size a power of 2
|
||||
* @param[in] f0 Array half the size of f
|
||||
* @param[in] f1 Array half the size of f
|
||||
* @param[in] m_f 2^{m_f} is the smallest power of 2 greater or equal to the number of coefficients of f
|
||||
*/
|
||||
static void radix_t(uint16_t *f, const uint16_t *f0, const uint16_t *f1, uint32_t m_f) {
|
||||
switch (m_f) {
|
||||
case 4:
|
||||
f[0] = f0[0];
|
||||
f[1] = f1[0];
|
||||
f[2] = f0[1] ^ f1[0];
|
||||
f[3] = f[2] ^ f1[1];
|
||||
f[4] = f[2] ^ f0[2];
|
||||
f[5] = f[3] ^ f1[2];
|
||||
f[6] = f[4] ^ f0[3] ^ f1[2];
|
||||
f[7] = f[3] ^ f0[3] ^ f1[3];
|
||||
f[8] = f[4] ^ f0[4];
|
||||
f[9] = f[5] ^ f1[4];
|
||||
f[10] = f[6] ^ f0[5] ^ f1[4];
|
||||
f[11] = f[7] ^ f0[5] ^ f1[4] ^ f1[5];
|
||||
f[12] = f[8] ^ f0[5] ^ f0[6] ^ f1[4];
|
||||
f[13] = f[7] ^ f[9] ^ f[11] ^ f1[6];
|
||||
f[14] = f[6] ^ f0[6] ^ f0[7] ^ f1[6];
|
||||
f[15] = f[7] ^ f0[7] ^ f1[7];
|
||||
return;
|
||||
|
||||
case 3:
|
||||
f[0] = f0[0];
|
||||
f[1] = f1[0];
|
||||
f[2] = f0[1] ^ f1[0];
|
||||
f[3] = f[2] ^ f1[1];
|
||||
f[4] = f[2] ^ f0[2];
|
||||
f[5] = f[3] ^ f1[2];
|
||||
f[6] = f[4] ^ f0[3] ^ f1[2];
|
||||
f[7] = f[3] ^ f0[3] ^ f1[3];
|
||||
return;
|
||||
|
||||
case 2:
|
||||
f[0] = f0[0];
|
||||
f[1] = f1[0];
|
||||
f[2] = f0[1] ^ f1[0];
|
||||
f[3] = f[2] ^ f1[1];
|
||||
return;
|
||||
|
||||
case 1:
|
||||
f[0] = f0[0];
|
||||
f[1] = f1[0];
|
||||
return;
|
||||
|
||||
default:
|
||||
;
|
||||
|
||||
size_t n = ((size_t)1) << (m_f - 2);
|
||||
|
||||
uint16_t Q0[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t Q1[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t R0[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t R1[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
|
||||
uint16_t Q[1 << 2 * (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t R[1 << 2 * (PARAM_FFT_T - 2)] = {0};
|
||||
|
||||
memcpy(Q0, f0 + n, 2 * n);
|
||||
memcpy(Q1, f1 + n, 2 * n);
|
||||
memcpy(R0, f0, 2 * n);
|
||||
memcpy(R1, f1, 2 * n);
|
||||
|
||||
radix_t (Q, Q0, Q1, m_f - 1);
|
||||
radix_t (R, R0, R1, m_f - 1);
|
||||
|
||||
memcpy(f, R, 4 * n);
|
||||
memcpy(f + 2 * n, R + n, 2 * n);
|
||||
memcpy(f + 3 * n, Q + n, 2 * n);
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
f[2 * n + i] ^= Q[i];
|
||||
f[3 * n + i] ^= f[2 * n + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Recursively computes syndromes of family w
|
||||
*
|
||||
* This function is a subroutine of the function fft_t
|
||||
*
|
||||
* @param[out] f Array receiving the syndromes
|
||||
* @param[in] w Array storing the family
|
||||
* @param[in] f_coeffs Length of syndromes vector
|
||||
* @param[in] m 2^m is the smallest power of 2 greater or equal to the length of family w
|
||||
* @param[in] m_f 2^{m_f} is the smallest power of 2 greater or equal to the length of f
|
||||
* @param[in] betas FFT constants
|
||||
*/
|
||||
static void fft_t_rec(uint16_t *f, const uint16_t *w, size_t f_coeffs,
|
||||
uint8_t m, uint32_t m_f, const uint16_t *betas) {
|
||||
size_t k = ((size_t)1) << (m - 1);
|
||||
uint16_t gammas[PARAM_M - 2] = {0};
|
||||
uint16_t deltas[PARAM_M - 2] = {0};
|
||||
uint16_t gammas_sums[1 << (PARAM_M - 1)];
|
||||
uint16_t u[1 << (PARAM_M - 2)] = {0};
|
||||
uint16_t f0[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t f1[1 << (PARAM_FFT_T - 2)] = {0};
|
||||
uint16_t betas_sums[1 << (PARAM_M - 1)] = {0};
|
||||
|
||||
// Step 1
|
||||
if (m_f == 1) {
|
||||
for (size_t i = 0; i < (((size_t)1) << m); ++i) {
|
||||
f[0] ^= w[i];
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < m; ++j) {
|
||||
for (size_t ki = 0; ki < (((size_t)1) << j); ++ki) {
|
||||
size_t index = (((size_t)1) << j) + ki;
|
||||
betas_sums[index] = betas_sums[ki] ^ betas[j];
|
||||
f[1] ^= PQCLEAN_HQC2561CCA2_LEAKTIME_gf_mul(betas_sums[index], w[index]);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute gammas and deltas
|
||||
for (uint8_t i = 0; i < m - 1; ++i) {
|
||||
gammas[i] = PQCLEAN_HQC2561CCA2_LEAKTIME_gf_mul(betas[i], PQCLEAN_HQC2561CCA2_LEAKTIME_gf_inverse(betas[m - 1]));
|
||||
deltas[i] = PQCLEAN_HQC2561CCA2_LEAKTIME_gf_square(gammas[i]) ^ gammas[i];
|
||||
}
|
||||
|
||||
// Compute gammas subset sums
|
||||
compute_subset_sums(gammas_sums, gammas, m - 1);
|
||||
|
||||
/* Step 6: Compute u and v from w (aka w)
|
||||
* w[i] = u[i] + G[i].v[i]
|
||||
* w[k+i] = w[i] + v[i] = u[i] + (G[i]+1).v[i]
|
||||
* Transpose:
|
||||
* u[i] = w[i] + w[k+i]
|
||||
* v[i] = G[i].w[i] + (G[i]+1).w[k+i] = G[i].u[i] + w[k+i] */
|
||||
if (f_coeffs <= 3) { // 3-coefficient polynomial f case
|
||||
// Step 5: Compute f0 from u and f1 from v
|
||||
f1[1] = 0;
|
||||
u[0] = w[0] ^ w[k];
|
||||
f1[0] = w[k];
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
u[i] = w[i] ^ w[k + i];
|
||||
f1[0] ^= PQCLEAN_HQC2561CCA2_LEAKTIME_gf_mul(gammas_sums[i], u[i]) ^ w[k + i];
|
||||
}
|
||||
fft_t_rec(f0, u, (f_coeffs + 1) / 2, m - 1, m_f - 1, deltas);
|
||||
} else {
|
||||
uint16_t v[1 << (PARAM_M - 2)] = {0};
|
||||
|
||||
u[0] = w[0] ^ w[k];
|
||||
v[0] = w[k];
|
||||
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
u[i] = w[i] ^ w[k + i];
|
||||
v[i] = PQCLEAN_HQC2561CCA2_LEAKTIME_gf_mul(gammas_sums[i], u[i]) ^ w[k + i];
|
||||
}
|
||||
|
||||
// Step 5: Compute f0 from u and f1 from v
|
||||
fft_t_rec(f0, u, (f_coeffs + 1) / 2, m - 1, m_f - 1, deltas);
|
||||
fft_t_rec(f1, v, f_coeffs / 2, m - 1, m_f - 1, deltas);
|
||||
}
|
||||
|
||||
// Step 3: Compute g from g0 and g1
|
||||
radix_t(f, f0, f1, m_f);
|
||||
|
||||
// Step 2: compute f from g
|
||||
if (betas[m - 1] != 1) {
|
||||
uint16_t beta_m_pow = 1;
|
||||
for (size_t i = 1; i < (((size_t)1) << m_f); ++i) {
|
||||
beta_m_pow = PQCLEAN_HQC2561CCA2_LEAKTIME_gf_mul(beta_m_pow, betas[m - 1]);
|
||||
f[i] = PQCLEAN_HQC2561CCA2_LEAKTIME_gf_mul(beta_m_pow, f[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the syndromes f of the family w
|
||||
*
|
||||
* Since the syndromes linear map is the transpose of multipoint evaluation,
|
||||
* it uses exactly the same constants, either hardcoded or precomputed by compute_fft_lut(...). <br>
|
||||
* This follows directives from Bernstein, Chou and Schwabe given here:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*
|
||||
* @param[out] f Array of size 2*(PARAM_FFT_T) elements receiving the syndromes
|
||||
* @param[in] w Array of PARAM_GF_MUL_ORDER+1 elements
|
||||
* @param[in] f_coeffs Length of syndromes vector f
|
||||
*/
|
||||
void PQCLEAN_HQC2561CCA2_LEAKTIME_fft_t(uint16_t *f, const uint16_t *w, size_t f_coeffs) {
|
||||
// Transposed from Gao and Mateer algorithm
|
||||
uint16_t betas[PARAM_M - 1];
|
||||
uint16_t betas_sums[1 << (PARAM_M - 1)];
|
||||
size_t k = 1 << (PARAM_M - 1);
|
||||
uint16_t u[1 << (PARAM_M - 1)] = {0};
|
||||
uint16_t v[1 << (PARAM_M - 1)] = {0};
|
||||
uint16_t deltas[PARAM_M - 1];
|
||||
uint16_t f0[1 << (PARAM_FFT_T - 1)];
|
||||
uint16_t f1[1 << (PARAM_FFT_T - 1)];
|
||||
|
||||
compute_fft_betas(betas);
|
||||
compute_subset_sums(betas_sums, betas, PARAM_M - 1);
|
||||
|
||||
/* Step 6: Compute u and v from w (aka w)
|
||||
*
|
||||
* We had:
|
||||
* w[i] = u[i] + G[i].v[i]
|
||||
* w[k+i] = w[i] + v[i] = u[i] + (G[i]+1).v[i]
|
||||
* Transpose:
|
||||
* u[i] = w[i] + w[k+i]
|
||||
* v[i] = G[i].w[i] + (G[i]+1).w[k+i] = G[i].u[i] + w[k+i] */
|
||||
u[0] = w[0] ^ w[k];
|
||||
v[0] = w[k];
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
u[i] = w[i] ^ w[k + i];
|
||||
v[i] = PQCLEAN_HQC2561CCA2_LEAKTIME_gf_mul(betas_sums[i], u[i]) ^ w[k + i];
|
||||
}
|
||||
|
||||
// Compute deltas
|
||||
for (size_t i = 0; i < PARAM_M - 1; ++i) {
|
||||
deltas[i] = PQCLEAN_HQC2561CCA2_LEAKTIME_gf_square(betas[i]) ^ betas[i];
|
||||
}
|
||||
|
||||
// Step 5: Compute f0 from u and f1 from v
|
||||
fft_t_rec(f0, u, (f_coeffs + 1) / 2, PARAM_M - 1, PARAM_FFT_T - 1, deltas);
|
||||
fft_t_rec(f1, v, f_coeffs / 2, PARAM_M - 1, PARAM_FFT_T - 1, deltas);
|
||||
|
||||
// Step 3: Compute g from g0 and g1
|
||||
radix_t(f, f0, f1, PARAM_FFT_T);
|
||||
|
||||
// Step 2: beta_m = 1 so f = g
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the radix conversion of a polynomial f in GF(2^m)[x]
|
||||
*
|
||||
* Computes f0 and f1 such that f(x) = f0(x^2-x) + x.f1(x^2-x)
|
||||
* as proposed by Bernstein, Chou and Schwabe:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf
|
||||
*
|
||||
* @param[out] f0 Array half the size of f
|
||||
* @param[out] f1 Array half the size of f
|
||||
* @param[in] f Array of size a power of 2
|
||||
* @param[in] m_f 2^{m_f} is the smallest power of 2 greater or equal to the number of coefficients of f
|
||||
*/
|
||||
static void radix(uint16_t *f0, uint16_t *f1, const uint16_t *f, uint32_t m_f) {
|
||||
switch (m_f) {
|
||||
case 4:
|
||||
f0[4] = f[8] ^ f[12];
|
||||
f0[6] = f[12] ^ f[14];
|
||||
f0[7] = f[14] ^ f[15];
|
||||
f1[5] = f[11] ^ f[13];
|
||||
f1[6] = f[13] ^ f[14];
|
||||
f1[7] = f[15];
|
||||
f0[5] = f[10] ^ f[12] ^ f1[5];
|
||||
f1[4] = f[9] ^ f[13] ^ f0[5];
|
||||
|
||||
f0[0] = f[0];
|
||||
f1[3] = f[7] ^ f[11] ^ f[15];
|
||||
f0[3] = f[6] ^ f[10] ^ f[14] ^ f1[3];
|
||||
f0[2] = f[4] ^ f0[4] ^ f0[3] ^ f1[3];
|
||||
f1[1] = f[3] ^ f[5] ^ f[9] ^ f[13] ^ f1[3];
|
||||
f1[2] = f[3] ^ f1[1] ^ f0[3];
|
||||
f0[1] = f[2] ^ f0[2] ^ f1[1];
|
||||
f1[0] = f[1] ^ f0[1];
|
||||
return;
|
||||
|
||||
case 3:
|
||||
f0[0] = f[0];
|
||||
f0[2] = f[4] ^ f[6];
|
||||
f0[3] = f[6] ^ f[7];
|
||||
f1[1] = f[3] ^ f[5] ^ f[7];
|
||||
f1[2] = f[5] ^ f[6];
|
||||
f1[3] = f[7];
|
||||
f0[1] = f[2] ^ f0[2] ^ f1[1];
|
||||
f1[0] = f[1] ^ f0[1];
|
||||
return;
|
||||
|
||||
case 2:
|
||||
f0[0] = f[0];
|
||||
f0[1] = f[2] ^ f[3];
|
||||
f1[0] = f[1] ^ f0[1];
|
||||
f1[1] = f[3];
|
||||
return;
|
||||
|
||||
case 1:
|
||||
f0[0] = f[0];
|
||||
f1[0] = f[1];
|
||||
return;
|
||||
|
||||
default:
|
||||
;
|
||||
size_t n = ((size_t)1) << (m_f - 2);
|
||||
|
||||
uint16_t Q[2 * (1 << (PARAM_FFT - 2))];
|
||||
uint16_t R[2 * (1 << (PARAM_FFT - 2))];
|
||||
|
||||
uint16_t Q0[1 << (PARAM_FFT - 2)];
|
||||
uint16_t Q1[1 << (PARAM_FFT - 2)];
|
||||
uint16_t R0[1 << (PARAM_FFT - 2)];
|
||||
uint16_t R1[1 << (PARAM_FFT - 2)];
|
||||
|
||||
memcpy(Q, f + 3 * n, 2 * n);
|
||||
memcpy(Q + n, f + 3 * n, 2 * n);
|
||||
memcpy(R, f, 4 * n);
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
Q[i] ^= f[2 * n + i];
|
||||
R[n + i] ^= Q[i];
|
||||
}
|
||||
|
||||
radix(Q0, Q1, Q, m_f - 1);
|
||||
radix(R0, R1, R, m_f - 1);
|
||||
|
||||
memcpy(f0, R0, 2 * n);
|
||||
memcpy(f0 + n, Q0, 2 * n);
|
||||
memcpy(f1, R1, 2 * n);
|
||||
memcpy(f1 + n, Q1, 2 * n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Evaluates f at all subset sums of a given set
|
||||
*
|
||||
* This function is a subroutine of the function fft.
|
||||
*
|
||||
* @param[out] w Array
|
||||
* @param[in] f Array
|
||||
* @param[in] f_coeffs Number of coefficients of f
|
||||
* @param[in] m Number of betas
|
||||
* @param[in] m_f Number of coefficients of f (one more than its degree)
|
||||
* @param[in] betas FFT constants
|
||||
*/
|
||||
static void fft_rec(uint16_t *w, uint16_t *f, size_t f_coeffs,
|
||||
uint8_t m, uint32_t m_f, const uint16_t *betas) {
|
||||
|
||||
uint16_t f0[1 << (PARAM_FFT - 2)] = {0};
|
||||
uint16_t f1[1 << (PARAM_FFT - 2)] = {0};
|
||||
uint16_t gammas[PARAM_M - 2] = {0};
|
||||
uint16_t deltas[PARAM_M - 2] = {0};
|
||||
size_t k = ((size_t)1) << (m - 1);
|
||||
uint16_t gammas_sums[1 << (PARAM_M - 2)] = {0};
|
||||
uint16_t u[1 << (PARAM_M - 2)] = {0};
|
||||
uint16_t v[1 << (PARAM_M - 2)] = {0};
|
||||
|
||||
// Step 1
|
||||
if (m_f == 1) {
|
||||
uint16_t tmp[PARAM_M - (PARAM_FFT - 1)];
|
||||
for (size_t i = 0; i < m; ++i) {
|
||||
tmp[i] = PQCLEAN_HQC2561CCA2_LEAKTIME_gf_mul(betas[i], f[1]);
|
||||
}
|
||||
|
||||
w[0] = f[0];
|
||||
for (size_t j = 0; j < m; ++j) {
|
||||
for (size_t ki = 0; ki < (((size_t)1) << j); ++ki) {
|
||||
w[(((size_t)1) << j) + ki] = w[ki] ^ tmp[j];
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2: compute g
|
||||
if (betas[m - 1] != 1) {
|
||||
uint16_t beta_m_pow = 1;
|
||||
for (size_t i = 1; i < (((size_t)1) << m_f); ++i) {
|
||||
beta_m_pow = PQCLEAN_HQC2561CCA2_LEAKTIME_gf_mul(beta_m_pow, betas[m - 1]);
|
||||
f[i] = PQCLEAN_HQC2561CCA2_LEAKTIME_gf_mul(beta_m_pow, f[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3
|
||||
radix(f0, f1, f, m_f);
|
||||
|
||||
// Step 4: compute gammas and deltas
|
||||
for (uint8_t i = 0; i < m - 1; ++i) {
|
||||
gammas[i] = PQCLEAN_HQC2561CCA2_LEAKTIME_gf_mul(betas[i], PQCLEAN_HQC2561CCA2_LEAKTIME_gf_inverse(betas[m - 1]));
|
||||
deltas[i] = PQCLEAN_HQC2561CCA2_LEAKTIME_gf_square(gammas[i]) ^ gammas[i];
|
||||
}
|
||||
|
||||
// Compute gammas sums
|
||||
compute_subset_sums(gammas_sums, gammas, m - 1);
|
||||
|
||||
// Step 5
|
||||
fft_rec(u, f0, (f_coeffs + 1) / 2, m - 1, m_f - 1, deltas);
|
||||
|
||||
if (f_coeffs <= 3) { // 3-coefficient polynomial f case: f1 is constant
|
||||
w[0] = u[0];
|
||||
w[k] = u[0] ^ f1[0];
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
w[i] = u[i] ^ PQCLEAN_HQC2561CCA2_LEAKTIME_gf_mul(gammas_sums[i], f1[0]);
|
||||
w[k + i] = w[i] ^ f1[0];
|
||||
}
|
||||
} else {
|
||||
fft_rec(v, f1, f_coeffs / 2, m - 1, m_f - 1, deltas);
|
||||
|
||||
// Step 6
|
||||
memcpy(w + k, v, 2 * k);
|
||||
w[0] = u[0];
|
||||
w[k] ^= u[0];
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
w[i] = u[i] ^ PQCLEAN_HQC2561CCA2_LEAKTIME_gf_mul(gammas_sums[i], v[i]);
|
||||
w[k + i] ^= w[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Evaluates f on all fields elements using an additive FFT algorithm
|
||||
*
|
||||
* f_coeffs is the number of coefficients of f (one less than its degree). <br>
|
||||
* The FFT proceeds recursively to evaluate f at all subset sums of a basis B. <br>
|
||||
* This implementation is based on the paper from Gao and Mateer: <br>
|
||||
* Shuhong Gao and Todd Mateer, Additive Fast Fourier Transforms over Finite Fields,
|
||||
* IEEE Transactions on Information Theory 56 (2010), 6265--6272.
|
||||
* http://www.math.clemson.edu/~sgao/papers/GM10.pdf <br>
|
||||
* and includes improvements proposed by Bernstein, Chou and Schwabe here:
|
||||
* https://binary.cr.yp.to/mcbits-20130616.pdf <br>
|
||||
* Constants betas, gammas and deltas involved in the algorithm are either hardcoded or precomputed
|
||||
* by the subroutine compute_fft_lut(...). <br>
|
||||
* Note that on this first call (as opposed to the recursive calls to fft_rec), gammas are equal to betas,
|
||||
* meaning the first gammas subset sums are actually the subset sums of betas (except 1). <br>
|
||||
* Also note that f is altered during computation (twisted at each level).
|
||||
*
|
||||
* @param[out] w Array
|
||||
* @param[in] f Array of 2^PARAM_FFT elements
|
||||
* @param[in] f_coeffs Number coefficients of f (i.e. deg(f)+1)
|
||||
*/
|
||||
void PQCLEAN_HQC2561CCA2_LEAKTIME_fft(uint16_t *w, const uint16_t *f, size_t f_coeffs) {
|
||||
uint16_t betas[PARAM_M - 1] = {0};
|
||||
uint16_t betas_sums[1 << (PARAM_M - 1)] = {0};
|
||||
uint16_t f0[1 << (PARAM_FFT - 1)] = {0};
|
||||
uint16_t f1[1 << (PARAM_FFT - 1)] = {0};
|
||||
uint16_t deltas[PARAM_M - 1];
|
||||
size_t k = 1 << (PARAM_M - 1);
|
||||
uint16_t u[1 << (PARAM_M - 1)] = {0};
|
||||
uint16_t v[1 << (PARAM_M - 1)] = {0};
|
||||
|
||||
// Follows Gao and Mateer algorithm
|
||||
compute_fft_betas(betas);
|
||||
|
||||
// Step 1: PARAM_FFT > 1, nothing to do
|
||||
|
||||
// Compute gammas sums
|
||||
compute_subset_sums(betas_sums, betas, PARAM_M - 1);
|
||||
|
||||
// Step 2: beta_m = 1, nothing to do
|
||||
|
||||
// Step 3
|
||||
radix(f0, f1, f, PARAM_FFT);
|
||||
|
||||
// Step 4: Compute deltas
|
||||
for (size_t i = 0; i < PARAM_M - 1; ++i) {
|
||||
deltas[i] = PQCLEAN_HQC2561CCA2_LEAKTIME_gf_square(betas[i]) ^ betas[i];
|
||||
}
|
||||
|
||||
// Step 5
|
||||
fft_rec(u, f0, (f_coeffs + 1) / 2, PARAM_M - 1, PARAM_FFT - 1, deltas);
|
||||
fft_rec(v, f1, f_coeffs / 2, PARAM_M - 1, PARAM_FFT - 1, deltas);
|
||||
|
||||
// Step 6, 7 and error polynomial computation
|
||||
memcpy(w + k, v, 2 * k);
|
||||
|
||||
// Check if 0 is root
|
||||
w[0] = u[0];
|
||||
|
||||
// Check if 1 is root
|
||||
w[k] ^= u[0];
|
||||
|
||||
// Find other roots
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
w[i] = u[i] ^ PQCLEAN_HQC2561CCA2_LEAKTIME_gf_mul(betas_sums[i], v[i]);
|
||||
w[k + i] ^= w[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Arranges the received word vector in a form w such that applying the additive FFT transpose to w yields the BCH syndromes of the received word vector.
|
||||
*
|
||||
* Since the received word vector gives coefficients of the primitive element alpha, we twist accordingly. <br>
|
||||
* Furthermore, the additive FFT transpose needs elements indexed by their decomposition on the chosen basis,
|
||||
* so we apply the adequate permutation.
|
||||
*
|
||||
* @param[out] w Array of size 2^PARAM_M
|
||||
* @param[in] vector Array of size VEC_N1_SIZE_BYTES
|
||||
*/
|
||||
void PQCLEAN_HQC2561CCA2_LEAKTIME_fft_t_preprocess_bch_codeword(uint16_t *w, const uint8_t *vector) {
|
||||
uint16_t r[1 << PARAM_M];
|
||||
uint16_t gammas[PARAM_M - 1];
|
||||
uint16_t gammas_sums[1 << (PARAM_M - 1)];
|
||||
size_t k = 1 << (PARAM_M - 1);
|
||||
|
||||
// Unpack the received word vector into array r
|
||||
size_t i;
|
||||
for (i = 0; i < VEC_N1_SIZE_BYTES - (PARAM_N1 % 8 != 0); ++i) {
|
||||
for (size_t j = 0; j < 8; ++j) {
|
||||
r[8 * i + j] = (vector[i] >> j) & 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Last byte
|
||||
for (size_t j = 0; j < PARAM_N1 % 8; ++j) {
|
||||
r[8 * i + j] = (vector[i] >> j) & 1;
|
||||
}
|
||||
|
||||
// Complete r with zeros
|
||||
memset(r + PARAM_N1, 0, 2 * ((1 << PARAM_M) - PARAM_N1));
|
||||
|
||||
compute_fft_betas(gammas);
|
||||
compute_subset_sums(gammas_sums, gammas, PARAM_M - 1);
|
||||
|
||||
// Twist and permute r adequately to obtain w
|
||||
w[0] = 0;
|
||||
w[k] = -r[0] & 1;
|
||||
for (i = 1; i < k; ++i) {
|
||||
w[i] = -r[PQCLEAN_HQC2561CCA2_LEAKTIME_gf_log(gammas_sums[i])] & gammas_sums[i];
|
||||
w[k + i] = -r[PQCLEAN_HQC2561CCA2_LEAKTIME_gf_log(gammas_sums[i] ^ 1)] & (gammas_sums[i] ^ 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieves the error polynomial error from the evaluations w of the ELP (Error Locator Polynomial) on all field elements.
|
||||
*
|
||||
* @param[out] error Array of size VEC_N1_SIZE_BYTES
|
||||
* @param[in] w Array of size 2^PARAM_M
|
||||
*/
|
||||
void PQCLEAN_HQC2561CCA2_LEAKTIME_fft_retrieve_bch_error_poly(uint8_t *error, const uint16_t *w) {
|
||||
uint16_t gammas[PARAM_M - 1];
|
||||
uint16_t gammas_sums[1 << (PARAM_M - 1)];
|
||||
size_t k = 1 << (PARAM_M - 1);
|
||||
size_t index = PARAM_GF_MUL_ORDER;
|
||||
|
||||
compute_fft_betas(gammas);
|
||||
compute_subset_sums(gammas_sums, gammas, PARAM_M - 1);
|
||||
|
||||
error[0] ^= 1 ^ ((uint16_t) - w[0] >> 15);
|
||||
uint8_t bit = 1 ^ ((uint16_t) - w[k] >> 15);
|
||||
error[index / 8] ^= bit << (index % 8);
|
||||
|
||||
for (size_t i = 1; i < k; ++i) {
|
||||
index = PARAM_GF_MUL_ORDER - PQCLEAN_HQC2561CCA2_LEAKTIME_gf_log(gammas_sums[i]);
|
||||
bit = 1 ^ ((uint16_t) - w[i] >> 15);
|
||||
error[index / 8] ^= bit << (index % 8);
|
||||
|
||||
index = PARAM_GF_MUL_ORDER - PQCLEAN_HQC2561CCA2_LEAKTIME_gf_log(gammas_sums[i] ^ 1);
|
||||
bit = 1 ^ ((uint16_t) - w[k + i] >> 15);
|
||||
error[index / 8] ^= bit << (index % 8);
|
||||
}
|
||||
}
|
||||
18
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/fft.h
Normal file
18
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/fft.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef PQCLEAN_HQC2561CCA2_LEAKTIME_FFT_H
|
||||
#define PQCLEAN_HQC2561CCA2_LEAKTIME_FFT_H
|
||||
|
||||
/**
|
||||
* @file fft.h
|
||||
* Header file of fft.c
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC2561CCA2_LEAKTIME_fft_t(uint16_t *f, const uint16_t *w, size_t f_coeffs);
|
||||
void PQCLEAN_HQC2561CCA2_LEAKTIME_fft_t_preprocess_bch_codeword(uint16_t *w, const uint8_t *vector);
|
||||
|
||||
void PQCLEAN_HQC2561CCA2_LEAKTIME_fft(uint16_t *w, const uint16_t *f, size_t f_coeffs);
|
||||
void PQCLEAN_HQC2561CCA2_LEAKTIME_fft_retrieve_bch_error_poly(uint8_t *error, const uint16_t *w);
|
||||
|
||||
#endif
|
||||
99
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/gf.c
Normal file
99
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/gf.c
Normal file
File diff suppressed because one or more lines are too long
18
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/gf.h
Normal file
18
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/gf.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef PQCLEAN_HQC2561CCA2_LEAKTIME_GF_H
|
||||
#define PQCLEAN_HQC2561CCA2_LEAKTIME_GF_H
|
||||
|
||||
/**
|
||||
* @file gf.h
|
||||
* Header file of gf.c
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint16_t PQCLEAN_HQC2561CCA2_LEAKTIME_gf_log(uint16_t elt);
|
||||
uint16_t PQCLEAN_HQC2561CCA2_LEAKTIME_gf_mul(uint16_t a, uint16_t b);
|
||||
uint16_t PQCLEAN_HQC2561CCA2_LEAKTIME_gf_square(uint16_t a);
|
||||
uint16_t PQCLEAN_HQC2561CCA2_LEAKTIME_gf_inverse(uint16_t a);
|
||||
uint16_t PQCLEAN_HQC2561CCA2_LEAKTIME_gf_mod(uint16_t i);
|
||||
|
||||
#endif
|
||||
123
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/gf2x.c
Normal file
123
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/gf2x.c
Normal file
@ -0,0 +1,123 @@
|
||||
/**
|
||||
* \file gf2x.c
|
||||
* \brief Implementation of multiplication of two polynomials
|
||||
*/
|
||||
|
||||
#include "gf2x.h"
|
||||
#include "parameters.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define WORD_TYPE uint64_t
|
||||
#define WORD_TYPE_BITS (sizeof(WORD_TYPE) * 8)
|
||||
#define UTILS_VECTOR_ARRAY_SIZE CEIL_DIVIDE(PARAM_N, WORD_TYPE_BITS)
|
||||
|
||||
static int vect_mul_precompute_rows(WORD_TYPE *o, const WORD_TYPE *v);
|
||||
|
||||
|
||||
/**
|
||||
* @brief A subroutine used in the function sparse_dense_mul()
|
||||
*
|
||||
* @param[out] o Pointer to an array
|
||||
* @param[in] v Pointer to an array
|
||||
* @return 0 if precomputation is successful, -1 otherwise
|
||||
*/
|
||||
static int vect_mul_precompute_rows(WORD_TYPE *o, const WORD_TYPE *v) {
|
||||
int8_t var;
|
||||
for (size_t i = 0; i < PARAM_N; ++i) {
|
||||
var = 0;
|
||||
|
||||
// All the bits that we need are in the same block
|
||||
if (((i % WORD_TYPE_BITS) == 0) && (i != PARAM_N - (PARAM_N % WORD_TYPE_BITS))) {
|
||||
var = 1;
|
||||
}
|
||||
|
||||
// Cases where the bits are in before the last block, the last block and the first block
|
||||
if (i > PARAM_N - WORD_TYPE_BITS) {
|
||||
if (i >= PARAM_N - (PARAM_N % WORD_TYPE_BITS)) {
|
||||
var = 2;
|
||||
} else {
|
||||
var = 3;
|
||||
}
|
||||
}
|
||||
|
||||
switch (var) {
|
||||
case 0:
|
||||
// Take bits in the last block and the first one
|
||||
o[i] = 0;
|
||||
o[i] += v[i / WORD_TYPE_BITS] >> (i % WORD_TYPE_BITS);
|
||||
o[i] += v[(i / WORD_TYPE_BITS) + 1] << (WORD_TYPE_BITS - (i % WORD_TYPE_BITS));
|
||||
break;
|
||||
|
||||
case 1:
|
||||
o[i] = v[i / WORD_TYPE_BITS];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
o[i] = 0;
|
||||
o[i] += v[i / WORD_TYPE_BITS] >> (i % WORD_TYPE_BITS);
|
||||
o[i] += v[0] << ((PARAM_N - i) % WORD_TYPE_BITS);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
o[i] = 0;
|
||||
o[i] += v[i / WORD_TYPE_BITS] >> (i % WORD_TYPE_BITS);
|
||||
o[i] += v[(i / WORD_TYPE_BITS) + 1] << (WORD_TYPE_BITS - (i % WORD_TYPE_BITS));
|
||||
o[i] += v[0] << ((WORD_TYPE_BITS - i + (PARAM_N % WORD_TYPE_BITS)) % WORD_TYPE_BITS);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Multiplies two vectors
|
||||
*
|
||||
* This function multiplies two vectors: a sparse vector of Hamming weight equal to <b>weight</b> and a dense (random) vector.
|
||||
* The vector <b>a1</b> is the sparse vector and <b>a2</b> is the dense vector.
|
||||
* We notice that the idea is explained using vector of 32 bits elements instead of 64 (the algorithm works in booth cases).
|
||||
*
|
||||
* @param[out] o Pointer to a vector that is the result of the multiplication
|
||||
* @param[in] a1 Pointer to the sparse vector stored by position
|
||||
* @param[in] a2 Pointer to the dense vector
|
||||
* @param[in] weight Integer that is the weight of the sparse vector
|
||||
*/
|
||||
void PQCLEAN_HQC2561CCA2_LEAKTIME_vect_mul(uint8_t *o, const uint32_t *a1, const uint8_t *a2, uint16_t weight) {
|
||||
WORD_TYPE v1[UTILS_VECTOR_ARRAY_SIZE] = {0};
|
||||
WORD_TYPE res[UTILS_VECTOR_ARRAY_SIZE] = {0};
|
||||
WORD_TYPE precomputation_array [PARAM_N] = {0};
|
||||
WORD_TYPE row [UTILS_VECTOR_ARRAY_SIZE] = {0};
|
||||
uint32_t index;
|
||||
|
||||
PQCLEAN_HQC2561CCA2_LEAKTIME_load8_arr(v1, UTILS_VECTOR_ARRAY_SIZE, a2, VEC_N_SIZE_BYTES);
|
||||
vect_mul_precompute_rows(precomputation_array, v1);
|
||||
|
||||
for (size_t i = 0; i < weight; ++i) {
|
||||
int32_t k = UTILS_VECTOR_ARRAY_SIZE;
|
||||
|
||||
for (size_t j = 0; j < UTILS_VECTOR_ARRAY_SIZE - 1; ++j) {
|
||||
index = WORD_TYPE_BITS * (uint32_t)j - a1[i];
|
||||
if (index > PARAM_N) {
|
||||
index += PARAM_N;
|
||||
}
|
||||
row[j] = precomputation_array[index];
|
||||
}
|
||||
|
||||
index = WORD_TYPE_BITS * (UTILS_VECTOR_ARRAY_SIZE - 1) - a1[i];
|
||||
row[UTILS_VECTOR_ARRAY_SIZE - 1] = precomputation_array[(index < PARAM_N ? index : index + PARAM_N)] & BITMASK(PARAM_N, WORD_TYPE_BITS);
|
||||
|
||||
while (k--) {
|
||||
res[k] ^= row[k];
|
||||
}
|
||||
}
|
||||
|
||||
PQCLEAN_HQC2561CCA2_LEAKTIME_store8_arr(o, VEC_N_SIZE_BYTES, res, UTILS_VECTOR_ARRAY_SIZE);
|
||||
}
|
||||
13
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/gf2x.h
Normal file
13
src/kem/hqc/pqclean_hqc-256-1-cca2_leaktime/gf2x.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef PQCLEAN_HQC2561CCA2_LEAKTIME_GF2X_H
|
||||
#define PQCLEAN_HQC2561CCA2_LEAKTIME_GF2X_H
|
||||
|
||||
/**
|
||||
* @file gf2x.h
|
||||
* @brief Header file for gf2x.c
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void PQCLEAN_HQC2561CCA2_LEAKTIME_vect_mul(uint8_t *o, const uint32_t *a1, const uint8_t *a2, uint16_t weight);
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user