diff --git a/crypto_kem/ledakemlt12/META.yml b/crypto_kem/ledakemlt12/META.yml index c1f3846a..7748c267 100644 --- a/crypto_kem/ledakemlt12/META.yml +++ b/crypto_kem/ledakemlt12/META.yml @@ -3,10 +3,10 @@ type: kem claimed-nist-level: 1 claimed-security: IND-CCA2 length-public-key: 6520 -length-secret-key: 26 -length-ciphertext: 6520 +length-secret-key: 50 +length-ciphertext: 6544 length-shared-secret: 32 -nistkat-sha256: c49a3f0ff5f3e7d6b41995649d7003daf7c06d9539fc28cb3b93ed02dcbe09d4 +nistkat-sha256: c0bd75093e2bbae8bf5717939c59c3c695ee9a60d765fcf6fb06d8db385b04c7 principal-submitters: - Marco Baldi auxiliary-submitters: @@ -16,4 +16,4 @@ auxiliary-submitters: - Paolo Santini implementations: - name: leaktime - version: 2.? + version: 2.1 diff --git a/crypto_kem/ledakemlt12/leaktime/H_Q_matrices_generation.c b/crypto_kem/ledakemlt12/leaktime/H_Q_matrices_generation.c index 70a9727a..93702434 100644 --- a/crypto_kem/ledakemlt12/leaktime/H_Q_matrices_generation.c +++ b/crypto_kem/ledakemlt12/leaktime/H_Q_matrices_generation.c @@ -1,32 +1,58 @@ #include "H_Q_matrices_generation.h" #include "gf2x_arith_mod_xPplusOne.h" -void PQCLEAN_LEDAKEMLT12_LEAKTIME_generateHPosOnes_HtrPosOnes( - POSITION_T HPosOnes[N0][DV], - POSITION_T HtrPosOnes[N0][DV], - AES_XOF_struct *keys_expander) { +void PQCLEAN_LEDAKEMLT12_LEAKTIME_generateHPosOnes(POSITION_T HPosOnes[N0][DV], + AES_XOF_struct *keys_expander) { + for (int i = 0; i < N0; i++) { /* Generate a random block of Htr */ - PQCLEAN_LEDAKEMLT12_LEAKTIME_rand_circulant_sparse_block(&HtrPosOnes[i][0], DV, keys_expander); - } - for (int i = 0; i < N0; i++) { - /* Obtain directly the sparse representation of the block of H */ - for (int k = 0; k < DV; k++) { - HPosOnes[i][k] = (P - HtrPosOnes[i][k]) % P; /* transposes indexes */ - } + PQCLEAN_LEDAKEMLT12_LEAKTIME_rand_circulant_sparse_block(&HPosOnes[i][0], + DV, + keys_expander); } } -void PQCLEAN_LEDAKEMLT12_LEAKTIME_generateQsparse( - POSITION_T pos_ones[N0][M], - AES_XOF_struct *keys_expander) { +void PQCLEAN_LEDAKEMLT12_LEAKTIME_generateQPosOnes(POSITION_T QPosOnes[N0][M], + AES_XOF_struct *keys_expander) { + for (int i = 0; i < N0; i++) { int placed_ones = 0; for (int j = 0; j < N0; j++) { - PQCLEAN_LEDAKEMLT12_LEAKTIME_rand_circulant_sparse_block(&pos_ones[i][placed_ones], + PQCLEAN_LEDAKEMLT12_LEAKTIME_rand_circulant_sparse_block(&QPosOnes[i][placed_ones], qBlockWeights[i][j], keys_expander); placed_ones += qBlockWeights[i][j]; } } } + +void PQCLEAN_LEDAKEMLT12_LEAKTIME_transposeHPosOnes(POSITION_T HtrPosOnes[N0][DV], /* output*/ + POSITION_T HPosOnes[N0][DV]) { + + for (int i = 0; i < N0; i++) { + /* Obtain directly the sparse representation of the block of H */ + for (int k = 0; k < DV; k++) { + HtrPosOnes[i][k] = (P - HPosOnes[i][k]) % P; /* transposes indexes */ + }// end for k + } +} + +void PQCLEAN_LEDAKEMLT12_LEAKTIME_transposeQPosOnes(POSITION_T QtrPosOnes[N0][M], /* output*/ + POSITION_T QPosOnes[N0][M]) { + + unsigned transposed_ones_idx[N0] = {0x00}; + for (unsigned source_row_idx = 0; source_row_idx < N0 ; source_row_idx++) { + int currQoneIdx = 0; // position in the column of QtrPosOnes[][...] + int endQblockIdx = 0; + for (int blockIdx = 0; blockIdx < N0; blockIdx++) { + endQblockIdx += qBlockWeights[source_row_idx][blockIdx]; + for (; currQoneIdx < endQblockIdx; currQoneIdx++) { + QtrPosOnes[blockIdx][transposed_ones_idx[blockIdx]] = (P - + QPosOnes[source_row_idx][currQoneIdx]) % P; + transposed_ones_idx[blockIdx]++; + } + } + } +} + + diff --git a/crypto_kem/ledakemlt12/leaktime/H_Q_matrices_generation.h b/crypto_kem/ledakemlt12/leaktime/H_Q_matrices_generation.h index 0bf43055..0e6856d1 100644 --- a/crypto_kem/ledakemlt12/leaktime/H_Q_matrices_generation.h +++ b/crypto_kem/ledakemlt12/leaktime/H_Q_matrices_generation.h @@ -5,7 +5,9 @@ #include "qc_ldpc_parameters.h" #include "rng.h" -void PQCLEAN_LEDAKEMLT12_LEAKTIME_generateHPosOnes_HtrPosOnes(POSITION_T HPosOnes[N0][DV], POSITION_T HtrPosOnes[N0][DV], AES_XOF_struct *niederreiter_keys_expander); -void PQCLEAN_LEDAKEMLT12_LEAKTIME_generateQsparse(POSITION_T pos_ones[N0][M], AES_XOF_struct *niederreiter_keys_expander); +void PQCLEAN_LEDAKEMLT12_LEAKTIME_generateHPosOnes(POSITION_T HPosOnes[N0][DV], AES_XOF_struct *keys_expander); +void PQCLEAN_LEDAKEMLT12_LEAKTIME_generateQPosOnes(POSITION_T QPosOnes[N0][M], AES_XOF_struct *keys_expander); +void PQCLEAN_LEDAKEMLT12_LEAKTIME_transposeHPosOnes(POSITION_T HtrPosOnes[N0][DV], POSITION_T HPosOnes[N0][DV]); +void PQCLEAN_LEDAKEMLT12_LEAKTIME_transposeQPosOnes(POSITION_T QtrPosOnes[N0][M], POSITION_T QPosOnes[N0][M]); #endif diff --git a/crypto_kem/ledakemlt12/leaktime/Makefile b/crypto_kem/ledakemlt12/leaktime/Makefile index 09326171..32e38b8e 100644 --- a/crypto_kem/ledakemlt12/leaktime/Makefile +++ b/crypto_kem/ledakemlt12/leaktime/Makefile @@ -3,10 +3,10 @@ LIB=libledakemlt12_leaktime.a HEADERS=api.h bf_decoding.h dfr_test.h gf2x_arith_mod_xPplusOne.h \ gf2x_arith.h H_Q_matrices_generation.h \ - niederreiter.h qc_ldpc_parameters.h rng.h + niederreiter.h qc_ldpc_parameters.h rng.h sort.h OBJECTS=bf_decoding.o dfr_test.o gf2x_arith_mod_xPplusOne.o \ - gf2x_arith.o H_Q_matrices_generation.o kem.o niederreiter.o rng.o + gf2x_arith.o H_Q_matrices_generation.o kem.o niederreiter.o rng.o sort.o CFLAGS=-O3 -Wall -Werror -Wextra -Wvla -Wpedantic -Wmissing-prototypes -std=c99 \ -I../../../common $(EXTRAFLAGS) diff --git a/crypto_kem/ledakemlt12/leaktime/Makefile.Microsoft_nmake b/crypto_kem/ledakemlt12/leaktime/Makefile.Microsoft_nmake index fbad677a..5915e0b5 100644 --- a/crypto_kem/ledakemlt12/leaktime/Makefile.Microsoft_nmake +++ b/crypto_kem/ledakemlt12/leaktime/Makefile.Microsoft_nmake @@ -2,7 +2,7 @@ # nmake /f Makefile.Microsoft_nmake LIBRARY=libledakemlt12_leaktime.lib -OBJECTS=bf_decoding.obj dfr_test.obj gf2x_arith_mod_xPplusOne.obj gf2x_arith.obj H_Q_matrices_generation.obj kem.obj niederreiter.obj rng.obj +OBJECTS=bf_decoding.obj dfr_test.obj gf2x_arith_mod_xPplusOne.obj gf2x_arith.obj H_Q_matrices_generation.obj kem.obj niederreiter.obj rng.obj sort.obj CFLAGS=/nologo /I ..\..\..\common /W4 /WX diff --git a/crypto_kem/ledakemlt12/leaktime/api.h b/crypto_kem/ledakemlt12/leaktime/api.h index fd2f6b8b..d5d741cc 100644 --- a/crypto_kem/ledakemlt12/leaktime/api.h +++ b/crypto_kem/ledakemlt12/leaktime/api.h @@ -3,9 +3,9 @@ #include -#define PQCLEAN_LEDAKEMLT12_LEAKTIME_CRYPTO_SECRETKEYBYTES 26 +#define PQCLEAN_LEDAKEMLT12_LEAKTIME_CRYPTO_SECRETKEYBYTES 50 #define PQCLEAN_LEDAKEMLT12_LEAKTIME_CRYPTO_PUBLICKEYBYTES 6520 -#define PQCLEAN_LEDAKEMLT12_LEAKTIME_CRYPTO_CIPHERTEXTBYTES 6520 +#define PQCLEAN_LEDAKEMLT12_LEAKTIME_CRYPTO_CIPHERTEXTBYTES 6544 #define PQCLEAN_LEDAKEMLT12_LEAKTIME_CRYPTO_BYTES 32 #define PQCLEAN_LEDAKEMLT12_LEAKTIME_CRYPTO_ALGNAME "LEDAKEMLT12" diff --git a/crypto_kem/ledakemlt12/leaktime/dfr_test.c b/crypto_kem/ledakemlt12/leaktime/dfr_test.c index 9ea239a9..86f74bd2 100644 --- a/crypto_kem/ledakemlt12/leaktime/dfr_test.c +++ b/crypto_kem/ledakemlt12/leaktime/dfr_test.c @@ -2,70 +2,45 @@ #include "dfr_test.h" #include "gf2x_arith_mod_xPplusOne.h" #include "qc_ldpc_parameters.h" +#include "sort.h" #include -/* Tests if the current code attains the desired DFR. If that is the case, - * computes the threshold for the second iteration of the decoder and returns this values - * (max DV * M), on failure it returns 255 >> DV * M */ -uint8_t PQCLEAN_LEDAKEMLT12_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M]) { +int PQCLEAN_LEDAKEMLT12_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M], uint8_t *secondIterThreshold) { - POSITION_T LSparse_loc[N0][DV * M]; - POSITION_T rotated_column[DV * M]; - /* Gamma matrix: an N0 x N0 block circulant matrix with block size p - * gamma[a][b][c] stores the intersection of the first column of the a-th - * block of L with the c-th column of the b-th block of L. - * Gamma computation can be accelerated employing symmetry and QC properties */ - unsigned int gamma[N0][N0][P] = {{{0}}}; + POSITION_T LSparse_loc[N0][DV * M]; /* vector of N_0 sparse blocks */ + int gamma[N0][N0][P] = {{{0}}}; + int maxMut[N0], maxMutMinusOne[N0]; + int allBlockMaxSumst, allBlockMaxSumstMinusOne; unsigned int gammaHist[N0][DV * M + 1] = {{0}}; - unsigned int maxMut[N0], maxMutMinusOne[N0]; - unsigned int firstidx, secondidx, intersectionval; - unsigned int allBlockMaxSumst, allBlockMaxSumstMinusOne; - unsigned int toAdd, histIdx; - /*transpose blocks of L, we need its columns */ for (int i = 0; i < N0; i++) { for (int j = 0; j < DV * M; j++) { if (LSparse[i][j] != 0) { - LSparse_loc[i][j] = (P - LSparse[i][j]); + LSparse_loc[i][j] = (P - LSparse[i][j]) ; } } - PQCLEAN_LEDAKEMLT12_LEAKTIME_quicksort_sparse(LSparse_loc[i]); + PQCLEAN_LEDAKEMLT12_LEAKTIME_uint32_sort(LSparse_loc[i], DV * M); } + for (int i = 0; i < N0; i++ ) { for (int j = 0; j < N0; j++ ) { - for (int k = 0; k < P; k++) { - /* compute the rotated sparse column needed */ - for (int idxToRotate = 0; idxToRotate < (DV * M); idxToRotate++) { - rotated_column[idxToRotate] = (LSparse_loc[j][idxToRotate] + k) % P; + for (int k = 0; k < (DV * M); k++) { + for (int l = 0; l < (DV * M); l++) { + gamma[i][j][ (P + LSparse_loc[i][k] - LSparse_loc[j][l]) % P ]++; } - PQCLEAN_LEDAKEMLT12_LEAKTIME_quicksort_sparse(rotated_column); - /* compute the intersection amount */ - firstidx = 0, secondidx = 0; - intersectionval = 0; - while ( (firstidx < DV * M) && (secondidx < DV * M) ) { - if ( LSparse_loc[i][firstidx] == rotated_column[secondidx] ) { - intersectionval++; - firstidx++; - secondidx++; - } else if ( LSparse_loc[i][firstidx] > rotated_column[secondidx] ) { - secondidx++; - } else { /*if ( LSparse_loc[i][firstidx] < rotated_column[secondidx] ) */ - firstidx++; - } - } - gamma[i][j][k] = intersectionval; - } } } + for (int i = 0; i < N0; i++ ) { for (int j = 0; j < N0; j++ ) { gamma[i][j][0] = 0; } } + /* build histogram of values in gamma */ for (int i = 0; i < N0; i++ ) { for (int j = 0; j < N0; j++ ) { @@ -77,9 +52,9 @@ uint8_t PQCLEAN_LEDAKEMLT12_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M]) { for (int gammaBlockRowIdx = 0; gammaBlockRowIdx < N0; gammaBlockRowIdx++) { - toAdd = T_BAR - 1; + unsigned int toAdd = T_BAR - 1; maxMutMinusOne[gammaBlockRowIdx] = 0; - histIdx = DV * M; + unsigned int histIdx = DV * M; while ( (histIdx > 0) && (toAdd > 0)) { if (gammaHist[gammaBlockRowIdx][histIdx] > toAdd ) { maxMutMinusOne[gammaBlockRowIdx] += histIdx * toAdd; @@ -93,7 +68,6 @@ uint8_t PQCLEAN_LEDAKEMLT12_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M]) { maxMut[gammaBlockRowIdx] = histIdx + maxMutMinusOne[gammaBlockRowIdx]; } - /*seek max values across all gamma blocks */ allBlockMaxSumst = maxMut[0]; allBlockMaxSumstMinusOne = maxMutMinusOne[0]; @@ -106,7 +80,8 @@ uint8_t PQCLEAN_LEDAKEMLT12_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M]) { allBlockMaxSumstMinusOne; } if (DV * M > (allBlockMaxSumstMinusOne + allBlockMaxSumst)) { - return (uint8_t) allBlockMaxSumst + 1; + *secondIterThreshold = allBlockMaxSumst + 1; + return 1; } - return DFR_TEST_FAIL; + return 0; } diff --git a/crypto_kem/ledakemlt12/leaktime/dfr_test.h b/crypto_kem/ledakemlt12/leaktime/dfr_test.h index 39673efb..ad35e440 100644 --- a/crypto_kem/ledakemlt12/leaktime/dfr_test.h +++ b/crypto_kem/ledakemlt12/leaktime/dfr_test.h @@ -1,8 +1,6 @@ #ifndef DFR_TEST_H #define DFR_TEST_H -#define DFR_TEST_FAIL (255) - -uint8_t PQCLEAN_LEDAKEMLT12_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M]); +int PQCLEAN_LEDAKEMLT12_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M], uint8_t *secondIterThreshold); #endif diff --git a/crypto_kem/ledakemlt12/leaktime/gf2x_arith_mod_xPplusOne.c b/crypto_kem/ledakemlt12/leaktime/gf2x_arith_mod_xPplusOne.c index b2de57d4..72fe5df5 100644 --- a/crypto_kem/ledakemlt12/leaktime/gf2x_arith_mod_xPplusOne.c +++ b/crypto_kem/ledakemlt12/leaktime/gf2x_arith_mod_xPplusOne.c @@ -1,5 +1,6 @@ #include "gf2x_arith_mod_xPplusOne.h" #include "rng.h" +#include "sort.h" #include // memcpy(...), memset(...) @@ -62,81 +63,15 @@ void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_add(DIGIT Res[], const DIGIT A[], con PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_add(Res, A, B, NUM_DIGITS_GF2X_ELEMENT); } -static int partition(POSITION_T arr[], int lo, int hi) { - POSITION_T x = arr[hi]; - POSITION_T tmp; - int i = (lo - 1); - for (int j = lo; j <= hi - 1; j++) { - if (arr[j] <= x) { - i++; - tmp = arr[i]; - arr[i] = arr[j]; - arr[j] = tmp; - } - } - tmp = arr[i + 1]; - arr[i + 1] = arr[hi]; - arr[hi] = tmp; - - return i + 1; -} - -void PQCLEAN_LEDAKEMLT12_LEAKTIME_quicksort_sparse(POSITION_T Res[]) { - int stack[DV * M]; - int hi, lo, pivot, tos = -1; - stack[++tos] = 0; - stack[++tos] = (DV * M) - 1; - while (tos >= 0 ) { - hi = stack[tos--]; - lo = stack[tos--]; - pivot = partition(Res, lo, hi); - if ( (pivot - 1) > lo) { - stack[++tos] = lo; - stack[++tos] = pivot - 1; - } - if ( (pivot + 1) < hi) { - stack[++tos] = pivot + 1; - stack[++tos] = hi; - } - } -} - -static void gf2x_mod(DIGIT out[], const DIGIT in[]) { - - int i, j, posTrailingBit, maskOffset; - DIGIT mask, aux[2 * NUM_DIGITS_GF2X_ELEMENT]; - - memcpy(aux, in, 2 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - memset(out, 0x00, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - - for (i = 0; i < (2 * NUM_DIGITS_GF2X_ELEMENT) - NUM_DIGITS_GF2X_MODULUS; i += 1) { - for (j = DIGIT_SIZE_b - 1; j >= 0; j--) { - mask = ((DIGIT)0x1) << j; - if (aux[i] & mask) { - aux[i] ^= mask; - posTrailingBit = (DIGIT_SIZE_b - 1 - j) + i * DIGIT_SIZE_b + P; - maskOffset = (DIGIT_SIZE_b - 1 - (posTrailingBit % DIGIT_SIZE_b)); - mask = (DIGIT) 0x1 << maskOffset; - aux[posTrailingBit / DIGIT_SIZE_b] ^= mask; - } - } - } - - for (j = DIGIT_SIZE_b - 1; j >= MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS; j--) { - mask = ((DIGIT)0x1) << j; - if (aux[i] & mask) { - aux[i] ^= mask; - posTrailingBit = (DIGIT_SIZE_b - 1 - j) + i * DIGIT_SIZE_b + P; - maskOffset = (DIGIT_SIZE_b - 1 - (posTrailingBit % DIGIT_SIZE_b)); - mask = (DIGIT) 0x1 << maskOffset; - aux[posTrailingBit / DIGIT_SIZE_b] ^= mask; - } - } - - for (i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) { - out[NUM_DIGITS_GF2X_ELEMENT - 1 - i] = aux[2 * NUM_DIGITS_GF2X_ELEMENT - 1 - i]; - } +static void gf2x_mod(DIGIT out[], const DIGIT in[]) { + DIGIT aux[NUM_DIGITS_GF2X_ELEMENT + 1]; + memcpy(aux, in, (NUM_DIGITS_GF2X_ELEMENT + 1)*DIGIT_SIZE_B); + PQCLEAN_LEDAKEMLT12_LEAKTIME_right_bit_shift_n(NUM_DIGITS_GF2X_ELEMENT + 1, aux, + MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS); + PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_add(out, aux + 1, in + NUM_DIGITS_GF2X_ELEMENT, + NUM_DIGITS_GF2X_ELEMENT); + out[0] &= ((DIGIT)1 << MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS) - 1; } static void left_bit_shift(const int length, DIGIT in[]) { @@ -333,16 +268,13 @@ void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul(DIGIT Res[], const DIGIT A[], con /*PRE: the representation of the sparse coefficients is sorted in increasing order of the coefficients themselves */ -void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul_dense_to_sparse( - DIGIT Res[], - const DIGIT dense[], - POSITION_T sparse[], unsigned int nPos) { +void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul_dense_to_sparse(DIGIT Res[], const DIGIT dense[], + POSITION_T sparse[], unsigned int nPos) { DIGIT aux[2 * NUM_DIGITS_GF2X_ELEMENT] = {0x00}; DIGIT resDouble[2 * NUM_DIGITS_GF2X_ELEMENT] = {0x00}; memcpy(aux + NUM_DIGITS_GF2X_ELEMENT, dense, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - memcpy(resDouble + NUM_DIGITS_GF2X_ELEMENT, dense, - NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); + memcpy(resDouble + NUM_DIGITS_GF2X_ELEMENT, dense, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); if (sparse[0] != INVALID_POS_VALUE) { left_bit_shift_wide_n(2 * NUM_DIGITS_GF2X_ELEMENT, resDouble, sparse[0]); @@ -382,15 +314,15 @@ void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_transpose_in_place_sparse(int sizeA, POSI } -void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul_sparse(size_t sizeR, POSITION_T Res[], - size_t sizeA, const POSITION_T A[], - size_t sizeB, const POSITION_T B[]) { +void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul_sparse(int sizeR, POSITION_T Res[], + int sizeA, const POSITION_T A[], + int sizeB, const POSITION_T B[]) { /* compute all the coefficients, filling invalid positions with P*/ - size_t lastFilledPos = 0; - for (size_t i = 0 ; i < sizeA ; i++) { - for (size_t j = 0 ; j < sizeB ; j++) { - uint32_t prod = A[i] + B[j]; + int lastFilledPos = 0; + for (int i = 0 ; i < sizeA ; i++) { + for (int j = 0 ; j < sizeB ; j++) { + uint32_t prod = ((uint32_t) A[i]) + ((uint32_t) B[j]); prod = ( (prod >= P) ? prod - P : prod); if ((A[i] != INVALID_POS_VALUE) && (B[j] != INVALID_POS_VALUE)) { @@ -405,12 +337,12 @@ void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul_sparse(size_t sizeR, POSITION_T R Res[lastFilledPos] = INVALID_POS_VALUE; lastFilledPos++; } - PQCLEAN_LEDAKEMLT12_LEAKTIME_quicksort_sparse(Res); + PQCLEAN_LEDAKEMLT12_LEAKTIME_uint32_sort(Res, sizeR); /* eliminate duplicates */ POSITION_T lastReadPos = Res[0]; int duplicateCount; - size_t write_idx = 0; - size_t read_idx = 0; + int write_idx = 0; + int read_idx = 0; while (read_idx < sizeR && Res[read_idx] != INVALID_POS_VALUE) { lastReadPos = Res[read_idx]; read_idx++; @@ -531,9 +463,8 @@ void PQCLEAN_LEDAKEMLT12_LEAKTIME_rand_circulant_sparse_block(POSITION_T *pos_on } /* Returns random weight-t circulant block */ -void PQCLEAN_LEDAKEMLT12_LEAKTIME_rand_circulant_blocks_sequence( - DIGIT sequence[N0 * NUM_DIGITS_GF2X_ELEMENT], - AES_XOF_struct *seed_expander_ctx) { +void PQCLEAN_LEDAKEMLT12_LEAKTIME_rand_circulant_blocks_sequence(DIGIT sequence[N0 * NUM_DIGITS_GF2X_ELEMENT], + AES_XOF_struct *seed_expander_ctx) { int rndPos[NUM_ERRORS_T], duplicated, counter = 0; int p, polyIndex, exponent; @@ -563,6 +494,39 @@ void PQCLEAN_LEDAKEMLT12_LEAKTIME_rand_circulant_blocks_sequence( } + +void PQCLEAN_LEDAKEMLT12_LEAKTIME_rand_error_pos(POSITION_T errorPos[NUM_ERRORS_T], + AES_XOF_struct *seed_expander_ctx) { + + int duplicated, counter = 0; + + while (counter < NUM_ERRORS_T) { + uint32_t p = rand_range(N0 * NUM_BITS_GF2X_ELEMENT, P_BITS, seed_expander_ctx); + duplicated = 0; + for (int j = 0; j < counter; j++) if (errorPos[j] == p) { + duplicated = 1; + } + if (duplicated == 0) { + errorPos[counter] = p; + counter++; + } + } +} + +void PQCLEAN_LEDAKEMLT12_LEAKTIME_expand_error(DIGIT sequence[N0 * NUM_DIGITS_GF2X_ELEMENT], + POSITION_T errorPos[NUM_ERRORS_T]) { + + memset(sequence, 0x00, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); + + for (int j = 0; j < NUM_ERRORS_T; j++) { + int polyIndex = errorPos[j] / P; + int exponent = errorPos[j] % P; + PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_set_coeff( sequence + NUM_DIGITS_GF2X_ELEMENT * polyIndex, exponent, + ( (DIGIT) 1)); + } +} + + void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_tobytes(uint8_t *bytes, const DIGIT *poly) { size_t i, j; for (i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) { diff --git a/crypto_kem/ledakemlt12/leaktime/gf2x_arith_mod_xPplusOne.h b/crypto_kem/ledakemlt12/leaktime/gf2x_arith_mod_xPplusOne.h index 8fa0d40a..ced3ccf9 100644 --- a/crypto_kem/ledakemlt12/leaktime/gf2x_arith_mod_xPplusOne.h +++ b/crypto_kem/ledakemlt12/leaktime/gf2x_arith_mod_xPplusOne.h @@ -21,15 +21,16 @@ void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_set_coeff(DIGIT poly[], unsigned int expo void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_toggle_coeff(DIGIT poly[], unsigned int exponent); int PQCLEAN_LEDAKEMLT12_LEAKTIME_population_count(DIGIT *poly); void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_add(DIGIT Res[], const DIGIT A[], const DIGIT B[]); -void PQCLEAN_LEDAKEMLT12_LEAKTIME_quicksort_sparse(POSITION_T Res[]); void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul(DIGIT Res[], const DIGIT A[], const DIGIT B[]); void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_transpose_in_place(DIGIT A[]); void PQCLEAN_LEDAKEMLT12_LEAKTIME_rand_circulant_sparse_block(POSITION_T *pos_ones, int countOnes, AES_XOF_struct *seed_expander_ctx); void PQCLEAN_LEDAKEMLT12_LEAKTIME_rand_circulant_blocks_sequence(DIGIT *sequence, AES_XOF_struct *seed_expander_ctx); +void PQCLEAN_LEDAKEMLT12_LEAKTIME_rand_error_pos(POSITION_T errorPos[NUM_ERRORS_T], AES_XOF_struct *seed_expander_ctx); +void PQCLEAN_LEDAKEMLT12_LEAKTIME_expand_error(DIGIT sequence[N0 * NUM_DIGITS_GF2X_ELEMENT], POSITION_T errorPos[NUM_ERRORS_T]); void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_add_sparse(int sizeR, POSITION_T Res[], int sizeA, const POSITION_T A[], int sizeB, const POSITION_T B[]); void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_transpose_in_place_sparse(int sizeA, POSITION_T A[]); int PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_inverse(DIGIT out[], const DIGIT in[]); -void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul_sparse(size_t sizeR, POSITION_T Res[], size_t sizeA, const POSITION_T A[], size_t sizeB, const POSITION_T B[]); +void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul_sparse(int sizeR, POSITION_T Res[], int sizeA, const POSITION_T A[], int sizeB, const POSITION_T B[]); void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul_dense_to_sparse(DIGIT Res[], const DIGIT dense[], POSITION_T sparse[], unsigned int nPos); void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_tobytes(uint8_t *bytes, const DIGIT *poly); void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_frombytes(DIGIT *poly, const uint8_t *poly_bytes); diff --git a/crypto_kem/ledakemlt12/leaktime/kem.c b/crypto_kem/ledakemlt12/leaktime/kem.c index 5a06bf0b..85958986 100644 --- a/crypto_kem/ledakemlt12/leaktime/kem.c +++ b/crypto_kem/ledakemlt12/leaktime/kem.c @@ -5,6 +5,7 @@ #include +/* static void pack_pk(uint8_t *pk_bytes, publicKeyNiederreiter_t *pk) { size_t i; for (i = 0; i < N0 - 1; i++) { @@ -36,57 +37,113 @@ static void pack_error(uint8_t *error_bytes, DIGIT *error_digits) { error_digits + i * NUM_DIGITS_GF2X_ELEMENT); } } +*/ -/* Generates a keypair - pk is the public key and sk is the secret key. */ -int PQCLEAN_LEDAKEMLT12_LEAKTIME_crypto_kem_keypair(unsigned char *pk, unsigned char *sk) { - AES_XOF_struct niederreiter_keys_expander; - publicKeyNiederreiter_t pk_nie; +/* IND-CCA2 Keygen */ +int PQCLEAN_LEDAKEMLT12_LEAKTIME_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { - randombytes(((privateKeyNiederreiter_t *)sk)->prng_seed, TRNG_BYTE_LENGTH); - PQCLEAN_LEDAKEMLT12_LEAKTIME_seedexpander_from_trng(&niederreiter_keys_expander, ((privateKeyNiederreiter_t *)sk)->prng_seed); - PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_keygen(&pk_nie, (privateKeyNiederreiter_t *) sk, &niederreiter_keys_expander); - - pack_pk(pk, &pk_nie); + PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_keygen((publicKeyNiederreiter_t *) pk, + (privateKeyNiederreiter_t *) sk); return 0; } -/* Encrypt - pk is the public key, ct is a key encapsulation message - (ciphertext), ss is the shared secret.*/ -int PQCLEAN_LEDAKEMLT12_LEAKTIME_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk) { - AES_XOF_struct niederreiter_encap_key_expander; - unsigned char encapsulated_key_seed[TRNG_BYTE_LENGTH]; +/* IND-CCA2 Encapsulation */ +int PQCLEAN_LEDAKEMLT12_LEAKTIME_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) { + AES_XOF_struct hashedAndTruncatedSeed_expander; + POSITION_T errorPos[NUM_ERRORS_T]; DIGIT error_vector[N0 * NUM_DIGITS_GF2X_ELEMENT]; - uint8_t error_bytes[N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B]; - DIGIT syndrome[NUM_DIGITS_GF2X_ELEMENT]; - publicKeyNiederreiter_t pk_nie; + uint8_t seed[TRNG_BYTE_LENGTH]; + uint8_t ss_input[2 * TRNG_BYTE_LENGTH] = {0}; + uint8_t hashedSeed[HASH_BYTE_LENGTH]; + uint8_t hashedAndTruncatedSeed[TRNG_BYTE_LENGTH] = {0}; + uint8_t hashedErrorVector[HASH_BYTE_LENGTH]; + uint8_t hashedAndTruncatedErrorVector[TRNG_BYTE_LENGTH] = {0}; + uint8_t maskedSeed[TRNG_BYTE_LENGTH]; - randombytes(encapsulated_key_seed, TRNG_BYTE_LENGTH); - unpack_pk(&pk_nie, pk); + randombytes(seed, TRNG_BYTE_LENGTH); + memcpy(ss_input, seed, TRNG_BYTE_LENGTH); + HASH_FUNCTION(ss, ss_input, 2 * TRNG_BYTE_LENGTH); + HASH_FUNCTION(hashedSeed, seed, TRNG_BYTE_LENGTH); - PQCLEAN_LEDAKEMLT12_LEAKTIME_seedexpander_from_trng(&niederreiter_encap_key_expander, encapsulated_key_seed); - PQCLEAN_LEDAKEMLT12_LEAKTIME_rand_circulant_blocks_sequence(error_vector, &niederreiter_encap_key_expander); - pack_error(error_bytes, error_vector); - HASH_FUNCTION(ss, error_bytes, (N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B)); - PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_encrypt(syndrome, &pk_nie, error_vector); + memcpy(hashedAndTruncatedSeed, hashedSeed, TRNG_BYTE_LENGTH); - pack_ct(ct, syndrome); + memset(&hashedAndTruncatedSeed_expander, 0x00, sizeof(AES_XOF_struct)); + PQCLEAN_LEDAKEMLT12_LEAKTIME_seedexpander_from_trng(&hashedAndTruncatedSeed_expander, hashedAndTruncatedSeed); + PQCLEAN_LEDAKEMLT12_LEAKTIME_rand_error_pos(errorPos, &hashedAndTruncatedSeed_expander); + PQCLEAN_LEDAKEMLT12_LEAKTIME_expand_error(error_vector, errorPos); + HASH_FUNCTION(hashedErrorVector, (const uint8_t *) error_vector, (N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B)); + + memcpy(hashedAndTruncatedErrorVector, hashedErrorVector, TRNG_BYTE_LENGTH); + + for (int i = 0; i < TRNG_BYTE_LENGTH; ++i) { + maskedSeed[i] = seed[i] ^ hashedAndTruncatedErrorVector[i]; + } + + PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_encrypt((DIGIT *) ct, (const publicKeyNiederreiter_t *)pk, error_vector); + + memcpy(ct + (NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B), maskedSeed, TRNG_BYTE_LENGTH); return 0; } -/* Decrypt - ct is a key encapsulation message (ciphertext), sk is the private - key, ss is the shared secret */ -int PQCLEAN_LEDAKEMLT12_LEAKTIME_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk) { +/* INDCCA2 Decapsulation */ +int PQCLEAN_LEDAKEMLT12_LEAKTIME_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) { + AES_XOF_struct hashedAndTruncatedSeed_expander; + POSITION_T reconstructed_errorPos[NUM_ERRORS_T]; + DIGIT reconstructed_error_vector[N0 * NUM_DIGITS_GF2X_ELEMENT]; DIGIT decoded_error_vector[N0 * NUM_DIGITS_GF2X_ELEMENT]; - uint8_t decoded_error_bytes[N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B]; - DIGIT syndrome[NUM_DIGITS_GF2X_ELEMENT]; + uint8_t hashedErrorVector[HASH_BYTE_LENGTH]; + uint8_t hashedAndTruncatedErrorVector[TRNG_BYTE_LENGTH] = {0}; + uint8_t decoded_seed[TRNG_BYTE_LENGTH]; + uint8_t hashed_decoded_seed[HASH_BYTE_LENGTH]; + uint8_t hashedAndTruncated_decoded_seed[TRNG_BYTE_LENGTH] = {0}; + uint8_t ss_input[2 * TRNG_BYTE_LENGTH], tail[TRNG_BYTE_LENGTH] = {0}; - unpack_ct(syndrome, ct); - PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_decrypt(decoded_error_vector, (privateKeyNiederreiter_t *)sk, syndrome); - pack_error(decoded_error_bytes, decoded_error_vector); - HASH_FUNCTION(ss, decoded_error_bytes, (N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B)); + int decode_ok = PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_decrypt(decoded_error_vector, + (const privateKeyNiederreiter_t *)sk, + (DIGIT *)ct); + + HASH_FUNCTION(hashedErrorVector, + (const uint8_t *) decoded_error_vector, + (N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B)); + + memcpy(hashedAndTruncatedErrorVector, hashedErrorVector, TRNG_BYTE_LENGTH); + + for (int i = 0; i < TRNG_BYTE_LENGTH; ++i) { + decoded_seed[i] = ct[(NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B) + i] ^ + hashedAndTruncatedErrorVector[i]; + } + + HASH_FUNCTION(hashed_decoded_seed, decoded_seed, TRNG_BYTE_LENGTH); + + memcpy(hashedAndTruncated_decoded_seed, hashed_decoded_seed, TRNG_BYTE_LENGTH); + + memset(&hashedAndTruncatedSeed_expander, 0x00, sizeof(AES_XOF_struct)); + PQCLEAN_LEDAKEMLT12_LEAKTIME_seedexpander_from_trng(&hashedAndTruncatedSeed_expander, + hashed_decoded_seed); + + PQCLEAN_LEDAKEMLT12_LEAKTIME_rand_error_pos(reconstructed_errorPos, &hashedAndTruncatedSeed_expander); + + PQCLEAN_LEDAKEMLT12_LEAKTIME_expand_error(reconstructed_error_vector, reconstructed_errorPos); + + int equal = (0 == memcmp((const uint8_t *) decoded_error_vector, + (const uint8_t *) reconstructed_error_vector, + N0 * NUM_DIGITS_GF2X_ELEMENT)); + // equal == 1, if the reconstructed error vector match !!! + + int decryptOk = (decode_ok == 1 && equal == 1); + + memcpy(ss_input, decoded_seed, TRNG_BYTE_LENGTH); + + if (decryptOk == 1) { + memcpy(ss_input + sizeof(decoded_seed), tail, TRNG_BYTE_LENGTH); + } else { // decryption failure + memcpy(ss_input + sizeof(decoded_seed), ((const privateKeyNiederreiter_t *)sk)->decryption_failure_secret, TRNG_BYTE_LENGTH); + } + + HASH_FUNCTION(ss, ss_input, 2 * TRNG_BYTE_LENGTH); return 0; } diff --git a/crypto_kem/ledakemlt12/leaktime/niederreiter.c b/crypto_kem/ledakemlt12/leaktime/niederreiter.c index 273f2c41..2eb712c7 100644 --- a/crypto_kem/ledakemlt12/leaktime/niederreiter.c +++ b/crypto_kem/ledakemlt12/leaktime/niederreiter.c @@ -4,27 +4,32 @@ #include "gf2x_arith_mod_xPplusOne.h" #include "niederreiter.h" #include "qc_ldpc_parameters.h" +#include "randombytes.h" #include "rng.h" #include -void PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_keygen(publicKeyNiederreiter_t *pk, privateKeyNiederreiter_t *sk, AES_XOF_struct *keys_expander) { +void PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_keygen(publicKeyNiederreiter_t *pk, privateKeyNiederreiter_t *sk) { - POSITION_T HPosOnes[N0][DV]; // sequence of N0 circ block matrices (p x p): Hi - POSITION_T HtrPosOnes[N0][DV]; // Sparse tranposed circulant H - POSITION_T QPosOnes[N0][M]; // Sparse Q, Each row contains the position of the ones of all the blocks of a row of Q as exponent+P*block_position + AES_XOF_struct keys_expander; + POSITION_T HPosOnes[N0][DV]; + POSITION_T QPosOnes[N0][M]; POSITION_T LPosOnes[N0][DV * M]; POSITION_T auxPosOnes[DV * M]; unsigned char processedQOnes[N0]; - DIGIT Ln0dense[NUM_DIGITS_GF2X_ELEMENT]; - DIGIT Ln0Inv[NUM_DIGITS_GF2X_ELEMENT]; - int is_L_full = 0; - uint8_t threshold = (DV * M) / 2 + 1; // threshold for round 2 - sk->rejections = (int8_t) 0; + DIGIT Ln0dense[NUM_DIGITS_GF2X_ELEMENT] = {0}; + DIGIT Ln0Inv[NUM_DIGITS_GF2X_ELEMENT] = {0}; + int is_L_full; + int isDFRok; + memset(&keys_expander, 0x00, sizeof(AES_XOF_struct)); + randombytes(sk->prng_seed, TRNG_BYTE_LENGTH); + PQCLEAN_LEDAKEMLT12_LEAKTIME_seedexpander_from_trng(&keys_expander, sk->prng_seed); + + sk->rejections = (uint8_t) 0; do { - PQCLEAN_LEDAKEMLT12_LEAKTIME_generateHPosOnes_HtrPosOnes(HPosOnes, HtrPosOnes, keys_expander); - PQCLEAN_LEDAKEMLT12_LEAKTIME_generateQsparse(QPosOnes, keys_expander); + PQCLEAN_LEDAKEMLT12_LEAKTIME_generateHPosOnes(HPosOnes, &keys_expander); + PQCLEAN_LEDAKEMLT12_LEAKTIME_generateQPosOnes(QPosOnes, &keys_expander); for (int i = 0; i < N0; i++) { for (int j = 0; j < DV * M; j++) { LPosOnes[i][j] = INVALID_POS_VALUE; @@ -49,20 +54,21 @@ void PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_keygen(publicKeyNiederreiter_t *p } sk->rejections = sk->rejections + 1; if (is_L_full) { - threshold = PQCLEAN_LEDAKEMLT12_LEAKTIME_DFR_test(LPosOnes); + isDFRok = PQCLEAN_LEDAKEMLT12_LEAKTIME_DFR_test(LPosOnes, &(sk->secondIterThreshold)); } - } while (!is_L_full || threshold == DFR_TEST_FAIL); + } while (!is_L_full || !isDFRok); sk->rejections = sk->rejections - 1; - sk->threshold = threshold; - memset(Ln0dense, 0x00, sizeof(Ln0dense)); + PQCLEAN_LEDAKEMLT12_LEAKTIME_seedexpander(&keys_expander, + sk->decryption_failure_secret, + (unsigned long)TRNG_BYTE_LENGTH); + for (int j = 0; j < DV * M; j++) { if (LPosOnes[N0 - 1][j] != INVALID_POS_VALUE) { PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_set_coeff(Ln0dense, LPosOnes[N0 - 1][j], 1); } } - memset(Ln0Inv, 0x00, sizeof(Ln0Inv)); PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_inverse(Ln0Inv, Ln0dense); for (int i = 0; i < N0 - 1; i++) { PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul_dense_to_sparse(pk->Mtr + i * NUM_DIGITS_GF2X_ELEMENT, @@ -76,45 +82,43 @@ void PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_keygen(publicKeyNiederreiter_t *p } } +void PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_encrypt(DIGIT syndrome[], + const publicKeyNiederreiter_t *pk, + const DIGIT err[]) { -void PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_encrypt(DIGIT *syndrome, const publicKeyNiederreiter_t *pk, const DIGIT *err) { - int i; DIGIT saux[NUM_DIGITS_GF2X_ELEMENT]; memset(syndrome, 0x00, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - for (i = 0; i < N0 - 1; i++) { + for (size_t i = 0; i < N0 - 1; i++) { PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul(saux, pk->Mtr + i * NUM_DIGITS_GF2X_ELEMENT, err + i * NUM_DIGITS_GF2X_ELEMENT); PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_add(syndrome, syndrome, saux); + } PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_add(syndrome, syndrome, err + (N0 - 1)*NUM_DIGITS_GF2X_ELEMENT); } - int PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_decrypt(DIGIT *err, const privateKeyNiederreiter_t *sk, const DIGIT *syndrome) { AES_XOF_struct niederreiter_decrypt_expander; POSITION_T HPosOnes[N0][DV]; - POSITION_T HtrPosOnes[N0][DV]; POSITION_T QPosOnes[N0][M]; - POSITION_T QtrPosOnes[N0][M]; - POSITION_T auxPosOnes[DV * M]; POSITION_T LPosOnes[N0][DV * M]; + POSITION_T auxPosOnes[DV * M]; + POSITION_T HtrPosOnes[N0][DV]; + POSITION_T QtrPosOnes[N0][M]; POSITION_T auxSparse[DV * M]; POSITION_T Ln0trSparse[DV * M]; - unsigned char processedQOnes[N0]; - unsigned transposed_ones_idx[N0]; + DIGIT err_computed[N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B] = {0}; DIGIT privateSyndrome[NUM_DIGITS_GF2X_ELEMENT]; - DIGIT mockup_error_vector[N0 * NUM_DIGITS_GF2X_ELEMENT]; + unsigned char processedQOnes[N0]; int rejections = sk->rejections; - int currQoneIdx, endQblockIdx; - int decryptOk, err_weight; PQCLEAN_LEDAKEMLT12_LEAKTIME_seedexpander_from_trng(&niederreiter_decrypt_expander, sk->prng_seed); - do { - PQCLEAN_LEDAKEMLT12_LEAKTIME_generateHPosOnes_HtrPosOnes(HPosOnes, HtrPosOnes, &niederreiter_decrypt_expander); - PQCLEAN_LEDAKEMLT12_LEAKTIME_generateQsparse(QPosOnes, &niederreiter_decrypt_expander); + PQCLEAN_LEDAKEMLT12_LEAKTIME_generateHPosOnes(HPosOnes, &niederreiter_decrypt_expander); + PQCLEAN_LEDAKEMLT12_LEAKTIME_generateQPosOnes(QPosOnes, &niederreiter_decrypt_expander); + for (int i = 0; i < N0; i++) { for (int j = 0; j < DV * M; j++) { LPosOnes[i][j] = INVALID_POS_VALUE; @@ -136,19 +140,8 @@ int PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_decrypt(DIGIT *err, const privateK rejections--; } while (rejections >= 0); - memset(transposed_ones_idx, 0x00, sizeof(transposed_ones_idx)); - for (unsigned source_row_idx = 0; source_row_idx < N0 ; source_row_idx++) { - currQoneIdx = 0; // position in the column of QtrPosOnes[][...] - endQblockIdx = 0; - for (int blockIdx = 0; blockIdx < N0; blockIdx++) { - endQblockIdx += qBlockWeights[source_row_idx][blockIdx]; - for (; currQoneIdx < endQblockIdx; currQoneIdx++) { - QtrPosOnes[blockIdx][transposed_ones_idx[blockIdx]] = (P - - QPosOnes[source_row_idx][currQoneIdx]) % P; - transposed_ones_idx[blockIdx]++; - } - } - } + PQCLEAN_LEDAKEMLT12_LEAKTIME_transposeHPosOnes(HtrPosOnes, HPosOnes); + PQCLEAN_LEDAKEMLT12_LEAKTIME_transposeQPosOnes(QtrPosOnes, QPosOnes); for (int i = 0; i < DV * M; i++) { Ln0trSparse[i] = INVALID_POS_VALUE; @@ -158,34 +151,41 @@ int PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_decrypt(DIGIT *err, const privateK for (int i = 0; i < N0; i++) { PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul_sparse(DV * M, auxSparse, DV, HPosOnes[i], - qBlockWeights[i][N0 - 1], &QPosOnes[i][ M - qBlockWeights[i][N0 - 1]]); + qBlockWeights[i][N0 - 1], &QPosOnes[i][ M - qBlockWeights[i][N0 - 1] ] ); PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_add_sparse(DV * M, Ln0trSparse, DV * M, Ln0trSparse, DV * M, auxSparse); } - PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_transpose_in_place_sparse(DV * M, Ln0trSparse); - PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul_dense_to_sparse(privateSyndrome, syndrome, Ln0trSparse, DV * M); - /* prepare mockup error vector in case a decoding failure occurs */ - memset(mockup_error_vector, 0x00, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - memcpy(mockup_error_vector, syndrome, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - PQCLEAN_LEDAKEMLT12_LEAKTIME_seedexpander(&niederreiter_decrypt_expander, - ((unsigned char *) mockup_error_vector) + (NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B), - TRNG_BYTE_LENGTH); + PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul_dense_to_sparse(privateSyndrome, + syndrome, + Ln0trSparse, + DV * M); - memset(err, 0x00, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - decryptOk = PQCLEAN_LEDAKEMLT12_LEAKTIME_bf_decoding(err, (const POSITION_T (*)[DV]) HtrPosOnes, - (const POSITION_T (*)[M]) QtrPosOnes, privateSyndrome, sk->threshold); + int decryptOk = 0; + decryptOk = PQCLEAN_LEDAKEMLT12_LEAKTIME_bf_decoding(err_computed, + (const POSITION_T (*)[DV]) HtrPosOnes, + (const POSITION_T (*)[M]) QtrPosOnes, + privateSyndrome, sk->secondIterThreshold); - err_weight = 0; + int err_weight = 0; for (int i = 0 ; i < N0; i++) { - err_weight += PQCLEAN_LEDAKEMLT12_LEAKTIME_population_count(err + (NUM_DIGITS_GF2X_ELEMENT * i)); + err_weight += PQCLEAN_LEDAKEMLT12_LEAKTIME_population_count(err_computed + (NUM_DIGITS_GF2X_ELEMENT * i)); } decryptOk = decryptOk && (err_weight == NUM_ERRORS_T); - if (!decryptOk) { // TODO: not constant time, replace with cmov? - memcpy(err, mockup_error_vector, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); + /* prepare mockup error vector in case a decoding failure occurs */ + DIGIT err_mockup[N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B]; + memcpy(err_mockup, syndrome, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); + memcpy(err_mockup + NUM_DIGITS_GF2X_ELEMENT, sk->decryption_failure_secret, TRNG_BYTE_LENGTH); + memset(((unsigned char *) err_mockup) + (NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B) + TRNG_BYTE_LENGTH, 0x00, + (N0 - 1)*NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B - TRNG_BYTE_LENGTH); + + if (!decryptOk) { + memcpy(err, err_mockup, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); + } else { + memcpy(err, err_computed, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); } return decryptOk; diff --git a/crypto_kem/ledakemlt12/leaktime/niederreiter.h b/crypto_kem/ledakemlt12/leaktime/niederreiter.h index 17da4c29..581263b8 100644 --- a/crypto_kem/ledakemlt12/leaktime/niederreiter.h +++ b/crypto_kem/ledakemlt12/leaktime/niederreiter.h @@ -6,24 +6,19 @@ #include "rng.h" typedef struct { - /* raw entropy extracted from TRNG, will be deterministically expanded into - * H and Q during decryption */ unsigned char prng_seed[TRNG_BYTE_LENGTH]; - int8_t rejections; - uint8_t threshold; // for round 2 + uint8_t rejections; + uint8_t secondIterThreshold; + uint8_t decryption_failure_secret[TRNG_BYTE_LENGTH]; } privateKeyNiederreiter_t; typedef struct { DIGIT Mtr[(N0 - 1)*NUM_DIGITS_GF2X_ELEMENT]; - // Dense representation of the matrix M=Ln0*L, - // An array including a sequence of (N0-1) gf2x elements; - // each gf2x element is stored as a binary polynomial(mod x^P+1) - // with P coefficients. } publicKeyNiederreiter_t; -void PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_keygen(publicKeyNiederreiter_t *pk, privateKeyNiederreiter_t *sk, AES_XOF_struct *keys_expander); -void PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_encrypt(DIGIT syndrome[], const publicKeyNiederreiter_t *pk, const DIGIT *err); + +void PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_keygen(publicKeyNiederreiter_t *pk, privateKeyNiederreiter_t *sk); +void PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_encrypt(DIGIT syndrome[], const publicKeyNiederreiter_t *pk, const DIGIT err[]); int PQCLEAN_LEDAKEMLT12_LEAKTIME_niederreiter_decrypt(DIGIT *err, const privateKeyNiederreiter_t *sk, const DIGIT *syndrome); - #endif diff --git a/crypto_kem/ledakemlt12/leaktime/sort.c b/crypto_kem/ledakemlt12/leaktime/sort.c new file mode 100644 index 00000000..d4fb98d0 --- /dev/null +++ b/crypto_kem/ledakemlt12/leaktime/sort.c @@ -0,0 +1,87 @@ +#include "sort.h" + +/* + Constant-time uint32_t sorting by Daniel J. Bernstein + Source: https://sorting.cr.yp.to +*/ + +static void int32_sort(int32 *x, size_t n) { + size_t top, p, q, r, i, j; + + if (n < 2) { + return; + } + top = 1; + while (top < n - top) { + top += top; + } + + for (p = top; p >= 1; p >>= 1) { + i = 0; + while (i + 2 * p <= n) { + for (j = i; j < i + p; ++j) { + int32_MINMAX(x[j], x[j + p]); + } + i += 2 * p; + } + for (j = i; j < n - p; ++j) { + int32_MINMAX(x[j], x[j + p]); + } + + i = 0; + j = 0; + for (q = top; q > p; q >>= 1) { + if (j != i) { + for (;;) { + if (j == n - q) { + goto done; + } + int32 a = x[j + p]; + for (r = q; r > p; r >>= 1) { + int32_MINMAX(a, x[j + r]); + } + x[j + p] = a; + ++j; + if (j == i + p) { + i += 2 * p; + break; + } + } + } + while (i + p <= n - q) { + for (j = i; j < i + p; ++j) { + int32 a = x[j + p]; + for (r = q; r > p; r >>= 1) { + int32_MINMAX(a, x[j + r]); + } + x[j + p] = a; + } + i += 2 * p; + } + /* now i + p > n - q */ + j = i; + while (j < n - q) { + int32 a = x[j + p]; + for (r = q; r > p; r >>= 1) { + int32_MINMAX(a, x[j + r]); + } + x[j + p] = a; + ++j; + } +done: + ; + } + } +} + +/* can save time by integrating xor loops with int32_sort */ +void PQCLEAN_LEDAKEMLT12_LEAKTIME_uint32_sort(uint32_t *x, size_t n) { + size_t j; + for (j = 0; j < n; ++j) { + x[j] ^= 0x80000000; + } + int32_sort((int32_t *) x, n); + for (j = 0; j < n; ++j) { + x[j] ^= 0x80000000; + } +} diff --git a/crypto_kem/ledakemlt12/leaktime/sort.h b/crypto_kem/ledakemlt12/leaktime/sort.h new file mode 100644 index 00000000..300303c2 --- /dev/null +++ b/crypto_kem/ledakemlt12/leaktime/sort.h @@ -0,0 +1,22 @@ +#ifndef SORT_H +#define SORT_H + +#include +#include + +#define int32 int32_t + +#define int32_MINMAX(a,b) \ + do { \ + int32 ab = (b) ^ (a); \ + int32 c = (b) - (a); \ + c ^= ab & (c ^ (b)); \ + c >>= 31; \ + c &= ab; \ + (a) ^= c; \ + (b) ^= c; \ + } while(0) + +void PQCLEAN_LEDAKEMLT12_LEAKTIME_uint32_sort(uint32_t *x, size_t n); + +#endif diff --git a/crypto_kem/ledakemlt32/META.yml b/crypto_kem/ledakemlt32/META.yml index dad1126d..b5e2bf72 100644 --- a/crypto_kem/ledakemlt32/META.yml +++ b/crypto_kem/ledakemlt32/META.yml @@ -3,10 +3,10 @@ type: kem claimed-nist-level: 3 claimed-security: IND-CCA2 length-public-key: 12032 -length-secret-key: 34 -length-ciphertext: 12032 +length-secret-key: 66 +length-ciphertext: 12064 length-shared-secret: 48 -nistkat-sha256: 455dc69ee95196fe0526c3289fe46792acd55ac380b3c66be48eb3e3e10ad4e6 +nistkat-sha256: b8b17dbb77aa3c3c77f738be053b355185388859ae6baa5655bf7e8413020b7f principal-submitters: - Marco Baldi auxiliary-submitters: @@ -16,4 +16,4 @@ auxiliary-submitters: - Paolo Santini implementations: - name: leaktime - version: 2.? + version: 2.1 diff --git a/crypto_kem/ledakemlt32/leaktime/H_Q_matrices_generation.c b/crypto_kem/ledakemlt32/leaktime/H_Q_matrices_generation.c index 37a455b1..92eeb549 100644 --- a/crypto_kem/ledakemlt32/leaktime/H_Q_matrices_generation.c +++ b/crypto_kem/ledakemlt32/leaktime/H_Q_matrices_generation.c @@ -1,32 +1,58 @@ #include "H_Q_matrices_generation.h" #include "gf2x_arith_mod_xPplusOne.h" -void PQCLEAN_LEDAKEMLT32_LEAKTIME_generateHPosOnes_HtrPosOnes( - POSITION_T HPosOnes[N0][DV], - POSITION_T HtrPosOnes[N0][DV], - AES_XOF_struct *keys_expander) { +void PQCLEAN_LEDAKEMLT32_LEAKTIME_generateHPosOnes(POSITION_T HPosOnes[N0][DV], + AES_XOF_struct *keys_expander) { + for (int i = 0; i < N0; i++) { /* Generate a random block of Htr */ - PQCLEAN_LEDAKEMLT32_LEAKTIME_rand_circulant_sparse_block(&HtrPosOnes[i][0], DV, keys_expander); - } - for (int i = 0; i < N0; i++) { - /* Obtain directly the sparse representation of the block of H */ - for (int k = 0; k < DV; k++) { - HPosOnes[i][k] = (P - HtrPosOnes[i][k]) % P; /* transposes indexes */ - } + PQCLEAN_LEDAKEMLT32_LEAKTIME_rand_circulant_sparse_block(&HPosOnes[i][0], + DV, + keys_expander); } } -void PQCLEAN_LEDAKEMLT32_LEAKTIME_generateQsparse( - POSITION_T pos_ones[N0][M], - AES_XOF_struct *keys_expander) { +void PQCLEAN_LEDAKEMLT32_LEAKTIME_generateQPosOnes(POSITION_T QPosOnes[N0][M], + AES_XOF_struct *keys_expander) { + for (int i = 0; i < N0; i++) { int placed_ones = 0; for (int j = 0; j < N0; j++) { - PQCLEAN_LEDAKEMLT32_LEAKTIME_rand_circulant_sparse_block(&pos_ones[i][placed_ones], + PQCLEAN_LEDAKEMLT32_LEAKTIME_rand_circulant_sparse_block(&QPosOnes[i][placed_ones], qBlockWeights[i][j], keys_expander); placed_ones += qBlockWeights[i][j]; } } } + +void PQCLEAN_LEDAKEMLT32_LEAKTIME_transposeHPosOnes(POSITION_T HtrPosOnes[N0][DV], /* output*/ + POSITION_T HPosOnes[N0][DV]) { + + for (int i = 0; i < N0; i++) { + /* Obtain directly the sparse representation of the block of H */ + for (int k = 0; k < DV; k++) { + HtrPosOnes[i][k] = (P - HPosOnes[i][k]) % P; /* transposes indexes */ + }// end for k + } +} + +void PQCLEAN_LEDAKEMLT32_LEAKTIME_transposeQPosOnes(POSITION_T QtrPosOnes[N0][M], /* output*/ + POSITION_T QPosOnes[N0][M]) { + + unsigned transposed_ones_idx[N0] = {0x00}; + for (unsigned source_row_idx = 0; source_row_idx < N0 ; source_row_idx++) { + int currQoneIdx = 0; // position in the column of QtrPosOnes[][...] + int endQblockIdx = 0; + for (int blockIdx = 0; blockIdx < N0; blockIdx++) { + endQblockIdx += qBlockWeights[source_row_idx][blockIdx]; + for (; currQoneIdx < endQblockIdx; currQoneIdx++) { + QtrPosOnes[blockIdx][transposed_ones_idx[blockIdx]] = (P - + QPosOnes[source_row_idx][currQoneIdx]) % P; + transposed_ones_idx[blockIdx]++; + } + } + } +} + + diff --git a/crypto_kem/ledakemlt32/leaktime/H_Q_matrices_generation.h b/crypto_kem/ledakemlt32/leaktime/H_Q_matrices_generation.h index 23bd44f0..981b81d4 100644 --- a/crypto_kem/ledakemlt32/leaktime/H_Q_matrices_generation.h +++ b/crypto_kem/ledakemlt32/leaktime/H_Q_matrices_generation.h @@ -5,7 +5,9 @@ #include "qc_ldpc_parameters.h" #include "rng.h" -void PQCLEAN_LEDAKEMLT32_LEAKTIME_generateHPosOnes_HtrPosOnes(POSITION_T HPosOnes[N0][DV], POSITION_T HtrPosOnes[N0][DV], AES_XOF_struct *niederreiter_keys_expander); -void PQCLEAN_LEDAKEMLT32_LEAKTIME_generateQsparse(POSITION_T pos_ones[N0][M], AES_XOF_struct *niederreiter_keys_expander); +void PQCLEAN_LEDAKEMLT32_LEAKTIME_generateHPosOnes(POSITION_T HPosOnes[N0][DV], AES_XOF_struct *keys_expander); +void PQCLEAN_LEDAKEMLT32_LEAKTIME_generateQPosOnes(POSITION_T QPosOnes[N0][M], AES_XOF_struct *keys_expander); +void PQCLEAN_LEDAKEMLT32_LEAKTIME_transposeHPosOnes(POSITION_T HtrPosOnes[N0][DV], POSITION_T HPosOnes[N0][DV]); +void PQCLEAN_LEDAKEMLT32_LEAKTIME_transposeQPosOnes(POSITION_T QtrPosOnes[N0][M], POSITION_T QPosOnes[N0][M]); #endif diff --git a/crypto_kem/ledakemlt32/leaktime/Makefile b/crypto_kem/ledakemlt32/leaktime/Makefile index d8d4e9cb..75c23bdd 100644 --- a/crypto_kem/ledakemlt32/leaktime/Makefile +++ b/crypto_kem/ledakemlt32/leaktime/Makefile @@ -3,10 +3,10 @@ LIB=libledakemlt32_leaktime.a HEADERS=api.h bf_decoding.h dfr_test.h gf2x_arith_mod_xPplusOne.h \ gf2x_arith.h H_Q_matrices_generation.h \ - niederreiter.h qc_ldpc_parameters.h rng.h + niederreiter.h qc_ldpc_parameters.h rng.h sort.h OBJECTS=bf_decoding.o dfr_test.o gf2x_arith_mod_xPplusOne.o \ - gf2x_arith.o H_Q_matrices_generation.o kem.o niederreiter.o rng.o + gf2x_arith.o H_Q_matrices_generation.o kem.o niederreiter.o rng.o sort.o CFLAGS=-O3 -Wall -Werror -Wextra -Wvla -Wpedantic -Wmissing-prototypes -std=c99 \ -I../../../common $(EXTRAFLAGS) diff --git a/crypto_kem/ledakemlt32/leaktime/Makefile.Microsoft_nmake b/crypto_kem/ledakemlt32/leaktime/Makefile.Microsoft_nmake index f895e6dc..548f166c 100644 --- a/crypto_kem/ledakemlt32/leaktime/Makefile.Microsoft_nmake +++ b/crypto_kem/ledakemlt32/leaktime/Makefile.Microsoft_nmake @@ -2,7 +2,7 @@ # nmake /f Makefile.Microsoft_nmake LIBRARY=libledakemlt32_leaktime.lib -OBJECTS=bf_decoding.obj dfr_test.obj gf2x_arith_mod_xPplusOne.obj gf2x_arith.obj H_Q_matrices_generation.obj kem.obj niederreiter.obj rng.obj +OBJECTS=bf_decoding.obj dfr_test.obj gf2x_arith_mod_xPplusOne.obj gf2x_arith.obj H_Q_matrices_generation.obj kem.obj niederreiter.obj rng.obj sort.obj CFLAGS=/nologo /I ..\..\..\common /W4 /WX diff --git a/crypto_kem/ledakemlt32/leaktime/api.h b/crypto_kem/ledakemlt32/leaktime/api.h index 0a048aa3..21319bce 100644 --- a/crypto_kem/ledakemlt32/leaktime/api.h +++ b/crypto_kem/ledakemlt32/leaktime/api.h @@ -3,9 +3,9 @@ #include -#define PQCLEAN_LEDAKEMLT32_LEAKTIME_CRYPTO_SECRETKEYBYTES 34 +#define PQCLEAN_LEDAKEMLT32_LEAKTIME_CRYPTO_SECRETKEYBYTES 66 #define PQCLEAN_LEDAKEMLT32_LEAKTIME_CRYPTO_PUBLICKEYBYTES 12032 -#define PQCLEAN_LEDAKEMLT32_LEAKTIME_CRYPTO_CIPHERTEXTBYTES 12032 +#define PQCLEAN_LEDAKEMLT32_LEAKTIME_CRYPTO_CIPHERTEXTBYTES 12064 #define PQCLEAN_LEDAKEMLT32_LEAKTIME_CRYPTO_BYTES 48 #define PQCLEAN_LEDAKEMLT32_LEAKTIME_CRYPTO_ALGNAME "LEDAKEMLT32" diff --git a/crypto_kem/ledakemlt32/leaktime/dfr_test.c b/crypto_kem/ledakemlt32/leaktime/dfr_test.c index 73a52f6f..cfda84ea 100644 --- a/crypto_kem/ledakemlt32/leaktime/dfr_test.c +++ b/crypto_kem/ledakemlt32/leaktime/dfr_test.c @@ -2,70 +2,45 @@ #include "dfr_test.h" #include "gf2x_arith_mod_xPplusOne.h" #include "qc_ldpc_parameters.h" +#include "sort.h" #include -/* Tests if the current code attains the desired DFR. If that is the case, - * computes the threshold for the second iteration of the decoder and returns this values - * (max DV * M), on failure it returns 255 >> DV * M */ -uint8_t PQCLEAN_LEDAKEMLT32_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M]) { +int PQCLEAN_LEDAKEMLT32_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M], uint8_t *secondIterThreshold) { - POSITION_T LSparse_loc[N0][DV * M]; - POSITION_T rotated_column[DV * M]; - /* Gamma matrix: an N0 x N0 block circulant matrix with block size p - * gamma[a][b][c] stores the intersection of the first column of the a-th - * block of L with the c-th column of the b-th block of L. - * Gamma computation can be accelerated employing symmetry and QC properties */ - unsigned int gamma[N0][N0][P] = {{{0}}}; + POSITION_T LSparse_loc[N0][DV * M]; /* vector of N_0 sparse blocks */ + int gamma[N0][N0][P] = {{{0}}}; + int maxMut[N0], maxMutMinusOne[N0]; + int allBlockMaxSumst, allBlockMaxSumstMinusOne; unsigned int gammaHist[N0][DV * M + 1] = {{0}}; - unsigned int maxMut[N0], maxMutMinusOne[N0]; - unsigned int firstidx, secondidx, intersectionval; - unsigned int allBlockMaxSumst, allBlockMaxSumstMinusOne; - unsigned int toAdd, histIdx; - /*transpose blocks of L, we need its columns */ for (int i = 0; i < N0; i++) { for (int j = 0; j < DV * M; j++) { if (LSparse[i][j] != 0) { - LSparse_loc[i][j] = (P - LSparse[i][j]); + LSparse_loc[i][j] = (P - LSparse[i][j]) ; } } - PQCLEAN_LEDAKEMLT32_LEAKTIME_quicksort_sparse(LSparse_loc[i]); + PQCLEAN_LEDAKEMLT32_LEAKTIME_uint32_sort(LSparse_loc[i], DV * M); } + for (int i = 0; i < N0; i++ ) { for (int j = 0; j < N0; j++ ) { - for (int k = 0; k < P; k++) { - /* compute the rotated sparse column needed */ - for (int idxToRotate = 0; idxToRotate < (DV * M); idxToRotate++) { - rotated_column[idxToRotate] = (LSparse_loc[j][idxToRotate] + k) % P; + for (int k = 0; k < (DV * M); k++) { + for (int l = 0; l < (DV * M); l++) { + gamma[i][j][ (P + LSparse_loc[i][k] - LSparse_loc[j][l]) % P ]++; } - PQCLEAN_LEDAKEMLT32_LEAKTIME_quicksort_sparse(rotated_column); - /* compute the intersection amount */ - firstidx = 0, secondidx = 0; - intersectionval = 0; - while ( (firstidx < DV * M) && (secondidx < DV * M) ) { - if ( LSparse_loc[i][firstidx] == rotated_column[secondidx] ) { - intersectionval++; - firstidx++; - secondidx++; - } else if ( LSparse_loc[i][firstidx] > rotated_column[secondidx] ) { - secondidx++; - } else { /*if ( LSparse_loc[i][firstidx] < rotated_column[secondidx] ) */ - firstidx++; - } - } - gamma[i][j][k] = intersectionval; - } } } + for (int i = 0; i < N0; i++ ) { for (int j = 0; j < N0; j++ ) { gamma[i][j][0] = 0; } } + /* build histogram of values in gamma */ for (int i = 0; i < N0; i++ ) { for (int j = 0; j < N0; j++ ) { @@ -77,9 +52,9 @@ uint8_t PQCLEAN_LEDAKEMLT32_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M]) { for (int gammaBlockRowIdx = 0; gammaBlockRowIdx < N0; gammaBlockRowIdx++) { - toAdd = T_BAR - 1; + unsigned int toAdd = T_BAR - 1; maxMutMinusOne[gammaBlockRowIdx] = 0; - histIdx = DV * M; + unsigned int histIdx = DV * M; while ( (histIdx > 0) && (toAdd > 0)) { if (gammaHist[gammaBlockRowIdx][histIdx] > toAdd ) { maxMutMinusOne[gammaBlockRowIdx] += histIdx * toAdd; @@ -93,7 +68,6 @@ uint8_t PQCLEAN_LEDAKEMLT32_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M]) { maxMut[gammaBlockRowIdx] = histIdx + maxMutMinusOne[gammaBlockRowIdx]; } - /*seek max values across all gamma blocks */ allBlockMaxSumst = maxMut[0]; allBlockMaxSumstMinusOne = maxMutMinusOne[0]; @@ -106,7 +80,8 @@ uint8_t PQCLEAN_LEDAKEMLT32_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M]) { allBlockMaxSumstMinusOne; } if (DV * M > (allBlockMaxSumstMinusOne + allBlockMaxSumst)) { - return (uint8_t) allBlockMaxSumst + 1; + *secondIterThreshold = allBlockMaxSumst + 1; + return 1; } - return DFR_TEST_FAIL; + return 0; } diff --git a/crypto_kem/ledakemlt32/leaktime/dfr_test.h b/crypto_kem/ledakemlt32/leaktime/dfr_test.h index d1484ac9..ad013536 100644 --- a/crypto_kem/ledakemlt32/leaktime/dfr_test.h +++ b/crypto_kem/ledakemlt32/leaktime/dfr_test.h @@ -1,8 +1,6 @@ #ifndef DFR_TEST_H #define DFR_TEST_H -#define DFR_TEST_FAIL (255) - -uint8_t PQCLEAN_LEDAKEMLT32_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M]); +int PQCLEAN_LEDAKEMLT32_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M], uint8_t *secondIterThreshold); #endif diff --git a/crypto_kem/ledakemlt32/leaktime/gf2x_arith_mod_xPplusOne.c b/crypto_kem/ledakemlt32/leaktime/gf2x_arith_mod_xPplusOne.c index 9576d55d..0a70d8f7 100644 --- a/crypto_kem/ledakemlt32/leaktime/gf2x_arith_mod_xPplusOne.c +++ b/crypto_kem/ledakemlt32/leaktime/gf2x_arith_mod_xPplusOne.c @@ -1,5 +1,6 @@ #include "gf2x_arith_mod_xPplusOne.h" #include "rng.h" +#include "sort.h" #include // memcpy(...), memset(...) @@ -62,81 +63,15 @@ void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_add(DIGIT Res[], const DIGIT A[], con PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_add(Res, A, B, NUM_DIGITS_GF2X_ELEMENT); } -static int partition(POSITION_T arr[], int lo, int hi) { - POSITION_T x = arr[hi]; - POSITION_T tmp; - int i = (lo - 1); - for (int j = lo; j <= hi - 1; j++) { - if (arr[j] <= x) { - i++; - tmp = arr[i]; - arr[i] = arr[j]; - arr[j] = tmp; - } - } - tmp = arr[i + 1]; - arr[i + 1] = arr[hi]; - arr[hi] = tmp; - - return i + 1; -} - -void PQCLEAN_LEDAKEMLT32_LEAKTIME_quicksort_sparse(POSITION_T Res[]) { - int stack[DV * M]; - int hi, lo, pivot, tos = -1; - stack[++tos] = 0; - stack[++tos] = (DV * M) - 1; - while (tos >= 0 ) { - hi = stack[tos--]; - lo = stack[tos--]; - pivot = partition(Res, lo, hi); - if ( (pivot - 1) > lo) { - stack[++tos] = lo; - stack[++tos] = pivot - 1; - } - if ( (pivot + 1) < hi) { - stack[++tos] = pivot + 1; - stack[++tos] = hi; - } - } -} - -static void gf2x_mod(DIGIT out[], const DIGIT in[]) { - - int i, j, posTrailingBit, maskOffset; - DIGIT mask, aux[2 * NUM_DIGITS_GF2X_ELEMENT]; - - memcpy(aux, in, 2 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - memset(out, 0x00, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - - for (i = 0; i < (2 * NUM_DIGITS_GF2X_ELEMENT) - NUM_DIGITS_GF2X_MODULUS; i += 1) { - for (j = DIGIT_SIZE_b - 1; j >= 0; j--) { - mask = ((DIGIT)0x1) << j; - if (aux[i] & mask) { - aux[i] ^= mask; - posTrailingBit = (DIGIT_SIZE_b - 1 - j) + i * DIGIT_SIZE_b + P; - maskOffset = (DIGIT_SIZE_b - 1 - (posTrailingBit % DIGIT_SIZE_b)); - mask = (DIGIT) 0x1 << maskOffset; - aux[posTrailingBit / DIGIT_SIZE_b] ^= mask; - } - } - } - - for (j = DIGIT_SIZE_b - 1; j >= MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS; j--) { - mask = ((DIGIT)0x1) << j; - if (aux[i] & mask) { - aux[i] ^= mask; - posTrailingBit = (DIGIT_SIZE_b - 1 - j) + i * DIGIT_SIZE_b + P; - maskOffset = (DIGIT_SIZE_b - 1 - (posTrailingBit % DIGIT_SIZE_b)); - mask = (DIGIT) 0x1 << maskOffset; - aux[posTrailingBit / DIGIT_SIZE_b] ^= mask; - } - } - - for (i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) { - out[NUM_DIGITS_GF2X_ELEMENT - 1 - i] = aux[2 * NUM_DIGITS_GF2X_ELEMENT - 1 - i]; - } +static void gf2x_mod(DIGIT out[], const DIGIT in[]) { + DIGIT aux[NUM_DIGITS_GF2X_ELEMENT + 1]; + memcpy(aux, in, (NUM_DIGITS_GF2X_ELEMENT + 1)*DIGIT_SIZE_B); + PQCLEAN_LEDAKEMLT32_LEAKTIME_right_bit_shift_n(NUM_DIGITS_GF2X_ELEMENT + 1, aux, + MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS); + PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_add(out, aux + 1, in + NUM_DIGITS_GF2X_ELEMENT, + NUM_DIGITS_GF2X_ELEMENT); + out[0] &= ((DIGIT)1 << MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS) - 1; } static void left_bit_shift(const int length, DIGIT in[]) { @@ -331,16 +266,13 @@ void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_mul(DIGIT Res[], const DIGIT A[], con /*PRE: the representation of the sparse coefficients is sorted in increasing order of the coefficients themselves */ -void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_mul_dense_to_sparse( - DIGIT Res[], - const DIGIT dense[], - POSITION_T sparse[], unsigned int nPos) { +void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_mul_dense_to_sparse(DIGIT Res[], const DIGIT dense[], + POSITION_T sparse[], unsigned int nPos) { DIGIT aux[2 * NUM_DIGITS_GF2X_ELEMENT] = {0x00}; DIGIT resDouble[2 * NUM_DIGITS_GF2X_ELEMENT] = {0x00}; memcpy(aux + NUM_DIGITS_GF2X_ELEMENT, dense, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - memcpy(resDouble + NUM_DIGITS_GF2X_ELEMENT, dense, - NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); + memcpy(resDouble + NUM_DIGITS_GF2X_ELEMENT, dense, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); if (sparse[0] != INVALID_POS_VALUE) { left_bit_shift_wide_n(2 * NUM_DIGITS_GF2X_ELEMENT, resDouble, sparse[0]); @@ -380,15 +312,15 @@ void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_transpose_in_place_sparse(int sizeA, POSI } -void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_mul_sparse(size_t sizeR, POSITION_T Res[], - size_t sizeA, const POSITION_T A[], - size_t sizeB, const POSITION_T B[]) { +void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_mul_sparse(int sizeR, POSITION_T Res[], + int sizeA, const POSITION_T A[], + int sizeB, const POSITION_T B[]) { /* compute all the coefficients, filling invalid positions with P*/ - size_t lastFilledPos = 0; - for (size_t i = 0 ; i < sizeA ; i++) { - for (size_t j = 0 ; j < sizeB ; j++) { - uint32_t prod = A[i] + B[j]; + int lastFilledPos = 0; + for (int i = 0 ; i < sizeA ; i++) { + for (int j = 0 ; j < sizeB ; j++) { + uint32_t prod = ((uint32_t) A[i]) + ((uint32_t) B[j]); prod = ( (prod >= P) ? prod - P : prod); if ((A[i] != INVALID_POS_VALUE) && (B[j] != INVALID_POS_VALUE)) { @@ -403,12 +335,12 @@ void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_mul_sparse(size_t sizeR, POSITION_T R Res[lastFilledPos] = INVALID_POS_VALUE; lastFilledPos++; } - PQCLEAN_LEDAKEMLT32_LEAKTIME_quicksort_sparse(Res); + PQCLEAN_LEDAKEMLT32_LEAKTIME_uint32_sort(Res, sizeR); /* eliminate duplicates */ POSITION_T lastReadPos = Res[0]; int duplicateCount; - size_t write_idx = 0; - size_t read_idx = 0; + int write_idx = 0; + int read_idx = 0; while (read_idx < sizeR && Res[read_idx] != INVALID_POS_VALUE) { lastReadPos = Res[read_idx]; read_idx++; @@ -529,9 +461,8 @@ void PQCLEAN_LEDAKEMLT32_LEAKTIME_rand_circulant_sparse_block(POSITION_T *pos_on } /* Returns random weight-t circulant block */ -void PQCLEAN_LEDAKEMLT32_LEAKTIME_rand_circulant_blocks_sequence( - DIGIT sequence[N0 * NUM_DIGITS_GF2X_ELEMENT], - AES_XOF_struct *seed_expander_ctx) { +void PQCLEAN_LEDAKEMLT32_LEAKTIME_rand_circulant_blocks_sequence(DIGIT sequence[N0 * NUM_DIGITS_GF2X_ELEMENT], + AES_XOF_struct *seed_expander_ctx) { int rndPos[NUM_ERRORS_T], duplicated, counter = 0; int p, polyIndex, exponent; @@ -561,6 +492,39 @@ void PQCLEAN_LEDAKEMLT32_LEAKTIME_rand_circulant_blocks_sequence( } + +void PQCLEAN_LEDAKEMLT32_LEAKTIME_rand_error_pos(POSITION_T errorPos[NUM_ERRORS_T], + AES_XOF_struct *seed_expander_ctx) { + + int duplicated, counter = 0; + + while (counter < NUM_ERRORS_T) { + uint32_t p = rand_range(N0 * NUM_BITS_GF2X_ELEMENT, P_BITS, seed_expander_ctx); + duplicated = 0; + for (int j = 0; j < counter; j++) if (errorPos[j] == p) { + duplicated = 1; + } + if (duplicated == 0) { + errorPos[counter] = p; + counter++; + } + } +} + +void PQCLEAN_LEDAKEMLT32_LEAKTIME_expand_error(DIGIT sequence[N0 * NUM_DIGITS_GF2X_ELEMENT], + POSITION_T errorPos[NUM_ERRORS_T]) { + + memset(sequence, 0x00, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); + + for (int j = 0; j < NUM_ERRORS_T; j++) { + int polyIndex = errorPos[j] / P; + int exponent = errorPos[j] % P; + PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_set_coeff( sequence + NUM_DIGITS_GF2X_ELEMENT * polyIndex, exponent, + ( (DIGIT) 1)); + } +} + + void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_tobytes(uint8_t *bytes, const DIGIT *poly) { size_t i, j; for (i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) { diff --git a/crypto_kem/ledakemlt32/leaktime/gf2x_arith_mod_xPplusOne.h b/crypto_kem/ledakemlt32/leaktime/gf2x_arith_mod_xPplusOne.h index a43f1225..b26ff901 100644 --- a/crypto_kem/ledakemlt32/leaktime/gf2x_arith_mod_xPplusOne.h +++ b/crypto_kem/ledakemlt32/leaktime/gf2x_arith_mod_xPplusOne.h @@ -13,7 +13,7 @@ #define NUM_DIGITS_GF2X_MODULUS ((P+1+DIGIT_SIZE_b-1)/DIGIT_SIZE_b) #define MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS (P-DIGIT_SIZE_b*(NUM_DIGITS_GF2X_MODULUS-1)) #define INVALID_POS_VALUE (P) -#define P_BITS (17) // log_2(p) = 16.55406417 +#define P_BITS (17) void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_copy(DIGIT dest[], const DIGIT in[]); DIGIT PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_get_coeff(const DIGIT poly[], unsigned int exponent); @@ -21,15 +21,16 @@ void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_set_coeff(DIGIT poly[], unsigned int expo void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_toggle_coeff(DIGIT poly[], unsigned int exponent); int PQCLEAN_LEDAKEMLT32_LEAKTIME_population_count(DIGIT *poly); void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_add(DIGIT Res[], const DIGIT A[], const DIGIT B[]); -void PQCLEAN_LEDAKEMLT32_LEAKTIME_quicksort_sparse(POSITION_T Res[]); void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_mul(DIGIT Res[], const DIGIT A[], const DIGIT B[]); void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_transpose_in_place(DIGIT A[]); void PQCLEAN_LEDAKEMLT32_LEAKTIME_rand_circulant_sparse_block(POSITION_T *pos_ones, int countOnes, AES_XOF_struct *seed_expander_ctx); void PQCLEAN_LEDAKEMLT32_LEAKTIME_rand_circulant_blocks_sequence(DIGIT *sequence, AES_XOF_struct *seed_expander_ctx); +void PQCLEAN_LEDAKEMLT32_LEAKTIME_rand_error_pos(POSITION_T errorPos[NUM_ERRORS_T], AES_XOF_struct *seed_expander_ctx); +void PQCLEAN_LEDAKEMLT32_LEAKTIME_expand_error(DIGIT sequence[N0 * NUM_DIGITS_GF2X_ELEMENT], POSITION_T errorPos[NUM_ERRORS_T]); void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_add_sparse(int sizeR, POSITION_T Res[], int sizeA, const POSITION_T A[], int sizeB, const POSITION_T B[]); void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_transpose_in_place_sparse(int sizeA, POSITION_T A[]); int PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_inverse(DIGIT out[], const DIGIT in[]); -void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_mul_sparse(size_t sizeR, POSITION_T Res[], size_t sizeA, const POSITION_T A[], size_t sizeB, const POSITION_T B[]); +void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_mul_sparse(int sizeR, POSITION_T Res[], int sizeA, const POSITION_T A[], int sizeB, const POSITION_T B[]); void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_mul_dense_to_sparse(DIGIT Res[], const DIGIT dense[], POSITION_T sparse[], unsigned int nPos); void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_tobytes(uint8_t *bytes, const DIGIT *poly); void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_frombytes(DIGIT *poly, const uint8_t *poly_bytes); diff --git a/crypto_kem/ledakemlt32/leaktime/kem.c b/crypto_kem/ledakemlt32/leaktime/kem.c index d7e09732..2d126c92 100644 --- a/crypto_kem/ledakemlt32/leaktime/kem.c +++ b/crypto_kem/ledakemlt32/leaktime/kem.c @@ -5,6 +5,7 @@ #include +/* static void pack_pk(uint8_t *pk_bytes, publicKeyNiederreiter_t *pk) { size_t i; for (i = 0; i < N0 - 1; i++) { @@ -36,57 +37,113 @@ static void pack_error(uint8_t *error_bytes, DIGIT *error_digits) { error_digits + i * NUM_DIGITS_GF2X_ELEMENT); } } +*/ -/* Generates a keypair - pk is the public key and sk is the secret key. */ -int PQCLEAN_LEDAKEMLT32_LEAKTIME_crypto_kem_keypair(unsigned char *pk, unsigned char *sk) { - AES_XOF_struct niederreiter_keys_expander; - publicKeyNiederreiter_t pk_nie; +/* IND-CCA2 Keygen */ +int PQCLEAN_LEDAKEMLT32_LEAKTIME_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { - randombytes(((privateKeyNiederreiter_t *)sk)->prng_seed, TRNG_BYTE_LENGTH); - PQCLEAN_LEDAKEMLT32_LEAKTIME_seedexpander_from_trng(&niederreiter_keys_expander, ((privateKeyNiederreiter_t *)sk)->prng_seed); - PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_keygen(&pk_nie, (privateKeyNiederreiter_t *) sk, &niederreiter_keys_expander); - - pack_pk(pk, &pk_nie); + PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_keygen((publicKeyNiederreiter_t *) pk, + (privateKeyNiederreiter_t *) sk); return 0; } -/* Encrypt - pk is the public key, ct is a key encapsulation message - (ciphertext), ss is the shared secret.*/ -int PQCLEAN_LEDAKEMLT32_LEAKTIME_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk) { - AES_XOF_struct niederreiter_encap_key_expander; - unsigned char encapsulated_key_seed[TRNG_BYTE_LENGTH]; +/* IND-CCA2 Encapsulation */ +int PQCLEAN_LEDAKEMLT32_LEAKTIME_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) { + AES_XOF_struct hashedAndTruncatedSeed_expander; + POSITION_T errorPos[NUM_ERRORS_T]; DIGIT error_vector[N0 * NUM_DIGITS_GF2X_ELEMENT]; - uint8_t error_bytes[N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B]; - DIGIT syndrome[NUM_DIGITS_GF2X_ELEMENT]; - publicKeyNiederreiter_t pk_nie; + uint8_t seed[TRNG_BYTE_LENGTH]; + uint8_t ss_input[2 * TRNG_BYTE_LENGTH] = {0}; + uint8_t hashedSeed[HASH_BYTE_LENGTH]; + uint8_t hashedAndTruncatedSeed[TRNG_BYTE_LENGTH] = {0}; + uint8_t hashedErrorVector[HASH_BYTE_LENGTH]; + uint8_t hashedAndTruncatedErrorVector[TRNG_BYTE_LENGTH] = {0}; + uint8_t maskedSeed[TRNG_BYTE_LENGTH]; - randombytes(encapsulated_key_seed, TRNG_BYTE_LENGTH); - unpack_pk(&pk_nie, pk); + randombytes(seed, TRNG_BYTE_LENGTH); + memcpy(ss_input, seed, TRNG_BYTE_LENGTH); + HASH_FUNCTION(ss, ss_input, 2 * TRNG_BYTE_LENGTH); + HASH_FUNCTION(hashedSeed, seed, TRNG_BYTE_LENGTH); - PQCLEAN_LEDAKEMLT32_LEAKTIME_seedexpander_from_trng(&niederreiter_encap_key_expander, encapsulated_key_seed); - PQCLEAN_LEDAKEMLT32_LEAKTIME_rand_circulant_blocks_sequence(error_vector, &niederreiter_encap_key_expander); - pack_error(error_bytes, error_vector); - HASH_FUNCTION(ss, error_bytes, (N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B)); - PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_encrypt(syndrome, &pk_nie, error_vector); + memcpy(hashedAndTruncatedSeed, hashedSeed, TRNG_BYTE_LENGTH); - pack_ct(ct, syndrome); + memset(&hashedAndTruncatedSeed_expander, 0x00, sizeof(AES_XOF_struct)); + PQCLEAN_LEDAKEMLT32_LEAKTIME_seedexpander_from_trng(&hashedAndTruncatedSeed_expander, hashedAndTruncatedSeed); + PQCLEAN_LEDAKEMLT32_LEAKTIME_rand_error_pos(errorPos, &hashedAndTruncatedSeed_expander); + PQCLEAN_LEDAKEMLT32_LEAKTIME_expand_error(error_vector, errorPos); + HASH_FUNCTION(hashedErrorVector, (const uint8_t *) error_vector, (N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B)); + + memcpy(hashedAndTruncatedErrorVector, hashedErrorVector, TRNG_BYTE_LENGTH); + + for (int i = 0; i < TRNG_BYTE_LENGTH; ++i) { + maskedSeed[i] = seed[i] ^ hashedAndTruncatedErrorVector[i]; + } + + PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_encrypt((DIGIT *) ct, (const publicKeyNiederreiter_t *)pk, error_vector); + + memcpy(ct + (NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B), maskedSeed, TRNG_BYTE_LENGTH); return 0; } -/* Decrypt - ct is a key encapsulation message (ciphertext), sk is the private - key, ss is the shared secret */ -int PQCLEAN_LEDAKEMLT32_LEAKTIME_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk) { +/* INDCCA2 Decapsulation */ +int PQCLEAN_LEDAKEMLT32_LEAKTIME_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) { + AES_XOF_struct hashedAndTruncatedSeed_expander; + POSITION_T reconstructed_errorPos[NUM_ERRORS_T]; + DIGIT reconstructed_error_vector[N0 * NUM_DIGITS_GF2X_ELEMENT]; DIGIT decoded_error_vector[N0 * NUM_DIGITS_GF2X_ELEMENT]; - uint8_t decoded_error_bytes[N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B]; - DIGIT syndrome[NUM_DIGITS_GF2X_ELEMENT]; + uint8_t hashedErrorVector[HASH_BYTE_LENGTH]; + uint8_t hashedAndTruncatedErrorVector[TRNG_BYTE_LENGTH] = {0}; + uint8_t decoded_seed[TRNG_BYTE_LENGTH]; + uint8_t hashed_decoded_seed[HASH_BYTE_LENGTH]; + uint8_t hashedAndTruncated_decoded_seed[TRNG_BYTE_LENGTH] = {0}; + uint8_t ss_input[2 * TRNG_BYTE_LENGTH], tail[TRNG_BYTE_LENGTH] = {0}; - unpack_ct(syndrome, ct); - PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_decrypt(decoded_error_vector, (privateKeyNiederreiter_t *)sk, syndrome); - pack_error(decoded_error_bytes, decoded_error_vector); - HASH_FUNCTION(ss, decoded_error_bytes, (N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B)); + int decode_ok = PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_decrypt(decoded_error_vector, + (const privateKeyNiederreiter_t *)sk, + (DIGIT *)ct); + + HASH_FUNCTION(hashedErrorVector, + (const uint8_t *) decoded_error_vector, + (N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B)); + + memcpy(hashedAndTruncatedErrorVector, hashedErrorVector, TRNG_BYTE_LENGTH); + + for (int i = 0; i < TRNG_BYTE_LENGTH; ++i) { + decoded_seed[i] = ct[(NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B) + i] ^ + hashedAndTruncatedErrorVector[i]; + } + + HASH_FUNCTION(hashed_decoded_seed, decoded_seed, TRNG_BYTE_LENGTH); + + memcpy(hashedAndTruncated_decoded_seed, hashed_decoded_seed, TRNG_BYTE_LENGTH); + + memset(&hashedAndTruncatedSeed_expander, 0x00, sizeof(AES_XOF_struct)); + PQCLEAN_LEDAKEMLT32_LEAKTIME_seedexpander_from_trng(&hashedAndTruncatedSeed_expander, + hashed_decoded_seed); + + PQCLEAN_LEDAKEMLT32_LEAKTIME_rand_error_pos(reconstructed_errorPos, &hashedAndTruncatedSeed_expander); + + PQCLEAN_LEDAKEMLT32_LEAKTIME_expand_error(reconstructed_error_vector, reconstructed_errorPos); + + int equal = (0 == memcmp((const uint8_t *) decoded_error_vector, + (const uint8_t *) reconstructed_error_vector, + N0 * NUM_DIGITS_GF2X_ELEMENT)); + // equal == 1, if the reconstructed error vector match !!! + + int decryptOk = (decode_ok == 1 && equal == 1); + + memcpy(ss_input, decoded_seed, TRNG_BYTE_LENGTH); + + if (decryptOk == 1) { + memcpy(ss_input + sizeof(decoded_seed), tail, TRNG_BYTE_LENGTH); + } else { // decryption failure + memcpy(ss_input + sizeof(decoded_seed), ((const privateKeyNiederreiter_t *)sk)->decryption_failure_secret, TRNG_BYTE_LENGTH); + } + + HASH_FUNCTION(ss, ss_input, 2 * TRNG_BYTE_LENGTH); return 0; } diff --git a/crypto_kem/ledakemlt32/leaktime/niederreiter.c b/crypto_kem/ledakemlt32/leaktime/niederreiter.c index 66bc3f80..33397ae6 100644 --- a/crypto_kem/ledakemlt32/leaktime/niederreiter.c +++ b/crypto_kem/ledakemlt32/leaktime/niederreiter.c @@ -4,27 +4,32 @@ #include "gf2x_arith_mod_xPplusOne.h" #include "niederreiter.h" #include "qc_ldpc_parameters.h" +#include "randombytes.h" #include "rng.h" #include -void PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_keygen(publicKeyNiederreiter_t *pk, privateKeyNiederreiter_t *sk, AES_XOF_struct *keys_expander) { +void PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_keygen(publicKeyNiederreiter_t *pk, privateKeyNiederreiter_t *sk) { - POSITION_T HPosOnes[N0][DV]; // sequence of N0 circ block matrices (p x p): Hi - POSITION_T HtrPosOnes[N0][DV]; // Sparse tranposed circulant H - POSITION_T QPosOnes[N0][M]; // Sparse Q, Each row contains the position of the ones of all the blocks of a row of Q as exponent+P*block_position + AES_XOF_struct keys_expander; + POSITION_T HPosOnes[N0][DV]; + POSITION_T QPosOnes[N0][M]; POSITION_T LPosOnes[N0][DV * M]; POSITION_T auxPosOnes[DV * M]; unsigned char processedQOnes[N0]; - DIGIT Ln0dense[NUM_DIGITS_GF2X_ELEMENT]; - DIGIT Ln0Inv[NUM_DIGITS_GF2X_ELEMENT]; - int is_L_full = 0; - uint8_t threshold = (DV * M) / 2 + 1; // threshold for round 2 - sk->rejections = (int8_t) 0; + DIGIT Ln0dense[NUM_DIGITS_GF2X_ELEMENT] = {0}; + DIGIT Ln0Inv[NUM_DIGITS_GF2X_ELEMENT] = {0}; + int is_L_full; + int isDFRok; + memset(&keys_expander, 0x00, sizeof(AES_XOF_struct)); + randombytes(sk->prng_seed, TRNG_BYTE_LENGTH); + PQCLEAN_LEDAKEMLT32_LEAKTIME_seedexpander_from_trng(&keys_expander, sk->prng_seed); + + sk->rejections = (uint8_t) 0; do { - PQCLEAN_LEDAKEMLT32_LEAKTIME_generateHPosOnes_HtrPosOnes(HPosOnes, HtrPosOnes, keys_expander); - PQCLEAN_LEDAKEMLT32_LEAKTIME_generateQsparse(QPosOnes, keys_expander); + PQCLEAN_LEDAKEMLT32_LEAKTIME_generateHPosOnes(HPosOnes, &keys_expander); + PQCLEAN_LEDAKEMLT32_LEAKTIME_generateQPosOnes(QPosOnes, &keys_expander); for (int i = 0; i < N0; i++) { for (int j = 0; j < DV * M; j++) { LPosOnes[i][j] = INVALID_POS_VALUE; @@ -49,20 +54,21 @@ void PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_keygen(publicKeyNiederreiter_t *p } sk->rejections = sk->rejections + 1; if (is_L_full) { - threshold = PQCLEAN_LEDAKEMLT32_LEAKTIME_DFR_test(LPosOnes); + isDFRok = PQCLEAN_LEDAKEMLT32_LEAKTIME_DFR_test(LPosOnes, &(sk->secondIterThreshold)); } - } while (!is_L_full || threshold == DFR_TEST_FAIL); + } while (!is_L_full || !isDFRok); sk->rejections = sk->rejections - 1; - sk->threshold = threshold; - memset(Ln0dense, 0x00, sizeof(Ln0dense)); + PQCLEAN_LEDAKEMLT32_LEAKTIME_seedexpander(&keys_expander, + sk->decryption_failure_secret, + (unsigned long)TRNG_BYTE_LENGTH); + for (int j = 0; j < DV * M; j++) { if (LPosOnes[N0 - 1][j] != INVALID_POS_VALUE) { PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_set_coeff(Ln0dense, LPosOnes[N0 - 1][j], 1); } } - memset(Ln0Inv, 0x00, sizeof(Ln0Inv)); PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_inverse(Ln0Inv, Ln0dense); for (int i = 0; i < N0 - 1; i++) { PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_mul_dense_to_sparse(pk->Mtr + i * NUM_DIGITS_GF2X_ELEMENT, @@ -76,45 +82,43 @@ void PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_keygen(publicKeyNiederreiter_t *p } } +void PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_encrypt(DIGIT syndrome[], + const publicKeyNiederreiter_t *pk, + const DIGIT err[]) { -void PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_encrypt(DIGIT *syndrome, const publicKeyNiederreiter_t *pk, const DIGIT *err) { - int i; DIGIT saux[NUM_DIGITS_GF2X_ELEMENT]; memset(syndrome, 0x00, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - for (i = 0; i < N0 - 1; i++) { + for (size_t i = 0; i < N0 - 1; i++) { PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_mul(saux, pk->Mtr + i * NUM_DIGITS_GF2X_ELEMENT, err + i * NUM_DIGITS_GF2X_ELEMENT); PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_add(syndrome, syndrome, saux); + } PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_add(syndrome, syndrome, err + (N0 - 1)*NUM_DIGITS_GF2X_ELEMENT); } - int PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_decrypt(DIGIT *err, const privateKeyNiederreiter_t *sk, const DIGIT *syndrome) { AES_XOF_struct niederreiter_decrypt_expander; POSITION_T HPosOnes[N0][DV]; - POSITION_T HtrPosOnes[N0][DV]; POSITION_T QPosOnes[N0][M]; - POSITION_T QtrPosOnes[N0][M]; - POSITION_T auxPosOnes[DV * M]; POSITION_T LPosOnes[N0][DV * M]; + POSITION_T auxPosOnes[DV * M]; + POSITION_T HtrPosOnes[N0][DV]; + POSITION_T QtrPosOnes[N0][M]; POSITION_T auxSparse[DV * M]; POSITION_T Ln0trSparse[DV * M]; - unsigned char processedQOnes[N0]; - unsigned transposed_ones_idx[N0]; + DIGIT err_computed[N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B] = {0}; DIGIT privateSyndrome[NUM_DIGITS_GF2X_ELEMENT]; - DIGIT mockup_error_vector[N0 * NUM_DIGITS_GF2X_ELEMENT]; + unsigned char processedQOnes[N0]; int rejections = sk->rejections; - int currQoneIdx, endQblockIdx; - int decryptOk, err_weight; PQCLEAN_LEDAKEMLT32_LEAKTIME_seedexpander_from_trng(&niederreiter_decrypt_expander, sk->prng_seed); - do { - PQCLEAN_LEDAKEMLT32_LEAKTIME_generateHPosOnes_HtrPosOnes(HPosOnes, HtrPosOnes, &niederreiter_decrypt_expander); - PQCLEAN_LEDAKEMLT32_LEAKTIME_generateQsparse(QPosOnes, &niederreiter_decrypt_expander); + PQCLEAN_LEDAKEMLT32_LEAKTIME_generateHPosOnes(HPosOnes, &niederreiter_decrypt_expander); + PQCLEAN_LEDAKEMLT32_LEAKTIME_generateQPosOnes(QPosOnes, &niederreiter_decrypt_expander); + for (int i = 0; i < N0; i++) { for (int j = 0; j < DV * M; j++) { LPosOnes[i][j] = INVALID_POS_VALUE; @@ -136,19 +140,8 @@ int PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_decrypt(DIGIT *err, const privateK rejections--; } while (rejections >= 0); - memset(transposed_ones_idx, 0x00, sizeof(transposed_ones_idx)); - for (unsigned source_row_idx = 0; source_row_idx < N0 ; source_row_idx++) { - currQoneIdx = 0; // position in the column of QtrPosOnes[][...] - endQblockIdx = 0; - for (int blockIdx = 0; blockIdx < N0; blockIdx++) { - endQblockIdx += qBlockWeights[source_row_idx][blockIdx]; - for (; currQoneIdx < endQblockIdx; currQoneIdx++) { - QtrPosOnes[blockIdx][transposed_ones_idx[blockIdx]] = (P - - QPosOnes[source_row_idx][currQoneIdx]) % P; - transposed_ones_idx[blockIdx]++; - } - } - } + PQCLEAN_LEDAKEMLT32_LEAKTIME_transposeHPosOnes(HtrPosOnes, HPosOnes); + PQCLEAN_LEDAKEMLT32_LEAKTIME_transposeQPosOnes(QtrPosOnes, QPosOnes); for (int i = 0; i < DV * M; i++) { Ln0trSparse[i] = INVALID_POS_VALUE; @@ -158,34 +151,41 @@ int PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_decrypt(DIGIT *err, const privateK for (int i = 0; i < N0; i++) { PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_mul_sparse(DV * M, auxSparse, DV, HPosOnes[i], - qBlockWeights[i][N0 - 1], &QPosOnes[i][ M - qBlockWeights[i][N0 - 1]]); + qBlockWeights[i][N0 - 1], &QPosOnes[i][ M - qBlockWeights[i][N0 - 1] ] ); PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_add_sparse(DV * M, Ln0trSparse, DV * M, Ln0trSparse, DV * M, auxSparse); } - PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_transpose_in_place_sparse(DV * M, Ln0trSparse); - PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_mul_dense_to_sparse(privateSyndrome, syndrome, Ln0trSparse, DV * M); - /* prepare mockup error vector in case a decoding failure occurs */ - memset(mockup_error_vector, 0x00, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - memcpy(mockup_error_vector, syndrome, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - PQCLEAN_LEDAKEMLT32_LEAKTIME_seedexpander(&niederreiter_decrypt_expander, - ((unsigned char *) mockup_error_vector) + (NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B), - TRNG_BYTE_LENGTH); + PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_mul_dense_to_sparse(privateSyndrome, + syndrome, + Ln0trSparse, + DV * M); - memset(err, 0x00, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - decryptOk = PQCLEAN_LEDAKEMLT32_LEAKTIME_bf_decoding(err, (const POSITION_T (*)[DV]) HtrPosOnes, - (const POSITION_T (*)[M]) QtrPosOnes, privateSyndrome, sk->threshold); + int decryptOk = 0; + decryptOk = PQCLEAN_LEDAKEMLT32_LEAKTIME_bf_decoding(err_computed, + (const POSITION_T (*)[DV]) HtrPosOnes, + (const POSITION_T (*)[M]) QtrPosOnes, + privateSyndrome, sk->secondIterThreshold); - err_weight = 0; + int err_weight = 0; for (int i = 0 ; i < N0; i++) { - err_weight += PQCLEAN_LEDAKEMLT32_LEAKTIME_population_count(err + (NUM_DIGITS_GF2X_ELEMENT * i)); + err_weight += PQCLEAN_LEDAKEMLT32_LEAKTIME_population_count(err_computed + (NUM_DIGITS_GF2X_ELEMENT * i)); } decryptOk = decryptOk && (err_weight == NUM_ERRORS_T); - if (!decryptOk) { // TODO: not constant time, replace with cmov? - memcpy(err, mockup_error_vector, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); + /* prepare mockup error vector in case a decoding failure occurs */ + DIGIT err_mockup[N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B]; + memcpy(err_mockup, syndrome, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); + memcpy(err_mockup + NUM_DIGITS_GF2X_ELEMENT, sk->decryption_failure_secret, TRNG_BYTE_LENGTH); + memset(((unsigned char *) err_mockup) + (NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B) + TRNG_BYTE_LENGTH, 0x00, + (N0 - 1)*NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B - TRNG_BYTE_LENGTH); + + if (!decryptOk) { + memcpy(err, err_mockup, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); + } else { + memcpy(err, err_computed, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); } return decryptOk; diff --git a/crypto_kem/ledakemlt32/leaktime/niederreiter.h b/crypto_kem/ledakemlt32/leaktime/niederreiter.h index a954718d..e5497f92 100644 --- a/crypto_kem/ledakemlt32/leaktime/niederreiter.h +++ b/crypto_kem/ledakemlt32/leaktime/niederreiter.h @@ -6,24 +6,19 @@ #include "rng.h" typedef struct { - /* raw entropy extracted from TRNG, will be deterministically expanded into - * H and Q during decryption */ unsigned char prng_seed[TRNG_BYTE_LENGTH]; - int8_t rejections; - uint8_t threshold; // for round 2 + uint8_t rejections; + uint8_t secondIterThreshold; + uint8_t decryption_failure_secret[TRNG_BYTE_LENGTH]; } privateKeyNiederreiter_t; typedef struct { DIGIT Mtr[(N0 - 1)*NUM_DIGITS_GF2X_ELEMENT]; - // Dense representation of the matrix M=Ln0*L, - // An array including a sequence of (N0-1) gf2x elements; - // each gf2x element is stored as a binary polynomial(mod x^P+1) - // with P coefficients. } publicKeyNiederreiter_t; -void PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_keygen(publicKeyNiederreiter_t *pk, privateKeyNiederreiter_t *sk, AES_XOF_struct *keys_expander); -void PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_encrypt(DIGIT syndrome[], const publicKeyNiederreiter_t *pk, const DIGIT *err); + +void PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_keygen(publicKeyNiederreiter_t *pk, privateKeyNiederreiter_t *sk); +void PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_encrypt(DIGIT syndrome[], const publicKeyNiederreiter_t *pk, const DIGIT err[]); int PQCLEAN_LEDAKEMLT32_LEAKTIME_niederreiter_decrypt(DIGIT *err, const privateKeyNiederreiter_t *sk, const DIGIT *syndrome); - #endif diff --git a/crypto_kem/ledakemlt32/leaktime/sort.c b/crypto_kem/ledakemlt32/leaktime/sort.c new file mode 100644 index 00000000..2b6f8b8f --- /dev/null +++ b/crypto_kem/ledakemlt32/leaktime/sort.c @@ -0,0 +1,87 @@ +#include "sort.h" + +/* + Constant-time uint32_t sorting by Daniel J. Bernstein + Source: https://sorting.cr.yp.to +*/ + +static void int32_sort(int32 *x, size_t n) { + size_t top, p, q, r, i, j; + + if (n < 2) { + return; + } + top = 1; + while (top < n - top) { + top += top; + } + + for (p = top; p >= 1; p >>= 1) { + i = 0; + while (i + 2 * p <= n) { + for (j = i; j < i + p; ++j) { + int32_MINMAX(x[j], x[j + p]); + } + i += 2 * p; + } + for (j = i; j < n - p; ++j) { + int32_MINMAX(x[j], x[j + p]); + } + + i = 0; + j = 0; + for (q = top; q > p; q >>= 1) { + if (j != i) { + for (;;) { + if (j == n - q) { + goto done; + } + int32 a = x[j + p]; + for (r = q; r > p; r >>= 1) { + int32_MINMAX(a, x[j + r]); + } + x[j + p] = a; + ++j; + if (j == i + p) { + i += 2 * p; + break; + } + } + } + while (i + p <= n - q) { + for (j = i; j < i + p; ++j) { + int32 a = x[j + p]; + for (r = q; r > p; r >>= 1) { + int32_MINMAX(a, x[j + r]); + } + x[j + p] = a; + } + i += 2 * p; + } + /* now i + p > n - q */ + j = i; + while (j < n - q) { + int32 a = x[j + p]; + for (r = q; r > p; r >>= 1) { + int32_MINMAX(a, x[j + r]); + } + x[j + p] = a; + ++j; + } +done: + ; + } + } +} + +/* can save time by integrating xor loops with int32_sort */ +void PQCLEAN_LEDAKEMLT32_LEAKTIME_uint32_sort(uint32_t *x, size_t n) { + size_t j; + for (j = 0; j < n; ++j) { + x[j] ^= 0x80000000; + } + int32_sort((int32_t *) x, n); + for (j = 0; j < n; ++j) { + x[j] ^= 0x80000000; + } +} diff --git a/crypto_kem/ledakemlt32/leaktime/sort.h b/crypto_kem/ledakemlt32/leaktime/sort.h new file mode 100644 index 00000000..40d83195 --- /dev/null +++ b/crypto_kem/ledakemlt32/leaktime/sort.h @@ -0,0 +1,22 @@ +#ifndef SORT_H +#define SORT_H + +#include +#include + +#define int32 int32_t + +#define int32_MINMAX(a,b) \ + do { \ + int32 ab = (b) ^ (a); \ + int32 c = (b) - (a); \ + c ^= ab & (c ^ (b)); \ + c >>= 31; \ + c &= ab; \ + (a) ^= c; \ + (b) ^= c; \ + } while(0) + +void PQCLEAN_LEDAKEMLT32_LEAKTIME_uint32_sort(uint32_t *x, size_t n); + +#endif diff --git a/crypto_kem/ledakemlt52/META.yml b/crypto_kem/ledakemlt52/META.yml index 7076919a..a85d7d53 100644 --- a/crypto_kem/ledakemlt52/META.yml +++ b/crypto_kem/ledakemlt52/META.yml @@ -3,10 +3,10 @@ type: kem claimed-nist-level: 5 claimed-security: IND-CCA2 length-public-key: 19040 -length-secret-key: 42 -length-ciphertext: 19040 +length-secret-key: 82 +length-ciphertext: 19080 length-shared-secret: 64 -nistkat-sha256: 9cd9299d20a1c8c242730d3795683a9e87c6bcd0e691dc1fd54cd6a418266c36 +nistkat-sha256: 7a8d7c623bd3a8935861ec088e77a6701a254ac521d5e5150dc4537df4da8fd5 principal-submitters: - Marco Baldi auxiliary-submitters: @@ -16,4 +16,4 @@ auxiliary-submitters: - Paolo Santini implementations: - name: leaktime - version: 2.? + version: 2.1 diff --git a/crypto_kem/ledakemlt52/leaktime/H_Q_matrices_generation.c b/crypto_kem/ledakemlt52/leaktime/H_Q_matrices_generation.c index 8c1cdf0f..29c87b6d 100644 --- a/crypto_kem/ledakemlt52/leaktime/H_Q_matrices_generation.c +++ b/crypto_kem/ledakemlt52/leaktime/H_Q_matrices_generation.c @@ -1,32 +1,58 @@ #include "H_Q_matrices_generation.h" #include "gf2x_arith_mod_xPplusOne.h" -void PQCLEAN_LEDAKEMLT52_LEAKTIME_generateHPosOnes_HtrPosOnes( - POSITION_T HPosOnes[N0][DV], - POSITION_T HtrPosOnes[N0][DV], - AES_XOF_struct *keys_expander) { +void PQCLEAN_LEDAKEMLT52_LEAKTIME_generateHPosOnes(POSITION_T HPosOnes[N0][DV], + AES_XOF_struct *keys_expander) { + for (int i = 0; i < N0; i++) { /* Generate a random block of Htr */ - PQCLEAN_LEDAKEMLT52_LEAKTIME_rand_circulant_sparse_block(&HtrPosOnes[i][0], DV, keys_expander); - } - for (int i = 0; i < N0; i++) { - /* Obtain directly the sparse representation of the block of H */ - for (int k = 0; k < DV; k++) { - HPosOnes[i][k] = (P - HtrPosOnes[i][k]) % P; /* transposes indexes */ - } + PQCLEAN_LEDAKEMLT52_LEAKTIME_rand_circulant_sparse_block(&HPosOnes[i][0], + DV, + keys_expander); } } -void PQCLEAN_LEDAKEMLT52_LEAKTIME_generateQsparse( - POSITION_T pos_ones[N0][M], - AES_XOF_struct *keys_expander) { +void PQCLEAN_LEDAKEMLT52_LEAKTIME_generateQPosOnes(POSITION_T QPosOnes[N0][M], + AES_XOF_struct *keys_expander) { + for (int i = 0; i < N0; i++) { int placed_ones = 0; for (int j = 0; j < N0; j++) { - PQCLEAN_LEDAKEMLT52_LEAKTIME_rand_circulant_sparse_block(&pos_ones[i][placed_ones], + PQCLEAN_LEDAKEMLT52_LEAKTIME_rand_circulant_sparse_block(&QPosOnes[i][placed_ones], qBlockWeights[i][j], keys_expander); placed_ones += qBlockWeights[i][j]; } } } + +void PQCLEAN_LEDAKEMLT52_LEAKTIME_transposeHPosOnes(POSITION_T HtrPosOnes[N0][DV], /* output*/ + POSITION_T HPosOnes[N0][DV]) { + + for (int i = 0; i < N0; i++) { + /* Obtain directly the sparse representation of the block of H */ + for (int k = 0; k < DV; k++) { + HtrPosOnes[i][k] = (P - HPosOnes[i][k]) % P; /* transposes indexes */ + }// end for k + } +} + +void PQCLEAN_LEDAKEMLT52_LEAKTIME_transposeQPosOnes(POSITION_T QtrPosOnes[N0][M], /* output*/ + POSITION_T QPosOnes[N0][M]) { + + unsigned transposed_ones_idx[N0] = {0x00}; + for (unsigned source_row_idx = 0; source_row_idx < N0 ; source_row_idx++) { + int currQoneIdx = 0; // position in the column of QtrPosOnes[][...] + int endQblockIdx = 0; + for (int blockIdx = 0; blockIdx < N0; blockIdx++) { + endQblockIdx += qBlockWeights[source_row_idx][blockIdx]; + for (; currQoneIdx < endQblockIdx; currQoneIdx++) { + QtrPosOnes[blockIdx][transposed_ones_idx[blockIdx]] = (P - + QPosOnes[source_row_idx][currQoneIdx]) % P; + transposed_ones_idx[blockIdx]++; + } + } + } +} + + diff --git a/crypto_kem/ledakemlt52/leaktime/H_Q_matrices_generation.h b/crypto_kem/ledakemlt52/leaktime/H_Q_matrices_generation.h index 168fa743..b207eef3 100644 --- a/crypto_kem/ledakemlt52/leaktime/H_Q_matrices_generation.h +++ b/crypto_kem/ledakemlt52/leaktime/H_Q_matrices_generation.h @@ -5,7 +5,9 @@ #include "qc_ldpc_parameters.h" #include "rng.h" -void PQCLEAN_LEDAKEMLT52_LEAKTIME_generateHPosOnes_HtrPosOnes(POSITION_T HPosOnes[N0][DV], POSITION_T HtrPosOnes[N0][DV], AES_XOF_struct *niederreiter_keys_expander); -void PQCLEAN_LEDAKEMLT52_LEAKTIME_generateQsparse(POSITION_T pos_ones[N0][M], AES_XOF_struct *niederreiter_keys_expander); +void PQCLEAN_LEDAKEMLT52_LEAKTIME_generateHPosOnes(POSITION_T HPosOnes[N0][DV], AES_XOF_struct *keys_expander); +void PQCLEAN_LEDAKEMLT52_LEAKTIME_generateQPosOnes(POSITION_T QPosOnes[N0][M], AES_XOF_struct *keys_expander); +void PQCLEAN_LEDAKEMLT52_LEAKTIME_transposeHPosOnes(POSITION_T HtrPosOnes[N0][DV], POSITION_T HPosOnes[N0][DV]); +void PQCLEAN_LEDAKEMLT52_LEAKTIME_transposeQPosOnes(POSITION_T QtrPosOnes[N0][M], POSITION_T QPosOnes[N0][M]); #endif diff --git a/crypto_kem/ledakemlt52/leaktime/Makefile b/crypto_kem/ledakemlt52/leaktime/Makefile index 0c3b52fa..981ce732 100644 --- a/crypto_kem/ledakemlt52/leaktime/Makefile +++ b/crypto_kem/ledakemlt52/leaktime/Makefile @@ -3,10 +3,10 @@ LIB=libledakemlt52_leaktime.a HEADERS=api.h bf_decoding.h dfr_test.h gf2x_arith_mod_xPplusOne.h \ gf2x_arith.h H_Q_matrices_generation.h \ - niederreiter.h qc_ldpc_parameters.h rng.h + niederreiter.h qc_ldpc_parameters.h rng.h sort.h OBJECTS=bf_decoding.o dfr_test.o gf2x_arith_mod_xPplusOne.o \ - gf2x_arith.o H_Q_matrices_generation.o kem.o niederreiter.o rng.o + gf2x_arith.o H_Q_matrices_generation.o kem.o niederreiter.o rng.o sort.o CFLAGS=-O3 -Wall -Werror -Wextra -Wvla -Wpedantic -Wmissing-prototypes -std=c99 \ -I../../../common $(EXTRAFLAGS) diff --git a/crypto_kem/ledakemlt52/leaktime/Makefile.Microsoft_nmake b/crypto_kem/ledakemlt52/leaktime/Makefile.Microsoft_nmake index 0bb72b8b..a346d3b1 100644 --- a/crypto_kem/ledakemlt52/leaktime/Makefile.Microsoft_nmake +++ b/crypto_kem/ledakemlt52/leaktime/Makefile.Microsoft_nmake @@ -2,7 +2,7 @@ # nmake /f Makefile.Microsoft_nmake LIBRARY=libledakemlt52_leaktime.lib -OBJECTS=bf_decoding.obj dfr_test.obj gf2x_arith_mod_xPplusOne.obj gf2x_arith.obj H_Q_matrices_generation.obj kem.obj niederreiter.obj rng.obj +OBJECTS=bf_decoding.obj dfr_test.obj gf2x_arith_mod_xPplusOne.obj gf2x_arith.obj H_Q_matrices_generation.obj kem.obj niederreiter.obj rng.obj sort.obj CFLAGS=/nologo /I ..\..\..\common /W4 /WX diff --git a/crypto_kem/ledakemlt52/leaktime/api.h b/crypto_kem/ledakemlt52/leaktime/api.h index 11c84a4d..2943fba1 100644 --- a/crypto_kem/ledakemlt52/leaktime/api.h +++ b/crypto_kem/ledakemlt52/leaktime/api.h @@ -3,9 +3,9 @@ #include -#define PQCLEAN_LEDAKEMLT52_LEAKTIME_CRYPTO_SECRETKEYBYTES 42 +#define PQCLEAN_LEDAKEMLT52_LEAKTIME_CRYPTO_SECRETKEYBYTES 82 #define PQCLEAN_LEDAKEMLT52_LEAKTIME_CRYPTO_PUBLICKEYBYTES 19040 -#define PQCLEAN_LEDAKEMLT52_LEAKTIME_CRYPTO_CIPHERTEXTBYTES 19040 +#define PQCLEAN_LEDAKEMLT52_LEAKTIME_CRYPTO_CIPHERTEXTBYTES 19080 #define PQCLEAN_LEDAKEMLT52_LEAKTIME_CRYPTO_BYTES 64 #define PQCLEAN_LEDAKEMLT52_LEAKTIME_CRYPTO_ALGNAME "LEDAKEMLT52" diff --git a/crypto_kem/ledakemlt52/leaktime/dfr_test.c b/crypto_kem/ledakemlt52/leaktime/dfr_test.c index b93f68aa..a189ac18 100644 --- a/crypto_kem/ledakemlt52/leaktime/dfr_test.c +++ b/crypto_kem/ledakemlt52/leaktime/dfr_test.c @@ -2,70 +2,45 @@ #include "dfr_test.h" #include "gf2x_arith_mod_xPplusOne.h" #include "qc_ldpc_parameters.h" +#include "sort.h" #include -/* Tests if the current code attains the desired DFR. If that is the case, - * computes the threshold for the second iteration of the decoder and returns this values - * (max DV * M), on failure it returns 255 >> DV * M */ -uint8_t PQCLEAN_LEDAKEMLT52_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M]) { +int PQCLEAN_LEDAKEMLT52_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M], uint8_t *secondIterThreshold) { - POSITION_T LSparse_loc[N0][DV * M]; - POSITION_T rotated_column[DV * M]; - /* Gamma matrix: an N0 x N0 block circulant matrix with block size p - * gamma[a][b][c] stores the intersection of the first column of the a-th - * block of L with the c-th column of the b-th block of L. - * Gamma computation can be accelerated employing symmetry and QC properties */ - unsigned int gamma[N0][N0][P] = {{{0}}}; + POSITION_T LSparse_loc[N0][DV * M]; /* vector of N_0 sparse blocks */ + int gamma[N0][N0][P] = {{{0}}}; + int maxMut[N0], maxMutMinusOne[N0]; + int allBlockMaxSumst, allBlockMaxSumstMinusOne; unsigned int gammaHist[N0][DV * M + 1] = {{0}}; - unsigned int maxMut[N0], maxMutMinusOne[N0]; - unsigned int firstidx, secondidx, intersectionval; - unsigned int allBlockMaxSumst, allBlockMaxSumstMinusOne; - unsigned int toAdd, histIdx; - /*transpose blocks of L, we need its columns */ for (int i = 0; i < N0; i++) { for (int j = 0; j < DV * M; j++) { if (LSparse[i][j] != 0) { - LSparse_loc[i][j] = (P - LSparse[i][j]); + LSparse_loc[i][j] = (P - LSparse[i][j]) ; } } - PQCLEAN_LEDAKEMLT52_LEAKTIME_quicksort_sparse(LSparse_loc[i]); + PQCLEAN_LEDAKEMLT52_LEAKTIME_uint32_sort(LSparse_loc[i], DV * M); } + for (int i = 0; i < N0; i++ ) { for (int j = 0; j < N0; j++ ) { - for (int k = 0; k < P; k++) { - /* compute the rotated sparse column needed */ - for (int idxToRotate = 0; idxToRotate < (DV * M); idxToRotate++) { - rotated_column[idxToRotate] = (LSparse_loc[j][idxToRotate] + k) % P; + for (int k = 0; k < (DV * M); k++) { + for (int l = 0; l < (DV * M); l++) { + gamma[i][j][ (P + LSparse_loc[i][k] - LSparse_loc[j][l]) % P ]++; } - PQCLEAN_LEDAKEMLT52_LEAKTIME_quicksort_sparse(rotated_column); - /* compute the intersection amount */ - firstidx = 0, secondidx = 0; - intersectionval = 0; - while ( (firstidx < DV * M) && (secondidx < DV * M) ) { - if ( LSparse_loc[i][firstidx] == rotated_column[secondidx] ) { - intersectionval++; - firstidx++; - secondidx++; - } else if ( LSparse_loc[i][firstidx] > rotated_column[secondidx] ) { - secondidx++; - } else { /*if ( LSparse_loc[i][firstidx] < rotated_column[secondidx] ) */ - firstidx++; - } - } - gamma[i][j][k] = intersectionval; - } } } + for (int i = 0; i < N0; i++ ) { for (int j = 0; j < N0; j++ ) { gamma[i][j][0] = 0; } } + /* build histogram of values in gamma */ for (int i = 0; i < N0; i++ ) { for (int j = 0; j < N0; j++ ) { @@ -77,9 +52,9 @@ uint8_t PQCLEAN_LEDAKEMLT52_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M]) { for (int gammaBlockRowIdx = 0; gammaBlockRowIdx < N0; gammaBlockRowIdx++) { - toAdd = T_BAR - 1; + unsigned int toAdd = T_BAR - 1; maxMutMinusOne[gammaBlockRowIdx] = 0; - histIdx = DV * M; + unsigned int histIdx = DV * M; while ( (histIdx > 0) && (toAdd > 0)) { if (gammaHist[gammaBlockRowIdx][histIdx] > toAdd ) { maxMutMinusOne[gammaBlockRowIdx] += histIdx * toAdd; @@ -93,7 +68,6 @@ uint8_t PQCLEAN_LEDAKEMLT52_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M]) { maxMut[gammaBlockRowIdx] = histIdx + maxMutMinusOne[gammaBlockRowIdx]; } - /*seek max values across all gamma blocks */ allBlockMaxSumst = maxMut[0]; allBlockMaxSumstMinusOne = maxMutMinusOne[0]; @@ -106,7 +80,8 @@ uint8_t PQCLEAN_LEDAKEMLT52_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M]) { allBlockMaxSumstMinusOne; } if (DV * M > (allBlockMaxSumstMinusOne + allBlockMaxSumst)) { - return (uint8_t) allBlockMaxSumst + 1; + *secondIterThreshold = allBlockMaxSumst + 1; + return 1; } - return DFR_TEST_FAIL; + return 0; } diff --git a/crypto_kem/ledakemlt52/leaktime/dfr_test.h b/crypto_kem/ledakemlt52/leaktime/dfr_test.h index 92c49c75..c8dfd86a 100644 --- a/crypto_kem/ledakemlt52/leaktime/dfr_test.h +++ b/crypto_kem/ledakemlt52/leaktime/dfr_test.h @@ -1,8 +1,6 @@ #ifndef DFR_TEST_H #define DFR_TEST_H -#define DFR_TEST_FAIL (255) - -uint8_t PQCLEAN_LEDAKEMLT52_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M]); +int PQCLEAN_LEDAKEMLT52_LEAKTIME_DFR_test(POSITION_T LSparse[N0][DV * M], uint8_t *secondIterThreshold); #endif diff --git a/crypto_kem/ledakemlt52/leaktime/gf2x_arith_mod_xPplusOne.c b/crypto_kem/ledakemlt52/leaktime/gf2x_arith_mod_xPplusOne.c index 389e23f6..6b7ddb01 100644 --- a/crypto_kem/ledakemlt52/leaktime/gf2x_arith_mod_xPplusOne.c +++ b/crypto_kem/ledakemlt52/leaktime/gf2x_arith_mod_xPplusOne.c @@ -1,5 +1,6 @@ #include "gf2x_arith_mod_xPplusOne.h" #include "rng.h" +#include "sort.h" #include // memcpy(...), memset(...) @@ -62,81 +63,15 @@ void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_add(DIGIT Res[], const DIGIT A[], con PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_add(Res, A, B, NUM_DIGITS_GF2X_ELEMENT); } -static int partition(POSITION_T arr[], int lo, int hi) { - POSITION_T x = arr[hi]; - POSITION_T tmp; - int i = (lo - 1); - for (int j = lo; j <= hi - 1; j++) { - if (arr[j] <= x) { - i++; - tmp = arr[i]; - arr[i] = arr[j]; - arr[j] = tmp; - } - } - tmp = arr[i + 1]; - arr[i + 1] = arr[hi]; - arr[hi] = tmp; - - return i + 1; -} - -void PQCLEAN_LEDAKEMLT52_LEAKTIME_quicksort_sparse(POSITION_T Res[]) { - int stack[DV * M]; - int hi, lo, pivot, tos = -1; - stack[++tos] = 0; - stack[++tos] = (DV * M) - 1; - while (tos >= 0 ) { - hi = stack[tos--]; - lo = stack[tos--]; - pivot = partition(Res, lo, hi); - if ( (pivot - 1) > lo) { - stack[++tos] = lo; - stack[++tos] = pivot - 1; - } - if ( (pivot + 1) < hi) { - stack[++tos] = pivot + 1; - stack[++tos] = hi; - } - } -} - -static void gf2x_mod(DIGIT out[], const DIGIT in[]) { - - int i, j, posTrailingBit, maskOffset; - DIGIT mask, aux[2 * NUM_DIGITS_GF2X_ELEMENT]; - - memcpy(aux, in, 2 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - memset(out, 0x00, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - - for (i = 0; i < (2 * NUM_DIGITS_GF2X_ELEMENT) - NUM_DIGITS_GF2X_MODULUS; i += 1) { - for (j = DIGIT_SIZE_b - 1; j >= 0; j--) { - mask = ((DIGIT)0x1) << j; - if (aux[i] & mask) { - aux[i] ^= mask; - posTrailingBit = (DIGIT_SIZE_b - 1 - j) + i * DIGIT_SIZE_b + P; - maskOffset = (DIGIT_SIZE_b - 1 - (posTrailingBit % DIGIT_SIZE_b)); - mask = (DIGIT) 0x1 << maskOffset; - aux[posTrailingBit / DIGIT_SIZE_b] ^= mask; - } - } - } - - for (j = DIGIT_SIZE_b - 1; j >= MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS; j--) { - mask = ((DIGIT)0x1) << j; - if (aux[i] & mask) { - aux[i] ^= mask; - posTrailingBit = (DIGIT_SIZE_b - 1 - j) + i * DIGIT_SIZE_b + P; - maskOffset = (DIGIT_SIZE_b - 1 - (posTrailingBit % DIGIT_SIZE_b)); - mask = (DIGIT) 0x1 << maskOffset; - aux[posTrailingBit / DIGIT_SIZE_b] ^= mask; - } - } - - for (i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) { - out[NUM_DIGITS_GF2X_ELEMENT - 1 - i] = aux[2 * NUM_DIGITS_GF2X_ELEMENT - 1 - i]; - } +static void gf2x_mod(DIGIT out[], const DIGIT in[]) { + DIGIT aux[NUM_DIGITS_GF2X_ELEMENT + 1]; + memcpy(aux, in, (NUM_DIGITS_GF2X_ELEMENT + 1)*DIGIT_SIZE_B); + PQCLEAN_LEDAKEMLT52_LEAKTIME_right_bit_shift_n(NUM_DIGITS_GF2X_ELEMENT + 1, aux, + MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS); + PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_add(out, aux + 1, in + NUM_DIGITS_GF2X_ELEMENT, + NUM_DIGITS_GF2X_ELEMENT); + out[0] &= ((DIGIT)1 << MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS) - 1; } static void left_bit_shift(const int length, DIGIT in[]) { @@ -331,16 +266,13 @@ void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_mul(DIGIT Res[], const DIGIT A[], con /*PRE: the representation of the sparse coefficients is sorted in increasing order of the coefficients themselves */ -void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_mul_dense_to_sparse( - DIGIT Res[], - const DIGIT dense[], - POSITION_T sparse[], unsigned int nPos) { +void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_mul_dense_to_sparse(DIGIT Res[], const DIGIT dense[], + POSITION_T sparse[], unsigned int nPos) { DIGIT aux[2 * NUM_DIGITS_GF2X_ELEMENT] = {0x00}; DIGIT resDouble[2 * NUM_DIGITS_GF2X_ELEMENT] = {0x00}; memcpy(aux + NUM_DIGITS_GF2X_ELEMENT, dense, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - memcpy(resDouble + NUM_DIGITS_GF2X_ELEMENT, dense, - NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); + memcpy(resDouble + NUM_DIGITS_GF2X_ELEMENT, dense, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); if (sparse[0] != INVALID_POS_VALUE) { left_bit_shift_wide_n(2 * NUM_DIGITS_GF2X_ELEMENT, resDouble, sparse[0]); @@ -380,15 +312,15 @@ void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_transpose_in_place_sparse(int sizeA, POSI } -void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_mul_sparse(size_t sizeR, POSITION_T Res[], - size_t sizeA, const POSITION_T A[], - size_t sizeB, const POSITION_T B[]) { +void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_mul_sparse(int sizeR, POSITION_T Res[], + int sizeA, const POSITION_T A[], + int sizeB, const POSITION_T B[]) { /* compute all the coefficients, filling invalid positions with P*/ - size_t lastFilledPos = 0; - for (size_t i = 0 ; i < sizeA ; i++) { - for (size_t j = 0 ; j < sizeB ; j++) { - uint32_t prod = A[i] + B[j]; + int lastFilledPos = 0; + for (int i = 0 ; i < sizeA ; i++) { + for (int j = 0 ; j < sizeB ; j++) { + uint32_t prod = ((uint32_t) A[i]) + ((uint32_t) B[j]); prod = ( (prod >= P) ? prod - P : prod); if ((A[i] != INVALID_POS_VALUE) && (B[j] != INVALID_POS_VALUE)) { @@ -403,12 +335,12 @@ void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_mul_sparse(size_t sizeR, POSITION_T R Res[lastFilledPos] = INVALID_POS_VALUE; lastFilledPos++; } - PQCLEAN_LEDAKEMLT52_LEAKTIME_quicksort_sparse(Res); + PQCLEAN_LEDAKEMLT52_LEAKTIME_uint32_sort(Res, sizeR); /* eliminate duplicates */ POSITION_T lastReadPos = Res[0]; int duplicateCount; - size_t write_idx = 0; - size_t read_idx = 0; + int write_idx = 0; + int read_idx = 0; while (read_idx < sizeR && Res[read_idx] != INVALID_POS_VALUE) { lastReadPos = Res[read_idx]; read_idx++; @@ -529,9 +461,8 @@ void PQCLEAN_LEDAKEMLT52_LEAKTIME_rand_circulant_sparse_block(POSITION_T *pos_on } /* Returns random weight-t circulant block */ -void PQCLEAN_LEDAKEMLT52_LEAKTIME_rand_circulant_blocks_sequence( - DIGIT sequence[N0 * NUM_DIGITS_GF2X_ELEMENT], - AES_XOF_struct *seed_expander_ctx) { +void PQCLEAN_LEDAKEMLT52_LEAKTIME_rand_circulant_blocks_sequence(DIGIT sequence[N0 * NUM_DIGITS_GF2X_ELEMENT], + AES_XOF_struct *seed_expander_ctx) { int rndPos[NUM_ERRORS_T], duplicated, counter = 0; int p, polyIndex, exponent; @@ -561,6 +492,39 @@ void PQCLEAN_LEDAKEMLT52_LEAKTIME_rand_circulant_blocks_sequence( } + +void PQCLEAN_LEDAKEMLT52_LEAKTIME_rand_error_pos(POSITION_T errorPos[NUM_ERRORS_T], + AES_XOF_struct *seed_expander_ctx) { + + int duplicated, counter = 0; + + while (counter < NUM_ERRORS_T) { + uint32_t p = rand_range(N0 * NUM_BITS_GF2X_ELEMENT, P_BITS, seed_expander_ctx); + duplicated = 0; + for (int j = 0; j < counter; j++) if (errorPos[j] == p) { + duplicated = 1; + } + if (duplicated == 0) { + errorPos[counter] = p; + counter++; + } + } +} + +void PQCLEAN_LEDAKEMLT52_LEAKTIME_expand_error(DIGIT sequence[N0 * NUM_DIGITS_GF2X_ELEMENT], + POSITION_T errorPos[NUM_ERRORS_T]) { + + memset(sequence, 0x00, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); + + for (int j = 0; j < NUM_ERRORS_T; j++) { + int polyIndex = errorPos[j] / P; + int exponent = errorPos[j] % P; + PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_set_coeff( sequence + NUM_DIGITS_GF2X_ELEMENT * polyIndex, exponent, + ( (DIGIT) 1)); + } +} + + void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_tobytes(uint8_t *bytes, const DIGIT *poly) { size_t i, j; for (i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) { diff --git a/crypto_kem/ledakemlt52/leaktime/gf2x_arith_mod_xPplusOne.h b/crypto_kem/ledakemlt52/leaktime/gf2x_arith_mod_xPplusOne.h index 2286c55f..568fb53e 100644 --- a/crypto_kem/ledakemlt52/leaktime/gf2x_arith_mod_xPplusOne.h +++ b/crypto_kem/ledakemlt52/leaktime/gf2x_arith_mod_xPplusOne.h @@ -7,13 +7,13 @@ #include "rng.h" #define NUM_BITS_GF2X_ELEMENT (P) // 152267 -#define NUM_DIGITS_GF2X_ELEMENT ((P+DIGIT_SIZE_b-1)/DIGIT_SIZE_b) // 2380 +#define NUM_DIGITS_GF2X_ELEMENT ((P+DIGIT_SIZE_b-1)/DIGIT_SIZE_b) #define MSb_POSITION_IN_MSB_DIGIT_OF_ELEMENT ((P % DIGIT_SIZE_b) ? (P % DIGIT_SIZE_b)-1 : DIGIT_SIZE_b-1) #define NUM_BITS_GF2X_MODULUS (P+1) -#define NUM_DIGITS_GF2X_MODULUS ((P+1+DIGIT_SIZE_b-1)/DIGIT_SIZE_b) // 2380 +#define NUM_DIGITS_GF2X_MODULUS ((P+1+DIGIT_SIZE_b-1)/DIGIT_SIZE_b) #define MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS (P-DIGIT_SIZE_b*(NUM_DIGITS_GF2X_MODULUS-1)) #define INVALID_POS_VALUE (P) -#define P_BITS (18) // log_2(p) = 17.216243783 +#define P_BITS (18) void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_copy(DIGIT dest[], const DIGIT in[]); DIGIT PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_get_coeff(const DIGIT poly[], unsigned int exponent); @@ -21,17 +21,19 @@ void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_set_coeff(DIGIT poly[], unsigned int expo void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_toggle_coeff(DIGIT poly[], unsigned int exponent); int PQCLEAN_LEDAKEMLT52_LEAKTIME_population_count(DIGIT *poly); void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_add(DIGIT Res[], const DIGIT A[], const DIGIT B[]); -void PQCLEAN_LEDAKEMLT52_LEAKTIME_quicksort_sparse(POSITION_T Res[]); void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_mul(DIGIT Res[], const DIGIT A[], const DIGIT B[]); void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_transpose_in_place(DIGIT A[]); void PQCLEAN_LEDAKEMLT52_LEAKTIME_rand_circulant_sparse_block(POSITION_T *pos_ones, int countOnes, AES_XOF_struct *seed_expander_ctx); void PQCLEAN_LEDAKEMLT52_LEAKTIME_rand_circulant_blocks_sequence(DIGIT *sequence, AES_XOF_struct *seed_expander_ctx); +void PQCLEAN_LEDAKEMLT52_LEAKTIME_rand_error_pos(POSITION_T errorPos[NUM_ERRORS_T], AES_XOF_struct *seed_expander_ctx); +void PQCLEAN_LEDAKEMLT52_LEAKTIME_expand_error(DIGIT sequence[N0 * NUM_DIGITS_GF2X_ELEMENT], POSITION_T errorPos[NUM_ERRORS_T]); void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_add_sparse(int sizeR, POSITION_T Res[], int sizeA, const POSITION_T A[], int sizeB, const POSITION_T B[]); void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_transpose_in_place_sparse(int sizeA, POSITION_T A[]); int PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_inverse(DIGIT out[], const DIGIT in[]); -void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_mul_sparse(size_t sizeR, POSITION_T Res[], size_t sizeA, const POSITION_T A[], size_t sizeB, const POSITION_T B[]); +void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_mul_sparse(int sizeR, POSITION_T Res[], int sizeA, const POSITION_T A[], int sizeB, const POSITION_T B[]); void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_mul_dense_to_sparse(DIGIT Res[], const DIGIT dense[], POSITION_T sparse[], unsigned int nPos); void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_tobytes(uint8_t *bytes, const DIGIT *poly); void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_frombytes(DIGIT *poly, const uint8_t *poly_bytes); + #endif diff --git a/crypto_kem/ledakemlt52/leaktime/kem.c b/crypto_kem/ledakemlt52/leaktime/kem.c index 316d14d0..1d48e3e1 100644 --- a/crypto_kem/ledakemlt52/leaktime/kem.c +++ b/crypto_kem/ledakemlt52/leaktime/kem.c @@ -5,6 +5,7 @@ #include +/* static void pack_pk(uint8_t *pk_bytes, publicKeyNiederreiter_t *pk) { size_t i; for (i = 0; i < N0 - 1; i++) { @@ -36,57 +37,113 @@ static void pack_error(uint8_t *error_bytes, DIGIT *error_digits) { error_digits + i * NUM_DIGITS_GF2X_ELEMENT); } } +*/ -/* Generates a keypair - pk is the public key and sk is the secret key. */ -int PQCLEAN_LEDAKEMLT52_LEAKTIME_crypto_kem_keypair(unsigned char *pk, unsigned char *sk) { - AES_XOF_struct niederreiter_keys_expander; - publicKeyNiederreiter_t pk_nie; +/* IND-CCA2 Keygen */ +int PQCLEAN_LEDAKEMLT52_LEAKTIME_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { - randombytes(((privateKeyNiederreiter_t *)sk)->prng_seed, TRNG_BYTE_LENGTH); - PQCLEAN_LEDAKEMLT52_LEAKTIME_seedexpander_from_trng(&niederreiter_keys_expander, ((privateKeyNiederreiter_t *)sk)->prng_seed); - PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_keygen(&pk_nie, (privateKeyNiederreiter_t *) sk, &niederreiter_keys_expander); - - pack_pk(pk, &pk_nie); + PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_keygen((publicKeyNiederreiter_t *) pk, + (privateKeyNiederreiter_t *) sk); return 0; } -/* Encrypt - pk is the public key, ct is a key encapsulation message - (ciphertext), ss is the shared secret.*/ -int PQCLEAN_LEDAKEMLT52_LEAKTIME_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk) { - AES_XOF_struct niederreiter_encap_key_expander; - unsigned char encapsulated_key_seed[TRNG_BYTE_LENGTH]; +/* IND-CCA2 Encapsulation */ +int PQCLEAN_LEDAKEMLT52_LEAKTIME_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) { + AES_XOF_struct hashedAndTruncatedSeed_expander; + POSITION_T errorPos[NUM_ERRORS_T]; DIGIT error_vector[N0 * NUM_DIGITS_GF2X_ELEMENT]; - uint8_t error_bytes[N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B]; - DIGIT syndrome[NUM_DIGITS_GF2X_ELEMENT]; - publicKeyNiederreiter_t pk_nie; + uint8_t seed[TRNG_BYTE_LENGTH]; + uint8_t ss_input[2 * TRNG_BYTE_LENGTH] = {0}; + uint8_t hashedSeed[HASH_BYTE_LENGTH]; + uint8_t hashedAndTruncatedSeed[TRNG_BYTE_LENGTH] = {0}; + uint8_t hashedErrorVector[HASH_BYTE_LENGTH]; + uint8_t hashedAndTruncatedErrorVector[TRNG_BYTE_LENGTH] = {0}; + uint8_t maskedSeed[TRNG_BYTE_LENGTH]; - randombytes(encapsulated_key_seed, TRNG_BYTE_LENGTH); - unpack_pk(&pk_nie, pk); + randombytes(seed, TRNG_BYTE_LENGTH); + memcpy(ss_input, seed, TRNG_BYTE_LENGTH); + HASH_FUNCTION(ss, ss_input, 2 * TRNG_BYTE_LENGTH); + HASH_FUNCTION(hashedSeed, seed, TRNG_BYTE_LENGTH); - PQCLEAN_LEDAKEMLT52_LEAKTIME_seedexpander_from_trng(&niederreiter_encap_key_expander, encapsulated_key_seed); - PQCLEAN_LEDAKEMLT52_LEAKTIME_rand_circulant_blocks_sequence(error_vector, &niederreiter_encap_key_expander); - pack_error(error_bytes, error_vector); - HASH_FUNCTION(ss, error_bytes, (N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B)); - PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_encrypt(syndrome, &pk_nie, error_vector); + memcpy(hashedAndTruncatedSeed, hashedSeed, TRNG_BYTE_LENGTH); - pack_ct(ct, syndrome); + memset(&hashedAndTruncatedSeed_expander, 0x00, sizeof(AES_XOF_struct)); + PQCLEAN_LEDAKEMLT52_LEAKTIME_seedexpander_from_trng(&hashedAndTruncatedSeed_expander, hashedAndTruncatedSeed); + PQCLEAN_LEDAKEMLT52_LEAKTIME_rand_error_pos(errorPos, &hashedAndTruncatedSeed_expander); + PQCLEAN_LEDAKEMLT52_LEAKTIME_expand_error(error_vector, errorPos); + HASH_FUNCTION(hashedErrorVector, (const uint8_t *) error_vector, (N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B)); + + memcpy(hashedAndTruncatedErrorVector, hashedErrorVector, TRNG_BYTE_LENGTH); + + for (int i = 0; i < TRNG_BYTE_LENGTH; ++i) { + maskedSeed[i] = seed[i] ^ hashedAndTruncatedErrorVector[i]; + } + + PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_encrypt((DIGIT *) ct, (const publicKeyNiederreiter_t *)pk, error_vector); + + memcpy(ct + (NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B), maskedSeed, TRNG_BYTE_LENGTH); return 0; } -/* Decrypt - ct is a key encapsulation message (ciphertext), sk is the private - key, ss is the shared secret */ -int PQCLEAN_LEDAKEMLT52_LEAKTIME_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk) { +/* INDCCA2 Decapsulation */ +int PQCLEAN_LEDAKEMLT52_LEAKTIME_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) { + AES_XOF_struct hashedAndTruncatedSeed_expander; + POSITION_T reconstructed_errorPos[NUM_ERRORS_T]; + DIGIT reconstructed_error_vector[N0 * NUM_DIGITS_GF2X_ELEMENT]; DIGIT decoded_error_vector[N0 * NUM_DIGITS_GF2X_ELEMENT]; - uint8_t decoded_error_bytes[N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B]; - DIGIT syndrome[NUM_DIGITS_GF2X_ELEMENT]; + uint8_t hashedErrorVector[HASH_BYTE_LENGTH]; + uint8_t hashedAndTruncatedErrorVector[TRNG_BYTE_LENGTH] = {0}; + uint8_t decoded_seed[TRNG_BYTE_LENGTH]; + uint8_t hashed_decoded_seed[HASH_BYTE_LENGTH]; + uint8_t hashedAndTruncated_decoded_seed[TRNG_BYTE_LENGTH] = {0}; + uint8_t ss_input[2 * TRNG_BYTE_LENGTH], tail[TRNG_BYTE_LENGTH] = {0}; - unpack_ct(syndrome, ct); - PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_decrypt(decoded_error_vector, (privateKeyNiederreiter_t *)sk, syndrome); - pack_error(decoded_error_bytes, decoded_error_vector); - HASH_FUNCTION(ss, decoded_error_bytes, (N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B)); + int decode_ok = PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_decrypt(decoded_error_vector, + (const privateKeyNiederreiter_t *)sk, + (DIGIT *)ct); + + HASH_FUNCTION(hashedErrorVector, + (const uint8_t *) decoded_error_vector, + (N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B)); + + memcpy(hashedAndTruncatedErrorVector, hashedErrorVector, TRNG_BYTE_LENGTH); + + for (int i = 0; i < TRNG_BYTE_LENGTH; ++i) { + decoded_seed[i] = ct[(NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B) + i] ^ + hashedAndTruncatedErrorVector[i]; + } + + HASH_FUNCTION(hashed_decoded_seed, decoded_seed, TRNG_BYTE_LENGTH); + + memcpy(hashedAndTruncated_decoded_seed, hashed_decoded_seed, TRNG_BYTE_LENGTH); + + memset(&hashedAndTruncatedSeed_expander, 0x00, sizeof(AES_XOF_struct)); + PQCLEAN_LEDAKEMLT52_LEAKTIME_seedexpander_from_trng(&hashedAndTruncatedSeed_expander, + hashed_decoded_seed); + + PQCLEAN_LEDAKEMLT52_LEAKTIME_rand_error_pos(reconstructed_errorPos, &hashedAndTruncatedSeed_expander); + + PQCLEAN_LEDAKEMLT52_LEAKTIME_expand_error(reconstructed_error_vector, reconstructed_errorPos); + + int equal = (0 == memcmp((const uint8_t *) decoded_error_vector, + (const uint8_t *) reconstructed_error_vector, + N0 * NUM_DIGITS_GF2X_ELEMENT)); + // equal == 1, if the reconstructed error vector match !!! + + int decryptOk = (decode_ok == 1 && equal == 1); + + memcpy(ss_input, decoded_seed, TRNG_BYTE_LENGTH); + + if (decryptOk == 1) { + memcpy(ss_input + sizeof(decoded_seed), tail, TRNG_BYTE_LENGTH); + } else { // decryption failure + memcpy(ss_input + sizeof(decoded_seed), ((const privateKeyNiederreiter_t *)sk)->decryption_failure_secret, TRNG_BYTE_LENGTH); + } + + HASH_FUNCTION(ss, ss_input, 2 * TRNG_BYTE_LENGTH); return 0; } diff --git a/crypto_kem/ledakemlt52/leaktime/niederreiter.c b/crypto_kem/ledakemlt52/leaktime/niederreiter.c index d8a70262..648132d7 100644 --- a/crypto_kem/ledakemlt52/leaktime/niederreiter.c +++ b/crypto_kem/ledakemlt52/leaktime/niederreiter.c @@ -4,27 +4,32 @@ #include "gf2x_arith_mod_xPplusOne.h" #include "niederreiter.h" #include "qc_ldpc_parameters.h" +#include "randombytes.h" #include "rng.h" #include -void PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_keygen(publicKeyNiederreiter_t *pk, privateKeyNiederreiter_t *sk, AES_XOF_struct *keys_expander) { +void PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_keygen(publicKeyNiederreiter_t *pk, privateKeyNiederreiter_t *sk) { - POSITION_T HPosOnes[N0][DV]; // sequence of N0 circ block matrices (p x p): Hi - POSITION_T HtrPosOnes[N0][DV]; // Sparse tranposed circulant H - POSITION_T QPosOnes[N0][M]; // Sparse Q, Each row contains the position of the ones of all the blocks of a row of Q as exponent+P*block_position + AES_XOF_struct keys_expander; + POSITION_T HPosOnes[N0][DV]; + POSITION_T QPosOnes[N0][M]; POSITION_T LPosOnes[N0][DV * M]; POSITION_T auxPosOnes[DV * M]; unsigned char processedQOnes[N0]; - DIGIT Ln0dense[NUM_DIGITS_GF2X_ELEMENT]; - DIGIT Ln0Inv[NUM_DIGITS_GF2X_ELEMENT]; - int is_L_full = 0; - uint8_t threshold = (DV * M) / 2 + 1; // threshold for round 2 - sk->rejections = (int8_t) 0; + DIGIT Ln0dense[NUM_DIGITS_GF2X_ELEMENT] = {0}; + DIGIT Ln0Inv[NUM_DIGITS_GF2X_ELEMENT] = {0}; + int is_L_full; + int isDFRok; + memset(&keys_expander, 0x00, sizeof(AES_XOF_struct)); + randombytes(sk->prng_seed, TRNG_BYTE_LENGTH); + PQCLEAN_LEDAKEMLT52_LEAKTIME_seedexpander_from_trng(&keys_expander, sk->prng_seed); + + sk->rejections = (uint8_t) 0; do { - PQCLEAN_LEDAKEMLT52_LEAKTIME_generateHPosOnes_HtrPosOnes(HPosOnes, HtrPosOnes, keys_expander); - PQCLEAN_LEDAKEMLT52_LEAKTIME_generateQsparse(QPosOnes, keys_expander); + PQCLEAN_LEDAKEMLT52_LEAKTIME_generateHPosOnes(HPosOnes, &keys_expander); + PQCLEAN_LEDAKEMLT52_LEAKTIME_generateQPosOnes(QPosOnes, &keys_expander); for (int i = 0; i < N0; i++) { for (int j = 0; j < DV * M; j++) { LPosOnes[i][j] = INVALID_POS_VALUE; @@ -49,20 +54,21 @@ void PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_keygen(publicKeyNiederreiter_t *p } sk->rejections = sk->rejections + 1; if (is_L_full) { - threshold = PQCLEAN_LEDAKEMLT52_LEAKTIME_DFR_test(LPosOnes); + isDFRok = PQCLEAN_LEDAKEMLT52_LEAKTIME_DFR_test(LPosOnes, &(sk->secondIterThreshold)); } - } while (!is_L_full || threshold == DFR_TEST_FAIL); + } while (!is_L_full || !isDFRok); sk->rejections = sk->rejections - 1; - sk->threshold = threshold; - memset(Ln0dense, 0x00, sizeof(Ln0dense)); + PQCLEAN_LEDAKEMLT52_LEAKTIME_seedexpander(&keys_expander, + sk->decryption_failure_secret, + (unsigned long)TRNG_BYTE_LENGTH); + for (int j = 0; j < DV * M; j++) { if (LPosOnes[N0 - 1][j] != INVALID_POS_VALUE) { PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_set_coeff(Ln0dense, LPosOnes[N0 - 1][j], 1); } } - memset(Ln0Inv, 0x00, sizeof(Ln0Inv)); PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_inverse(Ln0Inv, Ln0dense); for (int i = 0; i < N0 - 1; i++) { PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_mul_dense_to_sparse(pk->Mtr + i * NUM_DIGITS_GF2X_ELEMENT, @@ -76,45 +82,43 @@ void PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_keygen(publicKeyNiederreiter_t *p } } +void PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_encrypt(DIGIT syndrome[], + const publicKeyNiederreiter_t *pk, + const DIGIT err[]) { -void PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_encrypt(DIGIT *syndrome, const publicKeyNiederreiter_t *pk, const DIGIT *err) { - int i; DIGIT saux[NUM_DIGITS_GF2X_ELEMENT]; memset(syndrome, 0x00, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - for (i = 0; i < N0 - 1; i++) { + for (size_t i = 0; i < N0 - 1; i++) { PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_mul(saux, pk->Mtr + i * NUM_DIGITS_GF2X_ELEMENT, err + i * NUM_DIGITS_GF2X_ELEMENT); PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_add(syndrome, syndrome, saux); + } PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_add(syndrome, syndrome, err + (N0 - 1)*NUM_DIGITS_GF2X_ELEMENT); } - int PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_decrypt(DIGIT *err, const privateKeyNiederreiter_t *sk, const DIGIT *syndrome) { AES_XOF_struct niederreiter_decrypt_expander; POSITION_T HPosOnes[N0][DV]; - POSITION_T HtrPosOnes[N0][DV]; POSITION_T QPosOnes[N0][M]; - POSITION_T QtrPosOnes[N0][M]; - POSITION_T auxPosOnes[DV * M]; POSITION_T LPosOnes[N0][DV * M]; + POSITION_T auxPosOnes[DV * M]; + POSITION_T HtrPosOnes[N0][DV]; + POSITION_T QtrPosOnes[N0][M]; POSITION_T auxSparse[DV * M]; POSITION_T Ln0trSparse[DV * M]; - unsigned char processedQOnes[N0]; - unsigned transposed_ones_idx[N0]; + DIGIT err_computed[N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B] = {0}; DIGIT privateSyndrome[NUM_DIGITS_GF2X_ELEMENT]; - DIGIT mockup_error_vector[N0 * NUM_DIGITS_GF2X_ELEMENT]; + unsigned char processedQOnes[N0]; int rejections = sk->rejections; - int currQoneIdx, endQblockIdx; - int decryptOk, err_weight; PQCLEAN_LEDAKEMLT52_LEAKTIME_seedexpander_from_trng(&niederreiter_decrypt_expander, sk->prng_seed); - do { - PQCLEAN_LEDAKEMLT52_LEAKTIME_generateHPosOnes_HtrPosOnes(HPosOnes, HtrPosOnes, &niederreiter_decrypt_expander); - PQCLEAN_LEDAKEMLT52_LEAKTIME_generateQsparse(QPosOnes, &niederreiter_decrypt_expander); + PQCLEAN_LEDAKEMLT52_LEAKTIME_generateHPosOnes(HPosOnes, &niederreiter_decrypt_expander); + PQCLEAN_LEDAKEMLT52_LEAKTIME_generateQPosOnes(QPosOnes, &niederreiter_decrypt_expander); + for (int i = 0; i < N0; i++) { for (int j = 0; j < DV * M; j++) { LPosOnes[i][j] = INVALID_POS_VALUE; @@ -136,19 +140,8 @@ int PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_decrypt(DIGIT *err, const privateK rejections--; } while (rejections >= 0); - memset(transposed_ones_idx, 0x00, sizeof(transposed_ones_idx)); - for (unsigned source_row_idx = 0; source_row_idx < N0 ; source_row_idx++) { - currQoneIdx = 0; // position in the column of QtrPosOnes[][...] - endQblockIdx = 0; - for (int blockIdx = 0; blockIdx < N0; blockIdx++) { - endQblockIdx += qBlockWeights[source_row_idx][blockIdx]; - for (; currQoneIdx < endQblockIdx; currQoneIdx++) { - QtrPosOnes[blockIdx][transposed_ones_idx[blockIdx]] = (P - - QPosOnes[source_row_idx][currQoneIdx]) % P; - transposed_ones_idx[blockIdx]++; - } - } - } + PQCLEAN_LEDAKEMLT52_LEAKTIME_transposeHPosOnes(HtrPosOnes, HPosOnes); + PQCLEAN_LEDAKEMLT52_LEAKTIME_transposeQPosOnes(QtrPosOnes, QPosOnes); for (int i = 0; i < DV * M; i++) { Ln0trSparse[i] = INVALID_POS_VALUE; @@ -158,34 +151,41 @@ int PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_decrypt(DIGIT *err, const privateK for (int i = 0; i < N0; i++) { PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_mul_sparse(DV * M, auxSparse, DV, HPosOnes[i], - qBlockWeights[i][N0 - 1], &QPosOnes[i][ M - qBlockWeights[i][N0 - 1]]); + qBlockWeights[i][N0 - 1], &QPosOnes[i][ M - qBlockWeights[i][N0 - 1] ] ); PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_add_sparse(DV * M, Ln0trSparse, DV * M, Ln0trSparse, DV * M, auxSparse); } - PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_transpose_in_place_sparse(DV * M, Ln0trSparse); - PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_mul_dense_to_sparse(privateSyndrome, syndrome, Ln0trSparse, DV * M); - /* prepare mockup error vector in case a decoding failure occurs */ - memset(mockup_error_vector, 0x00, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - memcpy(mockup_error_vector, syndrome, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - PQCLEAN_LEDAKEMLT52_LEAKTIME_seedexpander(&niederreiter_decrypt_expander, - ((unsigned char *) mockup_error_vector) + (NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B), - TRNG_BYTE_LENGTH); + PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_mul_dense_to_sparse(privateSyndrome, + syndrome, + Ln0trSparse, + DV * M); - memset(err, 0x00, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); - decryptOk = PQCLEAN_LEDAKEMLT52_LEAKTIME_bf_decoding(err, (const POSITION_T (*)[DV]) HtrPosOnes, - (const POSITION_T (*)[M]) QtrPosOnes, privateSyndrome, sk->threshold); + int decryptOk = 0; + decryptOk = PQCLEAN_LEDAKEMLT52_LEAKTIME_bf_decoding(err_computed, + (const POSITION_T (*)[DV]) HtrPosOnes, + (const POSITION_T (*)[M]) QtrPosOnes, + privateSyndrome, sk->secondIterThreshold); - err_weight = 0; + int err_weight = 0; for (int i = 0 ; i < N0; i++) { - err_weight += PQCLEAN_LEDAKEMLT52_LEAKTIME_population_count(err + (NUM_DIGITS_GF2X_ELEMENT * i)); + err_weight += PQCLEAN_LEDAKEMLT52_LEAKTIME_population_count(err_computed + (NUM_DIGITS_GF2X_ELEMENT * i)); } decryptOk = decryptOk && (err_weight == NUM_ERRORS_T); - if (!decryptOk) { // TODO: not constant time, replace with cmov? - memcpy(err, mockup_error_vector, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); + /* prepare mockup error vector in case a decoding failure occurs */ + DIGIT err_mockup[N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B]; + memcpy(err_mockup, syndrome, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); + memcpy(err_mockup + NUM_DIGITS_GF2X_ELEMENT, sk->decryption_failure_secret, TRNG_BYTE_LENGTH); + memset(((unsigned char *) err_mockup) + (NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B) + TRNG_BYTE_LENGTH, 0x00, + (N0 - 1)*NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B - TRNG_BYTE_LENGTH); + + if (!decryptOk) { + memcpy(err, err_mockup, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); + } else { + memcpy(err, err_computed, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B); } return decryptOk; diff --git a/crypto_kem/ledakemlt52/leaktime/niederreiter.h b/crypto_kem/ledakemlt52/leaktime/niederreiter.h index a74e3169..cbd51c39 100644 --- a/crypto_kem/ledakemlt52/leaktime/niederreiter.h +++ b/crypto_kem/ledakemlt52/leaktime/niederreiter.h @@ -6,24 +6,19 @@ #include "rng.h" typedef struct { - /* raw entropy extracted from TRNG, will be deterministically expanded into - * H and Q during decryption */ unsigned char prng_seed[TRNG_BYTE_LENGTH]; - int8_t rejections; - uint8_t threshold; // for round 2 + uint8_t rejections; + uint8_t secondIterThreshold; + uint8_t decryption_failure_secret[TRNG_BYTE_LENGTH]; } privateKeyNiederreiter_t; typedef struct { DIGIT Mtr[(N0 - 1)*NUM_DIGITS_GF2X_ELEMENT]; - // Dense representation of the matrix M=Ln0*L, - // An array including a sequence of (N0-1) gf2x elements; - // each gf2x element is stored as a binary polynomial(mod x^P+1) - // with P coefficients. } publicKeyNiederreiter_t; -void PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_keygen(publicKeyNiederreiter_t *pk, privateKeyNiederreiter_t *sk, AES_XOF_struct *keys_expander); -void PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_encrypt(DIGIT syndrome[], const publicKeyNiederreiter_t *pk, const DIGIT *err); + +void PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_keygen(publicKeyNiederreiter_t *pk, privateKeyNiederreiter_t *sk); +void PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_encrypt(DIGIT syndrome[], const publicKeyNiederreiter_t *pk, const DIGIT err[]); int PQCLEAN_LEDAKEMLT52_LEAKTIME_niederreiter_decrypt(DIGIT *err, const privateKeyNiederreiter_t *sk, const DIGIT *syndrome); - #endif diff --git a/crypto_kem/ledakemlt52/leaktime/sort.c b/crypto_kem/ledakemlt52/leaktime/sort.c new file mode 100644 index 00000000..b677700d --- /dev/null +++ b/crypto_kem/ledakemlt52/leaktime/sort.c @@ -0,0 +1,87 @@ +#include "sort.h" + +/* + Constant-time uint32_t sorting by Daniel J. Bernstein + Source: https://sorting.cr.yp.to +*/ + +static void int32_sort(int32 *x, size_t n) { + size_t top, p, q, r, i, j; + + if (n < 2) { + return; + } + top = 1; + while (top < n - top) { + top += top; + } + + for (p = top; p >= 1; p >>= 1) { + i = 0; + while (i + 2 * p <= n) { + for (j = i; j < i + p; ++j) { + int32_MINMAX(x[j], x[j + p]); + } + i += 2 * p; + } + for (j = i; j < n - p; ++j) { + int32_MINMAX(x[j], x[j + p]); + } + + i = 0; + j = 0; + for (q = top; q > p; q >>= 1) { + if (j != i) { + for (;;) { + if (j == n - q) { + goto done; + } + int32 a = x[j + p]; + for (r = q; r > p; r >>= 1) { + int32_MINMAX(a, x[j + r]); + } + x[j + p] = a; + ++j; + if (j == i + p) { + i += 2 * p; + break; + } + } + } + while (i + p <= n - q) { + for (j = i; j < i + p; ++j) { + int32 a = x[j + p]; + for (r = q; r > p; r >>= 1) { + int32_MINMAX(a, x[j + r]); + } + x[j + p] = a; + } + i += 2 * p; + } + /* now i + p > n - q */ + j = i; + while (j < n - q) { + int32 a = x[j + p]; + for (r = q; r > p; r >>= 1) { + int32_MINMAX(a, x[j + r]); + } + x[j + p] = a; + ++j; + } +done: + ; + } + } +} + +/* can save time by integrating xor loops with int32_sort */ +void PQCLEAN_LEDAKEMLT52_LEAKTIME_uint32_sort(uint32_t *x, size_t n) { + size_t j; + for (j = 0; j < n; ++j) { + x[j] ^= 0x80000000; + } + int32_sort((int32_t *) x, n); + for (j = 0; j < n; ++j) { + x[j] ^= 0x80000000; + } +} diff --git a/crypto_kem/ledakemlt52/leaktime/sort.h b/crypto_kem/ledakemlt52/leaktime/sort.h new file mode 100644 index 00000000..db8c257f --- /dev/null +++ b/crypto_kem/ledakemlt52/leaktime/sort.h @@ -0,0 +1,22 @@ +#ifndef SORT_H +#define SORT_H + +#include +#include + +#define int32 int32_t + +#define int32_MINMAX(a,b) \ + do { \ + int32 ab = (b) ^ (a); \ + int32 c = (b) - (a); \ + c ^= ab & (c ^ (b)); \ + c >>= 31; \ + c &= ab; \ + (a) ^= c; \ + (b) ^= c; \ + } while(0) + +void PQCLEAN_LEDAKEMLT52_LEAKTIME_uint32_sort(uint32_t *x, size_t n); + +#endif diff --git a/test/Makefile b/test/Makefile index 188ae827..5f0def38 100644 --- a/test/Makefile +++ b/test/Makefile @@ -2,8 +2,8 @@ # override as desired TYPE=kem -SCHEME=kyber768 -IMPLEMENTATION=clean +SCHEME=ledakemlt12 +IMPLEMENTATION=leaktime SCHEME_DIR="../crypto_$(TYPE)/$(SCHEME)/$(IMPLEMENTATION)" SCHEME_UPPERCASE=$(shell echo $(SCHEME) | tr a-z A-Z | sed 's/-//g')